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