Bug: Browser-Client requested localhost:3081 statt cardecky-api.mana.how
nach Login. Ursache: API_BASE und authBaseUrl() lasen die Variable
über import.meta.env.PUBLIC_*, was unter SvelteKit nicht zuverlässig
inlined wird (Vite-direct, ohne SvelteKit-Wrapper-Hook).
Fix: \$env/dynamic/public liest die env zur Runtime aus den Node-
Server-Variablen (adapter-node) — Browser bekommt sie über den
SSR-Init-Snapshot. Damit muss die Variable nur als runtime-env am
Container hängen, nicht als Build-Arg.
docker-compose.production.yml: PUBLIC_CARDS_API_URL und
PUBLIC_MANA_AUTH_URL aus build.args nach environment verschoben.
Build-Pipeline: cards-web muss neu gebaut werden, sonst greift der
Wechsel von static→dynamic env nicht.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cards-Web läuft jetzt auch über die 15min-JWT-TTL hinaus weiter:
- Login schickt credentials:'include' → SSO-Cookie auf .mana.how
wird gesetzt (mana-auth-Standard).
- tryRefresh() ruft mana-auth POST /api/v1/auth/refresh mit Cookie-
Auth, holt frischen accessToken, legt ihn in localStorage. Multi-
Caller werden zu einer Promise gecoalesced (kein Refresh-Storm).
- ensureFreshToken() prüft beim Konstruktor + vor jedem API-Request,
ob der Token noch ≥60s gültig ist. Wenn nicht, proaktiver Refresh.
- API-Client: 401 → tryRefresh() → exactly-once Retry. Erst wenn das
auch 401 gibt, wird die Session lokal geleert (führt User zurück
auf /).
- uploadMedia (multipart) parallel mit demselben Pattern.
- Logout ruft mana-auth /logout mit Cookie-Auth, damit das SSO-Cookie
für andere *.mana.how-Apps auch weg ist (best-effort, nicht-fatal).
- Boot-Pfad: bei abgelaufenem Token im localStorage behalten wir das
User-Profil temporär und versuchen einen still-Refresh — User sieht
beim Reload kein Login-Flackern, wenn die Cookie-Session noch lebt.
svelte-check 384 files 0 errors, 7 Web-Tests grün, prod-Build sauber.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Echte Anmeldung gegen auth.mana.how/api/v1/auth/login statt
Dev-Stub-User-ID. accessToken (EdDSA-JWT, 15 min TTL) + Profil
(email, name, tier) leben in localStorage; jeder API-Call schickt
`Authorization: Bearer <jwt>`. Bei 401 wird die Session lokal
geleert — User landet beim nächsten Render auf der Login-Page.
`devUser.id` bleibt eine Vereinfachte UI-Sentinel (gibt id wenn
JWT ODER Dev-Stub aktiv) — alle existierenden Importer
funktionieren unverändert. Dev-Stub-Pfad bleibt als Fallback für
Tests + Anki-Importer-Migration. Filename `dev-stub.svelte.ts`
behalten, Inhalt komplett umgebaut (Sprint 10d wäre der Rename).
Account-Page zeigt Email + Name + Tier statt nur UUID. Header
zeigt Email statt UUID. Login-Form auf Landing-Page mit Email +
Passwort, error-Anzeige, autocomplete-Hints für Browser-Manager.
uploadMedia (multipart) angepasst: Bearer first, X-User-Id-Stub
als Fallback.
svelte-check 384 files 0 errors, 7 Web-Tests grün, prod-Build
sauber.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>