CLAUDE.md shrinks to rules + status + index (175 lines, down from 476). Dev setup, prod deploy, and per-phase build records move to docs/. Gotchas regrouped by domain (auth, frontend, PWA, testing, backend, deploy, platform) and unnumbered so they don't drift as new ones land. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.5 KiB
4.5 KiB
Fase 6 — what has been built
6.1 PWA injectManifest migration
apps/web/src/sw.ts— minimal custom SW:precacheAndRoute(self.__WB_MANIFEST)+skipWaiting/clients.claim. Namedsw.ts(notservice-worker.ts) to dodge SvelteKit's built-in interception (see the PWA gotchas inCLAUDE.md).apps/web/vite.config.ts— switched@vite-pwa/sveltekittostrategies: 'injectManifest'withsrcDir: 'src',filename: 'sw.ts',injectManifest.globPatternsfor the built shell.apps/web/src/routes/+layout.svelte— registers the SW viaonMount() → import('virtual:pwa-register').registerSW({ immediate: true }).@vite-pwa/sveltekitdoes NOT auto-register; without this call the virtual module is a no-op andnavigator.serviceWorker.getRegistration()returnsundefined.apps/web/tests/e2e/pwa.test.ts— P-01 (manifest shape) + P-02 (SW registration viawaitForFunctionpoll).
Note: the prod build later switched back to
strategies: 'generateSW'— see the PWA gotcha for the reason.
6.2 Manifest + iOS meta tags + placeholder icons
- Manifest driven by
vite.config.ts→SvelteKitPWA({ manifest: {…} }). Icons declared 192×192, 512×512, 512×512 maskable.theme_color: #0f172a,background_color: #f7f9fb,display: standalone. apps/web/static/icons/—icon-192.png,icon-512.png,icon-512-maskable.png,icon-180.pngplaceholder PNGs (slate background + "C" glyph). Generator:infra/scripts/generate-placeholder-icons.sh(ImageMagick). Replace with final artwork before public launch — noted instatic/icons/README.md.apps/web/src/app.html— iOS PWA meta tags:apple-mobile-web-app-capable,apple-mobile-web-app-status-bar-style,apple-mobile-web-app-title,apple-touch-icon.
6.3 Kong rate-limit (invitations only)
infra/kong.yml—rest-v1-invitationsroute:POST /rest/v1/collective_invitations, rate-limithour: 20, policy: local, limit_by: header (Authorization).strip_path: trueon a full-table path sends/upstream which PostgREST rejects withPGRST117, so the route also carries arequest-transformerplugin that rewrites the URI back to/collective_invitations.infra/docker-compose.dev.yml—KONG_PLUGINSenv var gainsrate-limiting(was missing).packages/test-utils/tests/rate-limit.test.ts— RL-02 only (21st invitation POST = 429). Gated behindRUN_RATE_LIMIT_TESTS=1so it's excluded fromjust test-all(Kong counters are shared state). Run viajust test-rate-limit, which also--force-recreates Kong to reset counters first.- Scope dropped during execution: Kong rate-limit on
/auth/v1/token+/auth/v1/authorizeremoved. Reasoning: Keycloak already offers native brute-force protection on the realm (bruteForceProtected: true,maxFailureWaitSeconds: 900,failureFactor: 30inkeycloak/realm-export.json), and stacking Kong on top throttles legitimate PKCE code exchanges during E2E (the same/auth/v1/tokenendpoint handles both password auth and code exchange — Kong can't distinguish). Seeplan/fase-6-deploy-prep.md§6.3 for the full rationale.
6.4 JWT rotation + production env template
infra/scripts/rotate-jwt.sh— bash script signing HS256anon+service_roleJWTs with a freshly-generated 48-byte secret viaopenssl dgst -sha256 -hmac + base64url. Prints the three values (SUPABASE_JWT_SECRET,PUBLIC_SUPABASE_ANON_KEY,SUPABASE_SERVICE_ROLE_KEY) for the operator to paste into.env. Does NOT touch files.- Dev secret rotated as a dry-run of the procedure.
.env+apps/web/.env.developmentupdated together (seeproject_env_keys_trapmemory — both files carryPUBLIC_SUPABASE_ANON_KEY). Deduped a pre-existing duplicatePUBLIC_SUPABASE_ANON_KEY=line in.env. .env.production.example— committed template with placeholders + rotation cadence note.
6.5 Lighthouse + RLS audit tooling
Justfile—just lighthouserecipe (prod build → node server on :3000 →lighthouse --only-categories=pwa,accessibility,best-practices→ HTML report). Requiresjust devto be up so the real Supabase stack is reachable.Justfile—just rls-auditdelegates toinfra/scripts/rls-audit.sh.infra/scripts/rls-audit.sh— signs an Eva JWT (non-member of the seed collective) withSUPABASE_JWT_SECRETand GETs eight REST endpoints (collectives,shopping_lists,shopping_items,task_lists,tasks,notes,collective_members,collective_invitations). Complementsrls-audit.test.ts; all 8 must return[].