# iOS Platform SDK — Best Practices & Reference

> **Package:** `ByteLystPlatformSDK` (Swift Package)
> **Location:** `learning_ai_common_plat/packages/swift-platform-sdk/`
> **Status:** ✅ Production-ready — 13 components, 5 apps migrated

---

## 1. Executive Summary

The **ByteLystPlatformSDK** is a shared Swift Package that provides 13 platform-agnostic components consumed by all iOS/watchOS/macOS apps in the ByteLyst ecosystem. Each product app creates thin wrapper files (5–15 LOC each) in a `Platform/` directory that inject product-specific config (productId, bundleId, baseURL) into the SDK.

**Goal:** Only app-specific business logic lives in the app repo. All platform infrastructure (auth, telemetry, keychain, feature flags, kill switch, blob storage, crash reporting, sync, licensing, biometrics, audit logging) comes from the shared SDK.

---

## 2. SDK Components (13)

| #   | Component             | Description                                                               | LOC  |
| --- | --------------------- | ------------------------------------------------------------------------- | ---- |
| 1   | `BLPlatformConfig`    | Product-specific config struct (productId, baseURL, bundleId, appGroupId) | 65   |
| 2   | `BLPlatformClient`    | Generic HTTP client with auth injection, x-request-id, fire-and-forget    | ~150 |
| 3   | `BLKeychain`          | Keychain CRUD (configurable service string)                               | ~80  |
| 4   | `BLTelemetryClient`   | Telemetry event queue + batch flush to platform-service                   | ~200 |
| 5   | `BLAuthClient`        | Full auth: login, register, refresh, password ops, email verification     | ~250 |
| 6   | `BLFeatureFlagClient` | Feature flag polling from `/flags/poll` with caching                      | ~120 |
| 7   | `BLSyncEngine`        | Generic offline-first sync with `BLSyncAdapter` protocol                  | ~180 |
| 8   | `BLBlobClient`        | Azure Blob Storage upload via SAS tokens                                  | ~130 |
| 9   | `BLKillSwitchClient`  | Kill switch check (fail-open, includes X-Request-Id)                      | ~60  |
| 10  | `BLLicenseClient`     | License key activation + status (URL-encodes key)                         | ~100 |
| 11  | `BLBiometricAuth`     | Face ID / Touch ID (`#if canImport(LocalAuthentication)` for watchOS)     | ~80  |
| 12  | `BLCrashReporter`     | MetricKit crash + performance reporting (`#if canImport(MetricKit)`)      | ~120 |
| 13  | `BLAuditLogger`       | Local rotating JSON audit log (iso8601 encode/decode matched)             | ~150 |

**Total SDK:** ~1,870 LOC across 13 source files + 1 test file.

---

## 3. App Adoption Matrix

