Harden owner and suggestion invariants for concurrent writes

This commit is contained in:
2026-02-08 21:37:46 +01:00
parent 569cea161f
commit fe6a9d5da4
13 changed files with 472 additions and 22 deletions

View File

@@ -34,6 +34,7 @@ stateDiagram-v2
- Register success (player, admin key path) issues cookie, trims fields, stores normalized username, hashes password.
- Register rejects missing/long username, weak password policy violations, missing display name, duplicate username, bad admin key, >24 chars username, >16 display name.
- Bootstrap-admin key path only works until the owner account exists; bootstrap admin is marked as owner.
- Database uniqueness guard enforces single owner row (`IsOwner=true`) even if writes bypass endpoint-level checks.
- `/api/auth/options` reports owner presence for registration UI behavior.
- Login success updates LastLoginAt and sets DisplayName if null; rejects wrong password/username; enforces length limits.
- Logout clears cookie.
@@ -50,6 +51,7 @@ stateDiagram-v2
### 3) Suggestions
- GET /mine returns only callers suggestions ordered by CreatedAt.
- POST /: success with valid data; enforces ≤5 per player; trims optional fields; requires display name; rejects bad image URL/ext, unreachable image (mocked), invalid game/youtube URLs, invalid player counts, missing name/too long.
- DB trigger also enforces suggestion cap for non-joker inserts, protecting against concurrent over-limit writes.
- Joker path: when phase=Vote and HasJoker=true allows creation, consumes joker, resets VotesFinal for all players.
- Phase gating: non-admin cannot create/update/delete outside Suggest (except joker create); admin bypasses phase checks for update/delete.
- PUT /{id}: player can edit own in Suggest; name locked outside Suggest; admin can edit any time; validation mirrors create.
@@ -60,6 +62,7 @@ stateDiagram-v2
- GET /mine: only in Vote, returns player votes; unauthorized/phase mismatch handled.
- POST /: creates or updates vote; rejects score outside 010; rejects when VotesFinal=true; enforces display name requirement and phase gating.
- Linked votes: when suggestions are linked, a single post updates all linked IDs; invalid suggestionId returns 400; linking root detection works for nested links.
- Concurrent vote upserts are handled with retry logic around unique-key conflicts to avoid server errors.
- Finalize: POST /finalize toggles VotesFinal flag; allowed only in Vote.
### 5) Results