v1.2.0: planes.owner_id + ownership checks + per-player onboarding (ISS-108, ISS-109) #153

Merged
kamilkrzywda merged 1 commits from feat/multiplayer-ownership into master 2026-09-26 18:41:07 +02:00
Owner

Multiplayer steps 4+5 of 12.

ISS-108 — per-player onboarding. New registrants get a starter plane at EDDF: buildStarterPlane(airports, id) extracted from buildSeed (byte-identical values, no RNG draws), reused by POST /api/register and the test mint hook for custom usernames. Legacy players without planes are out of scope (ponytail comment).

ISS-109 — planes.owner_id + ownership checks. New NOT NULL column in DDL + Drizzle mirror; one-time guarded migration backfills pre-v1.2.0 rows to "local" via SQLite constant ALTER default (idempotent). All seven plane actions plus repairPlane take the session player id and 403 "not your plane" on foreign planes through shared assertPlaneOwner(); performAction passes auth.player.id as its callback second arg, routes stay pass-throughs. Economy per-player via new getPlayer/updatePlayerEconomy helpers (getLocalPlayer stays for snapshot/engine). Sell last-plane guard is now PER OWNER; buyPlane stamps the buyer as owner.

Mint hook default → kamilkrzywda. e2e specs play with seeded planes by id, so the no-body mint resolves to the existing local player that owns them after backfill (no new rows); custom usernames create fresh accounts WITH onboarding. No e2e spec changes needed.

OpenAPI. Seven plane-targeted endpoints document 403; path count unchanged at eighteen — openapi.test.ts error-code lists updated.

Tests. New backfill migration test (client.test.ts), new ownership suite in actions.test.ts (403 both directions, per-owner last-plane guard, buyer stamped as owner with own cash debited); register + mint route tests assert the onboarding plane at EDDF. Local: tsc clean, 432/432 unit, 64 e2e specs list.

v1.2.0 — CHANGELOG entry added; package.json bumped.

Multiplayer steps 4+5 of 12. **ISS-108 — per-player onboarding.** New registrants get a starter plane at EDDF: `buildStarterPlane(airports, id)` extracted from `buildSeed` (byte-identical values, no RNG draws), reused by POST /api/register and the test mint hook for custom usernames. Legacy players without planes are out of scope (ponytail comment). **ISS-109 — planes.owner_id + ownership checks.** New NOT NULL column in DDL + Drizzle mirror; one-time guarded migration backfills pre-v1.2.0 rows to "local" via SQLite constant ALTER default (idempotent). All seven plane actions plus repairPlane take the session player id and 403 "not your plane" on foreign planes through shared `assertPlaneOwner()`; performAction passes auth.player.id as its callback second arg, routes stay pass-throughs. Economy per-player via new getPlayer/updatePlayerEconomy helpers (getLocalPlayer stays for snapshot/engine). Sell last-plane guard is now PER OWNER; buyPlane stamps the buyer as owner. **Mint hook default → kamilkrzywda.** e2e specs play with seeded planes by id, so the no-body mint resolves to the existing local player that owns them after backfill (no new rows); custom usernames create fresh accounts WITH onboarding. No e2e spec changes needed. **OpenAPI.** Seven plane-targeted endpoints document 403; path count unchanged at eighteen — openapi.test.ts error-code lists updated. **Tests.** New backfill migration test (client.test.ts), new ownership suite in actions.test.ts (403 both directions, per-owner last-plane guard, buyer stamped as owner with own cash debited); register + mint route tests assert the onboarding plane at EDDF. Local: tsc clean, 432/432 unit, 64 e2e specs list. v1.2.0 — CHANGELOG entry added; package.json bumped.
kamilkrzywda added 1 commit 2026-09-26 18:27:17 +02:00
kamilkrzywda scheduled this pull request to auto merge when all checks succeed 2026-09-26 18:30:39 +02:00
kamilkrzywda merged commit 306f81aec6 into master 2026-09-26 18:41:07 +02:00
kamilkrzywda deleted branch feat/multiplayer-ownership 2026-09-26 18:41:07 +02:00
Sign in to join this conversation.