Files
collective-lists/docs/history/fase-1.md
Oier Bravo Urtasun 768b3cda58 docs: split CLAUDE.md into docs/{development,deployment,history/fase-*}
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>
2026-04-18 22:21:20 +02:00

5.1 KiB
Raw Blame History

Fase 1 — what has been built

  • supabase/migrations/001_users.sqlusers table, handle_new_user trigger
  • supabase/migrations/002_collectives.sqlcollectives, collective_members, collective_invitations; auto-promote-oldest-admin trigger
  • supabase/migrations/003_rls.sql — full RLS policies, is_active_member/is_member/is_admin helpers, accept_invitation() function
  • supabase/migrations/004_storage.sqlavatars bucket (private, signed URLs)
  • apps/web/src/lib/supabase.ts — Supabase singleton with PKCE flow
  • apps/web/src/lib/auth.tslogin() / logout() via supabase.auth.signInWithOAuth
  • apps/web/src/lib/stores/auth.tscurrentUser, authLoading, isAuthenticated, displayName
  • apps/web/src/lib/stores/collective.tscurrentCollective, userCollectives, collectiveMembers
  • apps/web/src/lib/components/Avatar.svelte — initials / emoji / upload with deterministic colour hash
  • apps/web/src/lib/components/ImageCropper.svelte — lazy-loaded cropperjs, 1:1, 256×256 WebP output
  • apps/web/src/routes/+layout.svelte — auth state listener, collective bootstrap
  • apps/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 $effect
  • apps/web/src/routes/auth/callback/+page.svelte — PKCE code exchange
  • apps/web/src/routes/onboarding/+page.svelte — create collective or join via link
  • apps/web/src/routes/(app)/collective/manage/+page.svelte — members, roles, invite link generator
  • apps/web/src/routes/invitation/[token]/+page.svelte — accept invitation (auth-aware)
  • apps/web/src/routes/(app)/settings/+page.svelte — display name, avatar, language, sign out
  • apps/web/messages/en.json + es.json — all Fase 1 + 2a strings
  • packages/types/src/database.ts — manually seeded from migrations (update with just db-types once 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 in kong.yml before 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, pg
    • vitest.config.ts — loads root .env via loadEnv; single-fork mode (no parallelism races)
    • src/seed-constants.ts — fixed UUIDs for all 5 seed users + collective + seed list
    • src/supabase-clients.tscreateClientAs(userId) signs HS256 JWT with SUPABASE_JWT_SECRET; createAdminClient() uses service role key
    • src/db-helpers.tssql() via raw pg Pool for direct DB manipulation (bypasses RLS); used to set deleted_at = 8 days ago etc.
    • tests/rls-isolation.test.ts — F-series: Eva (non-member) sees zero rows, all writes blocked
    • tests/rls-collective.test.ts — B-series: collective read/update/invite by role
    • tests/rls-lists.test.ts — C-series: list CRUD, soft-delete, trash window, cross-collective isolation
    • tests/rls-items.test.ts — D-series: item CRUD by role, cross-collective item isolation
    • tests/rls-frequency.test.ts — E-series: frequency read-only + trigger populates on INSERT
  • supabase/tests/*.sql each start with CREATE EXTENSION IF NOT EXISTS pgtap; so they're idempotent on a fresh DB
    • 001_accept_invitation.sqlaccept_invitation() happy path + not_found / expired / already_used; uses set_config('request.jwt.claim.sub', …) to set auth.uid() for the test session, and looks up by token (not id)
    • 002_item_frequency_trigger.sql — trigger normalizes name with lower(trim(...)) and increments use_count on 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 from public.users to fire the BEFORE DELETE trigger and asserts the oldest remaining member is promoted
  • apps/web/playwright.config.ts — Playwright config; globalSetup is a Keycloak health check (not a session cache), reuseExistingServer: true
  • apps/web/tests/fixtures/users.ts — seed user constants (Ana, Borja, Carmen, David, Eva)
  • apps/web/tests/fixtures/login.tsloginAs(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 in beforeEach; cached storageState is NOT used (see the Playwright storageState gotcha in CLAUDE.md)
  • apps/web/tests/e2e/auth.test.ts — A-series: unauthenticated redirect, full login, collective visible in sidebar, sign-out, guest login
  • apps/web/tests/e2e/lists.test.ts — C-series: create (with reload-persistence check), soft-delete → appears in trash drawer, archive, guest read-only
  • apps/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