#114 — Lokale Docker-Testumgebung im go-loop + Backend-Erreichbarkeit-Anzeige #117
Labels
No labels
priority/could
priority/must
priority/should
priority/wont
status/blocked
status/claimed
status/done-migrated
type/bug
type/feature
type/infra
type/tech-debt
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
robert/todo#117
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Story: Lokale Docker-Testumgebung im go-loop + Backend-Erreichbarkeit-Anzeige
As a Mensch, der die Ergebnisse jedes "go"-Zyklus testen will,
I want to (a) dass die aktuelle Version jedes Mal lokal in einem Docker-Container läuft/erreichbar ist,
und (b) dass das Frontend klar anzeigt, wenn das Backend nicht erreichbar ist,
so that ich nicht raten muss, ob ein Fehler ein echter Bug oder nur eine kaputte lokale
Testumgebung ist.
Direkt vom Menschen beauftragt (kein "go"), im Anschluss an eine reale Debugging-Session, in der genau
dieses Fehlerbild auftrat: eine falsch konfigurierte lokale Dev-Umgebung (Vite-Proxy zeigte auf den
falschen Backend-Port) erzeugte 18+ gestapelte, nie verschwindende Toasts ("X failed"), die wie ein
Anwendungsfehler aussahen, aber tatsächlich nur "Backend nicht erreichbar" bedeuteten.
Teil 1 — Lokaler Review-Container (Infra, kein neuer Feature-Code)
docker-compose.dev.ymlbekommt einen neuenapp-Service, der das echte Produktions-Dockerfilebaut (Frontend in
wwwrootgebacken, vom Backend same-origin auf Port 8080 ausgeliefert) statt derHot-Reload-
dotnet watch/npm run dev-Kombination. Läuft gegen dieselbendb/redis-Services,exponiert auf
127.0.0.1:8090. Kein Vite-Dev-Proxy beteiligt — genau die Fehlerklasse, die dieDebugging-Session auslöste, kann hier gar nicht erst auftreten.
CLAUDE.mds Autonomous Loop undai/roles/00_team_overview.mds Autonomous-Loop-Beschreibungbekommen einen neuen Schritt (nach dem Push, vor dem Archivieren): den Container neu bauen/starten
und
curl -f http://localhost:8090/api/healthverifizieren, bevor der Zyklus endet. Siehedocs/dev-container.mds neuen Abschnitt "Local review container" für die vollständige Begründung.Live verifiziert, nachdem Docker Desktop (siehe unten) wieder lief:
docker compose up --build appgegen die bestehenden
db/redis-Container,curl http://localhost:8090/api/health→200 Healthy,und ein vollständiger Login+Datenabruf im echten Browser gegen
http://localhost:8090/— same-origin,kein Dev-Proxy beteiligt, exakt wie vorgesehen.
Zwischenzeitlicher Doppel-Ausfall, mitten in der Session, unabhängig von dieser Story: (1) Docker
Desktop stürzte mit einem defekten Unix-Socket-Reparse-Point unter
%LOCALAPPDATA%\Docker\run\dockerInferenceab, der sich auch nach hartem Schließen nicht löschenließ — behoben durch den Menschen (Docker Desktop neu gestartet; die tatsächliche Reparatur des
Reparse Points blieb Docker selbst überlassen, danach lief die Engine wieder sauber). (2) Diese
Maschine hat zwei unabhängige lokale Checkouts desselben Repos (
...\Git\todound...\Git\todo2, letzteres dieser Checkout) —db/redisliefen bereits unter demCompose-Projektnamen
todo(vom anderen Checkout gestartet), währenddocker composeaus diesemCheckout heraus standardmäßig einen eigenen Projektnamen
todo2annimmt und versucht hätte, einzweites
db/redis-Paar mit kollidierenden Port-Bindings anzulegen — gelöst durch explizites-p todo, um denselben Projekt-Namespace/Netzwerk zu treffen wie die bereits laufenden Container.Beide Vorfälle sind Umgebungs-/Setup-Eigenheiten dieser Maschine, keine Bugs in
docker-compose.dev.ymlselbst; nicht weiter dokumentiert, da nicht reproduzierbar ohne exakt diesen Zwei-Checkout-Aufbau.
Teil 2 — Backend-Erreichbarkeit-Anzeige (echtes Feature)
Neues, minimales Liveness-Endpoint
GET /api/health(Program.cs,MapHealthChecksmitPredicate = _ => false, also ohne die bestehendesmtp-email-Prüfung mitzuziehen) — bewusst unter/api, nicht unter dem bereits existierenden/health/email, damit Vites Dev-Proxy (der nur/api/*weiterleitet) es in jeder Dev-Topologie automatisch mitbekommt.
Frontend: neues
src/health/backendReachability.ts(Hand-rolled Pub/Sub, gleiches Muster wieofflineSync.ts) verfolgt einen eigenständigenreachable-Zustand, getrennt vonofflineSync.tssisOnline(das nurnavigator.onLinewiderspiegelt — ein falsch konfigurierter Dev-Proxy sieht davonaus wie "online").
callApi(api.tsx) ruft bei jedem fehlgeschlagenen RequestreportPossibleOutage()auf, die einen einzelnen, gebündelten
/api/health-Ping macht, bevor sie den bisherigenPro-Request-Toast unterdrückt oder zeigt — nur eine bestätigte echte Störung (auch der Ping schlägt
fehl) unterdrückt den Toast zugunsten des einen klaren Banners
(
BackendUnreachableBanner.tsx, oben inApp.tsx, sichtbar auch vor dem Login). Eineisolierte, echte App-Fehlermeldung einer einzelnen Anfrage (Ping erfolgreich) zeigt weiterhin ihren
eigenen Toast wie zuvor. Automatisches Wieder-Anpingen alle 5s, plus sofortige Erholung sobald
irgendeine andere Anfrage wieder erfolgreich ist.
Bewusst nicht angefasst:
OfflineBanner.tsx/offlineSync.ts(#97) — echtes Browser-Offline bleibtdessen Aufgabe;
reportPossibleOutagegibt sich dort sofort geschlagen (isOnline === false), umkeine zwei sich widersprechenden Banner gleichzeitig zu zeigen.
Live verifiziert, beide Richtungen: im echten Browser, mit tatsächlich unerreichbarem Backend
(ausgelöst durch den oben genannten Docker-Absturz): genau ein Banner ("Cannot reach the server.
Retrying automatically…"), null gestapelte Toasts — der exakte Gegensatz zum ursprünglich gemeldeten
Fehlerbild. Und die automatische Erholung: Backend neu gestartet, während die Seite mit sichtbarem
Banner offen blieb — ohne jede manuelle Aktion verschwand das Banner von selbst, sobald der nächste
5-Sekunden-Poll den wieder erreichbaren
/api/healthtraf (einreloadwar danach nur nötig, um denursprünglich fehlgeschlagenen Login-Check selbst erneut auszulösen — die Erreichbarkeits-Anzeige
erholt sich automatisch, ein hängengebliebener Login-Versuch nicht, das war nie Teil dieser Story).
Tests
backendReachability.test.ts(8 Tests): Ping-Bestätigung, Kurzschluss bei bereits bekanntem Ausfall,Bündelung gleichzeitiger Aufrufe, Browser-Offline-Kurzschluss, Benachrichtigung nur bei echter
Zustandsänderung, automatisches Polling/Erholung (Fake Timers).
BackendUnreachableBanner.test.tsx(2 Tests): rendert nichts wenn erreichbar, zeigt die Meldungwenn nicht.
api.test.ts: 3 bestehende Tests angepasst (differenzierter Fetch-Mock nach URL, damit einisolierter Fehler eines einzelnen Requests nicht versehentlich auch den Health-Ping mitreißt), 1
neuer Test für die Unterdrückung/Wiederherstellung des Toasts über eine ganze Sequenz.
Frontend-Testsuite grün (11 neue Tests, 3 wegen der neuen Erreichbarkeitsprüfung angepasst); Backend-Build sauber (0 Fehler, nur bereits
bestehende Warnungen); kein Docker-Testlauf dieses Mal möglich (siehe oben).