feat(lobby): F8-04b hierarchical sidebar + paid-tier gate for create-game
Reshape the lobby UI from a single Overview into a two-level sidebar (games · profile · DEV synthetic-reports) with four games sub-panels (active-past · recruitment · invitations · private-games). Move the `create new game` button into the private-games panel, merge the applications section into recruitment cards as status chips, and add DEV-only synthetic-report loader as a top-level screen. Add a paid-tier gate at backend `lobby.game.create`: free callers get `403 forbidden` before the lobby service is invoked. The UI hides the private-games sub-panel + create button on free tier (DEV affordances flag overrides). Update every integration test that creates a game to use a new `testenv.PromoteToPaid` helper; add a new `TestLobbyFlow_FreeUserCreateGameForbidden`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -142,7 +142,9 @@ because they cross domain boundaries:
|
||||
- **Public lobby games are admin-created** through
|
||||
`POST /api/v1/admin/games`. The user-facing
|
||||
`POST /api/v1/user/lobby/games` always emits `private` games owned by
|
||||
`X-User-ID`. Public games carry `owner_user_id IS NULL`; the partial
|
||||
`X-User-ID`, and is gated by `EntitlementProvider.IsPaid` — free-tier
|
||||
callers receive `403 forbidden` before the lobby service is invoked.
|
||||
Public games carry `owner_user_id IS NULL`; the partial
|
||||
index on `(owner_user_id) WHERE visibility = 'private'` keeps the
|
||||
private-owner lookup efficient.
|
||||
- **Authenticated lobby commands** flow through the gateway envelope
|
||||
|
||||
@@ -363,6 +363,18 @@ records the new game with `owner_user_id` set to the caller and
|
||||
visibility `private`, in state `draft`, with the request body's
|
||||
configuration as initial values.
|
||||
|
||||
The user surface is gated by the caller's paid tier. Backend reads
|
||||
`EntitlementProvider.IsPaid(userID)` before invoking the lobby
|
||||
service; free-tier callers are rejected with HTTP
|
||||
`403 forbidden` (canonical error code `forbidden`) and no `draft`
|
||||
row is created. The matching UI affordances — the `private games`
|
||||
sidebar sub-panel and its `create new game` button — are hidden from
|
||||
free-tier sessions in the lobby shell; the
|
||||
`VITE_GALAXY_DEV_AFFORDANCES` build flag overrides the UI gate so the
|
||||
owner can exercise both branches from a single test account in DEV
|
||||
bundles. Admin-driven public-game creation
|
||||
([Section 10](#10-administration)) bypasses the tier gate.
|
||||
|
||||
Public games are created exclusively through the admin surface
|
||||
([Section 10](#10-administration)). The user surface never produces a public game; this
|
||||
asymmetry is enforced in backend, not at the route level.
|
||||
|
||||
@@ -377,6 +377,18 @@ cancelled достижим из любого pre-finished-состояния.
|
||||
visibility `private`, в состоянии `draft`, с конфигурацией из
|
||||
тела запроса в качестве начальных значений.
|
||||
|
||||
User-surface гейтится платным тарифом вызывающего. Backend читает
|
||||
`EntitlementProvider.IsPaid(userID)` перед вызовом lobby-сервиса;
|
||||
free-tier-вызовы отклоняются с HTTP `403 forbidden`
|
||||
(канонический код ошибки `forbidden`), и `draft`-запись не
|
||||
создаётся. Соответствующие UI-аффордансы — подраздел
|
||||
`private games` в сайдбаре и кнопка `create new game` внутри него —
|
||||
скрыты в lobby-shell для free-tier-сессий; build-флаг
|
||||
`VITE_GALAXY_DEV_AFFORDANCES` переопределяет UI-гейт, чтобы owner
|
||||
мог в DEV-сборке проверять обе ветки с одного тестового аккаунта.
|
||||
Admin-создание public-игр ([Раздел 10](#10-администрирование))
|
||||
обходит тир-гейт.
|
||||
|
||||
Public-игры создаются исключительно через admin-surface
|
||||
([Раздел 10](#10-администрирование)). User-surface никогда не
|
||||
производит public-игру; асимметрия enforced в backend, не на
|
||||
|
||||
Reference in New Issue
Block a user