feat: public site layout shell + all 8 pages from playground #99

Merged
forgejo_admin merged 2 commits from 98-sveltekit-public-site into main 2026-03-27 04:08:54 +00:00

Summary

  • Restructure SvelteKit routing into (public) and (app) route groups per convention-sveltekit-spa
  • Port all 8 playground pages to production Svelte components with shared KQ toggle state
  • Public pages get their own layout (nav, footer, toggle) with zero Keycloak dependency; auth routes moved to (app)/ unchanged

Changes

  • src/routes/+layout.svelte -- New minimal root layout (just CSS import)
  • src/routes/(public)/+layout.svelte -- Public layout shell: site-nav, hamburger toggle, KQ toggle state, footer
  • src/routes/(public)/+page.svelte -- Home (hero, value props, explore cards, how to join)
  • src/routes/(public)/about/+page.svelte -- About (philosophy, divisions, recruitment, location)
  • src/routes/(public)/staff/+page.svelte -- Staff bios (static, hardcoded from playground with anchor IDs)
  • src/routes/(public)/teams/+page.svelte -- Dynamic: fetches /public/teams via publicFetch, KQ toggle
  • src/routes/(public)/tryouts/+page.svelte -- Tryout history + upcoming (static, KQ toggle)
  • src/routes/(public)/schedule/+page.svelte -- Schedule (tournaments + practice grid, KQ toggle)
  • src/routes/(public)/gear/+page.svelte -- Jersey gallery from MinIO (KQ toggle)
  • src/routes/(public)/sponsors/+page.svelte -- Sponsors + partners (static)
  • src/routes/(app)/+layout.svelte -- Existing Keycloak layout moved here, auth redirect merged in
  • src/routes/(app)/register/+page.svelte -- Inline nav stripped (layout provides it)
  • src/lib/public-api.js -- Unauthenticated fetch helper (plain fetch, null on error)
  • src/lib/program.svelte.js -- Shared KQ toggle state using Svelte 5 $state rune
  • src/app.css -- Replaced with playground shared/style.css (full design system)
  • Deleted: src/routes/+page.svelte (auth redirect moved to app layout)
  • Deleted: src/routes/tryouts/+page.svelte (replaced by public version)
  • Kept: (app)/teams/[id] and (app)/coaches/[id] (auth detail pages, no collision)

Test Plan

  • npm run build succeeds with adapter-static
  • All 8 public routes render without auth: /, /about, /staff, /teams, /tryouts, /schedule, /gear, /sponsors
  • Kings/Queens toggle persists across page navigation via localStorage
  • Queens pink color scheme swaps on toggle (body class)
  • Mobile hamburger menu opens/closes
  • Nav consistent across all public pages
  • Teams page fetches real data from /public/teams (or shows empty state gracefully)
  • Coach names on teams page link to staff page anchors
  • Auth routes still work: /admin, /coach, /my-players, /signin, /register
  • Keycloak auth flow unbroken for authenticated routes
  • No double-rendered nav on any page

Review Checklist

  • Passed automated review-fix loop
  • No secrets committed
  • No unnecessary file changes
  • Commit messages are descriptive
  • Closes #98
  • convention-sveltekit-spa -- architecture reference
  • Depends on: basketball-api#176 (public teams endpoint)
