Skip to content

Pre-beta audit remediation: security, features, UX, tests#102

Open
neonwatty wants to merge 31 commits intomainfrom
feat/pre-beta-audit-remediation
Open

Pre-beta audit remediation: security, features, UX, tests#102
neonwatty wants to merge 31 commits intomainfrom
feat/pre-beta-audit-remediation

Conversation

@neonwatty
Copy link
Copy Markdown
Collaborator

Summary

Comprehensive remediation of all findings from the pre-open-beta security and quality audit. 22 commits across 6 phases:

Phase 1: Critical Security Fixes

  • Secured SECURITY DEFINER RPCs — added auth.uid() guards to create_couple_for_user, update_couple_setting, convert_request_to_reminder (with NULL-safe handling for Vercel server actions)
  • Privatized milestone-photos bucket — set public = false, switched to signed URLs with legacy URL backward compatibility
  • Rate-limited login/signup — moved from direct client-side Supabase Auth to server actions with IP-based rate limiting (10/15min login, 5/hr signup)
  • Rate-limited onboarding — prevents email spam via couple creation cycling (5/hr per user)

Phase 2: Missing Features

  • Password reset flow — forgot-password page, server-side code exchange, reset-password form, rate-limited, email enumeration protection
  • Account deletion — password-confirmed, rate-limited, admin-client deletion with two-step UI confirmation in Settings > Data & Privacy

Phase 3: UX Polish

  • Dark mode on auth pages — replaced hardcoded bg-gray-50/text-gray-900 with semantic theme tokens
  • Dark mode on check-in page — same treatment
  • Check-in loading skeleton — was the only (app) route without one
  • Auth form accessibilityaria-required, aria-invalid, aria-live, autocomplete attributes
  • AlertDialog for destructive actions — replaced browser confirm() in love-languages, added confirmation to notes bulk delete and request delete
  • Waitlist email CTA — added styled button to confirmation template

Phase 4: Test Coverage (~120 new tests)

  • joinWaitlist server action
  • cleanup-storage cron job
  • bookends-reducer (50 tests, all 12 action types)
  • useCheckInMutations (29 tests)
  • couples.ts remaining functions (24 tests for 6 functions)

Phase 5: Performance

  • 28 foreign key indexes — all couple_id columns + other frequently-queried FKs for RLS query performance

Phase 6: Cleanup

  • Documented subscriptions table admin-only write intent
  • Fixed #main-content target for skip-to-content link

DB Migrations (4 new)

  • 00032_secure_rpc_functions.sql
  • 00033_private_milestone_photos.sql
  • 00034_add_foreign_key_indexes.sql
  • 00035_document_subscriptions_table.sql

Manual Step Required

Enable Leaked Password Protection in Supabase Dashboard → qc-production → Auth → Settings

Test plan

  • TypeScript typecheck passes
  • All 1671 tests pass (184 files)
  • No new lint errors
  • Verify dark mode on login/signup/check-in pages
  • Test password reset flow end-to-end
  • Test account deletion flow
  • Verify milestone photos still display (signed URLs)
  • Enable leaked password protection in Supabase Dashboard

🤖 Generated with Claude Code

neonwatty and others added 30 commits March 20, 2026 10:31
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…, types

Fixes 8 issues from spec review:
- Migration 00009 → 00031 (correct sequence)
- Server action moved to src/app/(auth)/signup/actions.ts (colocated)
- CSP update for PostHog host documented
- Beta gate clarified: allowed emails can still reach signup form
- WaitlistForm colocated with signup page
- shouldSendEmail() exclusion documented
- Server-side PostHog client (analytics-server.ts) specified
- DbWaitlist type addition to database.ts documented

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reviewed and fixed: reordered analytics before PostHog provider,
CSP reads env var instead of hardcoding, removed dead code,
added test env cleanup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Guards use IS NOT NULL AND != pattern to handle Vercel server actions
where auth.uid() may be NULL — blocks only when auth context is present
but caller does not match the target user or couple.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move password-based login and signup from direct client-side Supabase
Auth calls to server actions with IP-based rate limiting (10/15min for
login, 5/hour for signup). Includes Zod validation and full test coverage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add forgot-password and reset-password pages with server actions,
Zod validation, IP-based rate limiting, and email enumeration
protection. Includes unit tests and "Forgot password?" link on
the login page.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a server action with Zod validation, rate limiting (3/hour), and
password re-verification before calling admin.deleteUser. Wires a
two-step DeleteAccountPanel UI (Danger Zone card) below DataExportPanel
in the Data & Privacy settings tab, with 5 unit tests all passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace all hardcoded gray-*/blue-* Tailwind classes in login and signup
pages with semantic theme tokens (bg-muted/50, bg-card, text-foreground,
text-muted-foreground, border-input, bg-primary, text-primary-foreground,
etc.) so both pages render correctly in dark mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace hardcoded light-mode color classes (text-gray-*, bg-white, bg-gray-50, border-gray-*, bg-pink-50, text-pink-*) with semantic theme tokens (text-foreground, text-muted-foreground, bg-card, bg-muted/50, border-border, border-input, bg-primary/5, text-primary) so the check-in page renders correctly in dark mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add aria-required, autocomplete, role="alert", aria-live, aria-describedby, and aria-busy attributes to login and signup forms for screen reader and autofill support.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…uctive actions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements the joinWaitlist server action in src/app/(auth)/signup/actions.ts
and adds sendWaitlistConfirmation to src/lib/email/send.ts, with 10 unit tests
covering validation errors, rate limiting, duplicate suppression, happy path,
DB failure, and non-blocking Resend/email failures.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
29 tests covering all mutations in useCheckInMutations — startCheckIn,
completeCheckIn, abandonCheckIn, saveMoodDraft (debounce), note CRUD,
action item CRUD, and sync dispatch calls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add happy path, auth, DB error, and edge case tests for joinCouple,
leaveCouple, createInvite, resendInvite, getInviteStatusByToken, and
acceptInvite — bringing couples.test.ts to 37 tests total.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tPanel in settings test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ew signup components

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ax-lines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ax-lines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant