rebreak-monorepo/docs/superpowers/specs/2026-06-16-magic-dashboard-ios-section-design.md

168 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`?