| Component             | LysnrAI                                            | ChronoMind              | PeakPulse              | JarvisJr               | MindLyst                   |
| --------------------- | -------------------------------------------------- | ----------------------- | ---------------------- | ---------------------- | -------------------------- |
| `BLPlatformConfig`    | ⚠️ Config.swift (env loader, not BLPlatformConfig) | ✅ (inline in wrappers) | ✅ Config.swift        | ✅ Config.swift        | ✅ (inline in AuthService) |
| `BLPlatformClient`    | ⚠️ Not used (raw URLSession)                       | ✅ (internal)           | ✅ (internal)          | ✅ (internal)          | ✅ (internal)              |
| `BLKeychain`          | ✅ KeychainHelper                                  | ✅ KeychainHelper       | ✅ KeychainHelper      | ✅ KeychainHelper      | ✅ KeychainHelper          |
| `BLTelemetryClient`   | ✅ TelemetryService                                | ✅ TelemetryService     | ✅ TelemetryService    | ✅ TelemetryService    | ✅ TelemetryService        |
| `BLAuthClient`        | ✅ AuthService                                     | ✅ AuthService          | ✅ AuthService         | ✅ AuthService         | ✅ AuthService             |
| `BLFeatureFlagClient` | ✅ FeatureFlagService                              | ✅ FeatureFlagService   | ✅ FeatureFlagService  | ✅ FeatureFlagService  | ✅ FeatureFlagService      |
| `BLSyncEngine`        | ✅ CloudSyncService                                | ✅ PlatformSyncManager  | ✅ PlatformSyncManager | ✅ PlatformSyncManager | ⚠️ Not yet                 |
| `BLBlobClient`        | ✅ BlobService                                     | ❌ Not needed           | ❌ Phase 2             | ❌ Phase 2             | ❌ Phase 2                 |
| `BLKillSwitchClient`  | ✅ KillSwitchService                               | ❌ Not yet              | ✅ KillSwitchService   | ✅ KillSwitchService   | ❌ Not yet                 |
| `BLLicenseClient`     | ✅ LicenseService                                  | ❌ N/A                  | ❌ N/A                 | ❌ N/A                 | ❌ N/A                     |
| `BLBiometricAuth`     | ✅ BiometricAuth                                   | ❌ Not yet              | ❌ Phase 3             | ❌ Phase 3             | ❌ Phase 3                 |
| `BLCrashReporter`     | ❌ Not yet                                         | ✅ CrashReporter        | ✅ CrashReporter       | ✅ CrashReporter       | ❌ Not yet                 |
| `BLAuditLogger`       | ✅ AuditLogger                                     | ❌ Not yet              | ❌ Phase 2             | ❌ Phase 2             | ❌ Not yet                 |

**Legend:** ✅ = migrated to SDK wrapper (path shown) | ⚠️ = hand-rolled (needs migration) | ❌ = not used / future phase

> **Note on directory conventions:** PeakPulse, JarvisJr, LysnrAI, and MindLyst all use the recommended `Platform/` directory.
> ChronoMind uses `Shared/Cloud/` + `Shared/Diagnostics/` (valid for multi-target apps sharing across iOS/watchOS/macOS).

---

## 4. Integration Pattern

### 4.1 Xcode Project Setup

Add the SDK as a local Swift Package dependency:

```
File → Add Package Dependencies → Add Local...
→ Select: ../learning_ai_common_plat/packages/swift-platform-sdk/
```

Or in `Package.swift` / `project.yml`:

```yaml
packages:
  ByteLystPlatformSDK:
    path: ../../learning_ai_common_plat/packages/swift-platform-sdk
```

### 4.2 App Config (Platform/Config.swift)

Every app MUST have a `Config.swift` that creates the `BLPlatformConfig`:

```swift
import ByteLystPlatformSDK

enum AppConfig {
    static let platform = BLPlatformConfig(
        productId: "peakpulse",                        // ← product-specific
        baseURL: "http://localhost:4003/api",           // ← from Info.plist in prod
        platform: "ios",
        channel: "native",
        bundleId: "com.saravana.peakpulse",            // ← product-specific
        appGroupId: "group.com.saravana.peakpulse"     // ← optional
    )
}
```

### 4.3 Thin Wrapper Pattern

Each wrapper file is 5–15 LOC and delegates to the SDK:

```swift
// Platform/KeychainHelper.swift
import ByteLystPlatformSDK

enum KeychainHelper {
    private static let service = AppConfig.platform.bundleId

    @discardableResult
    static func save(key: String, value: String) -> Bool {
        BLKeychain.save(service: service, key: key, value: value)
    }

    static func read(key: String) -> String? {
        BLKeychain.read(service: service, key: key)
    }

    @discardableResult
    static func delete(key: String) -> Bool {
        BLKeychain.delete(service: service, key: key)
    }
}
```

### 4.4 Directory Structure

