2026-06-29 11:18:02 -05:00
< p align = "center" >
2026-07-07 21:47:20 -05:00
< img src = "docs/store/feature-graphic-1024x500.png" alt = "Closer feature graphic" width = "920" / >
2026-06-29 11:18:02 -05:00
< / p >
2026-06-20 22:20:31 -05:00
2026-06-29 11:18:02 -05:00
< h1 align = "center" > Closer< / h1 >
2026-06-20 22:20:31 -05:00
2026-06-29 11:18:02 -05:00
< p align = "center" >
< strong > A private space for two.< / strong > < br / >
2026-07-07 21:47:20 -05:00
Daily questions, mutual reveals, shared games, and calm rituals for couples.
2026-06-29 11:18:02 -05:00
< / p >
2026-06-17 19:59:07 -05:00
2026-06-28 15:53:41 -05:00
< p align = "center" >
2026-07-07 21:47:20 -05:00
< a href = "#screenshots" > Screenshots< / a >
·
< a href = "#what-makes-it-different" > What makes it different< / a >
·
< a href = "#platform-status" > Status< / a >
·
< a href = "#local-development" > Run locally< / a >
·
< a href = "#qa-and-release" > QA< / a >
2026-06-28 15:53:41 -05:00
< / p >
2026-06-21 08:15:20 -05:00
2026-07-07 21:47:20 -05:00
< p align = "center" >
< sub >
Android reference app · iOS scaffold in progress · Firebase backend · RevenueCat billing · Private repo
< / sub >
< / p >
2026-06-29 11:18:02 -05:00
2026-07-07 23:28:45 -05:00
< p align = "center" >
< img alt = "Android" src = "https://img.shields.io/badge/Android-reference%20app-3DDC84?style=flat-square&logo=android&logoColor=white" / >
< img alt = "iOS" src = "https://img.shields.io/badge/iOS-scaffold%20in%20progress-007AFF?style=flat-square&logo=apple&logoColor=white" / >
< img alt = "Firebase" src = "https://img.shields.io/badge/Firebase-backend-FFCA28?style=flat-square&logo=firebase&logoColor=black" / >
< img alt = "RevenueCat" src = "https://img.shields.io/badge/RevenueCat-billing-6D5DF6?style=flat-square" / >
< img alt = "License" src = "https://img.shields.io/badge/license-private-E5484D?style=flat-square" / >
< / p >
2026-07-07 21:47:20 -05:00
---
2026-06-29 11:18:02 -05:00
2026-07-07 21:47:20 -05:00
Closer is a native relationship app for couples who want a quieter way to check in with each other.
Each partner answers privately, reveals intentionally, and keeps a record of the conversations that
matter.
2026-06-21 08:15:20 -05:00
2026-07-07 21:47:20 -05:00
It is not a social network, therapy replacement, or productivity tracker. There are no public feeds,
likes, followers, or infinite-scroll loops. The product loop is small on purpose:
2026-06-21 08:15:20 -05:00
2026-07-07 21:47:20 -05:00
```text
answer honestly -> reveal together -> keep the conversation going
```
2026-06-21 08:15:20 -05:00
2026-07-07 23:28:45 -05:00
< h2 align = "center" > Screenshots< / h2 >
2026-06-17 19:59:07 -05:00
2026-07-08 14:53:12 -05:00
Fresh Android captures from the current emulator build.
2026-06-17 19:59:07 -05:00
2026-07-07 21:47:20 -05:00
< table >
< tr >
2026-07-08 14:53:12 -05:00
< td align = "center" > < strong > Ready · dark< / strong > < / td >
< td align = "center" > < strong > Ready · light< / strong > < / td >
< td align = "center" > < strong > Your turn · dark< / strong > < / td >
< td align = "center" > < strong > Reveal · dark< / strong > < / td >
< td align = "center" > < strong > Reveal · light< / strong > < / td >
2026-07-07 21:47:20 -05:00
< / tr >
< tr >
2026-07-08 14:53:12 -05:00
< td > < img src = "docs/screenshots/readme/home-daily-ready-dark.png" alt = "Home screen with the daily question ready to answer in dark mode" width = "160" / > < / td >
< td > < img src = "docs/screenshots/readme/home-daily-ready-light.png" alt = "Home screen with the daily question ready to answer in light mode" width = "160" / > < / td >
< td > < img src = "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 = "160" / > < / td >
< td > < img src = "docs/screenshots/readme/home-daily-reveal-dark.png" alt = "Home screen with the daily question reveal ready in dark mode" width = "160" / > < / td >
< td > < img src = "docs/screenshots/readme/home-daily-reveal-light.png" alt = "Home screen with the daily question reveal ready in light mode" width = "160" / > < / td >
2026-07-07 21:47:20 -05:00
< / tr >
< / table >
< table >
< tr >
< td align = "center" > < strong > Play< / strong > < / td >
< td align = "center" > < strong > This or That< / strong > < / td >
< td align = "center" > < strong > Today< / strong > < / td >
< td align = "center" > < strong > Challenge< / strong > < / td >
< / tr >
< tr >
< td > < img src = "docs/screenshots/readme/play-dark.png" alt = "Play hub in dark mode" width = "170" / > < / td >
< td > < img src = "docs/screenshots/readme/this-or-that-dark.png" alt = "This or That in dark mode" width = "170" / > < / td >
< td > < img src = "docs/screenshots/readme/today-dark.png" alt = "Daily question in dark mode" width = "170" / > < / td >
< td > < img src = "docs/screenshots/readme/challenge-dark.png" alt = "Connection challenge in dark mode" width = "170" / > < / td >
< / tr >
< / table >
2026-07-08 14:39:33 -05:00
< h2 align = "center" > Visual system< / h2 >
Closer uses paired light and dark illustration assets so the product can stay warm without fighting
the selected theme. The home daily-question card is intentionally people-forward: the ready-to-answer
and reveal-ready moments use the couple/cards artwork, while quieter waiting states can fall back to
the answer-card ritual art.
2026-07-07 23:28:45 -05:00
< h2 align = "center" > What makes it different< / h2 >
2026-07-07 21:47:20 -05:00
< table >
< tr >
< td width = "33%" > < strong > Private first< / strong > < br / > Partners answer independently before seeing each other's response.< / td >
< td width = "33%" > < strong > Mutual reveal< / strong > < br / > The app is built around intentional sharing, not performative posting.< / td >
< td width = "33%" > < strong > Couple-owned trust< / strong > < br / > Android encrypts answers, chat, history, and media on-device with couple-owned keys.< / td >
< / tr >
< tr >
< td width = "33%" > < strong > One subscription per couple< / strong > < br / > Premium unlocks for both partners through server-verified entitlements.< / td >
< td width = "33%" > < strong > Curated prompts< / strong > < br / > Question packs are written and reviewed, not generated at answer time.< / td >
< td width = "33%" > < strong > Calm by design< / strong > < br / > No feeds, likes, followers, public profiles, or pressure mechanics.< / td >
< / tr >
2026-07-08 14:39:33 -05:00
< tr >
< td width = "33%" > < strong > Theme-aware art< / strong > < br / > Light and dark illustrations are paired for the same product moments.< / td >
< td width = "33%" > < strong > Human warmth< / strong > < br / > The home ritual leads with people and recognizable Closer card artwork.< / td >
< td width = "33%" > < strong > Private rituals< / strong > < br / > The visual language reinforces answering alone, revealing together, and continuing gently.< / td >
< / tr >
2026-07-07 21:47:20 -05:00
< / table >
2026-07-07 23:28:45 -05:00
< h2 align = "center" > Product surface< / h2 >
2026-07-07 21:47:20 -05:00
| Area | Free | Premium |
2026-06-20 22:20:31 -05:00
| --- | --- | --- |
2026-07-07 21:47:20 -05:00
| Daily question | Included | Included |
| Private answers + mutual reveal | Included | Included |
| Curated question packs | Free + mixed access | Full access |
| Spin the Wheel | Included | Included |
| This or That / How Well Do You Know Me | Included | Included |
| Recent answer history | Included | Included |
| Memory Lane capsules | Limited | Full access |
| Desire Sync | Limited | Full access |
| Connection Challenges | Free + mixed access | Full access |
| Date ideas, matches, and bucket list | Included | Premium ideas gated |
| Push reminders + quiet hours | Included | Included |
| Account deletion | Included | Included |
Data export is not currently offered. The in-app privacy copy intentionally says so until a real export
flow exists.
2026-06-20 22:20:31 -05:00
2026-07-07 23:28:45 -05:00
< h2 align = "center" > Platform status< / h2 >
2026-06-21 08:15:20 -05:00
2026-07-07 21:47:20 -05:00
| Platform | Status | Notes |
| --- | --- | --- |
| Android | Reference implementation | Kotlin, Jetpack Compose, Material 3, Hilt, Room, DataStore, Firebase, Tink |
| iOS | Scaffold in progress | SwiftUI screen parity exists; pairing is blocked until E2EE interop is complete |
| Backend | Shared source of truth | Firebase Auth, Firestore, Cloud Functions, FCM, App Check |
| Billing | Server verified | RevenueCat webhook writes Firestore entitlements observed by the app |
2026-06-20 22:20:31 -05:00
2026-07-07 21:47:20 -05:00
Android is the product source of truth today. iOS has the app shell, Firebase/RevenueCat integration,
and SwiftUI screens, but end-to-end pairing waits on CryptoKit/Tink interoperability.
2026-06-21 08:15:20 -05:00
2026-07-07 23:28:45 -05:00
< h2 align = "center" > Architecture< / h2 >
2026-06-21 08:15:20 -05:00
2026-06-28 15:53:41 -05:00
```text
2026-07-07 21:47:20 -05:00
Android (Kotlin/Compose) iOS (SwiftUI)
Hilt · Room · DataStore MVVM · AppState · SPM
Tink AEAD · Argon2id CryptoKit interop in progress
\ /
\ /
v v
Firebase + RevenueCat
Auth · Firestore · Functions · FCM
App Check · server-verified billing
2026-06-28 15:53:41 -05:00
```
2026-06-20 22:20:31 -05:00
2026-07-07 21:47:20 -05:00
Core rules:
2026-06-20 22:20:31 -05:00
2026-07-07 21:47:20 -05:00
- Couple-scoped Firestore data. Users only read/write their own couple surface.
- Server-mediated pairing. Invite lifecycle runs through Cloud Functions.
- Local-first question content. Prompts ship with the app; assignment/sync uses Firebase.
- Server-verified premium. Clients observe entitlements; they do not self-grant access.
- No anonymous auth. Accounts use email/password or Google sign-in.
2026-06-16 20:16:47 -05:00
2026-07-07 23:28:45 -05:00
< h2 align = "center" > Security and privacy< / h2 >
2026-06-16 20:16:47 -05:00
2026-07-07 21:47:20 -05:00
- Android encrypts answer content, chat messages, media, capsules, and backed-up conversation history
on-device before sync.
- The server stores ciphertext for private content and never receives plaintext answers.
- Recovery phrase wrapping uses Argon2id-derived keys.
- Partner-assisted restore lets a trusted partner help restore the couple key to a new device.
- Quiet hours are enforced server-side before push delivery.
- Account deletion exists; data export does not yet.
2026-06-28 15:53:41 -05:00
2026-07-07 21:47:20 -05:00
The canonical technical reference is
[docs/Engineering_Reference_Manual.md ](docs/Engineering_Reference_Manual.md ).
2026-06-28 15:53:41 -05:00
2026-07-07 23:28:45 -05:00
< h2 align = "center" > Local development< / h2 >
2026-06-17 19:59:07 -05:00
2026-07-07 21:47:20 -05:00
< details open >
< summary > < strong > Prerequisites< / strong > < / summary >
2026-06-17 19:59:07 -05:00
2026-07-07 21:47:20 -05:00
- Android Studio, Android SDK, and JDK 17
- Node 20 for Firebase Functions tooling
- Firebase project with Auth, Firestore, Cloud Messaging, Crashlytics, Analytics, and App Check
- `app/google-services.json`
- RevenueCat project and Android API key
2026-06-17 19:59:07 -05:00
2026-07-07 21:47:20 -05:00
For iOS work:
2026-06-28 15:53:41 -05:00
2026-07-07 21:47:20 -05:00
- macOS, Xcode 16, XcodeGen, and iOS 17+
- `iphone/Closer/GoogleService-Info.plist`
- RevenueCat iOS API key
2026-06-20 22:20:31 -05:00
2026-07-07 21:47:20 -05:00
< / details >
2026-06-17 19:59:07 -05:00
2026-07-07 21:47:20 -05:00
< details >
< summary > < strong > Android< / strong > < / summary >
2026-06-17 19:59:07 -05:00
```bash
cp local.properties.example local.properties
2026-06-16 20:16:47 -05:00
```
2026-06-17 19:59:07 -05:00
```properties
sdk.dir=/path/to/Android/Sdk
2026-06-20 22:20:31 -05:00
RC_API_KEY_ANDROID=your_revenuecat_android_key
RC_API_KEY_IOS=your_revenuecat_ios_key
2026-06-16 20:16:47 -05:00
```
2026-06-17 19:59:07 -05:00
```bash
./gradlew :app:assembleDebug
./gradlew :app:installDebug
2026-07-07 21:47:20 -05:00
./gradlew :app:testDebugUnitTest
2026-06-17 19:59:07 -05:00
```
2026-06-16 20:16:47 -05:00
2026-07-07 21:47:20 -05:00
< / details >
2026-06-16 20:16:47 -05:00
2026-07-07 21:47:20 -05:00
< details >
< summary > < strong > iOS< / strong > < / summary >
2026-06-20 22:20:31 -05:00
```bash
cd iphone
xcodegen generate
xed Closer.xcodeproj
```
```bash
xcodebuild -project iphone/Closer.xcodeproj \
2026-07-07 21:47:20 -05:00
-scheme Closer \
-destination 'platform=iOS Simulator,name=iPhone 15' \
build
2026-06-20 22:20:31 -05:00
```
2026-07-07 21:47:20 -05:00
< / details >
< details >
< summary > < strong > Firebase Functions< / strong > < / summary >
2026-06-17 19:59:07 -05:00
```bash
cd functions
npm install
npm run build
2026-07-07 21:47:20 -05:00
npm test
2026-06-17 19:59:07 -05:00
```
2026-06-28 15:53:41 -05:00
```bash
2026-07-07 21:47:20 -05:00
npm run serve
2026-06-28 15:53:41 -05:00
```
2026-07-07 21:47:20 -05:00
< / details >
2026-06-17 19:59:07 -05:00
2026-07-07 23:28:45 -05:00
< h2 align = "center" > QA and release< / h2 >
2026-06-17 19:59:07 -05:00
2026-07-07 21:47:20 -05:00
The repo keeps repeatable QA checks close to the code:
2026-06-20 22:20:31 -05:00
2026-07-07 21:47:20 -05:00
| Check | Purpose |
| --- | --- |
| `scripts/theme-scan.sh` | Finds hardcoded theme/color regressions |
| `scripts/wiring-scan.sh` | Finds orphaned routes, dead actions, and silent wiring breaks |
| [docs/qa/ ](docs/qa/ ) | Manual QA playbooks and private MVP checklist |
| [docs/release/ ](docs/release/ ) | Internal testing, store assets, and release prep |
2026-06-17 19:59:07 -05:00
2026-07-07 23:28:45 -05:00
Live emulator fixtures and related credentials are intentionally local-only. Keep them in gitignored
files under `qa/` , never in the tracked README or public docs.
2026-06-17 19:59:07 -05:00
2026-07-07 23:28:45 -05:00
< h2 align = "center" > Repository map< / h2 >
2026-06-20 22:20:31 -05:00
2026-07-07 21:47:20 -05:00
```text
app/ Android app
iphone/ iOS app
functions/ Firebase Cloud Functions
server/ Optional Express service
seed/ Question content and seed tooling
scripts/ Static QA scanners
2026-07-07 23:28:45 -05:00
qa/ Local-only emulator fixture notes and smoke helpers
2026-07-07 21:47:20 -05:00
docs/ Architecture, release, screenshots, and QA docs
firestore.rules Firestore rules source of truth
```
2026-06-17 19:59:07 -05:00
2026-07-07 23:28:45 -05:00
< h2 align = "center" > Roadmap< / h2 >
2026-06-17 19:59:07 -05:00
2026-06-28 15:53:41 -05:00
In progress:
2026-06-20 22:20:31 -05:00
2026-07-07 21:47:20 -05:00
- iOS E2EE interoperability with Android's Tink key material
- More on-device/instrumented smoke coverage
- Activity `uiMode` sync for in-app theme and dark artwork
- Internal-testing release configuration, legal/support URLs, and RevenueCat offering validation
2026-06-20 22:20:31 -05:00
2026-07-07 21:47:20 -05:00
Out of scope for now:
2026-06-16 20:16:47 -05:00
2026-07-07 21:47:20 -05:00
- AI-generated core questions
- Group relationship spaces beyond dyadic couples
- Wear OS / watchOS companions
2026-06-28 15:53:41 -05:00
- Live video or voice sessions
2026-06-16 20:16:47 -05:00
2026-07-07 23:28:45 -05:00
< h2 align = "center" > Project docs< / h2 >
2026-06-20 22:20:31 -05:00
2026-06-28 15:53:41 -05:00
| Doc | Purpose |
| --- | --- |
2026-07-07 21:47:20 -05:00
| [docs/Engineering_Reference_Manual.md ](docs/Engineering_Reference_Manual.md ) | Architecture, security model, data model, and known landmines |
| [docs/brand/ ](docs/brand/ ) | Visual identity, asset system, generated art |
| [docs/release/ ](docs/release/ ) | Release prep and store assets |
| [docs/qa/ ](docs/qa/ ) | Manual QA checklist |
| [Future.md ](Future.md ) | Backlog and roadmap |
| [HISTORY.md ](HISTORY.md ) | Changelog and release notes |
| [PROJECT.md ](PROJECT.md ) | Scope, feature matrix, architectural decisions |
2026-06-20 22:20:31 -05:00
2026-07-07 23:28:45 -05:00
< h2 align = "center" > License< / h2 >
2026-06-16 20:16:47 -05:00
Private project. All rights reserved.