Make the platform list shared across users; keep games private
Platforms no longer have a user_id: there's one global list, unique by name, that every authenticated user reads from and writes to. Games are unchanged - still private per user, still referencing platform_id. - Migration: dropped platform.user_id and its FK, UNIQUE(user_id, name) -> UNIQUE(name), index on change_seq alone instead of (user_id, change_seq). Amended the one init migration in place rather than stacking a second one, since nothing is deployed yet. - db/query.sql: platform queries no longer take a user_id parameter. DeletePlatform's NOT EXISTS guard already checked games from any user (it never filtered the subquery by user_id), so deleting a shared platform is correctly blocked by any user's games on it, not just the deleter's. - routes.go: platform handlers still require auth (the list isn't public to anonymous requests) but no longer scope by user. - Tests: updated the mocks for the new signatures, added TestListPlatformsIsSharedAcrossUsers. Verified against a real Postgres: user A creates "PC", user B sees it immediately, both can add games against it, each only sees their own games, deleting the platform is blocked while either user has a game on it, and the name stays globally unique. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5072919b61
commit
7fbd403d30
8 files changed
+93
-86
No files matched your search
@@ -28,17 +28,18 @@ CREATE TABLE sessions (
|
||||
|
||||
CREATE INDEX idx_sessions_user_id ON sessions(user_id);
|
||||
|
||||
-- Platforms are shared: every user picks from and adds to the same list,
|
||||
-- unlike games, which are private per user_id.
|
||||
CREATE TABLE platform (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
name text NOT NULL,
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
deleted_at timestamptz,
|
||||
change_seq bigint NOT NULL DEFAULT nextval('change_seq_seq'),
|
||||
UNIQUE (user_id, name)
|
||||
UNIQUE (name)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_platform_user_change_seq ON platform(user_id, change_seq);
|
||||
CREATE INDEX idx_platform_change_seq ON platform(change_seq);
|
||||
|
||||
CREATE TABLE game (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
||||
+10
-9
@@ -40,37 +40,38 @@ WHERE token_hash = $1;
|
||||
|
||||
-- name: CreatePlatform :one
|
||||
INSERT INTO platform (
|
||||
user_id, name
|
||||
name
|
||||
) VALUES (
|
||||
$1, $2
|
||||
$1
|
||||
)
|
||||
RETURNING id, name;
|
||||
|
||||
-- name: GetPlatform :one
|
||||
SELECT id, name
|
||||
FROM platform
|
||||
WHERE id = $1 AND user_id = $2 AND deleted_at IS NULL;
|
||||
WHERE id = $1 AND deleted_at IS NULL;
|
||||
|
||||
-- name: ListPlatforms :many
|
||||
SELECT id, name
|
||||
FROM platform
|
||||
WHERE user_id = $1 AND deleted_at IS NULL
|
||||
WHERE deleted_at IS NULL
|
||||
ORDER BY name;
|
||||
|
||||
-- name: UpdatePlatform :one
|
||||
UPDATE platform
|
||||
SET name = $3
|
||||
WHERE id = $1 AND user_id = $2 AND deleted_at IS NULL
|
||||
SET name = $2
|
||||
WHERE id = $1 AND deleted_at IS NULL
|
||||
RETURNING id, name;
|
||||
|
||||
-- name: DeletePlatform :execrows
|
||||
-- Soft delete, so the FK on game.platform_id is never touched and never
|
||||
-- blocks this on its own; the NOT EXISTS guard is what stops a platform
|
||||
-- that still has active games from being deleted. Call GetPlatform first to
|
||||
-- tell "not found" apart from "blocked by games" when this affects 0 rows.
|
||||
-- that still has active games - from any user, since the list is shared -
|
||||
-- from being deleted. Call GetPlatform first to tell "not found" apart from
|
||||
-- "blocked by games" when this affects 0 rows.
|
||||
UPDATE platform
|
||||
SET deleted_at = now()
|
||||
WHERE platform.id = $1 AND platform.user_id = $2 AND platform.deleted_at IS NULL
|
||||
WHERE platform.id = $1 AND platform.deleted_at IS NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM game
|
||||
WHERE game.platform_id = platform.id AND game.deleted_at IS NULL
|
||||
|
||||
Reference in new issue
Block a user