diff --git a/docs/MOBILE_DRY_REFACTORING_ROADMAP.md b/docs/MOBILE_DRY_REFACTORING_ROADMAP.md new file mode 100644 index 00000000..ede4cc4f --- /dev/null +++ b/docs/MOBILE_DRY_REFACTORING_ROADMAP.md @@ -0,0 +1,454 @@ +# Mobile DRY Refactoring Roadmap + +> **Goal:** Eliminate hand-rolled platform code across all mobile surfaces (iOS, Android, React Native) by migrating to shared `@bytelyst/*` packages and SDKs. +> +> **Scope:** 14 mobile surfaces (iOS/Android/RN) across 8 product repos. 12 have gaps needing work. Estimated total effort: ~7.5 days. +> Surfaces with no gaps: PeakPulse iOS (gold standard, 9 wrappers), MindLyst Android (Koin, all 6 SDK components). +> +> **Date:** 2026-03-21 +> +> **Prerequisite:** All shared SDKs already exist and are tested: +> +> - `packages/swift-platform-sdk/` — 13 Swift components, 1,870 LOC +> - `packages/kotlin-platform-sdk/` — 13 Kotlin components, 35 tests +> - `packages/react-native-platform-sdk/` — createRNPlatformSDK(), AuthProvider, useAuth +> - 18 TypeScript client packages (`@bytelyst/*`) + +--- + +## Table of Contents + +1. [Phase 1 — ChronoMind Android: Replace Old Services with SDK](#phase-1) +2. [Phase 2 — JarvisJr Android: Wire Platform SDK from Scratch](#phase-2) +3. [Phase 3 — FlowMonk Mobile (RN): Add Missing Packages + Fix Raw Fetch](#phase-3) +4. [Phase 4 — LysnrAI Android: Migrate 6 Hand-Rolled Data Services](#phase-4) +5. [Phase 5 — NomGap (RN): Replace Raw Fetch in billing-api + photo-meal](#phase-5) +6. [Phase 6 — LysnrAI iOS: Migrate SSO, Usage, Sync, CertPinning](#phase-6) +7. [Phase 7 — Auth App Android: Wire BLAuthClient](#phase-7) +8. [Phase 8 — Auth App iOS: Add Telemetry, Flags, Kill Switch](#phase-8) +9. [Phase 9 — ChronoMind iOS + NoteLett Mobile: Minor Gaps](#phase-9) +10. [Verification Matrix](#verification-matrix) + +--- + + + +## Phase 1 — ChronoMind Android: Replace Old Services with SDK + +**Priority:** HIGH | **Effort:** 1 day | **Repo:** `learning_ai_clock` | **Commit:** [`2060a83`](https://github.com/saravanakumardb1/learning_ai_clock/commit/2060a83) + +### Context + +ChronoMind Android already had `platform/Config.kt` and `platform/PlatformModule.kt` (Hilt) providing all SDK clients. `LoginScreen.kt`, `SettingsScreen.kt`, and `TimerViewModel.kt` were **already migrated** to SDK clients in a prior session. The old services (`AuthService`, `TelemetryService`, `FeatureFlagService`) were dead code. `SyncRepository` used a hand-rolled `PlatformApiClient` with raw `HttpURLConnection`. + +### Files to Modify + +- `android/app/src/main/java/com/chronomind/app/auth/AuthService.kt` — DELETE +- `android/app/src/main/java/com/chronomind/app/auth/LoginScreen.kt` — UPDATE call sites +- `android/app/src/main/java/com/chronomind/app/telemetry/TelemetryService.kt` — DELETE +- `android/app/src/main/java/com/chronomind/app/telemetry/FeatureFlagService.kt` — DELETE +- `android/app/src/main/java/com/chronomind/app/sync/SyncRepository.kt` — UPDATE to use BLSyncEngine +- `android/app/src/main/java/com/chronomind/app/sync/PlatformApiClient.kt` — DELETE (replace with BLPlatformClient) +- `android/app/src/main/java/com/chronomind/app/di/AppModule.kt` — VERIFY old providers removed +- `android/app/src/main/java/com/chronomind/app/viewmodel/TimerViewModel.kt` — UPDATE to SDK clients +- `android/app/src/main/java/com/chronomind/app/ui/screens/SettingsScreen.kt` — UPDATE AuthService refs + +### Tasks + +- [x] **1.1 Audit call sites** — `LoginScreen.kt`, `SettingsScreen.kt`, `TimerViewModel.kt` already use SDK clients. No external references to old services. +- [x] **1.2 Update AppModule.kt** — No old `@Provides` for auth/telemetry/flags existed. Updated `SyncRepository` provider to inject `BLSecureStore`. +- [x] **1.3 Auth call sites** — Already migrated in prior session (`LoginScreen` → `BLAuthClient`, `SettingsScreen` → `BLAuthClient`). +- [x] **1.4 Telemetry call sites** — Already migrated (`TimerViewModel` injects `BLTelemetryClient`). +- [x] **1.5 Feature flag call sites** — Already migrated (`PlatformModule` provides `BLFeatureFlagClient`). +- [x] **1.6 Migrate sync** — `PlatformApiClient` rewritten from `HttpURLConnection` → OkHttp. `SyncRepository` now reads auth token from `BLSecureStore` via `tokenProvider` lambda instead of manual `SharedPreferences`. +- [x] **1.7 Wire KillSwitch** — `BLKillSwitchClient` injected in `MainActivity.kt` with kill switch check on app start. Shows blocking message if killed. +- [x] **1.8 Delete dead code** — `auth/AuthService.kt` (328 LOC), `telemetry/TelemetryService.kt` (178 LOC), `telemetry/FeatureFlagService.kt` (89 LOC) deleted. Net: **-567 lines**. +- [ ] **1.9 Build verification** — Requires Android SDK environment (corporate proxy). **TODO-1: Verify Gradle build compiles on dev machine.** + +--- + + + +## Phase 2 — JarvisJr Android: Wire Platform SDK from Scratch + +**Priority:** HIGH | **Effort:** 1 day | **Repo:** `learning_ai_jarvis_jr` | **Commit:** [`336535a`](https://github.com/saravanakumardb1/learning_ai_jarvis_jr/commit/336535a) + +### Context + +JarvisJr Android had no `platform/` module. It had a stub `sync/PlatformApiClient.kt` that returned `Result.success(Unit)` for everything. The app uses Hilt for DI. Full SDK wiring was needed from scratch. + +### Files to Create + +- `android/app/src/main/java/com/jarvisjr/app/platform/Config.kt` — NEW +- `android/app/src/main/java/com/jarvisjr/app/platform/PlatformModule.kt` — NEW (Hilt) + +### Files to Modify + +- `android/settings.gradle.kts` — add `includeBuild` for kotlin-platform-sdk +- `android/app/build.gradle.kts` — add kotlin-platform-sdk dependency +- `android/app/src/main/java/com/jarvisjr/app/di/AppModule.kt` — remove any old stubs +- `android/app/src/main/java/com/jarvisjr/app/sync/PlatformApiClient.kt` — DELETE (replace with SDK) + +### Tasks + +- [x] **2.1 Add kotlin-platform-sdk to build** — `includeBuild` in `settings.gradle.kts` + `implementation("com.bytelyst:platform-sdk")` in `app/build.gradle.kts`. +- [x] **2.2 Create `platform/Config.kt`** — `BLPlatformConfig(productId = "jarvisjr", baseUrl, platform = "android", applicationId = "com.jarvisjr.app")`. +- [x] **2.3 Create `platform/PlatformModule.kt`** — Hilt `@Module` providing 7 SDK components: `BLPlatformConfig`, `BLSecureStore`, `BLPlatformClient`, `BLAuthClient`, `BLTelemetryClient`, `BLFeatureFlagClient`, `BLKillSwitchClient`. +- [x] **2.4 Create LoginScreen** — New `ui/screens/LoginScreen.kt` using `BLAuthClient`. Auth gate wired in `MainActivity.kt`. +- [x] **2.5 Wire telemetry** — `AgentViewModel.kt` now injects `BLTelemetryClient`. +- [x] **2.6 Wire SettingsScreen** — Real user info from `BLAuthClient.authState` + logout button via `SettingsViewModel`. +- [x] **2.7 Wire KillSwitch** — `BLKillSwitchClient` check on app start in `MainActivity.kt`. +- [x] **2.8 Delete stub PlatformApiClient** — `sync/PlatformApiClient.kt` deleted. +- [ ] **2.9 Build verification** — Requires Android SDK environment. **TODO-2: Verify Gradle build compiles on dev machine.** + - [ ] `./gradlew :app:test` — all tests pass + +--- + + + +## Phase 3 — FlowMonk Mobile (RN): Add Missing Packages + Fix Raw Fetch + +**Priority:** MEDIUM | **Effort:** 0.5 day | **Repo:** `learning_ai_flowmonk` | **Commit:** [`ce70d8c`](https://github.com/saravanakumardb1/learning_ai_flowmonk/commit/ce70d8c) + +### Context + +FlowMonk mobile had 5 `@bytelyst/*` packages but was missing `telemetry-client`. Its `api.ts` was a hand-rolled fetch wrapper with no auth token injection. + +### Current Packages (5) + +`auth-client`, `feature-flag-client`, `kill-switch-client`, `offline-queue`, `platform-client` + +### Missing Packages (5) + +`telemetry-client`, `blob-client`, `design-tokens`, `api-client`, `react-native-platform-sdk` + +### Files to Modify + +- `mobile/package.json` — add 5 missing deps +- `mobile/src/lib/api.ts` — refactor to use `@bytelyst/api-client` or `@bytelyst/platform-client` +- `mobile/src/lib/clients.ts` — already has `authClient`, `featureFlagClient`, `killSwitchClient`, `offlineQueue`, `platformClient`; add `telemetryClient` + +### Files to Create + +- `mobile/src/lib/platform.ts` — centralized platform init (follow NoteLett pattern) + +### Tasks + +- [x] **3.1 Add `@bytelyst/telemetry-client`** to `mobile/package.json`. Other missing packages (`blob-client`, `design-tokens`, `api-client`, `react-native-platform-sdk`) deferred — not actively needed yet. +- [x] **3.2 Wire telemetryClient** in `mobile/src/lib/clients.ts` alongside existing 5 clients. +- [x] **3.3 Inject auth tokens in `api.ts`** — `json()` helper now reads token from `authClient.getAccessToken()` and adds `Authorization` + `X-Product-Id` headers to all API requests. Typed API surface preserved. +- [ ] **3.4 Build verification** — **TODO-3: Run `cd mobile && npm run typecheck` to verify.** + +--- + + + +## Phase 4 — LysnrAI Android: Migrate 6 Hand-Rolled Data Services + +**Priority:** MEDIUM | **Effort:** 1 day | **Repo:** `learning_voice_ai_agent` | **Commit:** [`24a09a2`](https://github.com/saravanakumardb1/learning_voice_ai_agent/commit/24a09a2) + +### Context + +LysnrAI Android had good SDK wiring (`platform/Config.kt` + `platform/PlatformModule.kt` with Hilt providing `BLTelemetryClient`, `BLFeatureFlagClient`, `BLKillSwitchClient`, `BLSecureStore`). **Note:** `BLAuthClient` is intentionally NOT in PlatformModule because `AuthViewModel` has deep LysnrAI-specific integration (DataStore, keyboard bridging, CloudSync). Audit found 11 of 13 `data/` services were **dead code** (zero external callers). + +### Hand-Rolled Services to Migrate + +| File | Current | Target SDK | +| ------------------------------ | ---------------------------- | --------------------------------------------------- | +| `data/FeatureFlagService.kt` | Raw HTTP + SharedPreferences | `BLFeatureFlagClient` (already in PlatformModule) | +| `data/KillSwitchService.kt` | Raw HTTP | `BLKillSwitchClient` (already in PlatformModule) | +| `data/BlobService.kt` | Raw HttpURLConnection | `BLBlobClient` | +| `data/LicenseService.kt` | Raw HTTP | `BLLicenseClient` | +| `data/SSOService.kt` | Raw HTTP + SharedPreferences | `BLAuthClient` (OAuth flows) | +| `data/UsageService.kt` | Raw HttpURLConnection | `BLPlatformClient` (generic fetch) | +| `data/ProfileService.kt` | Raw HTTP | `BLPlatformClient` (generic fetch) | +| `data/CertificatePinning.kt` | Custom OkHttp interceptor | Evaluate: keep or move to SDK | +| `data/GuestMode.kt` | SharedPreferences | Evaluate: keep (product-specific) | +| `sync/CloudSyncService.kt` | Raw HTTP | `BLSyncEngine` | +| `sync/OfflineQueue.kt` | Custom queue | `BLSyncEngine` or `@bytelyst/offline-queue` pattern | +| `sync/SessionSyncService.kt` | Raw HTTP | `BLSyncEngine` | +| `telemetry/TelemetryClient.kt` | Raw HTTP | `BLTelemetryClient` (already in PlatformModule) | + +### Tasks + +- [x] **4.1 Audit all data/ services for external callers** — grep found 11 of 13 services have zero external imports (dead code). +- [x] **4.2 Delete dead code (11 files, -1,005 LOC)**: + - [x] `data/FeatureFlagService.kt` (96 LOC) — superseded by `BLFeatureFlagClient` in PlatformModule + - [x] `data/KillSwitchService.kt` (63 LOC) — superseded by `BLKillSwitchClient` in PlatformModule + - [x] `data/BlobService.kt` (149 LOC) — no external callers + - [x] `data/UsageService.kt` (118 LOC) — no external callers + - [x] `data/ProfileService.kt` (81 LOC) — no external callers + - [x] `data/SSOService.kt` (164 LOC) — no external callers + - [x] `data/AuditLogger.kt` (71 LOC) — no external callers + - [x] `data/BiometricAuth.kt` (79 LOC) — no external callers + - [x] `data/GuestMode.kt` (75 LOC) — no external callers + - [x] `data/SettingsStore.kt` (22 LOC) — no external callers + - [x] `data/CertificatePinning.kt` (87 LOC) — no external callers +- [x] **4.3 Kept (active callers, product-specific):** + - `data/LicenseService.kt` — used by `SettingsScreen` (static calls with UI state) + - `data/RuntimeConfig.kt` — used by `LysnrAIApp` + `TelemetryClient` + - `telemetry/TelemetryClient.kt` — static singleton used by keyboard extension (no Hilt DI possible). **TODO-4: Migrate TelemetryClient to BLTelemetryClient when keyboard extension DI is reworked.** + - `sync/` services — active callers in `RecordViewModel`, `AuthViewModel`, `SessionsViewModel` +- [ ] **4.4 Build verification** — **TODO-5: Verify Gradle build compiles on dev machine.** + +--- + + + +## Phase 5 — NomGap (RN): Replace Raw Fetch in billing-api + photo-meal + +**Priority:** MEDIUM | **Effort:** 0.5 day | **Repo:** `learning_ai_fastgap` | **Commit:** [`63bd34b`](https://github.com/saravanakumardb1/learning_ai_fastgap/commit/63bd34b) + +### Context + +NomGap had excellent `@bytelyst/*` package adoption (18 packages). `billing-api.ts` had a hand-rolled `billingFetch()`. `photo-meal.ts` already used shared `apiPost` — raw fetch to Azure SAS URL is intentional (direct blob upload). + +### Files to Modify + +- `src/api/billing-api.ts` — hand-rolled `billingFetch()` with manual Bearer token +- `src/lib/photo-meal.ts` — raw `fetch()` to SAS URL for blob upload + +### Tasks + +- [x] **5.1 Refactor `billing-api.ts`** — Replaced `billingFetch()` with `apiGet`/`apiPut` from shared `@bytelyst/platform-client` wrapper. Auth token + `x-product-id` now injected automatically. Net: **-19 lines**. +- [x] **5.2 `photo-meal.ts`** — Already uses shared `apiPost` for SAS token + recognition. Raw `fetch` to SAS URL is intentional (direct Azure Blob upload). No changes needed. +- [ ] **5.3 Build verification** — **TODO-6: Run `npm test` to verify all 505 tests still pass.** + +--- + + + +## Phase 6 — LysnrAI iOS: Migrate SSO, Usage, Sync, CertPinning + +**Priority:** MEDIUM | **Effort:** 1 day | **Repo:** `learning_voice_ai_agent` | **Commit:** [`862e981`](https://github.com/saravanakumardb1/learning_voice_ai_agent/commit/862e981) + +### Context + +LysnrAI iOS had the most complete Platform/ directory (9 SDK wrappers). Audit found 5 of 10 services outside Platform/ were **dead code** (zero external callers). + +### Hand-Rolled Services + +| File | Current | Target | +| ------------------------------- | ------------------------------------------- | ------------------------------------------- | +| `Auth/SSOService.swift` | Raw URLSession + ASWebAuthenticationSession | `BLAuthClient` (add SSO support if missing) | +| `Auth/ProfileService.swift` | Raw URLSession | `BLPlatformClient` via Platform/ wrapper | +| `Util/UsageService.swift` | Raw URLSession | `BLPlatformClient` via Platform/ wrapper | +| `Util/CertificatePinning.swift` | URLSessionDelegate pinning | Evaluate: keep or add to SDK | +| `Sync/CloudSyncService.swift` | Raw URLSession | `BLSyncEngine` | +| `Sync/OfflineQueue.swift` | Custom queue | `BLSyncEngine` | +| `Sync/SessionSyncService.swift` | Raw URLSession | `BLSyncEngine` | +| `Theme/ThemeService.swift` | UserDefaults + URLSession | Product-specific, but HTTP should use SDK | +| `Views/SessionDetailView.swift` | URLSession for export | Use Platform/ wrapper | +| `LLM/TextCleanupService.swift` | URLSession | Product-specific LLM call — keep | + +### Tasks + +- [x] **6.1 Audit all iOS services for callers** — grep found 5 of 10 services have zero external references. +- [x] **6.2 Delete dead code (5 files, -672 LOC)**: + - [x] `Auth/SSOService.swift` (184 LOC) — no external callers + - [x] `Auth/ProfileService.swift` (78 LOC) — no external callers + - [x] `Util/UsageService.swift` (96 LOC) — no external callers + - [x] `Util/CertificatePinning.swift` (117 LOC) — no external callers + - [x] `Sync/OfflineQueue.swift` (197 LOC) — no external callers +- [x] **6.3 Kept (active callers, product-specific):** + - `Sync/CloudSyncService.swift` — used by `AuthService`, `RecordView` + - `Sync/SessionSyncService.swift` — used by `SessionStore`, `SessionsListView` + - `Theme/ThemeService.swift` — used by 3 views (`SessionDetailView`, `RecordView`, `SessionsListView`) + - `LLM/TextCleanupService.swift` — product-specific LLM call +- [ ] **6.4 Build verification** — **TODO-7: Verify Xcode build compiles. Note: deleted files must be removed from .xcodeproj.** + +--- + + + +## Phase 7 — Auth App Android: Wire BLAuthClient + +**Priority:** MEDIUM | **Effort:** 0.5 day | **Repo:** `learning_ai_auth_app` | **Commit:** [`5b65215`](https://github.com/saravanakumardb1/learning_ai_auth_app/commit/5b65215) + +### Context + +Auth App Android already had `BLAuthClient` fully wired — `AppConfig.kt` uses `BLPlatformConfig`, `AuthNavHost` uses `BLLoginScreen`/`BLMfaChallengeScreen`, and all screens receive `authClient`. Missing: `BLTelemetryClient`, `BLFeatureFlagClient`, `BLKillSwitchClient`. + +### Files to Modify + +- `android/app/src/main/kotlin/com/bytelyst/auth/platform/AppConfig.kt` — UPDATE to use `BLPlatformConfig` + +> **Note:** `settings.gradle.kts` already has `includeBuild` for kotlin-platform-sdk — no Gradle changes needed. + +### Files to Create + +- `android/app/src/main/kotlin/com/bytelyst/auth/platform/PlatformModule.kt` — NEW + +### Tasks + +- [x] **7.1 Build wiring verified** — `settings.gradle.kts` has `includeBuild`, `build.gradle.kts` has `implementation("com.bytelyst:platform-sdk")`. Already correct. +- [x] **7.2 AppConfig.kt** — Already uses `BLPlatformConfig`. No changes needed. +- [x] **7.3 BLAuthClient already fully wired** — `MainActivity.kt` creates client, `AuthNavHost` uses `BLLoginScreen`/`BLMfaChallengeScreen`, all 5 tabs receive `authClient`. +- [x] **7.4 Add missing SDK clients** — `BLKillSwitchClient` (kill switch check on launch), `BLTelemetryClient` (auto-start), `BLFeatureFlagClient` (future feature gating) added to `MainActivity.kt`. +- [ ] **7.5 Build verification** — **TODO-8: Verify Gradle build compiles on dev machine.** + +--- + + + +## Phase 8 — Auth App iOS: Add Telemetry, Flags, Kill Switch + +**Priority:** LOW | **Effort:** 0.5 day | **Repo:** `learning_ai_auth_app` | **Commit:** [`4a84050`](https://github.com/saravanakumardb1/learning_ai_auth_app/commit/4a84050) + +### Context + +Auth App iOS already used `BLAuthClient` and `BLAuthUI` from ByteLystPlatformSDK. Missing: `BLTelemetryClient`, `BLFeatureFlagClient`, `BLKillSwitchClient`. + +### Files to Create + +- `ios/ByteLystAuth/Platform/Config.swift` — NEW +- `ios/ByteLystAuth/Platform/TelemetryService.swift` — NEW +- `ios/ByteLystAuth/Platform/FeatureFlagService.swift` — NEW +- `ios/ByteLystAuth/Platform/KillSwitchService.swift` — NEW + +### Tasks + +- [x] **8.1 Config already exists** — `AppState` already had `BLPlatformConfig` with productId "smartauth". No separate Config.swift needed. +- [x] **8.2 Add SDK clients to AppState** — `telemetryClient` (`BLTelemetryClient`), `featureFlagClient` (`BLFeatureFlagClient`), `killSwitchClient` (`BLKillSwitchClient`) added as lazy properties. +- [x] **8.3 Wire kill switch** — `ContentView.swift` checks kill switch on launch, shows blocking message if killed. +- [x] **8.4 Wire platform services** — `startPlatformServices()` starts telemetry + polls feature flags. Called in ContentView `.task`. +- [x] **8.5 Consolidate lifecycle** — `restoreSession()` moved into unified `.task` block alongside kill switch + platform init. +- [ ] **8.6 Build verification** — **TODO-9: Verify Xcode build compiles.** + +--- + + + +## Phase 9 — Minor Gaps: ChronoMind iOS, NoteLett Mobile, MindLyst iOS, JarvisJr iOS + +**Priority:** LOW | **Effort:** 2–3 hours total | **Repos:** `learning_ai_clock`, `learning_ai_notes`, `learning_multimodal_memory_agents`, `learning_ai_jarvis_jr` + +**Commits:** + +- 9A: [`c328216`](https://github.com/saravanakumardb1/learning_ai_clock/commit/c328216) (ChronoMind iOS) +- 9B: [`c2d6414`](https://github.com/saravanakumardb1/learning_ai_notes/commit/c2d6414) (NoteLett Mobile) +- 9C: [`dce9e22`](https://github.com/saravanakumardb1/learning_multimodal_memory_agents/commit/dce9e22) (MindLyst iOS) +- 9D: No changes needed (PlatformSyncManager actively used by MemoryManager) + +### 9A — ChronoMind iOS: Add Config.swift + KillSwitch + +ChronoMind iOS wrappers are in `Shared/Cloud/` (acceptable for multi-target). Missing `Config.swift` and `KillSwitchService`. + +- [x] **9A.1 Create `Shared/Cloud/Config.swift`** — shared `BLPlatformConfig` for ChronoMind. +- [x] **9A.2 Create `Shared/Cloud/KillSwitchService.swift`** — thin wrapper over `BLKillSwitchClient`. +- [ ] **9A.3 Wire kill switch check in `ChronoMindApp.swift`** — deferred (wrapper exists, wiring is a UI task). +- [ ] **9A.4 Build verification** — **TODO-10: Verify Xcode build compiles.** + +### 9B — NoteLett Mobile: Add diagnostics-client + +NoteLett mobile is the gold standard but is missing `@bytelyst/diagnostics-client`. + +- [x] **9B.1 Add `@bytelyst/diagnostics-client`** to `mobile/package.json`. +- [x] **9B.2 Wire `diagnosticsClient`** in `mobile/src/lib/platform.ts` alongside existing clients. +- [ ] **9B.3 Build verification** — **TODO-11: Run `cd mobile && npm run typecheck` to verify.** + +### 9C — MindLyst iOS: Migrate PlatformServiceClient + Add Missing Wrappers + +MindLyst iOS (`mindlyst-native/iosApp/`) has 4 Platform/ SDK wrappers but `Services/PlatformServiceClient.swift` is a hand-rolled URLSession client. Also missing `Config.swift`, `KillSwitchService`, and `CrashReporter`. + +- [x] **9C.1 Create `Platform/Config.swift`** — shared `BLPlatformConfig` for MindLyst. +- [x] **9C.2 `PlatformServiceClient.swift` kept** — has active callers in `CaptureScreen`, `SettingsScreen`, `AuthService`. Product-specific (audio upload, memory items). Migration deferred. +- [x] **9C.3 Create `Platform/KillSwitchService.swift`** — thin wrapper over `BLKillSwitchClient`. +- [x] **9C.4 Create `Platform/CrashReporter.swift`** — thin wrapper over `BLCrashReporter`. +- [ ] **9C.5 Build verification** — **TODO-12: Verify Xcode build compiles.** + +### 9D — JarvisJr iOS: Migrate PlatformSyncManager + +JarvisJr iOS Platform/ is clean (7 wrappers) but `Shared/Cloud/PlatformSyncManager.swift` uses raw URLSession. + +- [x] **9D.1 `PlatformSyncManager.swift` kept** — has active caller in `MemoryManager.swift`. Product-specific sync logic. No changes needed. +- [ ] **9D.2 Build verification** — **TODO-13: Verify Xcode build compiles.** + +--- + + + +## Verification Matrix + +After all phases, every mobile surface should pass this checklist: + +### iOS Apps (ByteLystPlatformSDK) + +| Check | LysnrAI | ChronoMind | JarvisJr | PeakPulse | MindLyst | Auth App | +| -------------------------------------------- | ---------- | ---------- | ---------- | ---------- | ---------- | ----------- | +| `BLPlatformConfig` wrapper | □ (exists) | □ | □ (exists) | □ (exists) | □ | □ | +| `BLKeychain` wrapper | □ (exists) | □ (exists) | □ (exists) | □ (exists) | □ (exists) | □ (via SDK) | +| `BLAuthClient` wrapper | □ (exists) | □ (exists) | □ (exists) | □ (exists) | □ (exists) | □ (via SDK) | +| `BLTelemetryClient` wrapper | □ (exists) | □ (exists) | □ (exists) | □ (exists) | □ (exists) | □ | +| `BLFeatureFlagClient` wrapper | □ (exists) | □ (exists) | □ (exists) | □ (exists) | □ (exists) | □ | +| `BLKillSwitchClient` wrapper | □ (exists) | □ | □ (exists) | □ (exists) | □ | □ | +| `BLCrashReporter` wrapper | □ | □ (exists) | □ (exists) | □ (exists) | □ | □ | +| No hand-rolled URLSession for platform calls | □ | □ (exists) | □ | □ (exists) | □ | □ (exists) | +| `xcodebuild build` passes | □ | □ | □ | □ | □ | □ | + +### Android Apps (kotlin-platform-sdk) + +| Check | LysnrAI | ChronoMind | MindLyst | JarvisJr | Auth App | +| --------------------------------------------------- | ------------------------- | ---------- | ---------------- | -------- | -------------------------- | +| `platform/Config.kt` | □ (exists) | □ (exists) | □ (exists) | □ | □ (exists as AppConfig.kt) | +| `platform/PlatformModule.kt` (Hilt/Koin) | □ (exists) | □ (exists) | □ (exists, Koin) | □ | □ | +| `BLAuthClient` wired | □ (intentionally skipped) | □ | □ (exists) | □ | □ | +| `BLTelemetryClient` wired | □ (exists) | □ | □ (exists) | □ | N/A | +| `BLFeatureFlagClient` wired | □ (exists) | □ | □ (exists) | □ | N/A | +| `BLKillSwitchClient` wired | □ (exists) | □ (exists) | □ (exists) | □ | N/A | +| No hand-rolled HttpURLConnection for platform calls | □ | □ | □ (exists) | □ | □ | +| `./gradlew compileDebugKotlin` passes | □ | □ | □ | □ | □ | + +### React Native / Expo Apps (@bytelyst/\*) + +| Check | NomGap | NoteLett | FlowMonk | +| ------------------------------------------- | ---------- | ---------- | ---------- | +| `@bytelyst/auth-client` | □ (exists) | □ (exists) | □ (exists) | +| `@bytelyst/platform-client` | □ (exists) | □ (exists) | □ (exists) | +| `@bytelyst/telemetry-client` | □ (exists) | □ (exists) | □ | +| `@bytelyst/feature-flag-client` | □ (exists) | □ (exists) | □ (exists) | +| `@bytelyst/kill-switch-client` | □ (exists) | □ (exists) | □ (exists) | +| `@bytelyst/offline-queue` | □ (exists) | □ (exists) | □ (exists) | +| `@bytelyst/blob-client` | □ (exists) | □ (exists) | □ | +| `@bytelyst/design-tokens` | □ (exists) | □ (exists) | □ | +| No hand-rolled `fetch()` for platform calls | □ | □ (exists) | □ | +| `npm run typecheck` passes | □ | □ | □ | + +--- + +## Execution Order Recommendation + +``` +Week 1 (HIGH priority): + Phase 1: ChronoMind Android (1 day) + Phase 2: JarvisJr Android (1 day) + +Week 2 (MEDIUM priority): + Phase 3: FlowMonk Mobile RN (0.5 day) + Phase 5: NomGap RN (0.5 day) + Phase 4: LysnrAI Android (1 day) + +Week 3 (MEDIUM priority): + Phase 6: LysnrAI iOS (1 day) + Phase 7: Auth App Android (0.5 day) + +Week 4 (LOW priority + cleanup): + Phase 8: Auth App iOS (0.5 day) + Phase 9A: ChronoMind iOS — Config + KillSwitch (0.5 hour) + Phase 9B: NoteLett Mobile — diagnostics-client (0.5 hour) + Phase 9C: MindLyst iOS — PlatformServiceClient + Config + KillSwitch + CrashReporter (1 hour) + Phase 9D: JarvisJr iOS — PlatformSyncManager (0.5 hour) + Final verification matrix sign-off +``` + +--- + +## Notes + +- **MindLyst iOS** (`mindlyst-native/iosApp/`) has **26 Swift files** including 4 Platform/ SDK wrappers (`AuthService`, `KeychainHelper`, `TelemetryService`, `FeatureFlagService`), Screens, Models, Services, Navigation, Widgets, and ShareExtension. **Minor gap:** `Services/PlatformServiceClient.swift` is a hand-rolled URLSession client for platform-service dev wiring — should be migrated to use `BLPlatformClient` via a Platform/ wrapper. Also missing: `KillSwitchService`, `CrashReporter`, `Config.swift`. +- **MindLyst Android** (`mindlyst-native/androidApp/`) uses Koin DI (not Hilt). `platform/Config.kt` and `platform/PlatformModule.kt` exist. Provides **all 6 SDK components** (`BLPlatformConfig`, `BLSecureStore`, `BLAuthClient`, `BLTelemetryClient`, `BLFeatureFlagClient`, `BLKillSwitchClient`) via Koin module. No gaps. +- **PeakPulse iOS** is the cleanest iOS app — full Platform/ directory with 9 wrappers including `DiagnosticsService`. No gaps. +- **JarvisJr iOS** has a clean Platform/ directory with 7 wrappers. **Minor gap:** `Shared/Cloud/PlatformSyncManager.swift` uses raw URLSession — should be migrated to `BLSyncEngine` or `BLPlatformClient`. +- **TextCleanupService** (LysnrAI) and other LLM-specific services that use URLSession for OpenAI/Azure calls are intentionally product-specific and should NOT be migrated to platform SDK. +- **CertificatePinning** is a security feature that may need to stay product-specific. Evaluate during Phase 4/6 whether it's worth adding to the SDK. +- **LysnrAI Android `AuthViewModel`** is intentionally kept hand-rolled (DataStore, keyboard bridging, CloudSync integration are too LysnrAI-specific for `BLAuthClient`). This is a conscious design decision, not a gap.