347 lines
15 KiB
Markdown
347 lines
15 KiB
Markdown
# Closer
|
|
|
|
> *Private daily questions for couples who want honest answers before shared conversations.*
|
|
|
|
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.
|
|
|
|
---
|
|
|
|
## Pricing Philosophy
|
|
|
|
> *No shady trials. No cancellation friction. One subscription per couple, not per person.*
|
|
|
|
Subscription apps for couples have a trust problem — confusing trial wording, hard-to-cancel flows, and partners getting double-billed. Closer treats pricing the same way it treats relationships: **clear, straightforward, and built on honesty.**
|
|
|
|
| Principle | How Closer Handles It |
|
|
| --- | --- |
|
|
| Free tier | Generous by default. Daily questions, basic packs, recent history, spin wheel — all free, no time limit. |
|
|
| One sub per couple | One premium purchase unlocks it for both partners. No second billing. |
|
|
| Trial wording | No auto-renewal trials that silently convert. If there's a free period, you'll know exactly when and how it ends. |
|
|
| Cancellation | Clear, actionable instructions in-app and in docs. No hidden unsubscribe paths. |
|
|
| Restore | Works with one tap. If it breaks, support fixes it — no escalation maze. |
|
|
|
|
---
|
|
|
|
## Screenshots
|
|
|
|
<p>
|
|
<img src="docs/screenshots/01-onboarding.png" alt="Closer onboarding screen" width="180" />
|
|
<img src="docs/screenshots/03-home.png" alt="Closer home dashboard" width="180" />
|
|
<img src="docs/screenshots/04-daily-question.png" alt="Closer daily question answer screen" width="180" />
|
|
<img src="docs/screenshots/05-question-packs.png" alt="Closer question pack library" width="180" />
|
|
</p>
|
|
|
|
<p>
|
|
<img src="docs/screenshots/06-answer-history.png" alt="Closer answer history" width="180" />
|
|
<img src="docs/screenshots/08-play.png" alt="Closer play hub" width="180" />
|
|
<img src="docs/screenshots/09-date-builder.png" alt="Closer date planning screen" width="180" />
|
|
<img src="docs/screenshots/07-settings.png" alt="Closer settings screen" width="180" />
|
|
</p>
|
|
|
|
<p>
|
|
<img src="docs/screenshots/02-login.png" alt="Closer login screen" width="180" />
|
|
</p>
|
|
|
|
---
|
|
|
|
## 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, 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, full history, Desire Sync, Connection Challenges, Memory Lane, and analytics — **one subscription for both partners** |
|
|
|
|
---
|
|
|
|
## 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 — No Time Limit, No Hidden Cap
|
|
|
|
All of this is free, forever. No credits, no daily limits that magically shrink after a week.
|
|
|
|
- Anonymous onboarding → 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
|
|
- Question packs — 6,000+ bundled prompts across 22 categories (most packs included free)
|
|
- Spin wheel — category-based random questions for date nights
|
|
- Recent answer history (last 30 days)
|
|
- Push reminders with quiet-hour support
|
|
- Account deletion and data export
|
|
|
|
### Premium Tier (Per-Couple, Not Per-Person)
|
|
|
|
One purchase unlocks premium for both partners. No separate subscriptions.
|
|
|
|
- **Unlimited daily questions** with premium-only question packs
|
|
- **Full answer history** — search, filter, export the complete timeline
|
|
- **Saved spin wheel session history** — revisit what landed
|
|
- **Desire Sync** — preferences alignment exercise for tough conversations
|
|
- **Connection Challenges** — multi-day guided programs (communication, trust, intimacy)
|
|
- **Memory Lane** — time capsules with locked prompts that open on future dates
|
|
- **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
|
|
|
|
```text
|
|
.
|
|
├── 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](https://github.com/yonaskolb/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
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```properties
|
|
sdk.dir=/path/to/Android/Sdk
|
|
RC_API_KEY_ANDROID=your_revenuecat_android_key
|
|
RC_API_KEY_IOS=your_revenuecat_ios_key
|
|
```
|
|
|
|
### Android
|
|
|
|
```bash
|
|
./gradlew :app:assembleDebug
|
|
./gradlew :app:installDebug
|
|
```
|
|
|
|
Useful verification command:
|
|
|
|
```bash
|
|
./gradlew :app:compileDebugKotlin
|
|
```
|
|
|
|
### iOS
|
|
|
|
```bash
|
|
cd iphone
|
|
xcodegen generate
|
|
xed Closer.xcodeproj
|
|
```
|
|
|
|
Build from the command line:
|
|
|
|
```bash
|
|
xcodebuild -project iphone/Closer.xcodeproj \
|
|
-scheme Closer \
|
|
-destination 'platform=iOS Simulator,name=iPhone 15' \
|
|
build
|
|
```
|
|
|
|
### Firebase Functions
|
|
|
|
```bash
|
|
cd functions
|
|
npm install
|
|
npm run build
|
|
npm run serve
|
|
```
|
|
|
|
### Optional Server
|
|
|
|
```bash
|
|
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 `dev` branch
|
|
- 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.md`
|
|
- `docs/release/store-assets.md`
|
|
- `docs/qa/private-mvp-checklist.md`
|
|
- `docs/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.
|