---
name: Profile Manager Pattern (NuvioTV/Lumera)
description: "Central profile manager with active profile tracking, per-profile DataStore isolation, PIN hashing, and profile data cleanup."
version: 1.0.0
---

# Profile Manager Pattern — NuvioTV/Lumera

## Problem
NexStream had a basic profile system (Room DAO + PIN hashing) but was missing:
1. Central `ProfileManager` with `activeProfileId` StateFlow
2. Per-profile DataStore isolation for settings
3. Profile data cleanup on delete (DataStore files, plugin code dirs)
4. Max 5 profiles constraint (NuvioTV convention)

## Solution
Created `ProfileManager` at `app/src/main/java/com/nexstream/app/core/profile/ProfileManager.kt`

### Key Features
1. **Active profile tracking:** `StateFlow<Int>` persisted in SharedPreferences
2. **CRUD via Room DAO:** `createProfile()`, `deleteProfile()`, `updateProfile()`
3. **Per-profile DataStore:** `getProfileDataStore(profileId, featureName)` returns isolated DataStore
4. **Profile cleanup on delete:** removes DataStore files, plugin code directories
5. **Max 5 profiles:** same constraint as NuvioTV
6. **Auto-switch to primary:** if active profile is deleted, switches to profile 1

### Reference Implementations
- **NuvioTV:** `ProfileManager` + `ProfileDataStore` + `ProfileDataStoreFactory`
- **Lumera:** `ProfileConfigurationManager` + `ProfileEntity` (Room) + `ProfileViewModel`

### Key Methods
- `setActiveProfile(id: Int)` — persist active profile
- `createProfile(name, avatar, isKids)` — create with auto-ID assignment
- `deleteProfile(id)` — cleanup + DAO delete + auto-switch
- `getProfileDataStore(profileId, featureName)` — per-profile isolated DataStore
- `profiles: StateFlow<List<Profile>>` — live profile list
- `activeProfileId: StateFlow<Int>` — current active profile
- `canCreateProfile: Boolean` — max 5 check

### Pitfalls
- **Never delete profile 1** (primary) — always protected
- **DataStore file naming:** primary uses `featureName`, others use `featureName_p{profileId}`
- **Plugin code dirs:** delete `plugin_code_p{profileId}` recursively on profile delete
- **Use `scope.launch` not `viewModelScope.launch`** in ProfileManager (it's not a ViewModel)

## Files Created
- `core/profile/ProfileManager.kt` — central profile manager
