# Operations Guide — ToolCTRL everythingbutwork ## Lokale Entwicklung ```bash # Postgres (Docker) docker compose -f docker-compose.dev.yml up -d postgres # Migration anwenden cp .env.example .env pnpm --filter @cockpit/db migrate:up # API und Web pnpm --filter api dev # :3000 pnpm --filter web dev # :5173 (proxy /api+/trpc → :3000) ``` ## Authentik-Setup (Story 1.3) 1. In Authentik (auth.tool-ctrl.de) als Admin einloggen. 2. **Providers → Create → OAuth2/OpenID Provider** - Name: `cockpit` - Authorization flow: `default-provider-authorization-explicit-consent` - Client type: `Confidential` - Client ID + Secret automatisch generieren lassen, in `.env` übertragen. - Signing key: `authentik Self-signed Certificate` - Redirect URIs: `https://cockpit.tool-ctrl.de/api/auth/callback` (Prod), `http://localhost:3000/api/auth/callback` (Dev) 3. **Applications → Create** - Name: `everythingbutwork` - Slug: `cockpit` - Provider: `cockpit` - Launch URL: `https://cockpit.tool-ctrl.de/` 4. `.env`-Variablen ausfüllen: ``` AUTHENTIK_ISSUER=https://auth.tool-ctrl.de/application/o/cockpit/ AUTHENTIK_CLIENT_ID= AUTHENTIK_CLIENT_SECRET= ``` 5. Gruppen-Mapping (OQ-1) wird im API-Code per `AUTHENTIK_GROUP_TO_AREA`-Variable umgesetzt (Erweiterung in späterer Story). ## Production-Deployment ```bash # Auf der ToolCTRL-Infra: git pull docker compose pull docker compose build docker compose up -d # Migration: docker compose exec api node -e "import('@cockpit/db/client').then(async ({ createDbClient }) => { /* migrate via drizzle-kit in CI */ })" # Alternativ direkt via drizzle-kit von außen mit Production-DATABASE_URL. ``` ## Backups (Story 6.3) Tägliches `pg_dump` läuft im **Backup-Sidecar** (`docker-compose.yml` service `backup`): `scripts/backup-loop.sh` triggert `scripts/backup.sh` einmal pro Tag um `BACKUP_HOUR` (Default 03:00 Europe/Berlin). Dump im **Custom-Format** (`-Fc`, bereits komprimiert) nach `cockpit_backups:/backups` als `cockpit-.dump`. Retention `BACKUP_RETENTION_DAYS` (Default 14). Nach jedem Lauf ein Heartbeat an `POST /internal/cron/pg-dump-backup` (nur Logging — der Endpoint macht **kein** Backup). Restore-Drill quartalsweise. Konfiguration (optional, in `.env.production`): `BACKUP_HOUR`, `BACKUP_RETENTION_DAYS`. ```bash # Status / letztes Backup ansehen docker compose logs --tail=20 backup docker compose exec backup ls -lh /backups # Sofort ein Backup auslösen (außer der Reihe) docker compose exec backup /usr/local/bin/backup.sh ``` ### Restore-Anleitung 1. API stoppen: `docker compose stop api` 2. Backup aus `/backups` auswählen (`docker compose exec postgres ls -lh /backups`). 3. Restore in temporäre DB: ```bash docker compose exec postgres createdb -U cockpit cockpit_restore docker compose exec postgres pg_restore -U cockpit -d cockpit_restore /backups/.dump ``` (In die Produktiv-DB stattdessen mit `--clean --if-exists -d cockpit`.) 4. Smoke-Test: `curl http://localhost:3000/api/health` 5. API wieder starten: `docker compose start api` ## Healthcheck `GET /api/health` liefert: ```json { "status": "ok|degraded", "db": "ok|down", "authentik": "ok|down", "timestamp": "..." } ``` Wird von Docker und (Phase 2) externer Uptime-Überwachung genutzt. ## OQ-5 (Archivierung) Soft-Delete via `project.archiviert=true` + `archiviert_am`. Kein automatisches Löschen. Manuelle Bereinigung bei Bedarf durch DB-Admin via Migration.