Chore: Update-Skript erkennt den Container-Zustand, Merkposten ergänzt #10

Merged
florian.wilde merged 1 commits from chore/update-skript-und-entwicklungshinweis into main 2026-09-01 22:13:49 +00:00
2 changed files with 87 additions and 4 deletions
+15
View File
@@ -96,6 +96,9 @@ Statistiken, Benachrichtigungen, REST-API, PWA. Oberflächensprache **Deutsch**.
- **Dev-Umgebung**: Postgres auf `localhost:5439` (`docker-compose.dev.yml`), - **Dev-Umgebung**: Postgres auf `localhost:5439` (`docker-compose.dev.yml`),
Dev-Server auf **Port 3011** (3000 und 3010 sind von anderen Projekten belegt). Dev-Server auf **Port 3011** (3000 und 3010 sind von anderen Projekten belegt).
- **Screenshots**: `node scripts/shot.mjs <url> <ziel.png> [w] [h] [theme]`. - **Screenshots**: `node scripts/shot.mjs <url> <ziel.png> [w] [h] [theme]`.
Achtung: das Skript meldet sich **nicht** an — bei geschützten Seiten entsteht
kommentarlos ein Bild der Anmeldemaske. Für angemeldete Ansichten den
Login-Weg aus `scripts/screenshots.mjs` nachbauen.
- Next hängt selbst einen Block an diese Datei an — der bleibt drin. - Next hängt selbst einen Block an diese Datei an — der bleibt drin.
## Fortschritt ## Fortschritt
@@ -119,6 +122,18 @@ Statistiken, Benachrichtigungen, REST-API, PWA. Oberflächensprache **Deutsch**.
das ASCII-Schlusszeichen beendet den String. In JSX-Text und Kommentaren ok. das ASCII-Schlusszeichen beendet den String. In JSX-Text und Kommentaren ok.
- Heredocs im Bash-Tool sind bei langen TSX-Dateien unzuverlässig — dann das - Heredocs im Bash-Tool sind bei langen TSX-Dateien unzuverlässig — dann das
Write-Werkzeug benutzen. Write-Werkzeug benutzen.
- **Klickwege niemals gegen `npm run dev` prüfen.** Unter headless Chromium
scheitert der HMR-Socket (`ERR_INVALID_HTTP_RESPONSE`), dadurch hydratisiert
**keine** Seite und kein Knopf reagiert — ohne Seitenfehler, ohne
fehlgeschlagene Anfrage, es passiert einfach nichts. Sieht aus wie ein Fehler
im eigenen Code, ist aber die Umgebung. Stattdessen
`npm run build` und `PORT=3012 npm start`, dann dagegen klicken.
Formulare täuschen zusätzlich: die Anmeldung funktioniert auch ohne
JavaScript, wirkt also intakt.
- Vor `npm start` prüfen, ob der Port noch von einem früheren Lauf belegt ist —
sonst startet der neue Server gar nicht und man testet den alten Bau.
- Testdaten nach Klickproben wieder herstellen: die Proben schreiben in die
geseedete Entwicklungsdatenbank.
<!-- BEGIN:nextjs-agent-rules --> <!-- BEGIN:nextjs-agent-rules -->
+69 -1
View File
@@ -39,6 +39,10 @@ Ablauf: Datenbank sichern → Änderungen holen → Image bauen → neu starten
warten, bis die Instanz wieder antwortet. Die Datenbankmigrationen spielt der warten, bis die Instanz wieder antwortet. Die Datenbankmigrationen spielt der
Container beim Start selbst ein. Container beim Start selbst ein.
Geprüft wird zuerst http://127.0.0.1:APP_PORT/api/health. Ist der Port gar
nicht auf dem Host veröffentlicht — üblich hinter einem Reverse Proxy —,
zählt stattdessen der Healthcheck des Containers.
Optionen: Optionen:
--ohne-backup Keine Sicherung anlegen (nicht empfohlen) --ohne-backup Keine Sicherung anlegen (nicht empfohlen)
--ohne-pull Nichts aus dem Repository holen, nur neu bauen und starten --ohne-pull Nichts aus dem Repository holen, nur neu bauen und starten
@@ -196,31 +200,95 @@ gut "Container laufen."
schritt "Auf die Instanz warten" schritt "Auf die Instanz warten"
info "Die Datenbankmigrationen spielt der Container beim Start selbst ein." info "Die Datenbankmigrationen spielt der Container beim Start selbst ein."
# Der Container meldet seinen Zustand selbst — der HEALTHCHECK im Image fragt
# /api/health von innen ab. Das ist der verlässlichere Weg: hinter einem
# Reverse Proxy ist der App-Port oft gar nicht auf dem Host veröffentlicht,
# und dann sagt ein fehlschlagendes curl nichts über die Instanz aus.
# Gibt immer 0 zurück: die Funktion läuft auch im Fehlerpfad, und unter
# `set -e` dürfte eine Auskunft über den Zustand nicht selbst das Skript
# abbrechen, bevor der Weg zurück ausgegeben wurde.
container_zustand() {
local id
id=$($COMPOSE ps -q app 2>/dev/null || true)
if [ -z "$id" ]; then
printf 'kein-container'
return 0
fi
# Ohne HEALTHCHECK im Image ist .State.Health leer — dann bleibt der
# Laufzustand (running/exited) als grobe Auskunft.
docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}ohne-healthcheck:{{.State.Status}}{{end}}' \
"$id" 2>/dev/null || printf 'unbekannt'
return 0
}
GESUND=0 GESUND=0
UEBER_CONTAINER=0
for _ in $(seq 1 60); do for _ in $(seq 1 60); do
if curl -fsS "http://127.0.0.1:${PORT}/api/health" >/dev/null 2>&1; then if curl -fsS "http://127.0.0.1:${PORT}/api/health" >/dev/null 2>&1; then
GESUND=1 GESUND=1
break break
fi fi
if [ "$(container_zustand)" = "healthy" ]; then
GESUND=1
UEBER_CONTAINER=1
break
fi
sleep 2 sleep 2
done done
if [ "$GESUND" -eq 1 ]; then if [ "$GESUND" -eq 1 ]; then
if [ "$UEBER_CONTAINER" -eq 1 ]; then
gut "Der Container meldet sich gesund."
leise "Auf Port ${PORT} war nichts zu erreichen — das ist normal, wenn die App"
leise "nur über einen Reverse Proxy erreichbar ist und den Port nicht veröffentlicht."
else
ANTWORT=$(curl -fsS "http://127.0.0.1:${PORT}/api/health" 2>/dev/null || true) ANTWORT=$(curl -fsS "http://127.0.0.1:${PORT}/api/health" 2>/dev/null || true)
gut "Flimmer antwortet auf Port ${PORT}." gut "Flimmer antwortet auf Port ${PORT}."
leise "$ANTWORT" leise "$ANTWORT"
fi
printf '\n%s✓ Fertig — Version %s%s\n' "$GUT" "$NEUE_VERSION" "$AUS" printf '\n%s✓ Fertig — Version %s%s\n' "$GUT" "$NEUE_VERSION" "$AUS"
if [ "$VORHER_VERSION" != "$NEUE_VERSION" ]; then if [ "$VORHER_VERSION" != "$NEUE_VERSION" ]; then
info "Was sich geändert hat, steht in CHANGELOG.md." info "Was sich geändert hat, steht in CHANGELOG.md."
fi fi
[ -n "$SICHERUNG" ] && leise "Sicherung: $SICHERUNG" if [ -n "$SICHERUNG" ]; then
leise "Sicherung: $SICHERUNG"
fi
exit 0 exit 0
fi fi
# --- Fehlschlag: konkreter Weg zurück ---------------------------------------- # --- Fehlschlag: konkreter Weg zurück ----------------------------------------
printf '\n%s✗ Die Instanz antwortet nach zwei Minuten nicht.%s\n\n' "$FEHLER" "$AUS" >&2 printf '\n%s✗ Die Instanz antwortet nach zwei Minuten nicht.%s\n\n' "$FEHLER" "$AUS" >&2
# Der Container-Zustand grenzt ein, wo es klemmt — ohne ihn sähe ein nicht
# veröffentlichter Port genauso aus wie eine abgestürzte App.
ZUSTAND=$(container_zustand)
case "$ZUSTAND" in
kein-container)
info "Es läuft gar kein app-Container. Der Start ist offenbar fehlgeschlagen."
;;
starting)
info "Der Container startet noch. Möglicherweise dauern die Migrationen länger —"
info "sieh im Log nach und gib ihm etwas Zeit."
;;
unhealthy)
info "Der Container läuft, meldet sich aber als nicht gesund. Der Fehler liegt"
info "also in der Anwendung, nicht am Port."
;;
ohne-healthcheck:running)
info "Der Container läuft, das Image bringt aber keinen Healthcheck mit (ältere"
info "Fassung). Ob die App wirklich antwortet, verrät nur das Log."
;;
ohne-healthcheck:*)
info "Der Container ist nicht gelaufen: ${ZUSTAND#ohne-healthcheck:}"
;;
*)
info "Container-Zustand: ${ZUSTAND}"
;;
esac
printf '\n'
info "Log ansehen:" info "Log ansehen:"
printf ' %s logs --tail 50 app\n\n' "$COMPOSE" printf ' %s logs --tail 50 app\n\n' "$COMPOSE"