11 Commits
Author SHA1 Message Date
jschoubben eab696ce42 Merge pull request 'fix(db): grant app user permissions on players and games tables' (#5) from fix/db-permissions into main 2026-07-09 19:48:53 +02:00
Warre (hal-developer) 1e7772ad29 fix(db): grant app user permissions on players and games tables
PostgreSQL 15+ revokes CREATE from non-superusers in public schema by default.
Child 1's migration created the tables as postgres superuser, leaving the
txt_game_scores app user with no privileges — causing "permission denied"
on every request in production.

Adds a numbered provision migration to GRANT SELECT/INSERT/UPDATE on players
and games, plus USAGE/SELECT on games_id_seq, to the app user.

Task: d1c49d59-57bd-4eba-9e22-f25a04157ad4
2026-07-09 19:46:14 +02:00
jschoubben 8c3c95916d Merge pull request 'feat(scores): persist scores in Postgres, add scoreboard UI' (#4) from feat/score-persistence into main 2026-07-09 19:37:32 +02:00
Warre (hal-developer) f39f9f19fe feat(scores): persist scores in Postgres, add scoreboard UI
Introduces a long-lived `pid` cookie (365 d) as persistent player identity
alongside the existing 24 h `sid` session cookie.

On first visit, a player row is upserted into `players`. On round end, a
transaction inserts into `games` and updates aggregates (best_attempts on wins
only, streak counters, last_played_at). DB failures are caught and logged —
the game keeps serving.

Adds a 3×2 'Your best' stats panel and a public top-10 scoreboard (fewest
best_attempts ASC, earliest last_played_at as tie-breaker; identifiers
truncated to 8 chars; current player highlighted).

Infrastructure: adds `pg` dependency, Dockerfile now installs npm deps before
copying server.mjs, docker-compose forwards all provisioned TXT_GAME_DB_*
vars and joins the postgres_postgres network for container-to-container reach.

Task: d1c49d59-57bd-4eba-9e22-f25a04157ad4
2026-07-09 19:27:58 +02:00
jschoubben 4a6ae87ed3 Merge pull request 'feat(db): provision Postgres and add score schema migration' (#3) from feat/postgres-provision into main 2026-07-09 18:55:32 +02:00
jschoubben cbec696c59 feat(db): provision Postgres and add score schema migration
Wire in the txt_game_scores database provision and create the
players/games tables via a provision-scoped migration so Child 2
can implement the server-side score persistence.

- module.yml: requires postgres database (txt_game_scores) with
  env_map for host/port/user/password/name; empty env keys added
  so env-sync populates them after provisioning
- migrations/package.json: ESM, pg + typescript devdeps
- migrations/provision/postgres/000-init-scores.ts: creates
  players and games tables with idempotent IF NOT EXISTS guards
  and two supporting indexes (scoreboard sort, history lookup)

Server code, Dockerfile, and docker-compose.yml are unchanged —
server integration is deferred to the follow-on child task.

Task: 3dab55e3-9792-47a0-a4a6-ba7757517314
2026-07-09 18:51:18 +02:00
jschoubben 0139527147 Merge pull request 'fix(server): respond to HEAD / so health checks return 200' (#2) from fix/head-method into main 2026-07-09 17:55:05 +02:00
jschoubben 35c7c31f2e fix(server): respond to HEAD / so health checks return 200
curl -sSI and Traefik probes use HEAD; the server only handled GET,
causing HEAD / to fall through to the 404 handler.
2026-07-09 17:52:19 +02:00
jschoubben 026eebae3d Merge pull request 'fix(deploy): use registry image and correct docker list format' (#1) from fix/docker-build-format into main 2026-07-09 16:32:13 +02:00
jschoubben f385daf09c fix(deploy): use registry image and correct docker list format
- Fix module.yml docker: section from object to list format so
  the builder actually builds and pushes the image
- Replace build: . with registry image reference in compose
- Fix certresolver name from letsencrypt to le
- Add explicit container_name, remove unused default network
2026-07-09 16:26:21 +02:00
HAL 17adb00cc3 feat(txt-game): initial module scaffold
Number guessing game (1-100, 7 attempts) as a HAL custom-app module.
Serves HTML form UI with per-session state via cookie, no npm deps.
Traefik labels for txt.${DOMAIN} on websecure with letsencrypt TLS.
2026-07-08 17:27:27 +02:00