Skip to content

feat: Circulation of Love — anonymous, time-bound letter sharing - #82

Merged
TrainTravel merged 2 commits into
mainfrom
feat/love-circulation
Jun 21, 2026
Merged

feat: Circulation of Love — anonymous, time-bound letter sharing#82
TrainTravel merged 2 commits into
mainfrom
feat/love-circulation

Conversation

@TrainTravel

Copy link
Copy Markdown
Owner

Summary

Implements Circulation of Love — an opt-in surface where users share anonymous, time-bound letters in their primary language. Letters drift through a current visible to opted-in users in the same language for 7–30 days, then archive.

Philosophy: Inspired by the user's grandfather's idea of the circulation of love. Not a social network (no follows, profiles, replies, comments). The only reaction is "Hold this for a moment" — silent, idempotent, private to the author.

What's Included

Spec & Design — full spec in docs/specs/love-circulation.md + Lovable display prompt in docs/launch/lovable-circulation-display.md

Data Layer:

  • 3 tables: love_letters, letter_holdings, circulation_settings + full RLS (authors always see own letters; others only see passed+live+matching-language IF opted in)
  • Per-language pseudonym pools (16–20 natural-imagery names) + deterministic FNV-1a hash
  • Hooks: usePseudonym, useCirculationSettings, useLoveLetters

Edge Functions:

  • moderate-letter — Gemini 2.5 Flash pre-publish moderation (wide pass, softfail on ambiguous self-harm/PII, block on explicit harm/harassment)
  • circulate-letters — cron-style archival sweep (authenticated by CIRCULATION_CRON_SECRET)

UI (3 screens):

  • LettersInCirculationScreen — drift feed + Join CTA for non-opted-in
  • ShareALetterScreen — 500-char compose + pseudonym chip + softfail/block note rendering
  • CirculationSettingsScreen — receive/share toggles + 7/14/30 TTL chooser

Wiring:

  • 3 new JournalSteps, 3 new navigation openers on useJournal, Waves-icon tile on HomeScreen
  • animate-letter-drift keyframe (12s sine-like motion, respects prefers-reduced-motion)
  • Full bilingual coverage en/fr/es/ja/zh-Hans/zh-Hant

Tests:

  • 11 unit tests (pseudonym determinism, pool integrity, language-specific selection)
  • 5 E2E specs (navigation, CTA visibility, settings flow, TTL chooser)

Bug Fixes (from test validation)

  • 🟡 E2E auth setup: Added injectMockSession() + mockAuthRoutes() to beforeEach; all 5 circulation E2E specs now pass
  • 🟡 Language filter: Added .eq('language', primaryLang) to useLoveLetters.refresh() — users now only see letters in their primary language

Test Plan

  • ✅ vitest: 359 pass (32 files)
  • ✅ E2E: 5 pass in circulation.spec.ts
  • ✅ tsc: clean (0 errors)
  • ✅ Lint: no new issues

Manual verification needed:

  1. Opt in to Circulation → share a letter → verify pseudonym is stable, single regenerate works, moderation verdicts render correctly
  2. Switch primary language → verify feed shows only letters in new language
  3. Hold a letter → unhold → verify idempotency (duplicate holds don't error)
  4. Drift animation → verify smooth loop, staggered delays, respects prefers-reduced-motion

Pre-deployment checklist:

  • Deploy edge functions: supabase secrets set CIRCULATION_CRON_SECRET=... + supabase functions deploy moderate-letter circulate-letters
  • Schedule circulate-letters cron (daily archival sweep)
  • Lovable visual pass (paste docs/launch/lovable-circulation-display.md into Lovable for feed aesthetics)

🧠 Generated with Claude Code

TrainTravel and others added 2 commits June 20, 2026 22:47
Two blockers from test-engineer agent validation:
1. E2E circulation.spec.ts was missing auth mocks, causing 5 tests to timeout
   when trying to access home tile behind ProtectedRoute. Added
   injectMockSession() and mockAuthRoutes() to beforeEach.
2. useLoveLetters.refresh() had no language filter despite RLS comment claiming
   it enforces language isolation. Added .eq('language', primaryLang) for
   defense-in-depth and added primaryLang to dependency array.

All 5 E2E tests now pass. All 359 unit tests still pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@TrainTravel
TrainTravel merged commit 13ab984 into main Jun 21, 2026
1 check failed
@TrainTravel
TrainTravel deleted the feat/love-circulation branch June 21, 2026 21:20
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