# Magic Dashboard – iOS-Section Redesign ## Ziel Das Magic-Dashboard soll klar zwischen zwei eigenen Bausteinen trennen: 1. **Desktop-Schutz** (Mac/Windows) – das Gerät, auf dem Magic läuft. 2. **iOS-Verwaltung** (eigene iPhone/iPad-Geräte) – registrierte iOS-Geräte des Users mit Status, Sternen und passenden Aktionen. „Andere Geräte“ bleiben als sekundäre Information erhalten, sollen aber nicht den Fokus stehlen. Magic ist kein offenes Verwaltungstool für fremde Geräte. --- ## Annahmen (aus dem Abstimmungsgespräch) - Backend-iOS-Geräte werden immer gelistet. - Wenn ein iPhone/iPad per USB verbunden ist, werden Live-Daten (Supervision, Enrollment, Sideload, App) mit dem passenden Backend-Eintrag synchronisiert. - Ein per USB verbundenes, aber im Backend unbekanntes iOS-Gerät wird als **„Nicht erkennbar“** markiert. Der Hinweis verweist auf: ReBreak-App installieren → anmelden → Gerät registrieren. Erst danach ist es verwaltbar. - Supervise / Enroll / Sideload / App-Install bleiben im bestehenden Wizard (`/detect`, `/supervise`, `/enroll`, `/sideload`). Das Dashboard bietet nur den passenden Einstieg. --- ## Seitenstruktur ``` status.vue ├── Header (Profil, Logout) ├── Section: Aktives Gerät (Desktop-Hero) │ └── DeviceHeroCard für currentBackendDevice (mac/windows) ├── Section: Meine iOS-Geräte │ ├── UnknownIosDeviceCard (falls USB-Device nicht im Backend) │ └── IosDeviceCard[] für jedes Backend-iOS-Gerät │ (Sterne + Status + Action-Button) ├── Section: Weitere Geräte │ └── DeviceListItem[] für sonstige Backend-Geräte └── DeviceDetailSheet (weiterhin für Details/Cooldown) ``` --- ## Neue Komponenten ### `IosDeviceSection.vue` - Props: - `devices: ComputedDevice[]` – alle Backend-iOS-Geräte des Users - `iphone: IphoneDeviceState | null` – aktuell per USB erkanntes Gerät - `loading: boolean` - Zeigt den Section-Header und rendert die Liste von `IosDeviceCard`s. - Wenn `iphone` verbunden, aber kein passendes Backend-Gerät gefunden wird, wird `UnknownIosDeviceCard` angezeigt. - Wenn noch keine Backend-iOS-Geräte geladen wurden: Hinweis „Keine iOS-Geräte geladen“ + Aktualisieren-Button. - Wenn geladen und leer: Hinweis „Keine iOS-Geräte registriert. ReBreak-App installieren und Gerät hinzufügen.“ ### `IosDeviceCard.vue` - Props: - `device: ComputedDevice` - `iphone: IphoneDeviceState | null` – falls dieses Gerät per USB verbunden ist - `isConnected: boolean` - Zeigt: - Name/Modell - Status-Badge (`active`, `pending`, `unprotected` etc.) - Letzte Sichtung - `IosStarRating` + detaillierte Sternen-Liste, wenn `isConnected` - Sonst Hinweis: „Zum Live-Status iPhone per USB verbinden“ - Action-Button (ableitet sich aus dem gemergten Zustand): - Nicht supervised → „Supervisen" → `/supervise` - Supervised, aber Enrollment fehlt → „Enrollen" → `/enroll` - Enrollment vorhanden, aber Sideload-Profil fehlt → „Sideload installieren" → `/sideload` - Sideload vorhanden, aber App fehlt → „App installieren" (MDM-Befehl oder Link) - Alles okay → „Synchronisieren" (prüft Enrollment-, Sideload- und Supervision-Status; bei Abweichungen werden fehlende Profile/MDM-Kommandos gepusht; falls die lokale MDM-Version hinter der aktuellen ReBreak-MDM-Version zurückfällt, wird ein Update gepusht und der User informiert) - Während der 3-Tage-Kündigungs-Grace-Period → „ReBreak entfernen" (löst Offboarding aus: MDM-Profile entfernen, Gerät unsupervised setzen, Eintrag bereinigen) ### `UnknownIosDeviceCard.vue` - Props: - `iphone: IphoneDeviceState` - Zeigt: - Warn-Icon + „Dieses iPhone ist nicht erkennbar" - Modell, iOS-Version, UDID (nur zur Info) - Hinweis: „Mit keinem ReBreak-Konto verbunden. Um es zu verwalten: ReBreak-App installieren, anmelden und Gerät registrieren." - Keine Supervise-/Enroll-Aktionen. --- ## Datenfluss 1. User klickt in `status.vue` auf **Aktualisieren**. 2. `protection.refresh()` wird aufgerufen: - `detectIphoneState()` lädt das per USB verbundene iOS-Gerät. - `getMagicDevices()` lädt alle Backend-Geräte in den shared `useMagicDevices`-State. 3. `useDeviceStatus` liefert weiterhin: - `currentBackendDevice` (Desktop) - `otherDevices` (alles außer current) 4. `IosDeviceSection` erhält die Liste aller `otherDevices`, filtert intern auf `platform === 'ios'` und versucht, das verbundene `iphone` per Modell + Name zuzuordnen. 5. Action-Buttons leiten den User basierend auf dem gemergten Live-Status in den passenden Wizard-Schritt weiter. ### iOS-Matching Da Backend-`deviceId` (Capacitor-UUID) nicht mit USB-UDID übereinstimmt, erfolgt das Matching über: - `device.model` (Backend) ↔ `iphone.productType` (USB) - `device.name` (Backend) ↔ `iphone.name` (USB) als Fallback / Verfeinerung Sind mehrere Geräte mit identischem Modell vorhanden, wird das erste passende (`name` match) als verbunden markiert; bei Unklarheit wird das `iphone` nicht zugeordnet und erscheint als `UnknownIosDeviceCard`. --- ## Bestehende Komponenten – Anpassungen ### `DeviceHeroCard.vue` - Keine iOS-Sterne mehr anzeigen (`showIosStars` bleibt aber für zukünftige Flexibilität). - Aktionen bleiben auf Desktop-Schutz beschränkt. ### `DeviceListItem.vue` - Wird für „Weitere Geräte“ (andere Desktops) weiterverwendet. - iOS-Geräte verschwinden aus dieser Liste und werden in der neuen iOS-Section angezeigt. ### `DeviceDetailSheet.vue` - iOS-Sterne-Anzeige gilt für jedes iOS-Gerät, das gerade per USB verbunden ist (nicht nur `isCurrent`, da iOS-Geräte nie „current" sind). - Cooldown-Steuerung bleibt nur für `isCurrent`-Desktop-Geräte. ### `useDeviceStatus.ts` - Entfernt den Debug-`watchEffect` (bereits erledigt). - Fügt optional `iosDevices` und `desktopDevices` als getrennte Derived Lists hinzu, damit `status.vue` weniger Filter-Logik enthält. --- ## On-Demand-Verhalten bleibt erhalten - Kein automatisches Polling mehr. - Sterne/Status werden nur beim manuellen Refresh aktualisiert. - Das verhindert erneut Log-Spam durch wiederholte `detect_iphone_state`-Aufrufe. --- ## Fehlerbehandlung - Wenn `detectIphoneState` fehlschlägt: Fehler nur in `protection.lastError`; iOS-Section zeigt Backend-Liste weiterhin an. - Wenn `getMagicDevices` fehlschägt: `error`-Banner in `status.vue`. - Wenn Matching mehrdeutig: `UnknownIosDeviceCard` statt falscher Zuordnung. --- ## Kündigungs-Grace-Period & Offboarding - Solange das Gerät enrolled ist **und** das Abo aktiv ist, wird **nichts** deinstalliert. - Nach einer Kündigung bleibt das iOS-Gerät für **3 Tage** in der Liste sichtbar. - Der Button **„ReBreak entfernen"** ist **unsichtbar oder disabled**, solange die Grace-Period noch nicht begonnen hat. - Sobald die Grace-Period läuft, erscheint der Button ohne zusätzliche Sicherheitsabfrage. - Ein Klick darauf startet das Offboarding: 1. MDM-Enrollment-Profil und Sideload-Profil vom Gerät entfernen. 2. Gerät aus dem Supervised-Modus zurücksetzen. 3. Backend-Eintrag für das iOS-Gerät bereinigen. - **Backend-Abhängigkeit:** Es braucht ein Feld/Endpoint, der die Kündigung + verbleibende Grace-Period erkennbar macht (z. B. `subscriptionCancelledAt` im Profil oder dedizierter `/api/magic/subscription-status`). Das Offboarding selbst braucht einen neuen API-Endpoint oder Tauri-Command, der MDM-Remove + Unsupervise orchestriert. --- ## Offene Punkte / Nächste Schritte 1. Existiert bereits ein Backend-Feld/Endpoint für Kündigung + Grace-Period, oder muss der gebaut werden? 2. Wie wird die „aktuelle ReBreak-MDM-Version" bestimmt – ist sie im Profil hinterlegt, im Backend konfiguriert oder über eine Tauri-Funktion verfügbar? 3. Soll die App-Installation via MDM direkt aus dem Dashboard auslösbar sein, oder reicht ein Verweis auf `/sideload`?