#!/usr/bin/env bash # Startet Hugin lokal mit Beispieldaten zum Ausprobieren. # # scripts/demo.sh # Server auf http://127.0.0.1:8080, Daten in .demo/ # scripts/demo.sh --neu # Beispieldaten verwerfen und neu anlegen # HOST=0.0.0.0 scripts/demo.sh # auch von anderen Rechnern erreichbar (z. B. Windows-Test) # HUGIN_DATABASE_URL=postgresql+psycopg://hugin:hugin@127.0.0.1:55432/hugin scripts/demo.sh # # mit der PostgreSQL aus docker-compose.yml # # Beim ersten Start legt das Skript Tenants, Projekte, Personen und Keys an, # veröffentlicht die Beispielpakete und schreibt alle Keys nach .demo/keys.txt. set -euo pipefail RESET="" case "${1:-}" in "") ;; --neu|--new) RESET=1 ;; *) echo "Unbekannt: $1 (erlaubt: --neu)"; exit 2 ;; esac ROOT="$(cd "$(dirname "$0")/.." && pwd)" DEMO="$ROOT/.demo" PORT="${PORT:-8080}" URL="http://127.0.0.1:$PORT" mkdir -p "$DEMO" if [[ -n "${HUGIN_DATABASE_URL:-}" ]]; then # Eigene Datenbank (z. B. PostgreSQL): die Keys gehören zu dieser Datenbank KEYS="$DEMO/keys-$(printf '%s' "$HUGIN_DATABASE_URL" | shasum | cut -c1-8).txt" if [[ -n "$RESET" ]]; then echo "--neu mit eigener Datenbank: Daten dort selbst löschen, z. B. docker compose down -v"; exit 2 fi else # Nur die SQLite-Demo verwerfen; Keys anderer Datenbanken (keys-*.txt) bleiben [[ -n "$RESET" ]] && rm -f "$DEMO"/hugin.db* "$DEMO/keys.txt" "$DEMO/server.log" export HUGIN_DATABASE_URL="sqlite:///$DEMO/hugin.db" KEYS="$DEMO/keys.txt" fi export HUGIN_ADMIN_TOKEN="${HUGIN_ADMIN_TOKEN:-demo-admin}" ADMIN=(-H "Authorization: Bearer $HUGIN_ADMIN_TOKEN") if ! (cd "$ROOT/server" && uv run -q hugin-server migrate 2>"$DEMO/migrate.log"); then tail -1 "$DEMO/migrate.log" echo "Migration gescheitert; die Datenbank stammt vermutlich von einem älteren Stand (ganzer Fehler: $DEMO/migrate.log)." echo "Neu anlegen: bei SQLite 'scripts/demo.sh --neu'," echo "bei PostgreSQL aus docker-compose.yml 'docker compose down -v && docker compose up -d'." exit 1 fi if [[ -f "$KEYS" ]]; then echo "Beispieldaten vorhanden (.demo/). Keys: $KEYS" else (cd "$ROOT/server" && exec uv run -q hugin-server run --host "${HOST:-127.0.0.1}" --port "$PORT") >"$DEMO/server.log" 2>&1 & SERVER=$! trap 'kill $SERVER 2>/dev/null; wait $SERVER 2>/dev/null || true' EXIT for _ in $(seq 60); do curl -fsS "$URL/readyz" >/dev/null 2>&1 && break; sleep 0.25; done if curl -fsS "${ADMIN[@]}" "$URL/api/v1/admin/tenants" 2>/dev/null | grep -q '"plattform"'; then echo "Die Datenbank enthält schon Demo-Daten, aber die Keys dazu fehlen ($KEYS)." echo "Neu anlegen: bei PostgreSQL aus docker-compose.yml 'docker compose down -v && docker compose up -d'," echo "bei SQLite 'scripts/demo.sh --neu'." exit 1 fi api() { curl -fsS -H "Content-Type: application/json" "$@"; } field() { python3 -c "import json,sys; print(json.load(sys.stdin)['$1'])"; } for t in plattform:kern shop:api shop:web; do api "${ADMIN[@]}" "$URL/api/v1/admin/tenants" -d "{\"slug\":\"${t%%:*}\",\"name\":\"${t%%:*}\"}" >/dev/null 2>&1 || true api "${ADMIN[@]}" "$URL/api/v1/admin/tenants/${t%%:*}/projects" -d "{\"slug\":\"${t##*:}\",\"name\":\"${t##*:}\"}" >/dev/null done person() { api "${ADMIN[@]}" "$URL/api/v1/admin/tenants/$1/people" -d "$2" | field key; } key() { api "${ADMIN[@]}" "$URL/api/v1/admin/tenants/$1/keys" -d "$2" | field key; } AUTHOR=$(person plattform '{"name":"Autor","mail":"autor@firma.de","project":"kern","roles":["pub_author"]}') REVIEWER=$(person plattform '{"name":"Prüfer","mail":"pruefer@firma.de","roles":["pub_reviewer"]}') REVIEWER2=$(person plattform '{"name":"Prüfer 2","mail":"pruefer2@firma.de","roles":["pub_reviewer"]}') ADMIN_PERSON=$(person plattform '{"name":"Admin","mail":"admin@firma.de","roles":["pub_reviewer","tenant_admin"]}') SHOP_ADMIN=$(key shop '{"kind":"tenant","name":"Shop-Admin"}') SHOP_CI=$(key shop '{"kind":"project","name":"Shop CI","project":"api"}') SHOP_INT=$(key shop '{"kind":"integration","name":"Softwareverteilung"}') publish() { local zip="$DEMO/package.zip" rm -f "$zip"; (cd "$ROOT/contract/examples/packages/$1" && zip -qr "$zip" .) curl -fsS -H "Authorization: Bearer $AUTHOR" -H "Content-Type: application/zip" --data-binary "@$zip" "$URL/api/v1/drafts" >/dev/null local base="$URL/api/v1/packages/${1%/*}/versions/${1#*/}" api -H "Authorization: Bearer $AUTHOR" -X POST "$base/submit" >/dev/null [[ "${2:-}" == "open" ]] || api -H "Authorization: Bearer $REVIEWER" "$base/approve" -d '{"comment":"Demo"}' >/dev/null } for p in pub-munin-nutzen/1.4.0 pub-hausregeln/1.0.0 pub-munin-anbindung/1.0.0 pub-release-notiz/1.0.0 pub-code-review/1.0.0; do publish "$p" done # Pakete für den Alltag: Skills, Befehle und Subagenten zum Ausprobieren for p in pub-schlank pub-doku-schreiben pub-grill-me pub-fehlersuche pub-erklaeren pub-plan pub-commit-text \ pub-recherche pub-doku-pruefer pub-sicherheits-review; do publish "$p/1.0.0" done publish pub-munin-nutzen/1.5.0 open # liegt bei den Prüfungen curl -fsS "${ADMIN[@]}" -X PUT -H "Content-Type: application/json" "$URL/api/v1/admin/mandatory/pub-munin-anbindung" -d '{"tenant":null}' api -H "Authorization: Bearer $SHOP_CI" "$URL/api/v1/usage" \ -d '{"repo":"git.intern/shop/api","tools":{"claude":"2.1.302","opencode":"1.15.4"},"installed":{"pub-munin-nutzen":"1.4.0","pub-hausregeln":"1.0.0"}}' >/dev/null cat > "$KEYS" </dev/null; wait $SERVER 2>/dev/null || true trap - EXIT fi cat "$KEYS" echo echo "Weboberfläche: $URL API-Doku: $URL/api/docs MCP: $URL/mcp" echo "Beenden mit Strg+C." cd "$ROOT/server" && exec uv run -q hugin-server run --host "${HOST:-127.0.0.1}" --port "$PORT"