The couples super-app — Between · Paired · Lovewick · Widgetable · Life360 fused into one cinematic, end-to-end-encrypted product.
🌐 Live preview: https://sahith14.github.io/Couples-app/
Status: foundation + 3 feature sprints shipped. Real auth, real E2E chat (text + image + voice), real memory vault, real background location with SOS, real time capsules, planner, quests, notes, push notifications, 24h Instants, scheduled messages, live phone status, ₹149/mo paywall, 1:1 video call, and native widget code (iOS WidgetKit + Android Glance). A few cinematic add-ons (Memory Galaxy 3D, AI yearly recap renderer) are stubbed for follow-up sprints — seedocs/ROADMAP.mdfor the honest status of every feature.
.\setup.ps1That's it — the script installs deps, sets up .env, runs typecheck, and prints the next steps. For non-Windows or manual setup, see "Quick start (manual)" below.
soulsync/
├─ apps/
│ ├─ mobile/ Expo SDK 51 + expo-router (iOS, Android, web)
│ └─ admin/ Next.js 14 ops dashboard (server-only service-role)
├─ packages/
│ └─ shared/ Types · zod validators · tweetnacl crypto · theme tokens · constants
├─ supabase/
│ ├─ config.toml
│ ├─ migrations/ Numbered SQL: schema, RLS, RPCs, storage buckets, key exchange, ai
│ └─ functions/ Edge Functions (compose-message, ...)
└─ docs/ Architecture · auth · ai · deployment · monetization · viral · ASO · roadmap
- Auth: email/password + magic link; Google/Apple wired in UI, configurable in Supabase
- Pairing: 6-char invite codes via
generate_invite_code/redeem_invite_codeSQL RPCs with anti-double-pair guards - E2E key exchange: Curve25519 keypair generated on first launch, secret in
expo-secure-store, public synced toprofiles.public_key. Partner's key fetched viapartner_public_key()RPC every cold-start.
- Realtime text via
postgres_changeschannel + optimistic send - Image attachments — picker →
expo-image-manipulator→ encrypt with random secretbox key → upload ciphertext → wrap key for partner - Voice notes —
expo-avrecorder → same encrypt-and-wrap flow → tap-to-play with cached decryption - Reactions — long-press → 8-emoji picker → atomic
toggle_reactionRPC; jsonb shape{"❤️":["uid"]} - Read receipts —
mark_conversation_readRPC fires on screen entry and partner message arrival; ✓/✓✓ rendered on own messages - Disappearing messages —
expires_atschema +purge_expired_messagescron-ready function
- Photo upload with compression (1920w JPEG @0.78), grid view with signed URLs
- Video + album + secret-vault tables already in schema; UI hooks coming next
- Foreground watcher + insert into
location_pings; trigger updateslocation_latest - Background task (
expo-task-manager+expo-location.startLocationUpdatesAsync) flushes pings at 100m intervals with battery + charging state - SOS button on the map → writes
sos_events+ opens dialer to 911 - Ghost mode — RLS-enforced; partner literally cannot select your pings
- Custom month-grid calendar with event dots, today highlight, day picker
- Surprise events — hidden from partner via existing RLS (
surprise_for <> auth.uid()) - Local reminders scheduled 2h before each event via
expo-notifications
- Quests UI — daily / weekly / one-time sections;
complete_questRPC awards XP + bumps level viaadd_xp - Streak engine (
bump_streak) called from mood checkin - 5 themes live-switchable in Profile
- Time Capsules — preset durations (1mo → 5y), sealed countdown, glow when ready to open, local notif on unlock_at
- Heartbeat Mode — Reanimated breath cycle + Supabase Realtime presence + broadcast pulse events; haptic + ring expansion + "in sync" detection
- Shared Notes — realtime collab via
postgres_changes, debounced 600ms autosave, emoji + pin
compose-messageEdge Function — OpenAI-compatible (works with OpenRouter / Groq / Together viaOPENAI_BASE_URL), generates compliments / letters / apologies / good-mornings in 5 tones; audits toai_logs. Seedocs/AI_SETUP.md
- Paywall screen with all 3 tiers (Free / Plus / Infinite) sourced from
PREMIUM_GATES, monthly/yearly toggle, RevenueCat handoff stub
- Expo push token registered to
device_sessions+ mirrored onprofiles.push_token - Tap-to-deeplink routing for messages / SOS / capsules / memories / events
- 5 Android channels with appropriate importance + vibration
- Real KPIs over service-role Supabase
- Node 20+, pnpm 9+ (
npm i -g pnpm) - Supabase CLI (
npm i -g supabase) - For mobile: Xcode 15 (iOS) / Android Studio + JDK 17 (Android) — or just use Expo Go for everything except deep native modules (background location, push tokens, biometrics)
- Optional: Expo account for EAS builds, OpenAI API key for AI features
cd soulsync
pnpm install
cp .env.example .envFill .env with your Supabase project URL + anon key (also paste them into apps/mobile/.env and apps/admin/.env.local).
supabase login
supabase link --project-ref <YOUR_PROJECT_REF>
supabase db push # applies all migrations in supabase/migrationsThis creates every table, every RLS policy, the storage buckets, the pairing/XP/streak RPCs, and the new key-exchange + reaction + read-receipt + quest-completion RPCs (migration 009).
supabase secrets set OPENAI_API_KEY=sk-...
# Or route through any OpenAI-compatible provider:
supabase secrets set OPENAI_BASE_URL=https://openrouter.ai/api/v1
supabase secrets set OPENAI_MODEL_OVERRIDE=anthropic/claude-3.5-sonnet
supabase functions deploy compose-messagepnpm --filter @soulsync/mobile start
# press i (iOS sim), a (Android), or scan QR with Expo GoFor real native builds (background location, push, biometrics, voice recording):
pnpm --filter @soulsync/mobile exec eas build --profile development --platform iospnpm --filter @soulsync/admin dev
# http://localhost:3000[Expo RN App] ──HTTPS──▶ [Supabase Postgres]
│ │ RLS + Realtime
│ │ pgvector (future AI)
├──Realtime ws──────┘ + Presence (heartbeat)
├──Storage signed URLs──▶ [Storage buckets]
│ memories/chat/voice/avatars/replays
├──Edge Functions──▶ [compose-message] ──▶ [OpenAI-compatible API]
└──E2E box (tweetnacl) on device, ciphertext-only on server
▲
[Admin Next.js] (service-role)
End-to-end encryption: each device generates a Curve25519 keypair stored in
the platform keychain via expo-secure-store. Public keys are exchanged via
the profiles.public_key column at pair time (and re-fetched on every chat
load). Everything sensitive (chat text, chat images, chat voice notes,
secret-vault media keys) is sealed with nacl.box before reaching Postgres.
The server cannot read messages.
See docs/ROADMAP.md — every feature from the brief, with
status, blocking work, and the file you'd open to extend it.