Add SvelteKit route /jersey-public — System B frontend #243
Labels
No labels
domain:backend
domain:devops
domain:frontend
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ldraney/westside-app#243
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Type
Feature
Lineage
Standalone — part of System B (public jersey intake) production rollout. Playground prototype at
forgejo_admin/westside-playground#57. Architecture inarch-jersey-intake. Revised 2026-04-10 perfeedback_funnel_requires_auth.md— all new funnel-exposed PII surfaces must have documented auth. Reuses existing westside-landing Keycloak flow.Repo
forgejo_admin/westside-landingUser Story
As Marcus
I want a Keycloak-gated
/jersey-publicpage on the westside-landing siteSo that any player Marcus shares the link with can sign in, fill the form (with name and email prefilled from their Keycloak identity), and submit a jersey order
Context
westside-landing already has full Keycloak auth wired in production:
westside-basketball, client:westside-spa(PKCE public client)src/lib/keycloak.js— existinginitKeycloak(),isAuthenticated(),getUserName(),login(), etc.src/routes/(app)/+layout.svelte— runsinitKeycloak()on mount, has reactive$effectguard:if (!authenticated && !isPublic) goto('/signin')PUBLIC_APP_ROUTESallowlist inside(app)/+layout.svelte— routes that bypass the auth guard (currently:/register,/signin,/jersey,/jersey/success,/jersey/cancel,/checkout,/checkout/success,/checkout/cancel,/forgot-password,/reset-password)This ticket puts
/jersey-publicinside(app)/and DOES NOT add it toPUBLIC_APP_ROUTES. Result: unauthenticated visitors auto-redirect to/signin, complete Keycloak login (including self-registration if enabled on the realm), then bounce back to/jersey-publicwith a valid session. No new auth layer, no oauth2-proxy, no ingress changes.The playground page is at
/home/ldraney/westside-playground/jersey-public.html(438 lines) and has been visually approved by Lucas on 2026-04-10. Promotion followsfeedback_svelte_is_html.md— literal copy-paste plus Svelte 5$staterunes.File Targets
Files to create:
src/routes/(app)/jersey-public/+page.svelte— the new route. Copy form HTML structure from playground. Convert inline<script>to Svelte 5$staterunes for form state. Bindon:submit|preventDefault. POST to/api/jersey-public-orderswith JWT inAuthorization: Bearer <token>header.Files to verify/reference (do NOT modify unless strictly required):
src/routes/(app)/+layout.svelte— auth guard lives here. Do NOT add/jersey-publictoPUBLIC_APP_ROUTES. Read it to understand the pattern.src/lib/keycloak.js— importgetToken(),getUserName(),getEmail()(add the getter if it doesn't exist, matching existing style)Files the agent should NOT touch:
src/routes/(public)/*— any public (unauth) routesrc/routes/(app)/checkout/*,src/routes/(app)/jersey/*— Systems A and C, hands offPrefill from JWT
On mount, the form must:
readyfrom$lib/keycloak.jsgetUserName()for player_name,getEmail()for email — addgetEmail()helper to$lib/keycloak.jsif missing; it's a 3-line getter that readskeycloak.tokenParsed?.email)playerNameandemail$statefieldsAcceptance Criteria
/jersey-publicunauthenticated, I am redirected to/signin/jersey-publicwith my player name and email prefilled from the JWTPOST /api/jersey-public-orderswithAuthorization: Bearer <JWT>header (verify in DevTools)/jersey-publicis NOT inPUBLIC_APP_ROUTES— verify by grepTest Expectations
npm run test(or westside-landing's test runner)Constraints
$lib/keycloak.jshelpers — do NOT roll new auth code(app)/— do NOT add toPUBLIC_APP_ROUTES$staterunesfeedback_no_tailwind.md)Authorization: Bearer <token>header requiredChecklist
westside-landingmainnpm run devfeedback_funnel_requires_auth.md)/jersey-publicconfirmed absent fromPUBLIC_APP_ROUTESRelated
westside-basketball— projectstory:WS-S31— admin public jersey intake linkarch-jersey-intake— architecture docforgejo_admin/westside-playground#57— playground prototypefeedback_svelte_is_html.md— promotion philosophyfeedback_funnel_requires_auth.md— why this is Keycloak-gatedforgejo_admin/westside-playground#59— Keycloak-gated forms spike (answered "yes" by this ticket)Scope Review: APPROVED
Review note:
review-946-2026-04-10All template sections present, traceability triangle intact (story:WS-S31 verified on project-westside-basketball user-stories, arch-jersey-intake note exists and names
westside-landing/src/routes/jersey-publicas the exact System B frontend target, Forgejo issue #243 open). File targets verified against the live repo via Forgejo API:src/routes/(app)/exists,jersey-publicdoes NOT exist,src/lib/keycloak.jsexports match (initKeycloak/getToken/getUserName present, tokenParsed referenced, getEmail correctly flagged as absent),(app)/+layout.sveltehas the $effect guard and PUBLIC_APP_ROUTES allowlist matches the ticket body verbatim. Playground prototype verified at 438 lines.No decomposition needed (1 new file + 3-line helper, 1 repo, single cohesive feature). No scope leak into System A or System C — both explicitly marked do-not-touch. Auth chain cleanly reuses existing Keycloak infrastructure with no new layer.
Soft deps: #947 (migration, wave:1, parallel) and #948 (POST endpoint, wave:2). Neither blocks frontend development — endpoint can be stubbed for local dev.
Discovered scope (not blocking, create as new ticket)
[SCOPE]Updatearch-jersey-intakeSystem B section to reflect Keycloak-gated identity model perfeedback_funnel_requires_auth.md(arch doc currently describes System B as self-declared-identity; the ticket revision moves it to JWT claims).Verdict: APPROVED — ready to move backlog → todo.