mana-swift-core/devlog/2026-05-13/macher.md
Till JS 957a80251e devlog: 2 Tage geschrieben (v1.0.0 → v1.5.0)
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>
2026-05-15 22:21:46 +02:00

101 lines
4.5 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.

---
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.