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>
3.5 KiB
Fase 7 — collective-flow E2E coverage (2026-04-14)
12 new Playwright tests + 1 DB fixtures helper + 1 migration. Writing the tests uncovered three product-code bugs which are fixed as part of this phase.
Tests (all green, included in just test-e2e)
apps/web/tests/e2e/onboarding.test.ts— O-01..O-03: Eva auto-redirect to/onboarding, happy-path create, empty-name submit-disabled.apps/web/tests/e2e/invitation.test.ts— I-01..I-05: admin generates token, logged-out-then-accept, logged-in one-click accept, expired + already-used error states.apps/web/tests/e2e/manage-collective.test.ts— MC-02..MC-05: promote member → admin, demote back, remove member, generate pending invitation.apps/web/tests/fixtures/db.ts—resetEva()/seedExpiredInvitation()/seedUsedInvitation()/restoreSeedMembership()/countMembership(). All via raw SQL (bypasses RLS) so they don't depend onSUPABASE_SERVICE_ROLE_KEYbeing in the Playwright process env.
Scope dropped from the plan
- O-04 (multi-collective via a "+ new collective" button in the sidebar): the affordance does not exist in the UI; adding it would be feature work, out of a test-only phase.
- MC-01 (rename collective):
/collective/managehas no rename input; same reasoning.
Both are flagged in plan/fase-7-collective-flow-tests.md as future UI follow-ups.
Product-code fixes discovered while writing these tests (all committed with this phase)
-
supabase/migrations/012_create_collective_rpc.sql— atomiccreate_collective(name, emoji)RPC. Pre-existing onboarding flow did two separate REST calls (INSERT collectiveschained with.select().single(), thenINSERT collective_members). Both failed: the RETURNING on the first triggered the SELECT policy (is_member(id)) which the creator can't pass yet, and the second was gated byis_admin(collective_id)against a collective with zero admins. The RPC isSECURITY DEFINERand does both inserts atomically.onboarding/+page.sveltenow callssupabase.rpc('create_collective', {...}). -
routes/+layout.svelte— resume pending invitation after login.invitation/[token]/+page.sveltestashes the token insessionStorage.pendingInvitationTokenbefore triggering OAuth, but nothing read it back. Post-login redirect logic now checks sessionStorage and routes the user back to/invitation/<token>instead of defaulting to/onboardingor/lists. -
routes/(app)/collective/manage/+page.svelte— reactively reload members.onMountcalledloadMembers()once; if$currentCollectivewas still null at that point (race with the auth listener on a cold navigation), the query short-circuited and the list stayed empty. Now subscribed tocurrentCollectivesoloadMembersre-runs whenever the store resolves. -
routes/invitation/[token]/+page.svelte— wait for authLoading before deciding. Racing with the auth listener's first emit caused the page to see!$isAuthenticatedfor a freshly-authenticated user and trigger a redundant Keycloak round-trip. Now awaitsauthLoading → falsebefore branching.
Test IDs added to UI (stable selectors for Playwright)
- Onboarding:
onboarding-create-tab,onboarding-join-tab,collective-name-input,collective-submit. - Manage:
member-row-<uid>,role-select-<uid>,remove-member-<uid>,generate-invite,invite-link. - Invitation:
invitation-accept,invitation-error(withdata-error-keyattribute carrying the error key for assertion).