168 lines
7.8 KiB
Markdown
168 lines
7.8 KiB
Markdown
# 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`?
|