```
ios/
├── <AppName>/
│   ├── App/                    # Entry point
│   ├── Platform/               # ← SDK wrappers (5–15 LOC each)
│   │   ├── Config.swift        # BLPlatformConfig
│   │   ├── KeychainHelper.swift
│   │   ├── TelemetryService.swift
│   │   ├── AuthService.swift
│   │   ├── FeatureFlagService.swift
│   │   ├── KillSwitchService.swift
│   │   ├── CrashReporter.swift
│   │   └── PlatformSyncManager.swift
│   ├── Shared/                 # App-specific business logic
│   ├── Views/                  # SwiftUI screens
│   ├── ViewModels/             # @Observable MVVM
│   ├── Models/                 # Data models
│   ├── Services/               # App-specific services
│   └── Theme/                  # Design tokens
```

---

## 5. Rules & Conventions

### MUST follow

1. **Every app must have `Platform/Config.swift`** with a `BLPlatformConfig` instance
2. **Platform/ wrappers must be thin** — no business logic, just inject config + delegate
3. **Never copy SDK code into the app** — always `import ByteLystPlatformSDK`
4. **Never hardcode productId** — read from `AppConfig.platform.productId`
5. **Never hardcode baseURL** — use `BLPlatformConfig.fromInfoPlist()` or `AppConfig.platform.baseURL`
6. **Keychain keys must be bare** (e.g., `access_token`, NOT `productId_access_token`) — the bundleId service string provides namespace isolation
7. **All logging via `os.Logger`** — never `print()`
8. **All colors from theme** — never hardcode hex values

### MUST NOT do

1. Never implement auth flows directly — use `BLAuthClient` via wrapper
2. Never create raw `URLSession` requests to platform-service — use `BLPlatformClient`
3. Never roll your own telemetry queue — use `BLTelemetryClient`
4. Never implement feature flag polling — use `BLFeatureFlagClient`
5. Never access Keychain directly — use `BLKeychain` via wrapper

---

## 6. Gap Analysis & Remediation

### 6.1 MindLyst iOS — ✅ Directory Rename Complete

4 SDK wrapper files moved from `iosApp/Services/` → `iosApp/Platform/`. Xcode project references updated.

| File                          | New Location                               | Status   |
| ----------------------------- | ------------------------------------------ | -------- |
| `KeychainHelper.swift`        | `iosApp/Platform/KeychainHelper.swift`     | ✅ Moved |
| `TelemetryService.swift`      | `iosApp/Platform/TelemetryService.swift`   | ✅ Moved |
| `AuthService.swift`           | `iosApp/Platform/AuthService.swift`        | ✅ Moved |
| `FeatureFlagService.swift`    | `iosApp/Platform/FeatureFlagService.swift` | ✅ Moved |
| `PlatformServiceClient.swift` | `iosApp/Services/` (kept — app-specific)   | N/A      |

**Remaining MindLyst gaps (future phases):**

- `BLPlatformConfig` — currently created inline in `AuthService.init()`, should extract to `Platform/Config.swift`
- `BLKillSwitchClient`, `BLCrashReporter`, `BLSyncEngine` — not yet adopted

### 6.2 LysnrAI iOS — ✅ Config.swift + Directory Rename Complete

9 SDK wrapper files moved from `Auth/` and `Util/` → `Platform/`. New `Platform/Config.swift` created
with `BLPlatformConfig` (reading baseURL from existing `Config.platformServiceURL`). Xcode project references updated.

