- Add Closer tagline + private-space positioning at top - Add explicit anti-scope (not social, not therapy, not productivity) - Add Platform Status table (Android active, iOS in progress, backend shared) - Add MVP scope split: Free / Premium / Out-of-Scope - Add iOS folder layout with each layer's purpose - Add iOS build commands (xcodegen + xcodebuild) - Expand privacy section (App Check, server-verified subscriptions, E2EE note) - Clear MVP status breakdown: complete / in-progress / release-prep - Link HISTORY.md and PROJECT.md for deeper context |
||
|---|---|---|
| .vscode | ||
| app | ||
| docs | ||
| firestore-tests | ||
| functions | ||
| gradle/wrapper | ||
| iphone | ||
| seed | ||
| server | ||
| .eslintrc.js | ||
| .firebaserc | ||
| .gitignore | ||
| .prettierrc | ||
| README.md | ||
| build.gradle.kts | ||
| firebase.json | ||
| firestore.indexes.json | ||
| firestore.rules | ||
| gitleaks-current.json | ||
| gitleaks-history.json | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| local.properties.example | ||
| seed_generator.py | ||
| settings.gradle.kts | ||
| storage.rules | ||
README.md
Closer
A private space for two people to talk, reflect, and stay close.
Closer is a couples relationship app built for partners who want a steadier way to talk, reflect, and make time for each other. It turns relationship check-ins into small, intentional rituals — one daily question, curated conversation packs, private answers, partner reveal flows, gentle reminders, and shared date planning.
The app is not a social network, not a therapy replacement, and not a productivity tracker. There are no public feeds, no likes, no followers, and no infinite scroll. The core loop is simple: answer honestly, choose what to reveal, and keep a record of the conversations that mattered.
Closer is built as native apps on Android (Kotlin / Jetpack Compose) and iOS (SwiftUI), both backed by the same Firebase stack and shared data model.
Screenshots
What Closer Does
Closer gives couples a private, shared space for guided connection:
- Daily question — one prompt a day, with written, scale, multiple-choice, and this-or-that answer modes.
- Private-first answers — each partner answers independently before deciding whether to reveal or discuss.
- Question packs — 22+ curated categories spanning 6,000+ bundled prompts (communication, conflict, trust, intimacy, parenting, marriage, money, stress, date night, and more).
- Answer history — review past questions and answers, delete controls, and partner reveal support.
- Discussion threads — question-specific conversation threads and reactions for follow-up.
- Partner pairing — 6-character invite code, email invite flow, and partner-aware home states.
- Spin the wheel — category-based random questions for date nights, road trips, and low-pressure moments.
- Date tools — swipe-to-match date ideas, date planning preferences, and a shared bucket list.
- Settings & privacy — account, notifications, appearance, subscription, relationship, privacy, and account deletion flows.
- Subscriptions — free and premium tiers powered by RevenueCat (Google Play Billing on Android, StoreKit on iOS).
Product Shape
Closer is optimized for short, meaningful sessions rather than endless engagement.
| Area | Behavior |
|---|---|
| Home | Surfaces the next best action — daily question, partner activity, streaks, saved answers |
| Questions | Local-bundled content so the app stays fast and usable without waiting on the network |
| Partner Sync | Firebase Auth + Firestore isolate user, couple, invite, thread, and entitlement data per couple |
| Reminders | FCM + local notification preferences and quiet-hour controls |
| Premium | Unlocks deeper packs, wheel session history, full answer history, and advanced suggestion features |
Platform Status
| Platform | Stack | Status |
|---|---|---|
| Android | Kotlin · Jetpack Compose · Material 3 · Hilt · Room · DataStore | Active development — feature-complete MVP |
| iOS | SwiftUI · MVVM · async/await · Firebase iOS SDK | In progress — full scaffold + screen parity landed on dev branch |
| Backend | Firebase Auth · Firestore · Cloud Functions (TypeScript) · FCM · App Check | Shared source of truth for both platforms |
| Billing | RevenueCat · Google Play Billing · StoreKit | Server-verified entitlements via Cloud Function webhook |
The Android app is the reference implementation — the iOS port is built to mirror it screen-for-screen and consume the same backend.
MVP Feature Scope
Free Tier
- Anonymous trial → email or Google sign-up
- 6-character invite code pairing (with email invite fallback)
- Daily question with full answer modes (text, scale, multiple choice, this-or-that)
- Private answer reveal flow once both partners have answered
- Limited spin wheel sessions and basic question packs
- Recent answer history (last 30 days)
- Push reminders with quiet-hour support
- Account deletion and data export
Premium Tier (via RevenueCat)
- Unlimited daily questions and premium question packs
- Full answer history and saved spin wheel session history
- Desire Sync (preferences alignment exercise)
- Connection Challenges (multi-day programs)
- Memory Lane (time capsules)
- Advanced analytics and relationship insights
- Priority support
Out of Scope (Future)
- AI-assisted question suggestions
- Native group/relationship types beyond dyadic couples
- Wearable (Wear OS / watchOS) companions
- Live video or voice sessions
Tech Stack
Android
| Layer | Stack |
|---|---|
| Language | Kotlin 2.x |
| UI | Jetpack Compose, Material 3, Navigation Compose |
| Architecture | Clean architecture — core/ · data/ · domain/ · ui/ |
| State | ViewModel · Kotlin Coroutines · Kotlin Flow |
| Dependency Injection | Hilt |
| Local Data | Room · DataStore Preferences · bundled SQLite seed |
| SDK | min 26 · target 35 · compile 35 |
iOS
| Layer | Stack |
|---|---|
| Language | Swift 5.9 |
| UI | SwiftUI · NavigationStack · TabView |
| Architecture | MVVM · AppState ObservableObject · EnvironmentObject |
| Concurrency | async/await |
| Dependency Management | Swift Package Manager · XcodeGen (project.yml) |
| SDK | iOS 17+ |
Backend (Shared)
| Layer | Stack |
|---|---|
| Auth | Firebase Authentication (anonymous, email/password, Google) |
| Database | Cloud Firestore |
| Server Logic | Firebase Cloud Functions (TypeScript) |
| Push | Firebase Cloud Messaging (FCM) |
| Security | Firebase App Check · Play Integrity (Android) · DeviceCheck (iOS) |
| Billing | RevenueCat (server-verified entitlements) |
| Analytics | Firebase Analytics · Crashlytics |
Repository Layout
.
├── app/ # Native Android app (Kotlin)
│ └── src/main/java/app/closer
│ ├── core/ # Firebase, analytics, billing, navigation, notifications, security
│ ├── data/ # Room, Firestore data sources, repositories, seed parsing
│ ├── domain/ # Models and repository contracts
│ └── ui/ # Compose screens and feature ViewModels
├── iphone/ # Native iOS app (SwiftUI)
│ ├── ARCHITECTURE_AUDIT.md # iOS port blueprint (49 screens, schema, models)
│ ├── project.yml # XcodeGen project spec
│ ├── Package.swift # SPM dependency manifest
│ └── Closer/
│ ├── Models/ # Firestore + domain codable types
│ ├── Core/ # Auth, Billing, Notifications
│ ├── Services/ # FirestoreService (callable wrappers)
│ ├── Theme/ # CloserTheme (colors, typography, spacing)
│ ├── Components/ # Shared SwiftUI components
│ ├── Navigation/ # Root ContentView + TabView routing
│ ├── Onboarding/ # Onboarding, login, signup, profile creation
│ ├── Pairing/ # Invite code, partner confirm, recovery
│ ├── Home/ # Home dashboard, streak, partner mirror
│ ├── Questions/ # Daily question, answer reveal, history, packs
│ ├── Play/ # Play hub + games (ThisOrThat, HowWell, DesireSync)
│ ├── Wheel/ # Spin wheel with animated 8-slice picker
│ ├── Dates/ # Date swipe, matches, builder, bucket list
│ └── Settings/ # Settings, paywall, help, data export
├── functions/ # Firebase Cloud Functions (TypeScript)
│ └── src/
│ ├── auth/ # Auth flow + invite lifecycle
│ ├── billing/ # RevenueCat webhook + entitlement sync
│ ├── couples/ # Pairing, leave, daily question triggers
│ ├── questions/ # onAnswerWritten, onMessageWritten, threads
│ └── server/ # Internal Express webhook service (not client-facing)
├── server/ # Optional Express webhook/health service
├── seed/ # Question pack JSON and local DB generation
├── docs/ # QA notes, release prep, roadmap, screenshots
└── firestore.rules # Firestore security rules
Getting Started
Prerequisites
- Android: Android Studio · Android SDK · JDK 17
- iOS: Xcode 16 · macOS · XcodeGen (
brew install xcodegen) - Firebase: Project with Auth, Firestore, Cloud Messaging, Crashlytics, Analytics, App Check
- Android config:
app/google-services.json - iOS config:
iphone/Closer/GoogleService-Info.plist - Billing: RevenueCat project with Android and iOS API keys
- Node 20 for Firebase Functions tooling
Local config
# Android
cp local.properties.example local.properties
# iOS
cp iphone/Closer/GoogleService-Info.plist.example iphone/Closer/GoogleService-Info.plist
Add local-only values such as:
sdk.dir=/path/to/Android/Sdk
RC_API_KEY_ANDROID=your_revenuecat_android_key
RC_API_KEY_IOS=your_revenuecat_ios_key
Android
./gradlew :app:assembleDebug
./gradlew :app:installDebug
Useful verification command:
./gradlew :app:compileDebugKotlin
iOS
cd iphone
xcodegen generate
xed Closer.xcodeproj
Build from the command line:
xcodebuild -project iphone/Closer.xcodeproj \
-scheme Closer \
-destination 'platform=iOS Simulator,name=iPhone 15' \
build
Firebase Functions
cd functions
npm install
npm run build
npm run serve
Optional Server
cd server
npm install
npm run dev
Data Model
Closer combines local-first question content with cloud sync for shared relationship state:
- Room (Android) / local bundled JSON (iOS) stores seeded question categories, questions, and date preferences — the app stays usable offline.
- DataStore (Android) / UserDefaults (iOS) stores local settings and lightweight preferences.
- Firestore stores users, couples, invites, daily questions, answer history, date matches, bucket-list state, time capsules, gentle reminders, and entitlements.
- Cloud Functions handle pairing lifecycle, reminder workflows, billing entitlement sync, RevenueCat webhooks, partner activity triggers (FCM), and security checks.
- FCM delivers reminders and partner activity notifications to both platforms.
Privacy & Safety Principles
- Couple data is scoped by couple ID and protected by Firestore security rules — no other couple can read another couple's data.
- Answers are private first, then revealed intentionally by the partner.
- Account deletion and privacy screens are first-class surfaces in the app.
- App Check (Play Integrity on Android, DeviceCheck on iOS) blocks abusive backend access.
- Subscription state is verified server-side via Cloud Functions rather than trusting the client.
- All private answer and capsule content is end-to-end encrypted with couple-owned keys (Android uses Tink; iOS uses Apple CryptoKit in a follow-up batch).
Current Status
This is a private MVP / internal testing codebase.
Complete
- Android MVP — onboarding, auth (anonymous/email/Google), pairing, home, daily questions, question packs, answer history, spin wheel, date tools, settings, billing, notifications, Firebase integration, E2EE crypto layer
- iOS port scaffold — all 49 screens mapped to SwiftUI views, Firebase/RevenueCat integration, full screen parity landed on
devbranch - Backend — 17 Cloud Functions (callable, triggers, scheduled, webhook) covering full relationship lifecycle
- Seeded question content — 6,000+ prompts across 22 categories
In Progress
- iOS Xcode project generation and build verification
- iOS E2EE layer (CryptoKit interop with Android Tink)
- Final QA pass on both platforms
Release Prep
docs/release/internal-testing-checklist.mddocs/release/store-assets.mddocs/qa/private-mvp-checklist.mddocs/qa/ui-review.md
Project History
See HISTORY.md for the full changelog and release notes.
See PROJECT.md for detailed scope, feature matrix, and architectural decisions.
License
Private project. All rights reserved.