# Kalei — User Journey Technical Map > Version 1.0 — February 2026 > Maps every user-facing flow to backend API endpoints, database operations, frontend components, and AI calls --- ## Architecture Summary **Backend:** Fastify 5.x (Node.js 22 LTS), Drizzle ORM, PostgreSQL 16, Redis 7 **Frontend:** React Native + Expo SDK 54+, Expo Router, TanStack Query v5, Zustand, MMKV v4 **AI:** Claude Haiku 4.5 (primary), Groq/Qwen fallback, provider-agnostic AI Gateway **Auth:** JWT with refresh token rotation, Apple/Google SSO **Billing:** Direct App Store / Google Play webhook integration --- ## 1. Authentication & Onboarding ### 1.1 Account Registration **User Action:** Enters email + password or taps Apple/Google SSO | Layer | Detail | |-------|--------| | **API** | `POST /auth/register` — body: `{ email, password, provider? }` | | **Validation** | Zod: email format, password 8+ chars, provider enum | | **DB Write** | `INSERT INTO users (id, email, password_hash, created_at)` | | **DB Write** | `INSERT INTO profiles (user_id, display_name, coaching_style, onboarding_complete)` | | **DB Write** | `INSERT INTO subscriptions (user_id, plan, status, started_at)` — defaults to `free` | | **Redis** | Set `rate:auth:{ip}` with TTL for brute-force protection | | **Response** | `{ access_token, refresh_token, user: { id, email, profile } }` | | **Frontend** | `AuthStore.setTokens()` → MMKV encrypted storage → navigate to onboarding | ### 1.2 Token Refresh | Layer | Detail | |-------|--------| | **API** | `POST /auth/refresh` — body: `{ refresh_token }` | | **DB Read** | `SELECT FROM refresh_tokens WHERE token = $1 AND revoked = false` | | **DB Write** | Revoke old token, issue new pair (rotation) | | **Redis** | Invalidate old session cache | ### 1.3 Onboarding Completion **User Action:** Completes screens 2-9 (style selection, first Turn) | Layer | Detail | |-------|--------| | **API** | `PATCH /me/profile` — body: `{ coaching_style, notification_time, onboarding_complete: true }` | | **DB Write** | `UPDATE profiles SET coaching_style = $1, notification_time = $2, onboarding_complete = true` | | **Push** | Schedule first notification via push service at chosen time | | **Frontend** | `OnboardingStore.complete()` → navigate to main tab navigator | --- ## 2. The Turn (Reframing) ### 2.1 Submit a Turn **User Action:** Types thought → taps "Turn it" | Layer | Detail | |-------|--------| | **Frontend** | Validate non-empty input, show Turn animation (1.5s kaleidoscope rotation) | | **API** | `POST /turns` — body: `{ input_text, coaching_style? }` | | **Rate Check** | Redis: `INCR rate:turns:{user_id}:{date}` → reject if > 3 (free) or > 100 (prism) | | **Entitlement** | `SELECT plan FROM subscriptions WHERE user_id = $1` → gate check | | **Safety** | Deterministic keyword scan → if flagged: `INSERT INTO safety_events`, return crisis response | | **AI Call** | AI Gateway → Claude Haiku 4.5: system prompt (coaching style + reframe instructions) + user input | | **AI Response** | JSON: `{ perspectives: [{ style, text, emotion_before, emotion_after }], micro_action: { if_clause, then_clause }, fragments_detected: [{ type, phrase, confidence }] }` | | **DB Write** | `INSERT INTO turns (id, user_id, input_text, perspectives, micro_action, fragments, emotion_vector, created_at)` | | **DB Write** | `INSERT INTO ai_usage_events (user_id, feature, model, input_tokens, output_tokens, latency_ms, cost_usd)` | | **Redis** | Increment daily counter, update streak cache | | **Response** | `{ turn_id, perspectives, micro_action, fragments, pattern_seed }` | | **Frontend** | Dismiss animation → render 3 perspective cards + micro-action card | ### 2.2 Save a Turn / Keepsake **User Action:** Taps save on a perspective card | Layer | Detail | |-------|--------| | **API** | `POST /turns/{id}/save` — body: `{ perspective_index, save_type: "keepsake" }` | | **DB Write** | `UPDATE turns SET saved = true, saved_perspective_index = $1` | | **DB Write** | `INSERT INTO evidence_wall_tiles (user_id, tile_type, source_feature, source_id, color_accent, created_at)` — type: `saved_keepsake` | | **Response** | `{ saved: true, gallery_id, evidence_tile_id }` | | **Frontend** | Success toast "Turn saved" → update Gallery cache via TanStack Query invalidation | ### 2.3 Get Turn History | Layer | Detail | |-------|--------| | **API** | `GET /turns?limit=20&offset=0&date=2026-02-21` | | **DB Read** | `SELECT id, input_text, perspectives, fragments, created_at FROM turns WHERE user_id = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3` | | **Cache** | Redis: cache recent 20 turns per user, 5 min TTL | --- ## 3. The Mirror (Journaling + Fragment Detection) ### 3.1 Start Mirror Session **User Action:** Opens Mirror tab → starts new session | Layer | Detail | |-------|--------| | **API** | `POST /mirror/sessions` — body: `{ prompt_id? }` | | **Rate Check** | Redis: `INCR rate:mirror:{user_id}:{week}` → reject if > 2 (free) | | **DB Write** | `INSERT INTO mirror_sessions (id, user_id, status, started_at)` — status: `active` | | **Response** | `{ session_id, opening_prompt }` | | **Frontend** | Navigate to session view, show opening prompt in AI bubble | ### 3.2 Send Message in Mirror **User Action:** Types and sends a message | Layer | Detail | |-------|--------| | **Frontend** | Append user message to local state, show AI thinking animation | | **API** | `POST /mirror/sessions/{id}/messages` — body: `{ content, message_type: "user" }` | | **DB Write** | `INSERT INTO mirror_messages (id, session_id, role, content, created_at)` | | **AI Call #1** | Fragment Detection: system prompt (10 distortion types + detection rules) + session context + new message | | **AI Response #1** | `{ fragments: [{ type, phrase, start_index, end_index, confidence }] }` | | **Entitlement Gate** | Free: filter to 3 types (catastrophizing, black_and_white, should_statements). Prism: all 10 | | **DB Write** | `INSERT INTO mirror_fragments (id, session_id, message_id, distortion_type, phrase, start_idx, end_idx, confidence)` | | **AI Call #2** | Reflective Response: system prompt (warm, non-directive, Mirror voice) + session history + detected fragments | | **AI Response #2** | `{ response_text, suggested_prompts: [] }` | | **DB Write** | `INSERT INTO mirror_messages (id, session_id, role: "assistant", content)` | | **Response** | `{ message_id, ai_response, fragments: [{ type, phrase, indices }] }` | | **Frontend** | Render AI response bubble, apply amber highlight underlines to user's message at fragment positions | ### 3.3 Tap Fragment Highlight → Inline Reframe **User Action:** Taps highlighted text in their message | Layer | Detail | |-------|--------| | **Frontend** | Open half-sheet modal with distortion info (local data from fragment detection response) | | **API** | `POST /mirror/fragments/{id}/reframe` — body: `{ fragment_id }` | | **Rate Check** | Free: 1 inline reframe per session | | **AI Call** | Quick reframe: system prompt + fragment context + distortion type | | **AI Response** | `{ reframes: [{ text, style }], can_turn: true }` | | **Response** | `{ reframes, turn_prefill }` — `turn_prefill` is the fragment phrase ready for Turn | | **Frontend** | Render reframes in half-sheet. "Take to Turn" button navigates to Turn tab with `input_text` pre-filled | ### 3.4 Close Mirror Session → Generate Reflection **User Action:** Taps "End Session" or navigates away | Layer | Detail | |-------|--------| | **API** | `POST /mirror/sessions/{id}/close` | | **DB Read** | Fetch all messages + fragments for session | | **AI Call** | Reflection generation: full session transcript + all fragments → themes, insight, pattern seed | | **AI Response** | `{ themes: [], fragment_summary: { total, by_type }, insight: "string", pattern_seed: "hash" }` | | **DB Write** | `UPDATE mirror_sessions SET status = "closed", reflection = $1, pattern_seed = $2, closed_at = NOW()` | | **DB Write** | `INSERT INTO evidence_wall_tiles (user_id, tile_type: "mirror_reflection", source_id, ...)` | | **Response** | `{ reflection, pattern_seed, fragment_summary }` | | **Frontend** | Show reflection card with generated kaleidoscope pattern thumbnail → auto-saved to Gallery | --- ## 4. The Lens (Goals + Actions) ### 4.1 Create Goal | Layer | Detail | |-------|--------| | **API** | `POST /lens/goals` — body: `{ title, description, target_date?, category? }` | | **AI Call** | Goal refinement: make SMART, suggest metrics, generate initial visualization description | | **DB Write** | `INSERT INTO lens_goals (id, user_id, title, description, target_date, visualization_text, status, created_at)` | | **Response** | `{ goal_id, refined_title, visualization, suggested_actions }` | ### 4.2 Get Daily Actions + Affirmation | Layer | Detail | |-------|--------| | **API** | `GET /lens/today` | | **DB Read** | Active goals + incomplete actions + today's affirmation | | **AI Call** (if no affirmation cached) | Generate daily affirmation based on active goals + recent progress | | **Redis** | Cache today's affirmation, 24h TTL | | **Response** | `{ goals: [...], today_actions: [...], affirmation: { text, goal_id } }` | ### 4.3 Complete Action | Layer | Detail | |-------|--------| | **API** | `POST /lens/actions/{id}/complete` | | **DB Write** | `UPDATE lens_actions SET completed = true, completed_at = NOW()` | | **DB Write** | `INSERT INTO evidence_wall_tiles (tile_type: "completed_action", source_id, color_accent: "emerald")` | | **Redis** | Update streak counter | | **Response** | `{ completed: true, goal_progress_pct, streak_count, evidence_tile_id }` | ### 4.4 Start Rehearsal Session **User Action:** On goal detail → taps "Rehearse" | Layer | Detail | |-------|--------| | **API** | `POST /lens/goals/{id}/rehearsal` | | **Rate Check** | Free: 1/week, Prism: unlimited | | **DB Read** | Fetch goal details + user's recent Mirror/Turn data for personalization | | **AI Call** | Visualization script generation: first-person, multi-sensory, process-oriented, obstacle rehearsal | | **AI Response** | `{ script_segments: [{ text, duration_seconds, breathing_cue? }], total_duration }` | | **DB Write** | `INSERT INTO rehearsal_sessions (id, user_id, goal_id, script, duration, created_at)` | | **Response** | `{ session_id, script_segments, total_duration }` | | **Frontend** | Enter Rehearsal mode: timer ring, text card sequence with breathing animation pacing | ### 4.5 Complete Rehearsal | Layer | Detail | |-------|--------| | **API** | `POST /lens/rehearsals/{id}/complete` | | **DB Write** | `UPDATE rehearsal_sessions SET completed = true, completed_at = NOW()` | | **DB Write** | `INSERT INTO evidence_wall_tiles (tile_type: "rehearsal_complete", source_id, color_accent: "amethyst")` | | **Response** | `{ completed: true, evidence_tile_id }` | | **Frontend** | Success burst animation → navigate back to goal detail | --- ## 5. The Ritual (Daily Habit Sequences) ### 5.1 Start Ritual **User Action:** Taps "Start Ritual" on Turn tab or from notification | Layer | Detail | |-------|--------| | **API** | `POST /rituals/start` — body: `{ template: "morning" | "evening" | "quick" }` | | **Rate Check** | Free: only `quick` template allowed | | **DB Write** | `INSERT INTO ritual_sessions (id, user_id, template, status, started_at)` | | **DB Read** | Fetch user's active goals, recent fragments, streak data for personalization | | **AI Call** | Personalize ritual prompts based on user context | | **Response** | `{ session_id, steps: [{ type, prompt, duration_seconds }] }` | | **Frontend** | Enter Ritual mode: fragment-shaped step progress bar, step-by-step flow | ### 5.2 Ritual Step Completion Each step may trigger its own API call: | Step | API Calls | |------|-----------| | Mirror check-in | `POST /mirror/sessions` + `POST /mirror/sessions/{id}/messages` (lightweight, 1-2 exchanges) | | Turn | `POST /turns` (with ritual context flag) | | Lens review | `POST /lens/actions/{id}/complete` (for each completed action) | | Affirmation | `GET /lens/today` (cached) | | Gratitude | `POST /rituals/{id}/gratitude` — body: `{ text }` | ### 5.3 Complete Ritual | Layer | Detail | |-------|--------| | **API** | `POST /rituals/{id}/complete` | | **DB Write** | `UPDATE ritual_sessions SET status = "completed", completed_at = NOW()` | | **DB Write** | `INSERT INTO evidence_wall_tiles (tile_type: "ritual_complete", color_accent: "amber")` | | **Redis** | Update ritual streak: `INCR streak:ritual:{user_id}`, check context consistency (same time ± 30 min) | | **DB Write** | `UPDATE profiles SET ritual_streak = $1, ritual_consistency_score = $2` | | **Response** | `{ completed: true, streak_count, consistency_score, evidence_tile_id }` | | **Frontend** | Prismatic ring completion animation → streak view | --- ## 6. Gallery ### 6.1 Get All Patterns | Layer | Detail | |-------|--------| | **API** | `GET /gallery?view=all&limit=20&offset=0` | | **DB Read** | `SELECT id, source_feature, pattern_seed, preview_text, created_at FROM gallery_items WHERE user_id = $1 ORDER BY created_at DESC` | | **Cache** | Redis: cache first page, 2 min TTL | ### 6.2 Get Pattern Detail | Layer | Detail | |-------|--------| | **API** | `GET /gallery/{id}` | | **DB Read** | Full gallery item with source content, fragments, pattern seed | | **Frontend** | Render hero kaleidoscope pattern (deterministic from seed), source content, metadata | ### 6.3 Search / Filter | Layer | Detail | |-------|--------| | **API** | `GET /gallery/search?q=text&feature=turn&distortion=catastrophizing&from=2026-01-01` | | **DB Read** | Full-text search on gallery content + filter joins | ### 6.4 Generate Pattern Card (Share) | Layer | Detail | |-------|--------| | **API** | `POST /gallery/{id}/share` | | **Backend** | Generate Pattern Card image: kaleidoscope pattern + reframe text overlay + Kalei watermark | | **Response** | `{ share_url, image_url }` | | **Frontend** | Native share sheet with generated image | --- ## 7. Evidence Wall ### 7.1 Get Evidence Wall | Layer | Detail | |-------|--------| | **API** | `GET /evidence-wall?limit=50` | | **DB Read** | `SELECT * FROM evidence_wall_tiles WHERE user_id = $1 ORDER BY created_at DESC` | | **Entitlement** | Free: 30-day window (`WHERE created_at > NOW() - INTERVAL '30 days'`). Prism: all history | | **Response** | `{ tiles: [...], connections: [...], stage: "empty" | "early" | "mid" | "full" }` | | **Frontend** | Render mosaic view based on stage, assign tile shapes (diamond, hex, rect, pentagon, triangle) based on tile_type | ### 7.2 Get Tile Detail | Layer | Detail | |-------|--------| | **API** | `GET /evidence-wall/tiles/{id}` | | **DB Read** | Tile + source data (join to turns/mirror_sessions/lens_actions/ritual_sessions/rehearsal_sessions) | | **Response** | `{ tile, source_content, source_feature, created_at }` | | **Frontend** | Half-sheet with tile detail, source content, link to source feature | ### 7.3 Contextual Evidence Surfacing **Trigger:** AI detects low self-efficacy language in Mirror or Turn | Layer | Detail | |-------|--------| | **AI Detection** | During Mirror fragment detection or Turn processing, flag self-efficacy score < threshold | | **DB Read** | `SELECT * FROM evidence_wall_tiles WHERE user_id = $1 ORDER BY relevance_score DESC LIMIT 2` | | **Response** | Included in Mirror/Turn response: `{ evidence_nudge: { tiles: [...], message: "..." } }` | | **Frontend** | Render gentle card below main content with 1-2 evidence tiles | --- ## 8. Spectrum (Phase 2) ### 8.1 Weekly Aggregation (Background Job) | Layer | Detail | |-------|--------| | **Trigger** | Cron: Sunday 6pm UTC | | **DB Read** | All turns + mirror_sessions + lens_actions for user's week | | **AI Call** | Batch API (50% cost): analyze emotional vectors, fragment patterns, Turn impact | | **DB Write** | `INSERT INTO spectrum_weekly (user_id, week_start, river_data, glass_data, impact_data, rhythm_data, growth_score, insight_text)` | | **Push** | Notification: "Your weekly Spectrum insight is ready" | ### 8.2 Get Spectrum Dashboard | Layer | Detail | |-------|--------| | **API** | `GET /spectrum/dashboard` | | **Entitlement** | Free: simplified `{ weekly_insight_text, basic_fragment_count }`. Prism: full dashboard | | **DB Read** | Latest weekly + monthly aggregates | | **Response** | `{ river, glass, impact, rhythm, growth, weekly_insight, monthly_insight? }` | | **Frontend** | Render 5 visualization components from spectrum-visualizations.svg data | ### 8.3 Monthly Deep Dive (Background Job) | Layer | Detail | |-------|--------| | **Trigger** | Cron: 1st of month | | **DB Read** | All weekly aggregates for the month | | **AI Call** | Batch API: month-over-month narrative generation | | **DB Write** | `INSERT INTO spectrum_monthly (user_id, month_start, narrative, growth_trajectory, milestone_events)` | --- ## 9. Billing & Entitlements ### 9.1 Entitlement Check (Middleware) Every rate-limited endpoint runs this check: ``` 1. Redis: GET entitlement:{user_id} → if cached, return 2. DB: SELECT plan, status FROM subscriptions WHERE user_id = $1 AND status = 'active' 3. Redis: SET entitlement:{user_id} = plan, EX 300 (5 min cache) 4. Return plan → middleware applies feature gates ``` ### 9.2 App Store Webhook | Layer | Detail | |-------|--------| | **API** | `POST /billing/webhooks/apple` | | **Validation** | Verify Apple JWT signature | | **DB Write** | `INSERT/UPDATE subscriptions SET plan = $1, status = $2, apple_transaction_id = $3` | | **Redis** | Invalidate `entitlement:{user_id}` cache | | **DB Write** | `INSERT INTO entitlement_snapshots (user_id, plan, event_type, timestamp)` | ### 9.3 Google Play Webhook Same pattern as Apple, with Google-specific JWT validation and `google_purchase_token`. --- ## 10. Safety System ### 10.1 Crisis Detection Pipeline Every AI-processed input runs through: ``` Stage 1: Deterministic keyword scan (regex, ~1ms) → If match: flag, skip AI, return crisis template Stage 2: AI confirmation (during normal processing) → AI output includes safety_flag: boolean → If flagged: return hardcoded crisis response (never AI-generated) Stage 3: Logging → INSERT INTO safety_events (user_id, input_hash, detection_stage, action_taken) → Alert: send to safety dashboard ``` ### 10.2 Crisis Response | Layer | Detail | |-------|--------| | **Response** | Hardcoded template: empathetic acknowledgment + 988 Suicide & Crisis Lifeline + Crisis Text Line | | **UI** | Full-screen modal with prominent crisis resource links, "I'm OK" dismiss button | | **Logging** | All crisis events logged, never the content itself | --- ## Database Schema Summary ### Core Tables | Table | Key Columns | Indexes | |-------|------------|---------| | `users` | id (uuid), email, password_hash, created_at | email (unique) | | `profiles` | user_id (FK), display_name, coaching_style, notification_time, onboarding_complete, ritual_streak, ritual_consistency_score | user_id (unique) | | `subscriptions` | user_id (FK), plan (enum), status, started_at, expires_at, apple_transaction_id?, google_purchase_token? | user_id, status | | `refresh_tokens` | id, user_id (FK), token_hash, revoked, expires_at | token_hash, user_id | ### Feature Tables | Table | Key Columns | Indexes | |-------|------------|---------| | `turns` | id, user_id, input_text (encrypted), perspectives (jsonb), micro_action (jsonb), fragments (jsonb), emotion_vector (jsonb), saved, pattern_seed, created_at | user_id + created_at | | `mirror_sessions` | id, user_id, status, reflection (jsonb), pattern_seed, started_at, closed_at | user_id + status | | `mirror_messages` | id, session_id (FK), role, content (encrypted), created_at | session_id + created_at | | `mirror_fragments` | id, session_id (FK), message_id (FK), distortion_type (enum), phrase, start_idx, end_idx, confidence | session_id, distortion_type | | `lens_goals` | id, user_id, title, description, target_date, visualization_text, status, created_at | user_id + status | | `lens_actions` | id, goal_id (FK), text, if_clause, then_clause, completed, completed_at | goal_id + completed | | `rehearsal_sessions` | id, user_id, goal_id (FK), script (jsonb), duration, completed, started_at, completed_at | user_id + goal_id | | `ritual_sessions` | id, user_id, template (enum), status, steps_completed (jsonb), started_at, completed_at | user_id + created_at | | `gallery_items` | id, user_id, source_feature (enum), source_id, content_preview, pattern_seed, distortion_types (text[]), created_at | user_id + source_feature, full-text on content_preview | | `evidence_wall_tiles` | id, user_id, tile_type (enum), source_feature, source_id, color_accent, metadata (jsonb), created_at | user_id + created_at, user_id + tile_type | ### Analytics Tables | Table | Key Columns | Indexes | |-------|------------|---------| | `spectrum_weekly` | id, user_id, week_start, river_data (jsonb), glass_data (jsonb), impact_data (jsonb), rhythm_data (jsonb), growth_score, insight_text | user_id + week_start | | `spectrum_monthly` | id, user_id, month_start, narrative (text), growth_trajectory (jsonb), milestone_events (jsonb) | user_id + month_start | | `ai_usage_events` | id, user_id, feature, model, input_tokens, output_tokens, latency_ms, cost_usd, created_at | user_id + feature, created_at | | `safety_events` | id, user_id, input_hash, detection_stage, action_taken, created_at | user_id, created_at | ### Enum Types ```sql CREATE TYPE plan_type AS ENUM ('free', 'prism'); CREATE TYPE subscription_status AS ENUM ('active', 'expired', 'canceled', 'trial', 'grace_period'); CREATE TYPE distortion_type AS ENUM ('catastrophizing', 'black_and_white', 'mind_reading', 'fortune_telling', 'personalization', 'discounting_positives', 'emotional_reasoning', 'should_statements', 'labeling', 'overgeneralization'); CREATE TYPE tile_type AS ENUM ('saved_keepsake', 'mirror_reflection', 'completed_action', 'self_correction', 'streak_milestone', 'goal_completion', 'reframe_echo', 'rehearsal_complete', 'ritual_complete'); CREATE TYPE ritual_template AS ENUM ('morning', 'evening', 'quick'); CREATE TYPE source_feature AS ENUM ('turn', 'mirror', 'lens', 'rehearsal', 'ritual'); ``` --- ## Redis Key Patterns | Key | Type | TTL | Purpose | |-----|------|-----|---------| | `rate:turns:{user_id}:{date}` | counter | 24h | Daily Turn rate limit | | `rate:mirror:{user_id}:{week}` | counter | 7d | Weekly Mirror rate limit | | `rate:rehearsal:{user_id}:{week}` | counter | 7d | Weekly Rehearsal rate limit | | `entitlement:{user_id}` | string | 5 min | Cached subscription plan | | `streak:daily:{user_id}` | hash | — | Current daily streak count + last active date | | `streak:ritual:{user_id}` | hash | — | Ritual streak + consistency data | | `affirmation:{user_id}:{date}` | string | 24h | Today's cached affirmation | | `turns:recent:{user_id}` | list | 5 min | Cached recent turns | | `session:{session_id}` | hash | 2h | Active Mirror session context | --- ## AI Gateway Call Patterns ### Cost Tiers | Feature | Model | Est. Cost/Call | Caching | |---------|-------|----------------|---------| | Turn (reframe) | Claude Haiku 4.5 | ~$0.003 | System prompt cached (40% saving) | | Mirror (fragment detection) | Claude Haiku 4.5 | ~$0.002 | System prompt cached | | Mirror (reflective response) | Claude Haiku 4.5 | ~$0.003 | System prompt cached | | Mirror (session reflection) | Claude Haiku 4.5 | ~$0.005 | — | | Lens (goal refinement) | Claude Haiku 4.5 | ~$0.004 | — | | Rehearsal (script gen) | Claude Haiku 4.5 | ~$0.008 | — | | Ritual (personalization) | Claude Haiku 4.5 | ~$0.003 | System prompt cached | | Spectrum (weekly) | Claude Batch API | ~$0.010 | Batch (50% off) | | Spectrum (monthly) | Claude Batch API | ~$0.015 | Batch (50% off) | | Safety (confirmation) | Included in feature call | $0 | Part of existing call | ### Prompt Template Versioning All prompts stored as versioned templates: `prompts/{feature}/{version}.json` | Prompt | Current Version | |--------|----------------| | turn_reframe | v1.0 | | mirror_fragment_detect | v1.0 | | mirror_reflect | v1.0 | | mirror_session_close | v1.0 | | lens_goal_refine | v1.0 | | rehearsal_script | v1.0 | | ritual_personalize | v1.0 | | spectrum_weekly | v1.0 | | spectrum_monthly | v1.0 | | safety_check | v1.0 | --- ## Frontend Component Architecture ### Navigation ``` AppNavigator (Expo Router) ├── (auth) │ ├── login.tsx │ ├── register.tsx │ └── onboarding/ │ ├── welcome.tsx │ ├── metaphor.tsx │ ├── turn-demo.tsx │ ├── style-select.tsx │ ├── notifications.tsx │ └── first-turn.tsx ├── (tabs) │ ├── turn/ │ │ ├── index.tsx — Turn home + input │ │ ├── results.tsx — Turn results display │ │ ├── ritual-select.tsx — Ritual template picker │ │ └── ritual-flow.tsx — Active ritual flow │ ├── mirror/ │ │ ├── index.tsx — Session list + new session │ │ └── session.tsx — Active Mirror session │ ├── lens/ │ │ ├── index.tsx — Goal dashboard │ │ ├── create-goal.tsx — 6-step goal creation │ │ ├── goal-detail.tsx — Goal detail + actions │ │ └── rehearsal.tsx — Rehearsal session │ ├── gallery/ │ │ ├── index.tsx — Pattern grid + filters │ │ └── detail.tsx — Pattern detail + share │ └── you/ │ ├── index.tsx — Profile + stats │ ├── evidence-wall.tsx — Evidence Wall mosaic │ ├── spectrum.tsx — Spectrum dashboard │ ├── settings.tsx — App settings │ └── subscription.tsx — Plan management └── (modals) ├── fragment-detail.tsx — Half-sheet for fragment info ├── upgrade.tsx — Prism upgrade prompt ├── crisis.tsx — Crisis response (safety) ├── share-card.tsx — Pattern card share sheet └── rate-limit.tsx — Rate limit notice ``` ### Shared Components | Component | Usage | SVG Asset | |-----------|-------|-----------| | `FragmentIcon` | Everywhere — the core ◇ | `fragment-icons.svg` | | `TabBar` | Main navigation | `icons-tab-bar.svg` | | `DistortionBadge` | Mirror highlights, Gallery filters | `icons-distortions.svg` | | `ActionIcon` | Buttons, list items, settings | `icons-actions.svg` | | `KaleidoscopePattern` | Gallery, Turn result, share card | `patterns-kaleidoscope.svg` | | `ProgressRing` | Lens goals, Rehearsal timer | `progress-indicators.svg` | | `StepDots` | Lens 6-step, Ritual flow | `progress-indicators.svg` | | `StreakCalendar` | Ritual tracking, You stats | `progress-indicators.svg` | | `EvidenceMosaic` | Evidence Wall | `evidence-wall.svg` | | `LoadingSpinner` | All loading states | `loading-animations.svg` | | `SkeletonShimmer` | Data loading | `loading-animations.svg` | | `TurnAnimation` | Turn processing | `loading-animations.svg` | | `AIThinkingBubble` | Mirror AI processing | `loading-animations.svg` | | `SuccessBurst` | Completion celebrations | `loading-animations.svg` | | `BreathingLogo` | Splash, idle states | `loading-animations.svg` | | `StatusBar` | Device chrome | `device-chrome.svg` | | `NavHeader` | All screens | `device-chrome.svg` | | `TabBarFrame` | Tab bar container | `device-chrome.svg` | | `Toast` | Success/error feedback | `device-chrome.svg` | | `InputAccessory` | Mirror, Turn text input | `device-chrome.svg` | | `ShardCluster` | Empty states, backgrounds | `decorative-shards.svg` | | `PrismaticDivider` | Section separators | `decorative-shards.svg` | | `CornerAccent` | Card decorations | `decorative-shards.svg` | | `SpectrumRiver` | Spectrum dashboard | `spectrum-visualizations.svg` | | `SpectrumGlass` | Spectrum dashboard | `spectrum-visualizations.svg` | | `SpectrumImpact` | Spectrum dashboard | `spectrum-visualizations.svg` | | `SpectrumRhythm` | Spectrum dashboard | `spectrum-visualizations.svg` | | `SpectrumGrowth` | Spectrum dashboard | `spectrum-visualizations.svg` |