SansanandClaude Sonnet 5 384c4a7217 Restrict platform-list edits to admins
Anyone authenticated can still read the shared platform list, but only an
admin may add, rename or delete from it.

- users.is_admin boolean, defaulting to false. The very first account ever
  registered becomes an admin automatically (CreateUser's INSERT uses
  NOT EXISTS (SELECT 1 FROM users) for is_admin), so there's always at
  least one without manual setup; promoting anyone beyond that is a manual
  UPDATE for now (documented in the migration's comment on the column).
- GetSessionAndUser, GetUserByEmail and GetUserByID now also select
  is_admin, and it flows through to model.User (and so to
  /api/auth/{register,login,me}'s response) and to the auth middleware's
  authedUser.
- New requireAdminMiddleware + addAdminAuth, layered on top of the existing
  auth middleware. Wired onto create/update/delete-platform; list/get stay
  on plain addAuth, since reading the list only requires being logged in.

Verified end to end: the first registered user comes back is_admin:true,
the second false; the non-admin gets 403 on create/update/delete-platform
but 200 on list; the admin can do all of it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-03 11:39:21 +02:00
2026-10-03 11:39:21 +02:00

Completed

A tracker for a video game collection: what you own, which platform it's on, your score for it, and whether (and when) you finished it.

Status

Each account has its own private collection. The API is usable; there's no GUI yet beyond two read-only clients (see below).

Running it

just docker-up    # starts Postgres and the API on :8080
just docker-down  # stops them

Or against a Postgres you already have running locally:

export DATABASE_URL="postgres://postgres:password@localhost:5432/gamedb?sslmode=disable"
just run-api

The API creates its database and runs migrations on startup if needed. Browse http://localhost:8080/docs for the generated API docs.

Using the API

# Register (also logs you in)
curl -X POST localhost:8080/api/auth/register -H 'Content-Type: application/json' \
  -d '{"email":"you@example.com","password":"a long password","name":"You"}'
# -> {"token": "...", "user": {...}}

TOKEN=... # the token from above

curl -X POST localhost:8080/api/platforms -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' -d '{"name":"PC"}'

curl localhost:8080/api/games -H "Authorization: Bearer $TOKEN"

A browser-based client can skip the Authorization header: register/login also set an httpOnly session cookie.

Other clients

  • just run-tui — a read-only terminal viewer of /games (no login yet)
  • just run-gui — a read-only raylib desktop viewer of /games (no login yet; planned to move to Fyne)

Development

just test   # go test ./...
just sqlc   # regenerate internal/db after changing db/query.sql or a migration

Schema changes go in db/migrations as a new <timestamp>_<name>.up.sql / .down.sql pair; sqlc.yaml reads the schema from that directory directly, so there's no separate schema file to keep in sync.

S
Description
No description provided
Readme
229 KiB
0 Stars 1 Watchers 0 Forks
v0.0.3
Latest
2026-10-03 20:24:31 +02:00
Languages
TypeScript 47.1%
Go 46.3%
HTML 2%
PLpgSQL 1.9%
Dockerfile 0.9%
Other 1.8%