feat(web): SvelteKit PWA shell with login #3

Merged
BBergle merged 2 commits from feat/web-shell into main 2026-09-21 08:27:39 -04:00
Owner

What and why

How this was verified

  • CI is green
  • Tests added or updated for the behaviour that changed
  • Verified manually (describe how):

Invariants

  • Raw ingested bytes remain immutable; derived tables stay rebuildable
  • No stored odometer added; wear still derived from installs
  • Physical quantities stored as SI integers
  • New user-owned tables have user_id + RLS policy + repository scope
  • No secret can reach a response model, log line, or error message
  • Migration survives upgrade -> downgrade -1 -> upgrade

Risks and follow-ups

## What and why <!-- What changed, and what problem it solves. Link the issue if there is one. --> ## How this was verified <!-- Be specific and honest. "Ran the tests" is not enough — say which, and what they proved. If something is untested, say so here rather than leaving the reviewer to find out. --> - [ ] CI is green - [ ] Tests added or updated for the behaviour that changed - [ ] Verified manually (describe how): ## Invariants <!-- Tick only what applies to this change. See CLAUDE.md. --> - [ ] Raw ingested bytes remain immutable; derived tables stay rebuildable - [ ] No stored odometer added; wear still derived from installs - [ ] Physical quantities stored as SI integers - [ ] New user-owned tables have `user_id` + RLS policy + repository scope - [ ] No secret can reach a response model, log line, or error message - [ ] Migration survives `upgrade -> downgrade -1 -> upgrade` ## Risks and follow-ups <!-- What might this break? What did you deliberately leave out? -->
BBergle added 1 commit 2026-09-21 08:18:48 -04:00
feat(web): SvelteKit PWA shell with login
CI / Repo hygiene (pull_request) Successful in 2s
CI / API (lint, types, tests) (pull_request) Successful in 2s
CI / Migrations reversible (pull_request) Successful in 3s
CI / Web (lint, typecheck, build) (pull_request) Failing after 8s
7bef79fae5
Phase 0 scaffolding for the frontend: SvelteKit + adapter-static in SPA mode
(fallback index.html, ssr disabled in the root layout — no Node process in
production, Caddy serves build/ directly per docs/PLAN.md), a login page and
auth store backed by /api/v1/auth/{login,me,logout}, an installable-PWA shell
(hand-written manifest, iOS meta/safe-area handling, an install-onboarding
banner), and a Dockerfile whose only job is to produce a buildable /app/build
artifact for deploy/ to consume.

Service worker notes, since the wiring isn't obvious from the diff:

- injectManifest, not generateSW: the caching policy needs to say "never
  cache /api/*", which generateSW's declarative config can't express as
  precisely as hand-written Workbox routes can.
- Uses the base `vite-plugin-pwa` plugin, not `@vite-pwa/sveltekit`'s
  SvelteKit-specific wrapper. That wrapper's injectManifest build expects
  SvelteKit's own built-in src/service-worker.{js,ts} convention to have
  already transpiled the file — but that native build only permits importing
  SvelteKit's own three virtual modules and hard-rejects `workbox-*` imports,
  which our SW needs. The base plugin bundles src/service-worker.ts directly
  instead, which works. SvelteKit's native service-worker convention is
  explicitly disabled (`kit.files.serviceWorker` pointed at a path that
  doesn't exist) so the two builds can't collide and silently clobber each
  other's output — they do, if both are left enabled, and the failure mode is
  silent (the SW builds fine, just precaches nothing).
- workbox-core/precaching/routing/strategies had to be added as direct
  devDependencies even though workbox-build depends on them — pnpm doesn't
  hoist transitive deps into the top-level node_modules, so the SW bundle
  step couldn't resolve them otherwise.
- The SPA fallback index.html doesn't exist yet at service-worker-build time
  (adapter-static writes it after all Vite plugins finish), so it can't be
  glob-hashed into the precache manifest normally. It gets a synthetic
  manifest entry instead, revisioned by a per-build-invocation timestamp
  (see the swIndexRevision comment in vite.config.ts) so the cached shell
  still invalidates correctly on every deploy.

Full rationale for each choice is inline as comments in vite.config.ts and
apps/web/README.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
BBergle added 1 commit 2026-09-21 08:21:02 -04:00
fix(web): pin packageManager, drop unused @vite-pwa/sveltekit dep
CI / Repo hygiene (pull_request) Successful in 2s
CI / API (lint, types, tests) (pull_request) Successful in 3s
CI / Migrations reversible (pull_request) Successful in 3s
CI / Web (lint, typecheck, build) (pull_request) Successful in 42s
65d9829e27
CI's web job runs bare `corepack enable && pnpm install --frozen-lockfile`
with no explicit pnpm version, so without a `packageManager` field corepack
can resolve a different pnpm than the one that generated the lockfile
(lockfileVersion 9, requires pnpm 9+) — that's what broke the first CI run.
Also drops @vite-pwa/sveltekit, left over from an earlier approach abandoned
in favor of the base vite-plugin-pwa plugin (see vite.config.ts) and no
longer imported anywhere.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
BBergle merged commit 1832059e03 into main 2026-09-21 08:27:39 -04:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: BBergle/bike-app#3