services: api: build: context: ./api dockerfile: docker/Dockerfile volumes: - ./api:/app # Optional: echte status.txt aus der Produktion zum Testen einbinden, z.B. # - ./status.txt:/status.txt:ro working_dir: /app # Achtung: Eine Aenderung des Host-Ports muss in .env (MONITOR_API_BASE) nachgezogen # werden - das Frontend laeuft im Browser und erreicht die API nicht ueber das # Compose-Netzwerk, sondern ueber genau diesen Port. ports: - "8091:8080" environment: # Der eingebaute PHP-Server arbeitet Anfragen sonst streng nacheinander ab: eine einzige # offene SSE-Verbindung (GET /api/v1/stream, bis zu 60s) blockiert damit jede weitere # Anfrage - gemessen 16s fuer ein GET /api/v1/tickets. Ab dem zweiten offenen Monitor # laeuft die API praktisch dauerhaft dicht, das Frontend faellt auf Demo-Daten zurueck # und der PO reagiert dann auf nichts mehr (Fehlerbericht zu Issue #27). PHP_CLI_SERVER_WORKERS: 4 MONITOR_DB_PATH: /app/data/monitor.sqlite MONITOR_ADMIN_API_KEY: ${MONITOR_ADMIN_API_KEY:-dev-admin-key} MONITOR_STATUS_FILE: /status.txt MONITOR_DESK_COUNT: 8 MONITOR_SSE_MAX_ITERATIONS: 30 MONITOR_SSE_POLL_INTERVAL: 2 MONITOR_SYNC_TRIGGER_FILE: /app/data/sync-requested CODEBERG_API_BASE: https://codeberg.org/api/v1 CODEBERG_TOKEN: ${CODEBERG_TOKEN:-} # Secret des Codeberg-Webhooks. Ohne diesen Wert weist POST /api/v1/webhooks/codeberg # jede Anfrage mit 401 ab - der Endpunkt ist aus dem Internet erreichbar und die # Signatur ist sein einziger Schutz. CODEBERG_WEBHOOK_SECRET: ${CODEBERG_WEBHOOK_SECRET:-} # Zaehldatei fuer den Hooks-KPI (Issue #38, GET /api/v1/webhooks/stats): wird bei jedem # Start dieses Containers von entrypoint.sh auf 0 zurueckgesetzt. MONITOR_HOOKS_COUNTER_FILE: /app/data/hooks-count # Haelt Backlog/Done aus Codeberg aktuell (F4, siehe API.md Abschnitt "Codeberg-Sync"): # laeuft dasselbe Image wie api und teilt sich ueber das ./api-Volume dieselbe SQLite-Datei. # Ohne diesen Service bleibt das Board leer, solange kein Agent selbst Tickets meldet. # # Der Watch-Modus laeuft aus zwei Gruenden: periodisch alle MONITOR_SYNC_INTERVAL Sekunden # und sofort, wenn der api-Container ueber die Trigger-Datei einen Codeberg-Webhook # weiterreicht (siehe Sync\SyncTrigger). Mit funktionierendem Webhook ist das Intervall nur # noch das Sicherheitsnetz fuer verpasste Zustellungen und darf deshalb gross sein. # # Dieser Service selbst baut weiterhin nur ausgehende Verbindungen auf und braucht kein # Port-Mapping. Die eingehende Freigabe betrifft ausschliesslich den api-Service, ueber den # Codeberg den Webhook zustellt. sync: build: context: ./api dockerfile: docker/Dockerfile volumes: - ./api:/app working_dir: /app restart: unless-stopped depends_on: - api environment: MONITOR_DB_PATH: /app/data/monitor.sqlite MONITOR_SYNC_INTERVAL: ${MONITOR_SYNC_INTERVAL:-600} MONITOR_SYNC_TRIGGER_FILE: /app/data/sync-requested CODEBERG_API_BASE: https://codeberg.org/api/v1 CODEBERG_TOKEN: ${CODEBERG_TOKEN:-} command: php bin/sync-codeberg.php --watch # Statisches Frontend (html/) - Phase 2 der Neuausrichtung (Buero-Visualisierung). # Nur zur lokalen Ansicht/Entwicklung, kein Build-Schritt noetig (Vanilla HTML/CSS/JS). web: image: nginx:alpine volumes: - ./html:/usr/share/nginx/html:ro # Ueberlagert den Platzhalter html/API.md - der muss existieren, weil in # einem read-only gemounteten Verzeichnis kein Mountpoint angelegt werden kann. - ./API.md:/usr/share/nginx/html/API.md:ro # Setzt office.html als Einstiegsseite (sonst 403 auf der Basis-URL) und liefert # /config.js aus. Als Template gemountet, damit das nginx-Image beim Start # MONITOR_API_BASE per envsubst einsetzt (Ausgabe: /etc/nginx/conf.d/default.conf). - ./docker/nginx/default.conf.template:/etc/nginx/templates/default.conf.template:ro environment: # Wird in docker/nginx/default.conf.template eingesetzt und als /config.js an den # Browser ausgeliefert. Leer = gleicher Origin (relatives /api/v1). MONITOR_API_BASE: ${MONITOR_API_BASE:-} # Speist nur den kosmetischen Reload-Countdown im Header (Issue #12) - gleicher # Default wie beim sync-Service oben, damit die Anzeige zur tatsaechlichen # Sync-Frequenz passt, wenn MONITOR_SYNC_INTERVAL nicht gesetzt ist. MONITOR_SYNC_INTERVAL: ${MONITOR_SYNC_INTERVAL:-600} ports: - "8090:80" # Fuehrt die Node-basierten Frontend-Tests (tests/frontend/) aus. Node/npm sind nur im # Container noetig, nicht auf dem Host (analog zum api-Service mit PHP/Composer). # Node >= 21 noetig: das Test-Skript in package.json uebergibt ein Glob-Muster an # "node --test", das aeltere Versionen als Dateinamen lesen und nicht aufloesen. frontend: image: node:24-alpine working_dir: /app volumes: - .:/app command: npm test