Procházet zdrojové kódy

[Scope] Phase 4 in-progress markers, 5.9 sign-out, 4.7 filter note

- Mark Phase 4.1-4.8 as in-progress ([~]) reflecting current state
- Add Phase 4.7 NOTE about home Genre Roll swapping to the structured
  filter (matches commit 99e7c5d)
- Add Phase 5.9: user-facing sign-out, with three open decisions
  flagged inline (control placement, anonymous-orphan warning, redirect)
- Add Phase 9.20: matching QA test for sign-out
- Add Section 9 success criterion for sign-out
- Repair a mangled bullet in Section 7 Deployment ("Next.js app
  container") that had lost its alternative-argon2 parenthetical

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
User před 2 měsíci
rodič
revize
68590193dc
1 změnil soubory, kde provedl 14 přidání a 11 odebrání
  1. 14 11
      PROJECT_SCOPE.md

+ 14 - 11
PROJECT_SCOPE.md

@@ -142,7 +142,7 @@ MovieDice solves group decision paralysis by combining collaborative curation (e
    - Top: movies already in the group's list (labeled "In Your List")
    - Below separator: TMDB search results (server-side filtered by adult field)
 4. User taps a TMDB result → movie inserted into DB with poster, genres, title, year,
-   trailer URL (fetched from TMDB via server proxy and stored at add-time;
+   trailer URL (fetched from TMDB via server proxy at add-time;
    validated against allowlist: youtube.com, themoviedb.org, imdb.com),
    and added-by attribution
 5. All group members see the new movie appear in real time
@@ -288,7 +288,7 @@ List Deletion flow (separate from self-removal):
 | Auth                 | Supabase Anonymous Sign-In via `@supabase/ssr`          | `signInAnonymously()` — no email, instant account, JWT for RLS; cookie-based session via `createBrowserClient`/`createServerClient` |
 | Movie Data           | TMDB API                                                | Posters, genres, metadata, trailer URLs; all calls via server-side proxy with `include_adult=false`                                 |
 | State Management     | TanStack Query (React Query)                            | Server state sync, caching with explicit `staleTime`, loading states                                                                |
-| Admin Sessions       | iron-session v8                                         | Encrypted HttpOnly cookie for Master Admin TOTP sessions (use v8 README directly — v7 patterns are incompatible)                    |
+| Admin Sessions       | iron-session v8                                        | Encrypted HttpOnly cookie for Master Admin TOTP sessions (use v8 README directly — v7 patterns are incompatible)                    |
 | 2FA (Master Admin)   | TOTP via otplib (or equivalent)                         | Authenticator-app compatible; TOTP secret never exposed client-side                                                                 |
 | PWA                  | @serwist/next                                           | App Router compatible, Workbox 7; requires authoring `app/sw.ts` and `tsconfig.worker.json`                                         |
 | Image Optimization   | sharp (local assets only)                               | TMDB posters use native sized URLs from TMDB CDN directly (not next/image)                                                          |
@@ -420,7 +420,7 @@ Configure HTTP security headers at the Caddy reverse proxy level (not in next.co
 ### Deployment
 
 - **Self-hosted Docker deployment** orchestrated via docker-compose
-- **Next.js app container**: multi-stage Dockerfile with `node:22-slim`, `output: 'standalone'`, non-root user, `tini` for PID 1 signal handling, `.dockerignore`; builder stage must install `python3 make g++` for argon2 native compilation (alternative: `@node-rs/argon2` with pre-compiled NAPI binaries eliminates node-gyp requirement)
+- **Next.js app container**: multi-stage Dockerfile with `node:22-slim`, `output: 'standalone'`, non-root user, `tini` for PID 1 signal handling, `.dockerignore`; builder stage must install `python3 make g++` for argon2 native build (alternative: `@node-rs/argon2` with pre-compiled NAPI binaries eliminates node-gyp requirement)
 - **Supabase self-hosted**: full Docker stack (Postgres, GoTrue, Realtime, PostgREST, Kong, Studio) using Supabase's official docker-compose configuration adapted for this project
 - **Supabase secret replacement (MANDATORY before first deployment)**: ALL default secrets must be replaced before the first `docker compose up`. Defaults are published on GitHub — a default JWT_SECRET allows forging JWTs that bypass all RLS. Replace these as a lockstep set: `JWT_SECRET` → regenerate both `ANON_KEY` and `SERVICE_ROLE_KEY` (they derive from JWT_SECRET); also replace `POSTGRES_PASSWORD`, `DASHBOARD_USERNAME`, `DASHBOARD_PASSWORD`. Consider adding a startup check that refuses to start if default values are detected.
 - **GoTrue configuration**: Set `GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED=true` (disabled by default — without it, `signInAnonymously()` returns 400); disable all other auth methods: `GOTRUE_EXTERNAL_EMAIL_ENABLED=false`, `GOTRUE_EXTERNAL_PHONE_ENABLED=false`, all OAuth providers disabled
@@ -486,14 +486,14 @@ Configure HTTP security headers at the Caddy reverse proxy level (not in next.co
 
 ### Phase 4: Randomizer (April 20-23, 2026) — MVP
 
-- [ ] 4.1 — Build "Roll the Dice!" and "Genre Roll!" button layout pinned above the movie grid
-- [ ] 4.2 — Implement randomizer logic: select a random unwatched movie from the eligible pool (single list when in a list view; all user lists combined when on the home page); on the home page, render result as a standalone teaser card in place — do not navigate into any list; announce result via `aria-live="polite"` region
-- [ ] 4.3 — Build in-app roll animation: scatter/flip/spin elimination sequence landing on winner (target 2-3 seconds); test performance on low-end mobile devices; respect `prefers-reduced-motion` (use simple fade-in on winner when enabled)
-- [ ] 4.4 — Implement re-roll on second tap of Roll button
-- [ ] 4.5 — Build Genre Roll text input UI
-- [ ] 4.6 — Implement emotion-to-genre mapping as a static TypeScript constant (see Section 10 reference table); translate genre labels to TMDB numeric genre IDs
-- [ ] 4.7 — Implement genre + emotion filter logic: normalize input (lowercase, tokenize on spaces/commas), map emotions to TMDB genre IDs, filter unwatched pool; if no matches, show "No matches — showing full list" and proceed unfiltered
-- [ ] 4.8 — Apply roll animation to genre-filtered results; document API routes in markdown
+- [~] 4.1 — Build "Roll the Dice!" and "Genre Roll!" button layout pinned above the movie grid
+- [~] 4.2 — Implement randomizer logic: select a random unwatched movie from the eligible pool (single list when in a list view; all user lists combined when on the home page); on the home page, render result as a standalone teaser card in place — do not navigate into any list; announce result via `aria-live="polite"` region
+- [~] 4.3 — Build in-app roll animation: scatter/flip/spin elimination sequence landing on winner (target 2-3 seconds); test performance on low-end mobile devices; respect `prefers-reduced-motion` (use simple fade-in on winner when enabled)
+- [~] 4.4 — Implement re-roll on second tap of Roll button
+- [~] 4.5 — Build Genre Roll text input UI
+- [~] 4.6 — Implement emotion-to-genre mapping as a static TypeScript constant (see Section 10 reference table); translate genre labels to TMDB numeric genre IDs
+- [~] 4.7 — Implement genre + emotion filter logic: normalize input (lowercase, tokenize on spaces/commas), map emotions to TMDB genre IDs, filter unwatched pool; if no matches, show "No matches — showing full list" and proceed unfiltered. NOTE: home-view Genre Roll swapped to `filterByGenresAndEmotionsStructured` (2026-04-14) — fixes genre-only rolls silently discarding the filter when `movies.genres` stores TMDB names, not numeric IDs.
+- [~] 4.8 — Apply roll animation to genre-filtered results; document API routes in markdown
 
 ### Phase 5: Landing Page and MVP Polish (April 23-26, 2026) — MVP CUTOFF
 
@@ -505,6 +505,7 @@ Configure HTTP security headers at the Caddy reverse proxy level (not in next.co
 - [ ] 5.6 — Error handling: invalid invite code, TMDB API failure, network errors
 - [ ] 5.7 — Configure HTTP security headers in Caddyfile: CSP (with self-hosted URLs, not \*.supabase.co), X-Frame-Options, X-Content-Type-Options, Referrer-Policy, HSTS (start with max-age=86400, increase before launch), Permissions-Policy; use Report-Only mode during testing
 - [ ] 5.8 — Final MVP smoke test and Docker production deployment
+- [ ] 5.9 — Implement user-facing sign-out: call `supabase.auth.signOut()` server-side (or via a dedicated API route), clear the session cookie, and redirect to the landing page. DECISIONS NEEDED: (a) where the sign-out control lives (header menu, settings page, or both); (b) whether to show a confirmation dialog warning that signing out of an anonymous account without a saved recovery code will orphan the account; (c) redirect target after sign-out (landing page assumed). Do not confuse with `/api/admin/logout`, which handles Master Admin TOTP sessions only.
 
 ---
 
@@ -554,6 +555,7 @@ Configure HTTP security headers at the Caddy reverse proxy level (not in next.co
 - [ ] 9.17 — Data retention test: verify inactive account cleanup job correctly identifies and deletes accounts inactive for 12+ months; verify orphan group handling (admin transfer or cascade delete); verify auth.users record removal
 - [ ] 9.18 — Docker security test: verify Kong/Postgres ports not accessible from host; verify Studio not publicly accessible; verify all default Supabase secrets have been replaced; verify Caddy TLS certificates persist across container restart
 - [ ] 9.19 — Backup test: verify pg_dump backup runs daily; test restore procedure
+- [ ] 9.20 — Sign-out test: verify sign-out clears the Supabase session cookie and redirects to landing page; verify signed-out user cannot access authenticated routes; verify sign-out control is distinct from `/api/admin/logout`; confirm any anonymous-account warning (if implemented per 5.9 decision) displays correctly before sign-out completes
 
 ### Phase 10: Launch (June 22 - July 5, 2026) — Full Feature Complete
 
@@ -601,6 +603,7 @@ Configure HTTP security headers at the Caddy reverse proxy level (not in next.co
 - Database backups run daily with successful restore verification
 - Sentry error events do not contain user UUIDs
 - Privacy policy contains all required GDPR/CCPA sections
+- User-facing sign-out clears the session cookie and redirects to the landing page; signed-out users cannot access authenticated routes
 
 ## 10. Reference: Emotion-to-Genre Mapping