Introduces a long-lived pid cookie (365 d, HttpOnly, SameSite=Strict) for persistent player identity alongside the existing 24 h sid session cookie
On first visit, player row is upserted into players (idempotent). On round end, a transaction inserts into games and updates aggregates: best_attempts (wins only), streaks, last_played_at
DB failures are caught, logged, and swallowed — the game keeps serving (degraded mode when env vars are missing)
Adds “Your best” stats panel (played / won / lost / best attempts / streak / best streak)
Adds public top-10 scoreboard ordered by fewest best_attempts ASC, tie-broken by earliest last_played_at; identifiers truncated to 8 chars; current player row highlighted
Infrastructure changes
Added package.json (pg ^8.13.3, "type":"module") and committed package-lock.json
Dockerfile now copies package.json + lockfile and runs npm ci --omit=dev before copying server.mjs
docker-compose.yml forwards all provisioned TXT_GAME_DB_* env vars into the container and joins the postgres_postgres network for container-to-container postgres access
module.yml version unchanged (builder owns versioning)
Test plan
Pipeline builds successfully (check after merge)
https://txt.zurag.be serves the updated UI with stats panel + scoreboard sections
Play a winning game → “Your best” shows attempts; scoreboard shows row with 8-char truncated ID
Play a losing game → games_lost increments, streak resets to 0
Restart container via HAL docker_restart on ace → reload same incognito window → values unchanged (DB persistence verified)
Task: d1c49d59-57bd-4eba-9e22-f25a04157ad4
Blocked by (completed): 3dab55e3-9792-47a0-a4a6-ba7757517314 (schema + provisioning)
## Summary
- Introduces a long-lived `pid` cookie (365 d, HttpOnly, SameSite=Strict) for persistent player identity alongside the existing 24 h `sid` session cookie
- On first visit, player row is upserted into `players` (idempotent). On round end, a transaction inserts into `games` and updates aggregates: `best_attempts` (wins only), streaks, `last_played_at`
- DB failures are caught, logged, and swallowed — the game keeps serving (degraded mode when env vars are missing)
- Adds **"Your best"** stats panel (played / won / lost / best attempts / streak / best streak)
- Adds **public top-10 scoreboard** ordered by fewest `best_attempts ASC`, tie-broken by earliest `last_played_at`; identifiers truncated to 8 chars; current player row highlighted
## Infrastructure changes
- Added `package.json` (`pg ^8.13.3`, `"type":"module"`) and committed `package-lock.json`
- `Dockerfile` now copies `package.json` + lockfile and runs `npm ci --omit=dev` before copying `server.mjs`
- `docker-compose.yml` forwards all provisioned `TXT_GAME_DB_*` env vars into the container and joins the `postgres_postgres` network for container-to-container postgres access
- `module.yml` version unchanged (builder owns versioning)
## Test plan
- [ ] Pipeline builds successfully (check after merge)
- [ ] https://txt.zurag.be serves the updated UI with stats panel + scoreboard sections
- [ ] Play a winning game → "Your best" shows attempts; scoreboard shows row with 8-char truncated ID
- [ ] Play a losing game → games_lost increments, streak resets to 0
- [ ] Restart container via HAL `docker_restart` on ace → reload same incognito window → values unchanged (DB persistence verified)
**Task:** d1c49d59-57bd-4eba-9e22-f25a04157ad4
**Blocked by (completed):** 3dab55e3-9792-47a0-a4a6-ba7757517314 (schema + provisioning)
Summary
pidcookie (365 d, HttpOnly, SameSite=Strict) for persistent player identity alongside the existing 24 hsidsession cookieplayers(idempotent). On round end, a transaction inserts intogamesand updates aggregates:best_attempts(wins only), streaks,last_played_atbest_attempts ASC, tie-broken by earliestlast_played_at; identifiers truncated to 8 chars; current player row highlightedInfrastructure changes
package.json(pg ^8.13.3,"type":"module") and committedpackage-lock.jsonDockerfilenow copiespackage.json+ lockfile and runsnpm ci --omit=devbefore copyingserver.mjsdocker-compose.ymlforwards all provisionedTXT_GAME_DB_*env vars into the container and joins thepostgres_postgresnetwork for container-to-container postgres accessmodule.ymlversion unchanged (builder owns versioning)Test plan
docker_restarton ace → reload same incognito window → values unchanged (DB persistence verified)Task: d1c49d59-57bd-4eba-9e22-f25a04157ad4 Blocked by (completed): 3dab55e3-9792-47a0-a4a6-ba7757517314 (schema + provisioning)
8c3c95916d.