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>
5.1 KiB
5.1 KiB
Fase 1 — what has been built
supabase/migrations/001_users.sql—userstable,handle_new_usertriggersupabase/migrations/002_collectives.sql—collectives,collective_members,collective_invitations; auto-promote-oldest-admin triggersupabase/migrations/003_rls.sql— full RLS policies,is_active_member/is_member/is_adminhelpers,accept_invitation()functionsupabase/migrations/004_storage.sql—avatarsbucket (private, signed URLs)apps/web/src/lib/supabase.ts— Supabase singleton with PKCE flowapps/web/src/lib/auth.ts—login()/logout()viasupabase.auth.signInWithOAuthapps/web/src/lib/stores/auth.ts—currentUser,authLoading,isAuthenticated,displayNameapps/web/src/lib/stores/collective.ts—currentCollective,userCollectives,collectiveMembersapps/web/src/lib/components/Avatar.svelte— initials / emoji / upload with deterministic colour hashapps/web/src/lib/components/ImageCropper.svelte— lazy-loaded cropperjs, 1:1, 256×256 WebP outputapps/web/src/routes/+layout.svelte— auth state listener, collective bootstrapapps/web/src/routes/(app)/+layout.ts— SSR disabled (ssr: false); no auth check here (see gotcha below)apps/web/src/routes/(app)/+layout.svelte— sidebar with collective switcher; auth redirect via$effectapps/web/src/routes/auth/callback/+page.svelte— PKCE code exchangeapps/web/src/routes/onboarding/+page.svelte— create collective or join via linkapps/web/src/routes/(app)/collective/manage/+page.svelte— members, roles, invite link generatorapps/web/src/routes/invitation/[token]/+page.svelte— accept invitation (auth-aware)apps/web/src/routes/(app)/settings/+page.svelte— display name, avatar, language, sign outapps/web/messages/en.json+es.json— all Fase 1 + 2a stringspackages/types/src/database.ts— manually seeded from migrations (update withjust db-typesonce CLI is wired)setup.sh— idempotent local dev setup (prerequisites, .env, Docker, migrations, seed, Paraglide)infra/kong-start.sh— Kong container entrypoint; substitutes${VAR}placeholders inkong.ymlbefore Kong starts (Kong 2.8 does not do this natively)
Test suite — initial scaffolding
packages/test-utils/— shared test infrastructure (Vitest integration tests)package.json—@colectivo/test-utils; depends on@supabase/supabase-js,jose,pgvitest.config.ts— loads root.envvialoadEnv; single-fork mode (no parallelism races)src/seed-constants.ts— fixed UUIDs for all 5 seed users + collective + seed listsrc/supabase-clients.ts—createClientAs(userId)signs HS256 JWT withSUPABASE_JWT_SECRET;createAdminClient()uses service role keysrc/db-helpers.ts—sql()via rawpgPool for direct DB manipulation (bypasses RLS); used to setdeleted_at = 8 days agoetc.tests/rls-isolation.test.ts— F-series: Eva (non-member) sees zero rows, all writes blockedtests/rls-collective.test.ts— B-series: collective read/update/invite by roletests/rls-lists.test.ts— C-series: list CRUD, soft-delete, trash window, cross-collective isolationtests/rls-items.test.ts— D-series: item CRUD by role, cross-collective item isolationtests/rls-frequency.test.ts— E-series: frequency read-only + trigger populates on INSERT
supabase/tests/*.sqleach start withCREATE EXTENSION IF NOT EXISTS pgtap;so they're idempotent on a fresh DB001_accept_invitation.sql—accept_invitation()happy path + not_found / expired / already_used; usesset_config('request.jwt.claim.sub', …)to setauth.uid()for the test session, and looks up bytoken(notid)002_item_frequency_trigger.sql— trigger normalizes name withlower(trim(...))and incrementsuse_counton repeat INSERTs. RLS write-blocks are covered by the Vitest suite instead (postgres superuser bypasses RLS here)003_promote_on_admin_leave.sql— deletes a synthetic admin frompublic.usersto fire theBEFORE DELETEtrigger and asserts the oldest remaining member is promoted
apps/web/playwright.config.ts— Playwright config;globalSetupis a Keycloak health check (not a session cache),reuseExistingServer: trueapps/web/tests/fixtures/users.ts— seed user constants (Ana, Borja, Carmen, David, Eva)apps/web/tests/fixtures/login.ts—loginAs(page, user)runs the real OAuth flow (Keycloak → GoTrue PKCE) and waits for the session token to land in localStorage. Each test that needs auth calls this inbeforeEach; cachedstorageStateis NOT used (see the Playwright storageState gotcha inCLAUDE.md)apps/web/tests/e2e/auth.test.ts— A-series: unauthenticated redirect, full login, collective visible in sidebar, sign-out, guest loginapps/web/tests/e2e/lists.test.ts— C-series: create (with reload-persistence check), soft-delete → appears in trash drawer, archive, guest read-onlyapps/web/tests/e2e/items.test.ts— D-series: seed list renders, add item (with reload-persistence check), toggle check, desktop-hover delete, frequency suggestions, guest read-only