# NexStream Audit Fixes — 2026-05-19

Build was at 6 compile errors when this session started. All fixed, then audit findings addressed.

## Build Fixes (0 errors confirmed)

| # | File | Error | Fix |
|---|------|-------|-----|
| 1-3 | `DebridTokenStorage.kt` lines 31,38,45 | Suspend fun called from non-suspend context | Changed `store()`→`storeBlocking()`, `retrieve()`→`retrieveBlocking()`, `delete()`→`deleteBlocking()` |
| 4 | `OnboardingViewModel.kt` line 8 | Unresolved reference `displayName` import | Removed `import com.nexstream.app.data.debrid.displayName` |
| 5-6 | `OnboardingViewModel.kt` lines 145,167 | `provider.displayName()` not callable (it's a property) | Changed to `provider.displayName` (no parens) |

Also added `deleteBlocking()` method to `SecureTokenStore` to match existing `storeBlocking()`/`retrieveBlocking()` pattern.

## Critical Fixes Applied

### C3: Navigation Crashes (3 missing NavHost destinations)
- **Screen.SeeAll** — Navigated from HomeScreen but had no composable() entry → crash
- **Screen.AllSources** — Navigated from DetailsScreen but had no composable() entry → crash
- **Screen.Profiles** — Navigated from SettingsScreen but had no composable() entry → crash

**Fix:** Created `SeeAllScreen.kt` and `AllSourcesScreen.kt` placeholder composables, added all 3 routes to `NexStreamNavHost.kt`. `Profiles` routes to existing `ProfileSelectScreen`.

### C5: Watch Progress Dropped on Screen Close
`PlayerViewModel.onCleared()` called `saveProgress()` inside `viewModelScope.launch`, but `viewModelScope` is already being cancelled at that point — the coroutine never runs.

**Fix:** Replaced with `CoroutineScope(SupervisorJob() + Dispatchers.IO)` that survives cancellation. Progress save runs first, then `playerManager.release()` in `finally` block.

### C7: Room Migration Safety
No `fallbackToDestructiveMigrationFrom()` was set, meaning a fresh install (version 0→1) would crash without explicit migration steps.

**Fix:** Added `.fallbackToDestructiveMigrationFrom(0)` — destructive only for fresh installs. Added migration template comments for future version bumps.

## Security (C8-C10) — Already Addressed, No Changes Needed

- **C8 (placeholder API keys):** Keys read from env/gradle properties, `isConfigured` validates at runtime. Not a vulnerability.
- **C9 (cleartext+backup):** Manifest already has `usesCleartextTraffic="false"`, `allowBackup="false"`, `fullBackupContent="false"`. `network_security_config.xml` enforces HTTPS-only.
- **C10 (tokens plaintext):** Trakt tokens stored in `SecureTokenStore` (Android Keystore AES-256/GCM). `TraktAuthManager` comment confirms: "Tokens are persisted in SecureTokenStore, not in DataStore". PINs hashed with PBKDF2 + salt.

## In Progress (needs completion next session)

### Hardcoded `profileId = 0` (C variant)
- `PlayerViewModel.saveProgress()` line 447: `profileId = 0` — **NEEDS**: `val profileId = preferencesManager.activeProfileId.first()`
- `PlayerViewModel.onCleared()` line 628: `profileId = 0` — same fix needed
- `SettingsViewModel.syncTraktNow()` line 676: `profileId = 0` — needs PreferencesManager injection
- `OnboardingViewModel.launchImportSync()`: `profileId = 1` — should read active profile

PlayerViewModel already has `PreferencesManager` injected (added this session). SettingsViewModel and OnboardingViewModel still need the injection.

### SettingsVM 65-flow combine
The single `combine()` with 40+ flows runs on Main thread. Should be refactored to district groups or `stateIn` with `SharingStarted.WhileSubscribed + Dispatchers.IO`. Not a crash but a perf concern.

### SeeAllScreen / AllSourcesScreen
Currently placeholder stubs. Need ViewModels wired to `AddonRepository.getCatalogRows()` and stream ranking respectively.