| File                       | New Location                                | Status                        |
| -------------------------- | ------------------------------------------- | ----------------------------- |
| `Platform/Config.swift`    | `LysnrAI/Platform/Config.swift`             | ✅ **New** (BLPlatformConfig) |
| `AuthService.swift`        | `LysnrAI/Platform/AuthService.swift`        | ✅ Moved from Auth/           |
| `KeychainHelper.swift`     | `LysnrAI/Platform/KeychainHelper.swift`     | ✅ Moved from Auth/           |
| `BiometricAuth.swift`      | `LysnrAI/Platform/BiometricAuth.swift`      | ✅ Moved from Auth/           |
| `TelemetryService.swift`   | `LysnrAI/Platform/TelemetryService.swift`   | ✅ Moved from Util/           |
| `FeatureFlagService.swift` | `LysnrAI/Platform/FeatureFlagService.swift` | ✅ Moved from Util/           |
| `KillSwitchService.swift`  | `LysnrAI/Platform/KillSwitchService.swift`  | ✅ Moved from Util/           |
| `LicenseService.swift`     | `LysnrAI/Platform/LicenseService.swift`     | ✅ Moved from Util/           |
| `BlobService.swift`        | `LysnrAI/Platform/BlobService.swift`        | ✅ Moved from Util/           |
| `AuditLogger.swift`        | `LysnrAI/Platform/AuditLogger.swift`        | ✅ Moved from Util/           |

Original `Config.swift` (env loader for Azure Speech/OpenAI) kept at `LysnrAI/Config.swift`.

### 6.3 ChronoMind iOS — Directory Convention (Optional)

ChronoMind wrappers are in `Shared/Cloud/` and `Shared/Diagnostics/` — all correctly use the SDK.
This structure works because `Shared/` is consumed by watchOS and macOS targets. Moving to `Platform/`
is optional; the cross-platform `Shared/` directory is valid for multi-target apps.

### 6.4 Missing SDK Features

| Feature                | Description                                                   | Priority |
| ---------------------- | ------------------------------------------------------------- | -------- |
| `BLNotificationClient` | UNUserNotificationCenter wrapper with permission + scheduling | P2       |
| `BLAppUpdateChecker`   | App Store version check + in-app update prompt                | P3       |
| `BLOnboardingTracker`  | Track onboarding progress, first-launch flag                  | P3       |
| `BLReviewPrompt`       | SKStoreReviewController with smart timing                     | P3       |

---

## 7. Testing

The SDK has a test target (`ByteLystPlatformSDKTests`) at `Tests/BLKeychainTests.swift`.

**Recommended additions:**

- Unit tests for each component using mock URLSession
- Integration tests against a local platform-service instance
- Snapshot tests for telemetry event schema compliance

Run tests:

```bash
swift test --package-path packages/swift-platform-sdk/
```

---

## 8. Versioning & Distribution

**Current:** Local Swift Package referenced via relative path (`../learning_ai_common_plat/packages/swift-platform-sdk/`).

**Future options (when open-sourcing or distributing):**

1. **Git tag versioning** — tag releases in common-plat, reference by version
2. **Binary XCFramework** — pre-build for CI speed
3. **Swift Package Registry** — when Apple's registry matures

**For now:** Local path reference is correct. All apps in the workspace reference the same source.

---

## 9. Quick Reference

### Add SDK to a new app

1. Add Swift Package dependency pointing to `../learning_ai_common_plat/packages/swift-platform-sdk/`
2. Create `Platform/Config.swift` with `BLPlatformConfig`
3. Create thin wrappers for each SDK component needed (start with KeychainHelper, TelemetryService, AuthService)
4. Import `ByteLystPlatformSDK` in each wrapper

### SDK source location

```
learning_ai_common_plat/packages/swift-platform-sdk/
├── Package.swift
├── Sources/
│   ├── BLPlatformConfig.swift
│   ├── BLPlatformClient.swift
│   ├── BLKeychain.swift
│   ├── BLTelemetryClient.swift
│   ├── BLAuthClient.swift
│   ├── BLFeatureFlagClient.swift
│   ├── BLSyncEngine.swift
│   ├── BLBlobClient.swift
│   ├── BLKillSwitchClient.swift
│   ├── BLLicenseClient.swift
│   ├── BLBiometricAuth.swift
│   ├── BLCrashReporter.swift
│   ├── BLAuditLogger.swift
│   └── ByteLystPlatformSDK.swift  ← module-level docs only
└── Tests/
    └── BLKeychainTests.swift
```
