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

9.6 KiB
Raw Blame History

Changelog

Alle Änderungen werden hier dokumentiert. Format orientiert an Keep a Changelog, Versionierung nach Semver.

[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:

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 .signedOutenterGuestMode().
  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.