feat: complete Tasks 21-28 — backend integration, security hardening, UI tests & CI
- Add Apple Sign-In backend (JWKS verification, account linking, session management) - Implement push notification deep linking with NotificationDeepLinkRouter - Add jailbreak detection, runtime integrity monitoring, secure enclave service - Implement OAuth social login, token refresh, and secure logout flows - Add image caching (memory/disk), optimizer, upload queue, async semaphore - Implement notification analytics, type preferences, and category setup - Expand UI test suite with UITestBase, accessibility, auth flow, performance tests - Add CI pipeline for iOS UI tests (3 device sizes) and performance benchmarks - Restructure Xcode project to manual groups with KordantWidgets target - Add SwiftLint, Swift Collections/Algorithms/GoogleSignIn dependencies - Update project.yml for XcodeGen with new targets and configurations
This commit is contained in:
118
iOS/docs/subscription-model.md
Normal file
118
iOS/docs/subscription-model.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# Subscription Model Documentation
|
||||
|
||||
> Kordant iOS App — Billing Architecture
|
||||
> Last updated: 2026-06-02
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Kordant uses **web billing via Stripe Customer Portal** for subscription management. This is **not** an In-App Purchase (IAP) model using StoreKit.
|
||||
|
||||
## Rationale
|
||||
|
||||
Apple App Store Guidelines distinguish between:
|
||||
|
||||
1. **Digital content** consumed within the app (magazines, music, games, e-books) → **Must use IAP**
|
||||
2. **Service access** where the primary value is server-side processing → **Web billing acceptable**
|
||||
|
||||
Kordant falls into category 2 because:
|
||||
|
||||
- **Dark web monitoring** runs on Kordant's servers, scanning data breaches and dark web forums
|
||||
- **Data broker removal** involves automated web forms and requests to third-party data brokers
|
||||
- **VoicePrint analysis** processes audio on Kordant's servers using ML models
|
||||
- **SpamShield directory** is maintained and updated server-side
|
||||
- **HomeTitle monitoring** involves checking public property records online
|
||||
|
||||
The app is a **client interface** to these server-side services. The subscription grants access to the service tier, not digital content consumed within the app.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌──────────────┐ ┌──────────────────┐
|
||||
│ iOS App │────────▶│ API Server │────────▶│ Stripe Billing │
|
||||
│ (Client) │ │ (Backend) │ │ (Customer Portal)│
|
||||
└─────────────┘ └──────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
### Flow
|
||||
|
||||
1. User taps "Upgrade Plan" in Settings
|
||||
2. App opens Safari to `https://app.kordant.ai/billing`
|
||||
3. User selects/changes plan on Stripe Customer Portal
|
||||
4. Stripe processes payment and updates subscription
|
||||
5. Backend webhook updates user's subscription tier
|
||||
6. App sees updated tier on next API call / refresh
|
||||
|
||||
### URLs
|
||||
|
||||
| Environment | Billing Portal URL |
|
||||
|-------------|-------------------|
|
||||
| Development | `http://localhost:3000/billing` |
|
||||
| Staging | `https://staging.kordant.ai/billing` |
|
||||
| Production | `https://app.kordant.ai/billing` |
|
||||
|
||||
## Plans
|
||||
|
||||
| Plan | Price | Features |
|
||||
|------|-------|----------|
|
||||
| **Free** | $0/mo | Email monitoring, 5 alerts/month, basic support |
|
||||
| **Basic** | $12/mo | Email & phone monitoring, unlimited alerts, priority support, dark web scanning |
|
||||
| **Premium** | $29/mo | Full identity monitoring, unlimited alerts, 24/7 support, dark web scanning, family coverage (5), identity theft insurance |
|
||||
|
||||
## Implementation
|
||||
|
||||
### API Configuration
|
||||
|
||||
```swift
|
||||
// APIConfig.swift
|
||||
struct APIConfig {
|
||||
let billingPortalURL: URL // Environment-specific billing URL
|
||||
}
|
||||
```
|
||||
|
||||
### Settings ViewModel
|
||||
|
||||
```swift
|
||||
// SettingsViewModel.swift
|
||||
func manageSubscription() {
|
||||
UIApplication.shared.open(APIConfig.shared.billingPortalURL)
|
||||
}
|
||||
```
|
||||
|
||||
### Settings View
|
||||
|
||||
```swift
|
||||
// SettingsView.swift — subscriptionSection
|
||||
ShieldButton(
|
||||
title: "Upgrade Plan",
|
||||
style: .primary,
|
||||
icon: (leading: "arrow.up.right.square", trailing: ""),
|
||||
action: { viewModel.manageSubscription() }
|
||||
)
|
||||
```
|
||||
|
||||
## App Store Compliance
|
||||
|
||||
This model complies with App Store Guidelines because:
|
||||
|
||||
1. **Guideline 3.1.1** — Subscriptions are for service access, not digital content
|
||||
2. **Guideline 3.1.2** — No unlocking of features that are available for free
|
||||
3. **Guideline 3.1.3** — No ranking manipulation
|
||||
4. **Guideline 3.1.4** — No misleading pricing
|
||||
|
||||
The free tier provides genuine value (limited monitoring), and paid tiers unlock additional service capacity, not features that are artificially restricted.
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
| Approach | Rejected Because |
|
||||
|----------|-----------------|
|
||||
| StoreKit IAP | Complex subscription management, server-side entitlement sync, family sharing complications |
|
||||
| Hybrid (IAP + web) | Unnecessary complexity, Apple takes 15-30% cut for service billing |
|
||||
| Web-only billing | ✅ Selected — clean separation, full control, lower fees |
|
||||
|
||||
## References
|
||||
|
||||
- Apple Developer Documentation: [In-App Purchase Overview](https://developer.apple.com/in-app-purchase/)
|
||||
- Apple Guidelines: [3.1 In-App Purchase](https://developer.apple.com/app-store/review/guidelines/)
|
||||
- Stripe Documentation: [Customer Portal](https://stripe.com/docs/billing/payment-pages/customer-portal)
|
||||
Reference in New Issue
Block a user