xcodebuild legt build/-Verzeichnis ab. .gitignore deckte nur .build/
(Swift Package Manager), nicht das Xcode-build/. Bei v1.5.0-Commit
sind ~400 Compiler-Artefakte (.o, .stringsdata, .pcm) rein-gerutscht.
Diese Files werden hier untracked und das Verzeichnis future-proof
ignoriert. Das v1.5.0-Tag verweist weiterhin auf den schmutzigen
Commit — Konsumenten ziehen mit dem nächsten pull diesen Cleanup
nach. Saubere v1.5.1 wäre Overkill für ein Artefakt-Aufräumen.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Apps können den 2FA-Status des eingeloggten Users lesen, damit
AccountView entscheidet ob "Zwei-Faktor aktivieren" oder
"Zwei-Faktor deaktivieren" angezeigt wird.
ProfileInfo (public struct) — id, email, name, emailVerified,
twoFactorEnabled.
AuthClient.getProfile() -> ProfileInfo — lädt das Profil vom
Server (GET /api/v1/auth/profile → Better Auths /api/auth/get-session).
Nutzt Session-Token als Bearer (Wire-Konvention).
4 neue Tests, 70/70 grün.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mini-Sprint B des 2FA-Vollausbaus. Apps können jetzt TOTP-2FA für
ihre User aktivieren und verwalten. Komplett additiv.
Neuer Public-Struct:
- TotpEnrollment { totpURI, backupCodes }
Neue Methoden in AuthClient+Account:
- enrollTotp(password:) -> TotpEnrollment — aktiviert 2FA, liefert
otpauth-URI (für QR) + Backup-Codes (einmalig)
- disableTotp(password:) — deaktiviert wieder
- getTotpUri(password:) -> String — Re-Display für zweites Gerät
- regenerateBackupCodes(password:) -> [String] — alte werden ungültig
Alle vier nutzen den authenticated-Pfad (Session-Token als Bearer).
Setzt mana-auth ≥ v1.3.0 + die neuen Wrapper-Endpoints für
/api/v1/auth/two-factor/{enable,disable,get-totp-uri,generate-backup-codes}
voraus.
7 neue Tests, 66/66 grün.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mini-Sprint A des 2FA-Vollausbaus. Apps mit aktivem TOTP-2FA können
sich nativ einloggen. Komplett additiv.
AuthClient.Status um .twoFactorRequired(token, methods, email)
erweitert. signIn() erkennt automatisch den Server-Pfad
{twoFactorRequired: true, ...} und routet zum neuen Status.
Neue Methoden in AuthClient+Account:
- verifyTotp(code:trustDevice:) — 6-stellige Codes aus Authenticator-
App. Bei Erfolg .signedIn, bei Fehler bleibt Status im Challenge
(User kann retry mit anderem Code).
- verifyBackupCode(code:trustDevice:) — einmalige Codes als Fallback.
Wire-Format: Client schickt {code, twoFactorToken, trustDevice} an
/api/v1/auth/two-factor/verify-{totp,backup-code}. Server (mana-auth)
re-injectet den twoFactorToken als better-auth.two_factor-Cookie und
delegiert an Better Auths Plugin.
5 neue Tests, 59/59 grün.
Setzt mana-auth-Server mit den entsprechenden Custom-Endpoints
voraus — siehe gleichzeitiger Commit im mana-Repo.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Native-Apps werden gegen mana-auth-Downtime gehärtet und können
einen anonymen Local-First-Modus anbieten. Komplett additiv.
AuthClient.Status um `.guest(id: String)` erweitert — persistente
lokale UUID ohne Server-Account, gleichberechtigt mit `.signedIn` als
"App ist nutzbar"-Zustand.
Neue Methoden:
- enterGuestMode() throws -> String — idempotent
- currentGuestId() -> String?
- clearGuestId()
- signOut(keepGuestMode: Bool = false) — Default-Verhalten unverändert
KeychainStore.Key.guestId neu. wipe() löscht nur Session-Felder
(accessToken/refreshToken/email); Guest-ID überlebt. Für komplettes
Vergessen: neue wipeAll().
refreshAccessToken() wipt nicht mehr blind bei jedem Nicht-200.
Heuristik via AuthError.invalidatesSession:
- Wipe bei invalidCredentials/unauthorized/tokenExpired/tokenInvalid/
emailNotVerified — Session ist tatsächlich tot.
- Behalten bei serviceUnavailable/serverInternal/networkFailure/
rateLimited — Apps werden bei mana-auth-Downtime nicht mehr in
Login geworfen.
Beim Wipe fällt der Status auf .guest(id) zurück, falls eine
Guest-Identität existiert; sonst auf .signedOut.
Tests:
- Mock-Setup auf per-test-ID-Routing migriert (analog mana-swift-ui),
löst Cross-Suite-Pollution zwischen AuthClient+Account und
AuthClient Guest-Mode + Resilience.
- 15 neue Tests für Guest-Mode + Refresh-Resilience.
- 54/54 Tests grün.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire-Konvention für authenticated Account-Endpoints (changeEmail,
changePassword, deleteAccount) geklärt. Server-seitig wurde in
mana-auth Better Auths bearer-Plugin aktiviert (requireSignature:
false), das Session-Tokens zu Session-Cookies konvertiert. Native-
Apps senden daher jetzt den Session-Token (refreshToken-Feldwert)
statt des JWT als Authorization: Bearer für diese drei Endpoints.
Der JWT bleibt für app-eigene Backends (memoro-api, cardecky-api,
manaspur-api) der richtige Authorization-Header — die Trennung ist
nur für mana-auth interne Endpoints.
currentSessionToken() als public Helper hinzu (symmetrisch zu
currentAccessToken).
38/38 Tests grün.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 1 aus dem Native-Auth-Vollausbau-Plan (Option A, siehe
mana/docs/MANA_SWIFT.md). 7 neue AuthClient-Methoden für die
Account-Reise: register, forgotPassword, resetPassword,
resendVerification, changeEmail, changePassword, deleteAccount.
AuthError jetzt mit 19 präzisen Cases gespiegelt aus
AuthErrorCode in mana-auth/lib/auth-errors.ts, plus
AuthError.classify() als public Helper und Equatable-Conformance.
AuthClient.lastError ergänzt — strukturierter Fehler für
ManaAuthUI das den .emailNotVerified-Gate programmatisch braucht.
signIn und refreshAccessToken auf neue Klassifikation umgestellt.
Breaking: AuthError.serverError hat zusätzliches code:-Argument.
Apps (cards-native, memoro-native) sind bereits angepasst.
38/38 Tests grün (26 neu): AuthErrorClassifyTests deckt jeden
ErrorCode + Status-Heuristik + Retry-After ab, AuthClientAccountTests
deckt jede neue Methode via URLProtocol-Mock ab.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
URL.appending(path:) behandelt das ? in Query-Strings als Pfad-
Component und URL-encoded es zu %3F. Server-Route-Matching scheiterte
mit 404 für alle Endpoints mit Query-Parametern.
Symptom in cards-native v0.8.x: alle Card-Counts und Due-Counts auf 0,
DeckDetailView Cards-Liste leer mit "Server-Fehler (404)" auf
/api/v1/cards?deck_id=X.
Fix: String-Konkatenation baseURL.absoluteString + path. Caller
liefert path inkl. führendem / und optionaler Query. URLRequest
parsed das Resultat korrekt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>