## Summary - Restructure SvelteKit routing into `(public)` and `(app)` route groups per `convention-sveltekit-spa` - Port all 8 playground pages to production Svelte components with shared KQ toggle state - Public pages get their own layout (nav, footer, toggle) with zero Keycloak dependency; auth routes moved to `(app)/` unchanged ## Changes - `src/routes/+layout.svelte` -- New minimal root layout (just CSS import) - `src/routes/(public)/+layout.svelte` -- Public layout shell: site-nav, hamburger toggle, KQ toggle state, footer - `src/routes/(public)/+page.svelte` -- Home (hero, value props, explore cards, how to join) - `src/routes/(public)/about/+page.svelte` -- About (philosophy, divisions, recruitment, location) - `src/routes/(public)/staff/+page.svelte` -- Staff bios (static, hardcoded from playground with anchor IDs) - `src/routes/(public)/teams/+page.svelte` -- Dynamic: fetches `/public/teams` via publicFetch, KQ toggle - `src/routes/(public)/tryouts/+page.svelte` -- Tryout history + upcoming (static, KQ toggle) - `src/routes/(public)/schedule/+page.svelte` -- Schedule (tournaments + practice grid, KQ toggle) - `src/routes/(public)/gear/+page.svelte` -- Jersey gallery from MinIO (KQ toggle) - `src/routes/(public)/sponsors/+page.svelte` -- Sponsors + partners (static) - `src/routes/(app)/+layout.svelte` -- Existing Keycloak layout moved here, auth redirect merged in - `src/routes/(app)/register/+page.svelte` -- Inline nav stripped (layout provides it) - `src/lib/public-api.js` -- Unauthenticated fetch helper (plain fetch, null on error) - `src/lib/program.svelte.js` -- Shared KQ toggle state using Svelte 5 `$state` rune - `src/app.css` -- Replaced with playground `shared/style.css` (full design system) - Deleted: `src/routes/+page.svelte` (auth redirect moved to app layout) - Deleted: `src/routes/tryouts/+page.svelte` (replaced by public version) - Kept: `(app)/teams/[id]` and `(app)/coaches/[id]` (auth detail pages, no collision) ## Test Plan - [x] `npm run build` succeeds with adapter-static - [ ] All 8 public routes render without auth: `/`, `/about`, `/staff`, `/teams`, `/tryouts`, `/schedule`, `/gear`, `/sponsors` - [ ] Kings/Queens toggle persists across page navigation via localStorage - [ ] Queens pink color scheme swaps on toggle (body class) - [ ] Mobile hamburger menu opens/closes - [ ] Nav consistent across all public pages - [ ] Teams page fetches real data from `/public/teams` (or shows empty state gracefully) - [ ] Coach names on teams page link to staff page anchors - [ ] Auth routes still work: `/admin`, `/coach`, `/my-players`, `/signin`, `/register` - [ ] Keycloak auth flow unbroken for authenticated routes - [ ] No double-rendered nav on any page ## Review Checklist - [x] Passed automated review-fix loop - [x] No secrets committed - [x] No unnecessary file changes - [x] Commit messages are descriptive ## Related Notes - Closes #98 - `convention-sveltekit-spa` -- architecture reference - Depends on: `basketball-api#176` (public teams endpoint)
feat: add public site with route groups and 8 playground pages (#98)
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
a1db264e20
Restructure SvelteKit routing into (public) and (app) route groups.
Public pages get their own layout (nav, footer, KQ toggle) with no
Keycloak dependency. All existing auth routes moved to (app)/ group
unchanged. Teams page fetches live data via publicFetch helper.

- Create (public)/ group with 8 pages: home, about, staff, teams,
  schedule, tryouts, gear, sponsors
- Create (app)/ group, move all existing auth routes into it
- New root +layout.svelte (minimal, just CSS import)
- (app)/+layout.svelte retains Keycloak init, auth guards, nav chrome
- Copy playground shared/style.css to app.css (full design system)
- Add src/lib/public-api.js (unauthenticated fetch helper)
- Add src/lib/program.svelte.js (shared KQ toggle state with $state)
- Delete old root +page.svelte (auth redirect moved to app layout)
- Delete (app)/tryouts/ (replaced by public version)
- Keep (app)/teams/[id] and (app)/coaches/[id] (auth detail pages)
- Strip inline nav from (app)/register/+page.svelte

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: remove unused tierOrder variable from teams page
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
fd195b1a9d
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

QA Review

Scope Verification

Reviewed all 35 changed files (4511 additions, 3119 deletions). Verified against issue #98 spec and all 7 review comments.

Architecture

  • Route groups: (public)/ and (app)/ correctly isolate layouts. Group names do not appear in URLs.
  • Root layout: Minimal -- just import '../app.css' and {@render children()}. Correct.
  • App layout: Keycloak init, auth guard, role-based nav chrome all preserved from original. PUBLIC_APP_ROUTES correctly scoped to (app)-only routes.
  • Public layout: Nav, footer, KQ toggle state, <svelte:body class:queens-active>. No Keycloak dependency.
  • Auth redirect: Old root +page.svelte redirect logic migrated to (app)/+layout.svelte onMount. Signin-only redirect (not / since that's now the public home).

Files Checked

Check Status
8 public pages match playground content Pass
Nav/footer in layout only, not in pages Pass
No inline nav in register page Pass -- 6-line nav block removed
teams/[id] and coaches/[id] kept under (app) Pass
tryouts deleted from (app), replaced by (public) Pass
publicFetch helper (no Keycloak) Pass
programStore uses $state rune Pass
app.css from playground shared/style.css Pass
KQ toggle on teams, tryouts, schedule, gear Pass
Teams page uses publicFetch('/public/teams') Pass
Staff page is static (hardcoded bios) Pass
Build succeeds (adapter-static) Pass

Issues Found and Fixed

  1. Unused variable tierOrder declared but never referenced in (public)/teams/+page.svelte. Sort logic inlined values instead. Fixed in follow-up commit.

Pre-existing Issues (Not Introduced by This PR)

  • handleSignIn() function declared but never used in (app)/+layout.svelte (carried over from original layout)
  • A11y warnings in (app)/admin/teams/+page.svelte (pre-existing click handlers without keyboard events)

VERDICT: PASS

All 8 public pages, route group restructuring, layout shell, KQ toggle, and publicFetch helper implemented correctly per issue #98 spec. Build succeeds. One minor fix applied (unused variable). No regressions to auth routes.

## QA Review ### Scope Verification Reviewed all 35 changed files (4511 additions, 3119 deletions). Verified against issue #98 spec and all 7 review comments. ### Architecture - **Route groups**: `(public)/` and `(app)/` correctly isolate layouts. Group names do not appear in URLs. - **Root layout**: Minimal -- just `import '../app.css'` and `{@render children()}`. Correct. - **App layout**: Keycloak init, auth guard, role-based nav chrome all preserved from original. `PUBLIC_APP_ROUTES` correctly scoped to (app)-only routes. - **Public layout**: Nav, footer, KQ toggle state, `<svelte:body class:queens-active>`. No Keycloak dependency. - **Auth redirect**: Old root `+page.svelte` redirect logic migrated to `(app)/+layout.svelte` onMount. Signin-only redirect (not `/` since that's now the public home). ### Files Checked | Check | Status | |-------|--------| | 8 public pages match playground content | Pass | | Nav/footer in layout only, not in pages | Pass | | No inline nav in register page | Pass -- 6-line nav block removed | | teams/[id] and coaches/[id] kept under (app) | Pass | | tryouts deleted from (app), replaced by (public) | Pass | | publicFetch helper (no Keycloak) | Pass | | programStore uses $state rune | Pass | | app.css from playground shared/style.css | Pass | | KQ toggle on teams, tryouts, schedule, gear | Pass | | Teams page uses publicFetch('/public/teams') | Pass | | Staff page is static (hardcoded bios) | Pass | | Build succeeds (adapter-static) | Pass | ### Issues Found and Fixed 1. **Unused variable** `tierOrder` declared but never referenced in `(public)/teams/+page.svelte`. Sort logic inlined values instead. **Fixed** in follow-up commit. ### Pre-existing Issues (Not Introduced by This PR) - `handleSignIn()` function declared but never used in `(app)/+layout.svelte` (carried over from original layout) - A11y warnings in `(app)/admin/teams/+page.svelte` (pre-existing click handlers without keyboard events) ### VERDICT: PASS All 8 public pages, route group restructuring, layout shell, KQ toggle, and publicFetch helper implemented correctly per issue #98 spec. Build succeeds. One minor fix applied (unused variable). No regressions to auth routes.
Author
Owner

PR #99 Review

PR: feat: public site layout shell + all 8 pages from playground
Branch: 98-sveltekit-public-site
Parent issue: #98
Files changed: 35 (+4509, -3119)
Commits: 2 (feat commit + cleanup of unused tierOrder variable)


DOMAIN REVIEW

Tech stack: SvelteKit 5 (Svelte 5 runes), adapter-static SPA, CSS custom properties, Keycloak auth (existing)

Route group architecture -- CORRECT. The restructuring into (public)/ and (app)/ route groups follows SvelteKit conventions precisely. Route groups isolate layouts without affecting URLs. The root src/routes/ contains only +layout.svelte, +layout.js, (public)/, and (app)/ -- no orphan routes.

Critical check 1: Existing auth routes survive restructuring -- PASS. All 12 existing authenticated route directories are present under (app)/: admin, checkout, coach, coaches/[id], forgot-password, jersey, my-players, players/[id], register, reset-password, signin, teams/[id]. The (app)/+layout.svelte retains Keycloak initialization, the PUBLIC_APP_ROUTES allow-list, and the auth guard $effect that redirects unauthenticated users to /signin. The old root +page.svelte (auth redirect) was correctly deleted since / is now the public home page.

Critical check 2: No Keycloak dependency in public pages -- PASS. The (public)/+layout.svelte imports only svelte, $app/stores, and $lib/program.svelte.js. Zero Keycloak references. All 8 public pages import only programStore and/or publicFetch. The publicFetch helper in src/lib/public-api.js uses plain fetch() with no auth headers.

Critical check 3: CSS matches playground -- PASS. The app.css is a properly organized design system migrated from playground shared/style.css. Design tokens (colors, typography scale, spacing scale), .queens-active body class override (swaps --color-red to pink #e91e8c), .sr-only utility, :focus-visible outlines, and responsive breakpoints are all present.

Critical check 4: Route collisions resolved -- PASS. Public /teams (list page) lives in (public)/teams/+page.svelte. Auth /teams/[id] (detail page) lives in (app)/teams/[id]/+page.svelte. No collision -- different URL patterns. Public /staff vs auth /coaches/[id] -- same principle. The old (app)/tryouts/ was correctly deleted (404 confirms), replaced by (public)/tryouts/.

Critical check 5: Build succeeds -- PASS. CI runs npm run check + npm run build + test -f build/index.html. Both commits show all checks successful.

Svelte 5 patterns -- Good. Uses $state, $props, $effect, $derived runes correctly. The programStore in src/lib/program.svelte.js uses the getter/setter pattern around $state for cross-component reactivity. localStorage read happens in onMount (correct SSR guard), localStorage write happens in $effect with typeof window check.

publicFetch graceful degradation -- Good. Returns null on non-OK responses and network errors. Teams page checks if (data) before assignment. Loading state transitions to false regardless.

Accessibility -- Good. Nav has aria-label="Main navigation", hamburger has aria-expanded and aria-controls, .sr-only class exists, :focus-visible outlines are defined.

Sign-out redirect -- The (app) layout sign-out calls goto('/'), which now lands on the public home page instead of the old auth redirect page. This is correct and expected behavior for a site with a public front page.


BLOCKERS

None.

Test coverage assessment: The repo has zero test infrastructure (no vitest, no playwright, no test runner in package.json). This is a pre-existing condition on main -- not introduced by this PR. The CI validates via svelte-check (type checking) and vite build (compilation). Adding a test framework is discovered scope, not a blocker for this PR.

No secrets in code: The publicFetch fallback URL (https://basketball-api.tail5b443a.ts.net) is a Tailscale funnel URL, not a secret. MinIO asset URLs are similarly public CDN-style paths. No API keys, tokens, or credentials found.

No unvalidated user input: Public pages only display data; there are no forms or user input fields on public routes (registration/signin are under (app) with existing validation).

No DRY violations in auth paths: Auth logic lives exclusively in (app)/+layout.svelte. Public layout has zero auth code. Clean separation.


NITS

  1. Staff page: issue spec inconsistency -- The acceptance criteria in #98 says "Staff page fetches real coach data from /public/coaches via publicFetch" but Section 6 of the scope says "static coach cards (bios hardcoded from playground, no API)". The implementation follows the scope (hardcoded). The acceptance criteria checkbox should be updated to reflect reality, or this should be tracked as discovered scope for a future dynamic staff page.

  2. Hardcoded MinIO URLs in gear page -- Gear page images use hardcoded https://minio-api.tail5b443a.ts.net/assets/westside/jerseys/... URLs rather than constructing them from an environment variable. The logo in the public layout nav also uses a hardcoded MinIO URL. Consider extracting a VITE_ASSETS_URL env var for consistency with the VITE_API_URL pattern in publicFetch. Low risk since these are public asset URLs, but would simplify environment portability.

  3. Nav logo alt text -- The nav logo uses alt="Westside Kings &amp; Queens" which is fine, but the width="44" height="44" is hardcoded. If the logo aspect ratio changes, this could cause distortion. Minor since the logo is controlled.

  4. No <svelte:head> on all pages -- The schedule page includes SEO metadata (<svelte:head>) based on the WebFetch summary. Verify all 8 public pages include <title> and <meta name="description"> in <svelte:head> for SEO. This is a public-facing site.

  5. Queens program empty states -- Schedule and tryouts pages show Queens-specific "coming soon" messaging, which is good. Verify teams page also degrades gracefully when Queens teams data returns empty from the API (not just when the API is unreachable).


SOP COMPLIANCE

  • Branch named after issue: 98-sveltekit-public-site references issue #98
  • PR body has: Summary, Changes, Test Plan, Related sections
  • Related references plan slug -- References issue #98 and convention-sveltekit-spa, but no plan slug (this may be standalone board work, not plan-driven)
  • No secrets committed
  • No unnecessary file changes (all 35 files are in scope for the route restructuring + 8 new pages + CSS)
  • Commit messages are descriptive: feat commit references #98, fix commit describes the cleanup

PROCESS OBSERVATIONS

Deployment frequency: This is a large PR (35 files, +4509/-3119) but it's a coherent structural change -- route group restructuring + page porting. Smaller would have been splitting the restructuring from the page additions, but the two are tightly coupled (you can't test public pages without the route group).

Change failure risk: LOW. The route group pattern is well-understood SvelteKit. Auth routes are moved unchanged. CI validates build. The main risk is visual regression (CSS differences from playground), which requires manual visual testing.

Discovered scope: (1) Test framework setup for westside-app -- track as a separate issue. (2) Staff page dynamic data from /public/coaches API -- track when basketball-api endpoint is ready. (3) SEO metadata audit across all 8 public pages. (4) Asset URL environment variable extraction.

VERDICT: APPROVED

## PR #99 Review **PR**: feat: public site layout shell + all 8 pages from playground **Branch**: `98-sveltekit-public-site` **Parent issue**: #98 **Files changed**: 35 (+4509, -3119) **Commits**: 2 (feat commit + cleanup of unused `tierOrder` variable) --- ### DOMAIN REVIEW **Tech stack**: SvelteKit 5 (Svelte 5 runes), adapter-static SPA, CSS custom properties, Keycloak auth (existing) **Route group architecture** -- CORRECT. The restructuring into `(public)/` and `(app)/` route groups follows SvelteKit conventions precisely. Route groups isolate layouts without affecting URLs. The root `src/routes/` contains only `+layout.svelte`, `+layout.js`, `(public)/`, and `(app)/` -- no orphan routes. **Critical check 1: Existing auth routes survive restructuring** -- PASS. All 12 existing authenticated route directories are present under `(app)/`: admin, checkout, coach, coaches/[id], forgot-password, jersey, my-players, players/[id], register, reset-password, signin, teams/[id]. The `(app)/+layout.svelte` retains Keycloak initialization, the `PUBLIC_APP_ROUTES` allow-list, and the auth guard `$effect` that redirects unauthenticated users to `/signin`. The old root `+page.svelte` (auth redirect) was correctly deleted since `/` is now the public home page. **Critical check 2: No Keycloak dependency in public pages** -- PASS. The `(public)/+layout.svelte` imports only `svelte`, `$app/stores`, and `$lib/program.svelte.js`. Zero Keycloak references. All 8 public pages import only `programStore` and/or `publicFetch`. The `publicFetch` helper in `src/lib/public-api.js` uses plain `fetch()` with no auth headers. **Critical check 3: CSS matches playground** -- PASS. The `app.css` is a properly organized design system migrated from playground `shared/style.css`. Design tokens (colors, typography scale, spacing scale), `.queens-active` body class override (swaps `--color-red` to pink `#e91e8c`), `.sr-only` utility, `:focus-visible` outlines, and responsive breakpoints are all present. **Critical check 4: Route collisions resolved** -- PASS. Public `/teams` (list page) lives in `(public)/teams/+page.svelte`. Auth `/teams/[id]` (detail page) lives in `(app)/teams/[id]/+page.svelte`. No collision -- different URL patterns. Public `/staff` vs auth `/coaches/[id]` -- same principle. The old `(app)/tryouts/` was correctly deleted (404 confirms), replaced by `(public)/tryouts/`. **Critical check 5: Build succeeds** -- PASS. CI runs `npm run check` + `npm run build` + `test -f build/index.html`. Both commits show all checks successful. **Svelte 5 patterns** -- Good. Uses `$state`, `$props`, `$effect`, `$derived` runes correctly. The `programStore` in `src/lib/program.svelte.js` uses the getter/setter pattern around `$state` for cross-component reactivity. localStorage read happens in `onMount` (correct SSR guard), localStorage write happens in `$effect` with `typeof window` check. **publicFetch graceful degradation** -- Good. Returns `null` on non-OK responses and network errors. Teams page checks `if (data)` before assignment. Loading state transitions to `false` regardless. **Accessibility** -- Good. Nav has `aria-label="Main navigation"`, hamburger has `aria-expanded` and `aria-controls`, `.sr-only` class exists, `:focus-visible` outlines are defined. **Sign-out redirect** -- The `(app)` layout sign-out calls `goto('/')`, which now lands on the public home page instead of the old auth redirect page. This is correct and expected behavior for a site with a public front page. --- ### BLOCKERS None. **Test coverage assessment**: The repo has zero test infrastructure (no vitest, no playwright, no test runner in `package.json`). This is a pre-existing condition on `main` -- not introduced by this PR. The CI validates via `svelte-check` (type checking) and `vite build` (compilation). Adding a test framework is discovered scope, not a blocker for this PR. **No secrets in code**: The `publicFetch` fallback URL (`https://basketball-api.tail5b443a.ts.net`) is a Tailscale funnel URL, not a secret. MinIO asset URLs are similarly public CDN-style paths. No API keys, tokens, or credentials found. **No unvalidated user input**: Public pages only display data; there are no forms or user input fields on public routes (registration/signin are under `(app)` with existing validation). **No DRY violations in auth paths**: Auth logic lives exclusively in `(app)/+layout.svelte`. Public layout has zero auth code. Clean separation. --- ### NITS 1. **Staff page: issue spec inconsistency** -- The acceptance criteria in #98 says "Staff page fetches real coach data from /public/coaches via publicFetch" but Section 6 of the scope says "static coach cards (bios hardcoded from playground, no API)". The implementation follows the scope (hardcoded). The acceptance criteria checkbox should be updated to reflect reality, or this should be tracked as discovered scope for a future dynamic staff page. 2. **Hardcoded MinIO URLs in gear page** -- Gear page images use hardcoded `https://minio-api.tail5b443a.ts.net/assets/westside/jerseys/...` URLs rather than constructing them from an environment variable. The logo in the public layout nav also uses a hardcoded MinIO URL. Consider extracting a `VITE_ASSETS_URL` env var for consistency with the `VITE_API_URL` pattern in `publicFetch`. Low risk since these are public asset URLs, but would simplify environment portability. 3. **Nav logo `alt` text** -- The nav logo uses `alt="Westside Kings &amp; Queens"` which is fine, but the `width="44" height="44"` is hardcoded. If the logo aspect ratio changes, this could cause distortion. Minor since the logo is controlled. 4. **No `<svelte:head>` on all pages** -- The schedule page includes SEO metadata (`<svelte:head>`) based on the WebFetch summary. Verify all 8 public pages include `<title>` and `<meta name="description">` in `<svelte:head>` for SEO. This is a public-facing site. 5. **Queens program empty states** -- Schedule and tryouts pages show Queens-specific "coming soon" messaging, which is good. Verify teams page also degrades gracefully when Queens teams data returns empty from the API (not just when the API is unreachable). --- ### SOP COMPLIANCE - [x] Branch named after issue: `98-sveltekit-public-site` references issue #98 - [x] PR body has: Summary, Changes, Test Plan, Related sections - [ ] Related references plan slug -- References issue #98 and `convention-sveltekit-spa`, but no plan slug (this may be standalone board work, not plan-driven) - [x] No secrets committed - [x] No unnecessary file changes (all 35 files are in scope for the route restructuring + 8 new pages + CSS) - [x] Commit messages are descriptive: feat commit references #98, fix commit describes the cleanup --- ### PROCESS OBSERVATIONS **Deployment frequency**: This is a large PR (35 files, +4509/-3119) but it's a coherent structural change -- route group restructuring + page porting. Smaller would have been splitting the restructuring from the page additions, but the two are tightly coupled (you can't test public pages without the route group). **Change failure risk**: LOW. The route group pattern is well-understood SvelteKit. Auth routes are moved unchanged. CI validates build. The main risk is visual regression (CSS differences from playground), which requires manual visual testing. **Discovered scope**: (1) Test framework setup for westside-app -- track as a separate issue. (2) Staff page dynamic data from /public/coaches API -- track when basketball-api endpoint is ready. (3) SEO metadata audit across all 8 public pages. (4) Asset URL environment variable extraction. ### VERDICT: APPROVED
forgejo_admin deleted branch 98-sveltekit-public-site 2026-03-27 04:08:54 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/westside-app!99
No description provided.