## 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? -->
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>
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 main2026-09-21 08:27:39 -04:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What and why
How this was verified
Invariants
user_id+ RLS policy + repository scopeupgrade -> downgrade -1 -> upgradeRisks and follow-ups
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>