feat(deploy): publicsite-Container intern (Port 8081) + app.update im Deploy-Skript
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 1m9s
CI / Frontend Tests (Node/Vite) (push) Successful in 9m34s
CI / Docker Build & Push (push) Successful in 1m29s
CI / Deploy auf TrueNAS (Custom App) (push) Failing after 3s

- custom-app.compose.yaml: publicsite (nginx) ergaenzt, LAN-only, statisches HTML aus
  publicsite-Volume (POST /api/publish); PUBLICSITE_PORT-Platzhalter
- truenas-deploy.sh: bei existierender App app.update (statt nur redeploy), damit
  Compose-Aenderungen (neue Dienste) uebernommen werden
- CLAUDE.md: 5. Dienst dokumentiert

Verifiziert: publicsite Up auf 8081, publish -> HTTP 200 (inkl. abgabetiere-Seite).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-19 14:24:54 +02:00
parent 1484d04917
commit 0a4bcabd98
3 changed files with 45 additions and 12 deletions

View File

@@ -38,6 +38,7 @@ set -a; . "$ENV_FILE"; set +a
export REGISTRY="${REGISTRY:-git.rismer.de/gulum}"
export TAG="${TAG:-latest}"
export PORT="${PORT:-8090}"
export PUBLICSITE_PORT="${PUBLICSITE_PORT:-8081}"
log "=== Deploy $APP_NAME (TAG=$TAG, PORT=$PORT) ==="
@@ -54,36 +55,49 @@ log "Ziehe Images ..."
docker pull "$REGISTRY/gerbilmanager-api:$TAG" || fail "docker pull api fehlgeschlagen"
docker pull "$REGISTRY/gerbilmanager-frontend:$TAG" || fail "docker pull frontend fehlgeschlagen"
# --- Vorlage rendern + midclt-Payload bauen (python: sichere Escapes) ---
PAYLOAD_FILE="$(mktemp)"
trap 'rm -f "$PAYLOAD_FILE"' EXIT
python3 - "$TEMPLATE" > "$PAYLOAD_FILE" <<'PY'
import sys, os, json
# --- Vorlage rendern (python: sichere Substitution) ---
RENDERED="$(mktemp)"
trap 'rm -f "$RENDERED"' EXIT
python3 - "$TEMPLATE" > "$RENDERED" <<'PY'
import sys, os
tmpl = open(sys.argv[1], encoding="utf-8").read()
repl = {
"__POSTGRES_PASSWORD__": os.environ["POSTGRES_PASSWORD"],
"__REGISTRY__": os.environ.get("REGISTRY", "git.rismer.de/gulum"),
"__TAG__": os.environ.get("TAG", "latest"),
"__PORT__": os.environ.get("PORT", "8090"),
"__PUBLICSITE_PORT__": os.environ.get("PUBLICSITE_PORT", "8081"),
"__AI_BASEURL__": os.environ.get("AI__BaseUrl", ""),
"__AI_APIKEY__": os.environ.get("AI__ApiKey", ""),
"__AI_MODEL__": os.environ.get("AI__Model", "gemini-flash-latest"),
}
for k, v in repl.items():
tmpl = tmpl.replace(k, v)
print(json.dumps({"custom_app": True, "app_name": "gerbilmanager",
"custom_compose_config_string": tmpl}))
sys.stdout.write(tmpl)
PY
# midclt-Payload bauen: create braucht app_name+custom_app, update nur die Compose.
build_payload() { # $1 = create|update
python3 - "$RENDERED" "$1" <<'PY'
import sys, json
compose = open(sys.argv[1], encoding="utf-8").read()
if sys.argv[2] == "create":
print(json.dumps({"custom_app": True, "app_name": "gerbilmanager",
"custom_compose_config_string": compose}))
else:
print(json.dumps({"custom_compose_config_string": compose}))
PY
}
# --- Existiert die App schon? ---
EXISTS="$(midclt call app.query "[[\"name\",\"=\",\"$APP_NAME\"]]" 2>/dev/null | python3 -c 'import sys,json; print(len(json.load(sys.stdin)))' 2>/dev/null || echo 0)"
if [ "$EXISTS" -ge 1 ]; then
log "App existiert -> redeploy (frische Images sind bereits gezogen)"
midclt call app.redeploy "$APP_NAME" >/dev/null || fail "app.redeploy fehlgeschlagen"
log "App existiert -> app.update (Compose-Aenderungen uebernehmen, frische Images gezogen)"
midclt call app.update "$APP_NAME" "$(build_payload update)" >/dev/null || fail "app.update fehlgeschlagen"
else
log "App fehlt -> app.create (Custom App)"
midclt call app.create "$(cat "$PAYLOAD_FILE")" >/dev/null || fail "app.create fehlgeschlagen"
midclt call app.create "$(build_payload create)" >/dev/null || fail "app.create fehlgeschlagen"
fi
# --- Auf Gesundheit warten (Frontend proxyt /api/health -> API) ---