mana-swift-ui/CHANGELOG.md
Till JS 179c8fd675 feat(ManaFeedbackUI): ehrliche Aura-Soft-Anerkennung im Erfolgs-Zustand
Eingeloggte Nutzer sehen nach dem Absenden einen Aura-Hinweis. Keine
Sofort-Aura fuers blosse Absenden.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 14:04:28 +02:00

492 lines
22 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]
### Hinzugefügt
- **ManaFeedbackUI Soft-Anerkennung** — die Erfolgs-Ansicht zeigt
eingeloggten Nutzern jetzt einen ehrlichen Aura-Hinweis („Wird daraus
ein bestätigter Bug oder ein vielgewünschtes Feature, schreiben wir
dir Aura gut."). Keine Sofort-Aura fürs reine Absenden — Anerkennung
erst bei Bestätigung (siehe `mana/docs/INVITES_AND_AURA.md`).
- **`ManaSafariLink`** (ManaAuthUI) — öffnet eine URL **in-App** (iOS:
`SFSafariViewController`, macOS: System-Browser-Fallback) statt eine separate
Browser-App aufzureißen. Für rechtliche/redaktionelle Seiten (Impressum,
Datenschutz, Lizenz). Rendert als `Form`-Zeile wie ein `Link`.
- **`ManaAboutSection.Link.inApp`** (ManaAuthUI) — neuer Init-Parameter
(`inApp: Bool = false`). `true` → die „Über"-Sektion öffnet den Link via
``ManaSafariLink`` in-App statt extern. Damit deckt **eine** Sektion App-Info
*und* Rechtliches ab, statt einer separaten Legal-Links-Sektion pro App.
Additiv, Default unverändert (externer Link).
- **`ManaAppearanceSection`** (ManaThemeUI) — vereinheitlichte „Darstellung"-
Sektion für den Konto-/Einstellungen-Tab: bündelt `ManaAppearancePicker`
(Hell/Dunkel/Automatik) + `ManaThemeGallery` in *einer* `Section` mit Header
+ ökosystemweit gleichem Footer (`defaultFooter`). Die Einzel-Picker waren
schon geteilt, der Section-Rahmen + Footer-Wortlaut nicht — jede App baute
ihn (leicht abweichend) von Hand. Persistenz bleibt App-Sache (zwei `Binding`s
rein, kein `UserDefaults`-Schreiben); Theme-Pass via `unlocked`/`onLockedTap`
durchgereicht. Additiv.
- **`ManaComponentsUI`** (neues Library-Target) mit **`ManaPill`** — eine
einheitliche Kapsel-Pille (Filter-Chip / Bulk-Aktion) für alle nativen Apps.
Größe und Form sind zentral festgelegt (Referenz: seepuls-Filterleiste —
18/11 Padding, `.callout.semibold`, `Capsule`), die Farben kommen aus
`@Environment(\.manaTheme)` (keine Farb-Parameter → jede App behält ihre
Theme-Variant). Varianten `.selected` / `.neutral` / `.destructive` plus
`isOn`-Komfort-Init für Toggle-Filter. Behebt die zu kleinen Bulk-Aktions-
Pills im Auswahl-Modus und vereinheitlicht sie mit den seepuls-Filtern.
Dependency: nur `ManaTokens`.
- **`.manaCard(surface:border:cornerRadius:borderWidth:padding:)`**
(ManaThemeUI) — geteiltes Karten-Chrome für alle Verein-Apps: gefüllte
`surface`-Fläche, durchgehende **continuous** (Apple-Squircle-)Ecken und
optionaler Hairline-Border aus *einer* gemeinsamen Form (sauberer
Eckenverlauf statt zwei getrennter circular Shapes). Theming-agnostisch
(Farben explizit), nutzt `Radius`-Token als Defaults. Eine Quelle für die
Kartenoptik, statt pro Komponente hardcoded `cornerRadius` mal mit, mal ohne
Border. `ManaThemeUI` ist jetzt Dependency von `ManaAuthUI` + `ManaFeedbackUI`.
- **`RoundedRectangle.mana(_:)`** (ManaThemeUI) — Vereins-Standard-Form:
continuous (Squircle-)Ecke an einem `Radius`-Token. Für Buttons, Eingabe-
felder und kleine Inline-Boxen, die *keine* volle `.manaCard` brauchen, aber
dieselbe Ecken-Sprache sprechen sollen. Verhindert stilles Zurückfallen auf
den eckigeren `.circular`-Default.
- **`ManaAboutSection`** (ManaAuthUI) — vereinheitlichte „Über"-Sektion für den
Konto-Tab: App-Name + Version/Build (automatisch aus dem `Bundle`) +
konfigurierbare Link-Liste. `ManaAccountView` rendert sie an **fester
Position** (ganz unten, nach den App-Sektionen), wenn der neue `about:`-
Parameter gesetzt ist — additiv, kein Breaking-Change (Default `nil`). Beendet
das per-App-Handbauen der App-Info-Sektion (vorher uneinheitlich: comicello
App/Version/Build+Links, wordeck nur Hosts, memoro gar nichts).
### Geändert
- **Rest-Chrome auf `Radius`-Token + continuous gezogen** — `ManaTextField` /
`ManaSecureField` (Feld-Box + Border, jetzt `strokeBorder` statt `stroke`),
`ManaPrimaryButton`, die Feedback-Buttons (`ManaFeedbackCard`/`ManaFeedbackSheet`)
und die 2FA-Views (QR-Box, Backup-Code-Chips, Kopier-Buttons) nutzen statt
hardcoded `cornerRadius`-Literalen (6/8/10/12) jetzt `RoundedRectangle.mana(Radius.*)`.
Radien konvergieren auf die Token-Skala (Felder/Buttons → `Radius.md` 8,
Code-Chips → `Radius.sm` 4, QR-Box → `Radius.lg` 12); alle Ecken jetzt
continuous. Rein optisch, keine API-Änderung.
- **`ManaSignInCTA` (Login-CTA) + `ManaFeedbackCard` ziehen auf `.manaCard`** —
beide Karten teilen jetzt identisches Chrome (continuous Squircle-Ecken,
`Radius.lg`, 1pt-Border in `border`-Farbe). Vorher: Login rahmenlos mit
circular `cornerRadius 12`, Feedback mit getrenntem Background+Overlay-Border
bei `cornerRadius 16`, dessen Strich den Ecken nicht sauber folgte. Optische
Vereinheitlichung über alle Apps mit `ManaAccountView`. *Kein API-Bruch.*
- **`ManaSignInCTA`** (ManaAuthUI) — prominente Anmelde-Card für den
abgemeldeten Zustand: optionale Headline + Erklärtext + vollbreiter
Brand-Button (`ManaPrimaryButton`), komplett über `\.manaBrand`
getönt. Gehoben aus viadocus handgebautem `guestBanner`, der als
einzige App optisch „richtig" wirkte. Ersetzt die blasse Form-
Listenzeile, die ein nackter `Button`/`Label` in einer `Section`
rendert.
- **`ManaAccountView.Config.signInHeadline`** (ManaAuthUI) — Headline
über dem Anmelde-CTA (Default „Noch nicht angemeldet", `nil` blendet
sie aus).
### Geändert
- **`ManaThemeGallery` Reihenfolge + App-Brücke** — (1) **freigeschaltete
Variants stehen jetzt zuerst**, gesperrte danach (stabile Partition über
`unlocked`); vorher lagen freie Themes quer zwischen Schlössern verstreut.
(2) Der **„<App> öffnen"-Button bleibt nach dem Freischalten sichtbar** (mit
geändertem Infotext „Signatur-Theme von <App>" statt der Freischalt-
Aufforderung) — als dauerhafte Brücke zur Herkunfts-App, damit die anderen
mana-Apps immer erreichbar bleiben und klar bleibt, woher das Theme stammt.
Baseline-Variants (ohne Signatur-App) bekommen weiterhin keinen Button.
`onLockedTap` feuert jetzt auch beim freigeschalteten Button-Druck. Reine
View-Änderung, keine API-Signatur-Änderung. Siehe THEME_PASS.md.
- **`ManaThemeGallery` Theme-Pass-Lock** — gesperrte Variant öffnet die
Signatur-App **nicht mehr automatisch**. Tippen/Einrasten zentriert sie
nur; darunter erscheint „Probier <App> aus, um „<Variant>" freizuschalten"
**plus ein „<App> öffnen"-Button**, der erst auf Druck die eigene
Landingpage öffnet (`ManaTheme.signatureAppHomepage`, mana-swift-core
≥ 1.15.0; via `@Environment(\.openURL)`). `onLockedTap` ist jetzt ein
optionaler Analytics-Hook (feuert beim Button-Druck), keine Navigation
mehr — Konsumenten können den Closure droppen. Datei zugleich auf die
Repo-Konvention (4 Spaces) normalisiert. Siehe THEME_PASS.md.
- **`ManaAccountView` signed-out** rendert jetzt ``ManaSignInCTA`` statt
einer Label-Listenzeile — alle Apps, die ``ManaAccountView`` nutzen
(seepuls, pageta, wordeck, audioguide), bekommen den prominenten CTA
automatisch, ohne Code-Änderung.
- **`ManaFeedbackCard`** (ManaFeedbackUI) — prominenter Feedback-Block
für den Konto-/Einstellungen-Tab: Icon + aktivierender Titel
(„Hilf mit, die App zu formen") + ein Satz Einladung + gefüllter
CTA in Vereinsfarbe. Löst die dezente `ManaFeedbackButton`-Listenzeile
ab und präsentiert dasselbe `ManaFeedbackSheet`. Theme-aware
(`\.manaTheme`, `surface`+`border` als Karten-Rahmen). Copy
überschreibbar (`title`/`message`/`cta`).
- **`ManaAccountView.feedbackClient`** (ManaAuthUI) — neuer optionaler
Init-Parameter. Ist er gesetzt, rendert der Standard-Block die
`ManaFeedbackCard` an **fester Position** (direkt nach dem
Konto-/Anmelden-Block, vor `extra`) — vereinheitlicht Platzierung +
Optik des Feedbacks über alle Apps, statt es pro App handgebaut tief
im `extra`-Slot zu verstecken. `ManaAuthUI` hängt dafür neu von
`ManaFeedbackUI` ab. Additiv, kein Breaking-Change (Default `nil`).
- **`ManaPasswordStrength`** + **`ManaPasswordStrengthView`** (ManaAuthUI)
— segmentierte Passwortstärke-Anzeige unter den `newPassword`-Feldern
in `ManaSignUpView` und `ManaResetPasswordView`. Reine Heuristik
(Länge + Zeichenklassen, keine externe Bibliothek), testbar
(`PasswordStrengthTests`). Blendet sich bei leerem Feld aus, markiert
`.weak` per `brand.error`. Stufen: schwach/mittel/gut/stark.
## [0.9.0] — 2026-06-01
Minor — **zwei neue Library-Produkte** (`ManaFeedbackUI`,
`ManaThemeUI`) plus das vereinheitlichte Konto-Gerüst `ManaAccountView`
und der Passwort-Reveal in `ManaSecureField`.
### Hinzugefügt
- **`ManaThemeUI`** — neues Library-Produkt. Geteilte Theme-Galerie
(`ManaThemeGallery` — Orb-Karussell mit Snap-to-Center und
Lock-State für den Theme-Pass) plus `ManaAppearancePicker`
(Hell/Dunkel/System). Konsumiert `ManaTokens`. Beendet das
per-App-Handbauen der Theme-Auswahl. Siehe `mana/docs/THEME_PASS.md`.
- **`ManaAccountView`** (ManaAuthUI) — vereinheitlichtes Konto-Gerüst:
Form-basierter Standard-Block (E-Mail-Anzeige, E-Mail/Passwort ändern,
2FA, Konto löschen [Apple 5.1.1(v)], Abmelden) aus einem `AuthClient`,
plus Sign-In-CTA im abgemeldeten Zustand. Config-Flags
(`showChangeEmail`/`showChangePassword`/`showTwoFactor`),
`onSignIn`/`onSignOut`-Callbacks, `@ViewBuilder extra`-Slot für
App-spezifische Sektionen. Pendant zur Login-Konsolidierung — beendet
das per-App-Handbauen des Konto-Tabs.
- **`ManaFeedbackUI`** — neues Library-Produkt. `ManaFeedbackSheet`
(Kind-Picker Wunsch/Problem/Feedback, Titel, Beschreibung; bei anonymer
Nutzung optionales Kontakt-Mail-Feld + Moderations-Hinweis),
`ManaFeedbackButton` (Default-Label „Feedback" oder Custom-Label) und
der `.manaFeedbackSheet(isPresented:client:isLoggedIn:)`-Modifier für
eigene Trigger (z.B. Toolbar/Settings-Row). Postet via
`ManaCore.FeedbackClient` an die zentrale Wunsch-App — Pendant zum
Web-`@mana/shared-feedback`-Widget. Theming über `\.manaTheme`
(ManaTokens). Siehe `mana/docs/FEEDBACK_NATIVE_PLAN.md`.
### Geändert
- **`ManaSecureField`** (ManaAuthUI) — Augen-Button zum Sichtbarmachen
des Passworts (`SecureField` ↔ `TextField`, Default verborgen).
Barrierearm gelabelt („Passwort anzeigen"/„Passwort verbergen"),
Fokus bleibt über den Feld-Tausch erhalten. Der Button erscheint
erst, wenn etwas im Feld steht; ein geleertes Feld kehrt zur
Maskierung zurück. Auf macOS warnt ein Feststelltasten-Symbol
(`capslock.fill`) bei aktivem Caps-Lock — wie in Apples eigenen
Passwortfeldern. Wirkt ökosystemweit: alle nativen Apps teilen
diese Komponente (Login, Sign-Up, Reset, Passwort ändern, 2FA,
Konto löschen).
- `ManaWebShell`: Die Fehler-Leiste in `WebShellView` hat jetzt einen
„Erneut laden"-Button. Bisher war ein Lade-Fehler eine Sackgasse —
der User sah die Meldung, konnte die Seite aber nicht neu laden.
Intern via `reloadNudge` → `effectiveTarget.reloadToken`.
## [0.8.0] — 2026-05-22
Minor — **neues Library-Product `ManaLLMUI`**. Drop-in-Settings-UI
für die lokalen LLM-Backends aus `mana-swift-llm`. Pendant zu
`ManaAuthUI` — vorher hatte nur Memoro die UI handgeschrieben, die
drei anderen Konsumenten (pageta, comicello, herbatrium) hatten
gar nichts.
### Hintergrund
Vier Apps konsumieren `ManaLLM` (Memoro, Pageta, Comicello, Herbatrium).
Memoros 250-Zeilen-LLM-UI (Picker + Prepare + Cellular-Toggle) war
strukturell shared-fähig — wurde rausgehoben, generalisiert und steht
jetzt allen Apps zur Verfügung.
### Neu
- `ManaLLMUI`-Product (deps: `ManaLLM`, `ManaLLMShared`)
- `ManaLLMSettingsView` — Convenience-Wrapper, drei Sections in
einem Schwung
- `ManaLLMBackendPickerSection` — Picker mit Availability-Status +
Empfohlen-Badge
- `ManaLLMPrepareSection` — Download/Init-Card mit Progress, nur
sichtbar für Gemma-Backends (`shouldShow(for:)`-Gate)
- `ManaLLMDownloadPolicySection` — WiFi-only-Toggle
- `ManaLLMSettingsState` — `@Observable`-State-Klasse, hält
Backend-Wahl + Availability + Prepare-Progress + delegiert an die
Stores aus `mana-swift-llm`
- `ManaLLMContext` — App-spezifischer Kontext (`useCaseShort` +
`useCaseLong`) für Section-Texte. `.generic` als Fallback
### Migration
Apps die heute eigene LLM-Settings-UI haben (Memoro):
- `import ManaLLM` für die Settings-View durch `import ManaLLMUI` ersetzen
- Lokale `llmSection`/`llmPrepareSection`/`llmDownloadPolicySection`-
Bodies entfernen
- `ManaLLMSettingsView(context: ...)` einhängen
- `LLMBackendPreferenceStore` + `LLMDownloadOverCellularStore` bleiben
funktionsgleich — wandern aber nach `ManaLLM` (siehe
`mana-swift-llm` CHANGELOG)
Apps die heute keine LLM-Settings-UI haben (Pageta, Comicello,
Herbatrium):
- `ManaLLMUI`-Product in `project.yml` adden
- `ManaLLMSettingsView(context: ...)` an passender Stelle einhängen
(eigene Settings-View oder NavigationLink im Profile-Tab)
## [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.