feat(lobby): F8-04b hierarchical sidebar + paid-tier gate for create-game #62
Reference in New Issue
Block a user
Delete Branch "feature/f8-04b-lobby-restructure"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Reshape the lobby UI from a single Overview into a two-level sidebar (
games·profile· DEVsynthetic test reports) with fourgamessub-panels (active-past·recruitment·invitations·private-games). Move thecreate new gamebutton into theprivate-gamespanel, merge the applications section into recruitment cards as status chips, and add the DEV-only synthetic-report loader as a top-level screen.Add a paid-tier gate at backend
lobby.game.create: free callers get403 forbiddenbefore the lobby service is invoked. UI hides theprivate-gamessub-panel + create button on free tier;VITE_GALAXY_DEV_AFFORDANCESoverrides for owner testing.Backend
backend/internal/lobby/deps.go: extendEntitlementProviderwithIsPaid(ctx, userID) (bool, error).backend/internal/server/handlers_user_lobby_games.go::Create: checkh.svc.IsPaidbeforesvc.CreateGame, return403 forbiddenfor free callers.backend/cmd/backend/main.go::userEntitlementAdapter: implementIsPaidoverGetEntitlementSnapshot.backend/openapi.yaml: document the new403response.Integration
testenv.PromoteToPaidposts to/api/v1/admin/users/{user_id}/entitlementswith thepermanenttier.lobby_flow,runtime_lifecycle,notification_flow,engine_command_proxy,lobby_open_enrollment,admin_global_games_view,lobby_my_games) callsPromoteToPaidon the owner beforelobby.game.create.integration/lobby_free_tier_test.go::TestLobbyFlow_FreeUserCreateGameForbiddencovers the rejection path.UI
ui/frontend/src/lib/app-nav.svelte.ts: extendAppScreenwithgames-*literals andsynthetic-reports; sanitize fallback resolves invisible screens tolobby.ui/frontend/src/lib/lobby-data.svelte.ts: new session-wide store owning the four lobby panels' fan-out.ui/frontend/src/lib/screens/lobby-shell.svelte: two-level sidebar with desktop always-expanded submenu + mobile dropdown popover.games-active-past,games-recruitment,games-invitations,games-private-games,synthetic-reports);lobby-screen.sveltebecomes a tiny resolver.lobby-create-screen.svelte: inlinelobby.create.error.forbiddenonLobbyError.code === "forbidden"; refresh lobby data after success.ui/frontend/src/api/account.ts: decodeentitlement.is_paidfrom the FBSEntitlementSnapshot.Docs
docs/ARCHITECTURE.md,docs/FUNCTIONAL.md(§3.3),docs/FUNCTIONAL_ru.mdmirror,ui/docs/lobby.md,ui/docs/navigation.md,backend/openapi.yaml— all updated to describe the new structure and the tier gate.Test plan
decodeAccountViewextractsentitlement.isPaid(tests/account-decode.test.ts).lobby-flow, newlobby-tier-gateandlobby-recruitment-badgesspecs.TestLobbyFlow_FreeUserCreateGameForbidden+ every existingcreate-gameflow withPromoteToPaid(runs in this PR viaintegration.yaml).Decisions baked into the diff
is_paidpropagation; matches the diplomail precedent).rejectedapplication keeps the inline race-name form visible (re-apply path).