Tag 1: initiale Extraktion aus memoro-native. Tag 2: Reifung zu v1.5.0 (Account-Lifecycle, Guest-Mode + Refresh-Resilience, 2FA, ProfileInfo). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
101 lines
4.5 KiB
Markdown
101 lines
4.5 KiB
Markdown
---
|
||
date: 2026-05-13
|
||
day: 2
|
||
view: macher
|
||
weekday: Mittwoch
|
||
commits: 8
|
||
review: written
|
||
---
|
||
# Mittwoch, 2026-05-13 — Tag 2 (Macher-Sicht)
|
||
|
||
Reifung von v1.0.0 zu v1.5.0 in einer Schicht. Sechs Sinn-Abschnitte
|
||
(Transport-Fix, Account-Lifecycle, Session-Token-Auth, Guest-Mode +
|
||
Refresh-Resilience, 2FA-Login, 2FA-Enrollment, Profile) plus ein
|
||
chore-Cleanup. Build-Verzeichnis war versehentlich committet — am
|
||
Ende des Tages aufgeräumt.
|
||
|
||
## Stats
|
||
|
||
8 Commits, +5 427 / −2 895 LoC, 408 Files. **Achtung: 2 682 der
|
||
Deletions kamen aus `chore: untrack build/`** — der eigentliche
|
||
Code-Delta ist eher +2 700 / −200. Top-Dirs sind irreführend (alle
|
||
`build/`-Sub-Dirs), weil der Initial-Push das build/ mit hatte.
|
||
Tags: `transport`. Session 15:18 → 01:08, 62 aktive Minuten in
|
||
4 Blöcken, längster Fokus 48 Min.
|
||
|
||
## Versions-Schritte
|
||
|
||
- **Transport-Fix** — URL-Konstruktion encoded `?`-Query nicht mehr.
|
||
Klassischer Bug: Path-Encoding lief gegen Query-String, dadurch
|
||
`?from=…` als `%3Ffrom%3D…` rausgeschickt. 9 / −1 Zeilen.
|
||
- **v1.1.0 — Account-Lifecycle.** Change-Email, Change-Password,
|
||
Account-Delete als public API in ManaCore. ViewModels in
|
||
mana-swift-ui ziehen morgen nach.
|
||
- **v1.1.1 — Session-Token statt JWT für Account-Calls.**
|
||
Account-Operationen sind sensibel, brauchen frischen
|
||
Re-Auth-Token, nicht den allgemeinen JWT.
|
||
- **v1.2.0 — Guest-Mode + Refresh-Resilience.** Wenn ein Refresh
|
||
mit transienten Errors fehlschlägt (Netz-Timeout, 503), bleibt
|
||
die Session aktiv und retried. Wenn der Refresh hart 401 macht,
|
||
fällt der State auf `.guest` zurück statt blind alle Tokens zu
|
||
wipen. **Das war der wichtigste Fix** — vorher hat mobiles Netz
|
||
Memoro-User regelmäßig rausgeworfen.
|
||
- **v1.3.0 — 2FA-Login-Challenge.** Wenn Login `requires_2fa: true`
|
||
zurückgibt, dann zweiter Round-Trip mit Code.
|
||
- **v1.4.0 — 2FA-Enrollment.** Enroll-Init (QR-Secret) + Enroll-
|
||
Verify + Disable mit Passwort + Backup-Code-Regenerate.
|
||
- **v1.5.0 — getProfile() + ProfileInfo.** Name, E-Mail,
|
||
Mitgliedsstatus, Tier. +2 876 LoC — viel davon vendored swift-
|
||
jose-Updates, die für RS256-JWKS-Verify nötig waren.
|
||
- **chore: untrack build/** — `.gitignore` für `build/`, vorhandene
|
||
Tracked-Files raus.
|
||
|
||
## Architektur-Entscheidungen
|
||
|
||
- **Session-Token (kurze TTL) für Account-Calls**, nicht der
|
||
allgemeine JWT. Begründung: bei Account-Delete oder Email-Change
|
||
wäre ein gestohlener JWT katastrophal; frischer Session-Token
|
||
begrenzt das Schaden-Fenster.
|
||
- **Refresh-Resilience: transient vs. permanent.** Transiente
|
||
Errors (Netz, 503, Timeout) halten Session, retry mit Backoff.
|
||
Permanente Errors (401, invalid_grant) führen zu `.guest`.
|
||
Vorher: jede Refresh-Failure → Wipe.
|
||
- **Guest-Mode als eigener State**, nicht „signed-out". Apps
|
||
können Inhalt anzeigen, der Read-Only ist, ohne dass sie eine
|
||
Login-Wand zeigen müssen.
|
||
- **2FA-API additiv**, kein Breaking-Change. Apps, die kein 2FA
|
||
unterstützen, ignorieren `requires_2fa`-Field.
|
||
- **ProfileInfo als eigenes DTO**, nicht in AuthClient verbaut.
|
||
Profile ist datenzentriert, AuthClient ist State-zentriert.
|
||
- **swift-jose vendored**, statt SPM-Dependency. Public-API-
|
||
Invariante „keine externen Dependencies" (Compliance-Direktive)
|
||
bleibt.
|
||
|
||
## Trade-offs
|
||
|
||
- **+2 876 LoC für v1.5.0** klingt monströs, ist aber zu 80 %
|
||
vendored swift-jose. Eigentliche Profile-API ist klein.
|
||
- **Sechs Tags an einem Tag** ist viel — bei strikter Semver wäre
|
||
das eine Tagesserie, kein Sprint. Akzeptiert, weil jeder Tag
|
||
einen klar abgegrenzten Sinn-Abschnitt hat.
|
||
- **build/-Verzeichnis untracken nachträglich** war Aufwand
|
||
(2 682 deletions in einem Commit). Ursache: SwiftPM-CLI legt
|
||
build/ im Repo-Root an, statt unter DerivedData — `.gitignore`
|
||
hätte Tag 1 schon gehört.
|
||
- **Session-Token-Mechanik** in v1.1.1 nachgeschoben, weil
|
||
v1.1.0 das nicht hatte. Hätte v1.1.0 direkt richtig machen
|
||
sollen; akzeptiert als „erste Lernzyklen".
|
||
|
||
## Offene Punkte
|
||
|
||
- **Refresh-Resilience Test-Coverage**: Unit-Tests für transiente
|
||
vs. permanente Fehler-Pfade existieren, aber kein
|
||
Real-World-Test (instabiles Netz simulieren).
|
||
- **2FA-Backup-Codes-Storage**: ManaCore liefert sie als Strings
|
||
zurück; UI muss sie sicher anzeigen + kopierbar machen. Liegt
|
||
bei mana-swift-ui.
|
||
- **getProfile() Cache-Politik**: derzeit kein Cache. Bei häufigen
|
||
Calls hilft eine kurze TTL.
|
||
- **Schema-Drift gegen mana-auth**: wenn der Server `ProfileInfo`-
|
||
Schema ändert, gibt's keinen Wire-Check. Pre-Live-Smoke wäre
|
||
sinnvoll.
|