Builds the full parent-side experience for the recipient of an Ember gift,
plus a third Claude topic for the in-journal "talk it through" surface.
Frontend (web/app/r/[token]/*) — all token-scoped, all persists to
localStorage under ember:parent:{token}:v1, resumes mid-flow:
- welcome → letter → how-it-works → account ("Save your space")
- /home (Today) — composer + 3 starting points (Pick a prompt /
Talk it through with Ember / Record your voice). Bottom tabs:
Today / Journal / Prompts / Share
- /journal — List (grouped by month), Calendar (interactive — tap day),
Media. "+ New entry" FAB
- /journal/new — dedicated composer screen (FAB target + prompt-tap target,
takes ?promptId=)
- /prompts — All / Used filter; tap unused prompt → composer with prompt
- /ai — Claude chat (parent-reflect tone). "Save as journal entry" distills
the conversation into prose in the parent's first-person voice
- /voice — dedicated voice note (record → Whisper → editable transcript →
save with durationSeconds)
- /share — sharing settings + "Share what I've written so far" with
confirm modal. Sharing is one-time → archives the journal
- /share/when — How and when picker (when-ready / legacy / date /
milestone). Date and milestone require a specific calendar date
- /share/done — "She has it." success ack
Reusable components:
- EntryComposer — text + photo + voice (Whisper) used on Today,
/journal/new, and indirectly via /prompts
- BottomTabs — 4-tab nav with Today / Journal / Prompts / Share
- AvatarMenu — avatar circle → dropdown → Sign out (clears all
ember:parent:* + ember:onboarding:v1 + cookie, routes to /login)
Archived state — once sharing.sharedAt is set:
- /home shows "Your journal is shared." instead of composer
- /journal shows Archived banner, FAB hidden
- /prompts shows read-only banner, taps disabled
- /journal/new + /voice redirect to /journal
- /ai save button disabled
- /share replaces options with the Archived snapshot card
Server (server/src/routes/ai.ts):
- Adds 3rd topic "parent-reflect" to /ai/converse and /ai/summarize.
- Different Claude system prompt: warm, low-pressure, ok with silence,
never simulates anyone in the parent's life. Summarizer writes in
first-person from the parent's voice for direct insertion as an entry.
Docs:
- BACKEND_HANDOFF_V2.md — comprehensive page-by-page spec covering every
child + parent route, every API endpoint to build, full data model,
file storage, email, sharing/archive flow, migration plan from
localStorage. Supersedes BACKEND_HANDOFF.md (which only covered child
onboarding); the original is left in place for context.
Notes:
- Parent flow is currently localStorage-only — the recipientRoutes that
landed on main aren't wired yet. BACKEND_HANDOFF_V2 §10 documents the
migration plan.
- /login was intentionally not touched — main's existing login (with
real backend wiring) stands.
- Photos: inline data URLs (4MB cap) pending S3.
- Audio: transcript only on the parent side; raw audio storage is on
the backend handoff list.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
/r/[token]/*. Welcome → letter → how-it-works → account → home (Today) with bottom-tab nav (Today / Journal / Prompts / Share). All token-scoped, all persists per token to localStorage, resumes mid-flow./r/[token]/aiis a Claude chat with a third topicparent-reflect(warm, low-pressure, ok with silence, never simulates anyone in the parent's life). "Save as journal entry" distills the conversation into first-person prose for direct insertion.sharing.sharedAt.BACKEND_HANDOFF.mdleft in place.Routes
/r/[token]— "Take your time" landing/r/[token]/letter— personal letter (serif; renders generic ifpersonalMessagenot yet collected)/r/[token]/start— "Three things to know"/r/[token]/account— "Save your space" (email + password, no social login)/r/[token]/home— Today: composer + 3 starting points/r/[token]/journal— List / Calendar (interactive) / Media + FAB/r/[token]/journal/new— composer (also takes?promptId=)/r/[token]/prompts— All / Used filter/r/[token]/ai— Claude chat with "Save as entry"/r/[token]/voice— record → Whisper → editable transcript → save/r/[token]/share— sharing settings + share-now confirm modal/r/[token]/share/when— when-ready / legacy / date / milestone (date required for date + milestone)/r/[token]/share/done— "She has it." successReusable bits
EntryComposer— text + photo + voice (Whisper). Used by Today, /journal/new, /prompts (via /journal/new).BottomTabs— 4-tab nav.AvatarMenu— avatar → dropdown → Sign out (clears allember:parent:*+ember:onboarding:v1+ cookie, routes to/login).Server delta
server/src/routes/ai.ts— addstopic: "parent-reflect"to/ai/converseand/ai/summarize. Two new system prompts (converse + summarize) tuned for the parent surface.Out of scope (intentional, called out in BACKEND_HANDOFF_V2.md §10 + §13)
/loginwas intentionally not touched — main's existing email/password login (with real backend wiring) stands. The handoff doc notes that a unified login was prototyped on the recipient side and can be merged later.Test plan
OPENAI_API_KEYandANTHROPIC_API_KEYin root.env; runbun dev./r/abc→ tap-continue through letter / how-it-works / account → land on/home./home, type something + Save → entry appears in/journal. Try the mic — Whisper transcribes and appends./journal, switch to Calendar → tap a day with entries → see them below; switch to Media if you've added a photo./prompts, tap an unused prompt → opens composer with prompt context. Save → returns to/journal, prompt now in "Used"./ai, multi-turn with Ember → "Save as entry" → conversation distilled into a first-person journal entry./voice, record → review transcript (editable) → save → "Voice note" entry in/journal./share, tap "Change how this is shared" → pick a date / milestone (date required) → Continue → setting persists./share, tap "Share what I've written so far" → confirm modal → "She has it." success →/journalnow shows Archived banner, FAB hidden, prompts disabled, composer replaced with archived card./login, all parent state cleared.🤖 Generated with Claude Code