mana-swift-ui/CHANGELOG.md
Till JS d621cb8372 feat(brand): logoAssetName für Custom-Logos (v0.7.0)
ManaBrandConfig.logoAssetName ergänzt — Apps liefern einen Asset-
Catalog-Namen, ManaAuthScaffold rendert das Bundle-Asset 64×64pt
ohne Tint statt eines getinteten SF-Symbols. logoSymbol bleibt
Fallback.

Hintergrund: Pageta hat ein eigenes Apple-Icon-Composer-SVG; SF-
Symbol "book.pages" sah neben dem polierten App-Icon unecht aus.

Additive Änderung, alle bestehenden Apps quellkompatibel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 12:29:19 +02:00

254 lines
9.6 KiB
Markdown
Raw Permalink 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.

# Changelog
Alle Änderungen werden hier dokumentiert. Format orientiert an
[Keep a Changelog](https://keepachangelog.com), Versionierung nach
[Semver](https://semver.org).
## [Unreleased]
## [0.7.0] — 2026-05-22
Minor — **`logoAssetName`** in `ManaBrandConfig`. Apps können jetzt
ein eigenes Logo-Asset (Asset-Catalog-Name) statt eines SF-Symbols
für den Login-/Sign-Up-/Forgot-Password-Header liefern.
### Hintergrund
Pageta hat ein eigenes Apple-Icon-Composer-SVG; das SF-Symbol
`book.pages` (vorher) sah neben dem polierten App-Icon unecht aus.
Andere Apps mit echten Logo-Assets (kommt) werden den gleichen
Migrationspfad gehen können.
### Neu
- `ManaBrandConfig.logoAssetName: String?` — Name eines Image-Assets
im Bundle der konsumierenden App. Hat Vorrang vor `logoSymbol`.
- `ManaAuthScaffold` rendert `logoAssetName` 64×64pt, `aspectRatio(.fit)`,
ohne Tint (Asset behält Originalfarben — typisch Apple-Icon-
Composer-Output mit Gradient). Fallback bleibt SF-Symbol mit Tint.
### Geändert
- `ManaBrandConfig.init` hat einen zusätzlichen optionalen Parameter
`logoAssetName: String? = nil`. Quellkompatibel — bestehende Apps
brauchen nichts ändern.
- `systemDefault`-Config setzt `logoAssetName: nil` explizit (kein
Verhaltenswechsel).
### Tests
- 50/50 grün (keine neuen Tests — die `ManaBrandConfig`-Änderung ist
rein additiv, gerendertes Asset hängt am Bundle der App).
### Adoption
Apps mit eigenem Logo:
```swift
ManaBrandConfig(
appName: "Pageta",
logoSymbol: "book.pages", // SF-Fallback bleibt
logoAssetName: "PagetaLogo", // Asset-Catalog-Name, hat Vorrang
...
)
```
## [0.6.0] — 2026-05-17
Minor — **neues Library-Product `ManaWebShell`**. WKWebView-Hülle für
Hybrid-Apps (Web-Lese-Surfaces + native Submit/Widget/ShareExt).
Extrahiert aus den fast-byte-identischen `WebShell/`-Ordnern in
`seepuls-native` und `zitare-native` (~900 LOC, davon ~700 LOC
Duplikat). Audit 2026-05-17 Vorschlag V2.
### Neu
- `WebShellView` (public SwiftUI View) — `WKWebView`-Wrapper mit
Progress-Bar, Pull-to-Refresh (iOS), Fehler-Snackbar, External-Link-
Delegation in den System-Browser. Universal (iOS + macOS).
- `WebShellConfig` (public, Sendable) — Host-Whitelist mit Wildcard-
Support (`"*.mana.how"`), User-Agent, Theme-Hints (background,
progressTint, errorBackground/Foreground/Icon), User-Scripts.
- `WebTarget` (public, Equatable+Sendable) — URL + monoton wachsender
`reloadToken`. Forciert Reload bei Universal-Link auf aktuelle URL.
- `WebNavState` (public, @Observable, @MainActor) — reaktiver
Navigation-State (isLoading, estimatedProgress, lastError,
currentURL, canGoBack).
- `WebShellCoordinator` (public, @MainActor) — `WKNavigationDelegate`
+ `WKUIDelegate`-Implementierung. KVO-Observations, Pull-to-Refresh-
Action.
- `WebShellScripts` (public Enum, @MainActor) — vor-gefertigte
`WKUserScript`-Helfer: `preferDarkScheme`, `syncDarkMode(localStorageKey:)`,
`hideElements(selectors:tagName:)`. Apps stapeln nach Bedarf.
### Logging
- ManaWebShell loggt unter Subsystem `ev.mana.webshell`, Kategorie
`web`. App-OSLog bleibt unverändert.
### Tests
- `ManaWebShellTests` mit 6 Tests gegen `WebShellConfig.isAllowed`.
Coverage für exakte Hosts, `*.root`-Wildcard, Root-selbst,
Negativ-Cases, leere Whitelist. 6/6 grün.
### Migrations-Hinweis
`seepuls-native` und `zitare-native` können ihre lokalen
`Sources/Features/WebShell/`-Dateien gegen `ManaWebShell` ersetzen.
Pattern in `mana/docs/playbooks/HYBRID_NATIVE_APP.md` (entsteht
parallel). App-spezifisches (CookieBridge, App-Theme als
`config.backgroundColor`) bleibt in der App.
## [0.5.0] — 2026-05-14
Minor — `ManaTwoFactorAccountRow` + `ManaBackupCodeRegenerateView`.
Macht den 2FA-Vollausbau in der AccountView nutzbar. Setzt
mana-swift-core ≥ 1.5.0 voraus (`getProfile()`).
### Neu
- `ManaTwoFactorAccountRow` — Drop-in für AccountView. Holt den
2FA-Status via `AuthClient.getProfile()` und zeigt:
- **Off:** "Zwei-Faktor aktivieren" → öffnet `ManaTwoFactorEnrollView`
- **An:** "Zwei-Faktor aktiv" + "Backup-Codes erneuern" +
"Zwei-Faktor deaktivieren"
- `ManaBackupCodeRegenerateView` — Re-Auth via Passwort, zeigt neue
Backup-Codes + Copy-to-Clipboard.
- `TwoFactorAccountRowModel` — internes `@Observable`-VM, reloaded
Status nach Enroll/Disable/Regenerate.
Damit ist 2FA in den Apps end-to-end nutzbar — User kann aktivieren,
Backup-Codes verwalten, deaktivieren. Der Login-Flow ist seit v0.3.0
durchgängig.
## [0.4.0] — 2026-05-14
Minor — 2FA-Enrollment-UI (Mini-Sprint B). Setzt mana-swift-core
≥ 1.4.0 voraus.
### Neu
- `ManaTwoFactorEnrollView` + `TwoFactorEnrollmentViewModel` —
3-Phasen-Wizard:
1. Passwort eingeben (Re-Auth)
2. QR-Code (via `CoreImage.CIFilter.qrCodeGenerator`, plattform-
unabhängig auf iOS+macOS) scannen + 6-stelligen Test-Code
eingeben
3. Backup-Codes anzeigen + Copy-to-Clipboard
- `ManaTwoFactorDisableView` — Single-Step-Sheet, Re-Auth via
Passwort + destruktiver Bestätigungs-Button.
### Tests
- 5 neue Tests für Enroll-VM (Success, falsches PW, canSubmitVerify
6-Ziffern-Guard, confirmVerify Phase-Wechsel, backupCodes-Accessor).
- 44/44 grün.
## [0.3.0] — 2026-05-14
Minor — `ManaTwoFactorChallengeView` für 2FA-Login. Setzt
mana-swift-core ≥ 1.3.0 voraus (Status `.twoFactorRequired`).
### Neu
- `ManaTwoFactorChallengeView` + `TwoFactorChallengeViewModel` —
6-stelliger TOTP-Code-Input (Number-Pad auf iOS), Fallback auf
Backup-Codes via Toggle, "Abbrechen" routet via
`auth.signOut(keepGuestMode:)` zurück zum Login.
- `LoginViewModel.Status.twoFactorRequired(email:)` als neuer Case.
- `ManaLoginView` schaltet bei `.twoFactorRequired` automatisch auf
`ManaTwoFactorChallengeView` um (analog zu `.emailNotVerified`).
### Tests
- 6 neue Tests für `TwoFactorChallengeViewModel`: canSubmit-Guards
(TOTP 6 Ziffern, Backup beliebig), toggleMode-State-Reset, submit
bei Erfolg/Fehler, Backup-Code-Routing.
- 39/39 grün.
## [0.2.0] — 2026-05-13
Minor — Action-Level-Gate für Apps mit Guest-/Login-optional-Modus.
Komplett additiv; braucht `mana-swift-core` ≥ 1.2.0.
### ManaAuthUI — neu: ManaAuthGate
- `ManaAuthGate` — `@Observable`-State-Maschine, die eine Aktion erst
laufen lässt, wenn der User eingeloggt ist. Wenn nicht, wird das
Sign-In-Sheet aufgeklappt und die Aktion gemerkt; nach erfolgreichem
Sign-In läuft sie automatisch.
- Zwei `require`-Overloads: synchron (`() -> Void`) und async
(`() async -> Void`). Konsumenten schreiben `gate.require { ... }`
ohne sich um das Gate-Lifecycle zu kümmern.
- `ManaAuthGateModifier` / `View.manaAuthGate(_:signIn:)` — hängt das
Sign-In-Sheet an einen Root-View und beobachtet `auth.status`.
Wechsel auf `.signedIn` schließt das Sheet und löst die Pending-
Aktion aus; manuelles Dismiss verwirft die Pending-Aktion.
- `lastReason` als optionaler Telemetrie-Hint pro `require`-Call.
### Konvention
Native-Apps sollen `mana-swift-core` v1.2.0 + Guest-Mode + diesen Gate
als Standardweg nutzen. Pattern für Cards/Manaspur/Memoro:
1. Beim App-Start: `bootstrap()`, dann bei `.signedOut` → `enterGuestMode()`.
2. Root-View zeigt immer App-Inhalte; **nie** eine Vollbild-Login-Wall.
3. Aktionen, die einen Account brauchen, werden in
`gate.require { ... }` gewrappt — Login wird zur Inline-Eskalation
statt zum App-Block.
Memoro hat dieses Muster informell schon umgesetzt (ContentView ohne
Hard-Gate). Cards + Manaspur ziehen mit ihren nächsten Releases nach.
### Tests
- 7 neue Tests für `ManaAuthGate`: sofortiger Run bei `.signedIn`,
Defer bei `.signedOut`/`.guest`, `resolvePending` nach Sign-In,
`cancelPending`, `lastReason`-Tracking.
## [0.1.0] — 2026-05-13
Phase 2 aus dem Native-Auth-Vollausbau-Plan (Option A, siehe
`../mana/docs/MANA_SWIFT.md`). Entstanden weil drei Apps fast-byte-
identische `LoginView.swift`-Dateien hatten und Sign-Up/Forgot-PW
komplett fehlten.
### ManaAuthUI (neu)
- `ManaBrandConfig` — App-injiziertes Bündel aus appName, tagline,
primary/surface/background/error-Colors. Apps liefern hier ihr
Theme (z.B. forest für Cards/Manaspur, default-mana für Memoro).
- Base-Components: `ManaAuthScaffold`, `ManaPrimaryButton`,
`ManaTextField`, `ManaSecureField` — geteilte Bausteine, alle
brand-aware.
- `ManaLoginView` + `LoginViewModel` — Email/PW-Login mit
Sign-Up- und Forgot-PW-Buttons. Bei `.emailNotVerified` automatisch
ins `ManaEmailVerifyGateView` umgeleitet (Resend-Mail-Button).
- `ManaSignUpView` + `SignUpViewModel` — Registrierung mit
Email/Name/Passwort. Nach Submit: Bestätigungs-Mail-Hinweis-Screen.
- `ManaEmailVerifyGateView` — wenn Login `.emailNotVerified` warf,
bietet "Bestätigungs-Mail erneut senden".
- `ManaForgotPasswordView` + `ForgotPasswordViewModel` — Reset-Mail
anfordern. Server antwortet immer 200 (keine User-Enumeration),
UI meldet generisch.
- `ManaResetPasswordView` + `ResetPasswordViewModel` — neues
Passwort setzen mit Token aus Reset-Mail. Wird aus dem
Universal-Link-Handler der App aufgerufen.
- `ManaChangeEmailView`, `ManaChangePasswordView`,
`ManaDeleteAccountView` — Account-Bausteine für die AccountView
der App. **`ManaDeleteAccountView` ist App-Store-Pflicht
(Guideline 5.1.1(v))** für jede App mit Account-Erstellung.
### Tests
- ViewModel-Tests via URLProtocol-Mock für jeden Auth-Flow.
- Brand-Config-Defaults.
### Bekannte Einschränkungen
- `ManaChangeEmailView`/`ManaChangePasswordView`/`ManaDeleteAccountView`
funktionieren erst nach Phase-3-Server-PR (Bearer-Plugin in
`mana-auth`). UI ist fertig, Wire ist fertig, Server muss nachziehen.
- 2FA, Magic-Link, Passkey-Flows nicht enthalten. Folgen in v0.2.0
zusammen mit ManaCore v1.2.0 und dem Server-PR.