> **Private daily questions for couples — end-to-end encrypted, never read, never sold.**
> *You and your paired partner hold the only key.*
A native couples-relationship app that turns check-ins into small, intentional rituals: one daily question, curated conversation packs, private answers, mutual reveal, gentle reminders, shared games, and date planning — with **real E2EE** and **calmer UX**.
Not a social network. Not therapy. Not a productivity tracker. **No public feeds, no likes, no followers, no infinite scroll.**
The core loop is simple: *answer honestly → choose what to reveal → keep a record of the conversations that mattered.*
| 💑 **One subscription per couple** | No double-billing partners. Premium unlocks for both — server-verified. |
| 🚫 **No engagement traps** | No infinite scroll. No likes. No follower counts. One daily question is the loop. |
| 🌗 **Decoupled theme + art** | In-app light/dark controls art; system theme isn't required to match. |
| 📱 **Native on both platforms** | Kotlin/Compose on Android, SwiftUI on iOS — same Firebase backend, same data model. |
| 🧪 **QA you can run** | `scripts/theme-scan.sh` (Pass C) and `scripts/wiring-scan.sh` (Pass N) catch the silent-dead-feature and theme-hardcoding classes before merge. |
| <imgsrc="docs/screenshots/readme/home-daily-ready-dark.png"alt="Home screen with the daily question ready to answer in dark mode"width="180"/> | <imgsrc="docs/screenshots/readme/home-daily-your-turn-dark.png"alt="Home screen after the partner answered and it is your turn in dark mode"width="180"/> | <imgsrc="docs/screenshots/readme/home-daily-reveal-dark.png"alt="Home screen with the daily question reveal ready in dark mode"width="180"/> |
Other core screens:
| Play | This or That | Today | Challenge |
| :---: | :---: | :---: | :---: |
| <imgsrc="docs/screenshots/readme/play-dark.png"alt="Play hub in dark mode"width="160"/> | <imgsrc="docs/screenshots/readme/this-or-that-dark.png"alt="This or That in dark mode"width="160"/> | <imgsrc="docs/screenshots/readme/today-dark.png"alt="Daily question in dark mode"width="160"/> | <imgsrc="docs/screenshots/readme/challenge-dark.png"alt="Connection challenge in dark mode"width="160"/> |
Subscription apps for couples have a trust problem — confusing trial wording, hard-to-cancel flows, partners getting double-billed. Couples products have a *different* trust problem: partners are asked to be vulnerable in the same space where everything else (social, productivity, dating) wants their engagement, their data, and their attention.
- 🔒 **Encryption that earns the word.** Tink AEAD with couple-owned keys. Answers, messages, and history — server never sees plaintext. Recover with your phrase *or* your partner.
> 📐 iOS scaffold has **all 49 screens** mapped to SwiftUI views, Firebase + RevenueCat integration, and full screen parity on the `dev` branch. CryptoKit-based E2EE parity (interop with Android's Tink key material) is the only blocker for end-to-end iOS pairing.
> 🧪 `scripts/theme-scan.sh` and `scripts/wiring-scan.sh` are run before every QA pass. They statically catch the two costliest QA classes: hardcoded theme colors and silent dead features.
- 🔐 **E2EE content.** Tink AEAD with couple-owned keys. Answers, **chat messages** (text *and* images), locked capsules, and conversation history are encrypted on-device — the server only ever sees ciphertext. Messages live under `couples/{coupleId}/conversations/…`; images upload to Storage as opaque encrypted bytes, and even the inbox preview line is encrypted.
- 💾 **Encrypted conversation backup.** Chat and thread history is backed up as couple-key ciphertext — cheap incremental appends plus periodic full snapshots — so history can return to a new device. The backup is never readable server-side.
- 🪪 **Recovery phrase.** Server-blind; wiped from the inviter on acceptance. One of **two** recovery paths.
- 🤝 **Partner-assisted restore.** Lost or wiped your device? Your partner can restore your full history with **no recovery phrase**: your new device publishes a fresh public key, you read a 6-digit code aloud on a separate channel, and they wrap the couple key to that key (ECIES `keybox:v1:`). The server only relays the sealed blob — never the key itself. Your own devices get a *"was this you?"* security alert whenever a restore is requested or completes.
- 🌙 **Quiet hours, server-side.** Suppression is enforced where the push is **sent**, not where it might be foregrounded. Client cannot bypass by being backgrounded.
- 💸 **Server-verified billing.** Cloud Function writes `users/{uid}/entitlements/premium` from the RevenueCat webhook. Client cannot self-grant.
> Full architecture reference: [`docs/Engineering_Reference_Manual.md`](docs/Engineering_Reference_Manual.md) — the canonical source of truth for the security model, data model, and Cloud Functions wiring.
- 🔐 **iOS E2EE parity** (CryptoKit interop with Android's Tink key material) — *unblocks pairing from iOS*.
- 🧪 **On-device / instrumented test coverage** (Compose UI / Espresso smoke) — currently `app/src/test` only.
- 🎨 **Activity `uiMode` sync** to in-app theme (C-DARKART-002) — the dark-variant `-night` PNGs only render in the right combination today; architectural fix in `MainActivity`.