Files
certvia/docs/HANDOVER-DEVOPS.md
T
msolarczekandClaude Opus 4.8 71361df588 Übergabe-Dokument: DevOps (Deployment Test → Produktiv)
docs/HANDOVER-DEVOPS.md: Runtime-Architektur (Next standalone + Postgres/pgvector/
Redis/MinIO/Mailhog), Umgebungsvariablen, Build/Start, kritische Migrations-/
Bootstrap-Strategie (Migrationen laufen nicht beim Container-Start; erster
Superadmin fehlt), Persistenz/Backup, bekannte Lücken (worker-Script fehlt, MinIO-
Env, Reverse-Proxy/TLS, Healthcheck), Test-vs-Prod-Unterschiede, Deploy-Checkliste.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 10:58:46 +02:00

123 lines
7.5 KiB
Markdown

# DevOps-Übergabe — ISMS-Tool (Deployment Test → Produktiv)
> Stand: 2026-07-20 · Branch `main` · Commit `081c000`
> Zweck: Betrieb/Deployment. Gemeinsame Arbeit an Dockerfile, Einrichtung Testserver (remote), danach Produktivserver.
> Ergänzt: `docs/HANDOVER-DEV.md` (App-Architektur/Setup) und `docs/HANDOVER-PM.md` (fachlicher Status).
---
## 1. Überblick der Runtime
Die App ist eine **Next.js-16-Anwendung im Standalone-Modus** (`output: "standalone"` in `next.config`, Start via `node server.js`), zustandslos horizontal skalierbar. Zustand liegt ausschließlich in den Backing-Services.
| Service | Image / Herkunft | Port | Zweck | Persistenz |
|--------|------------------|------|-------|-----------|
| **app** | Multi-Stage-Build (`Dockerfile`) | 3000 | Web-App (Next.js standalone) | zustandslos |
| **postgres** | `pgvector/pgvector:pg16` | 5432 | Primärdatenbank (inkl. `vector`-Extension) | Volume `pgdata` |
| **redis** | `redis:7-alpine` | 6379 | Cache/Queue (für späteren BullMQ-Worker) | Volume `redisdata` |
| **minio** | `minio/minio:latest` | 9000/9001 | Objektspeicher (noch **ungenutzt**; für kommenden Logo-/Datei-Upload) | Volume `miniodata` |
| **mailhog** | `mailhog/mailhog` (Profil `dev`) | 1025/8025 | SMTP-Fang für Entwicklung | — |
| **worker** | s. Dockerfile (Profil `worker`) | — | **noch nicht lauffähig** (kein `worker`-npm-Script vorhanden) | — |
Alles bereits als **`docker-compose.yml`** im Repo-Root beschrieben; **`Dockerfile`** ist ein sauberer 3-Stage-Build (`deps``builder` mit `prisma generate` + `next build` → schlanker `runner` als non-root `app`-User).
---
## 2. Umgebungsvariablen (`.env`)
Vorlage: **`.env.example`**. Vollständige Liste:
| Variable | Zweck | Prod-Hinweis |
|----------|-------|-------------|
| `POSTGRES_USER` / `POSTGRES_PASSWORD` / `POSTGRES_DB` | Compose-Init von Postgres | **Secret** (Passwort) |
| `DATABASE_URL` | Prisma-Verbindungsstring | **Secret**; muss auf denselben DB-Nutzer/-Namen zeigen |
| `REDIS_URL` | Redis-Verbindung | — |
| `AUTH_SECRET` | NextAuth-Signaturschlüssel (JWT) | **Secret**, zwingend gesetzt & stark |
| `AUTH_URL` | Öffentliche Basis-URL der App | pro Umgebung (Test/Prod) unterschiedlich, inkl. `https://` |
| `AI_PROVIDER` / `AI_API_KEY` | KI-Chat / KI-Formulierungshilfe (noch ungenutzt) | Secret, optional |
| `SMTP_HOST/PORT/USER/PASSWORD/FROM` | E-Mail (noch ungenutzt; Einladungs-/Benachrichtigungsflow offen) | Secret, optional |
| `MINIO_ROOT_USER` / `MINIO_ROOT_PASSWORD` | Objektspeicher | **fehlen in `.env.example`** → für Prod ergänzen (sonst Compose-Defaults `isms`/`isms-secret`) |
> **Secrets** gehören nicht ins Git. Für Prod: Secret-Management (Docker Secrets / Env aus Vault / CI-Variablen). `.env.example` enthält nur Namen/Defaults.
---
## 3. Build & Start
```bash
# Image bauen
docker compose build app
# Test/lokal hochfahren (ohne dev-only mailhog)
docker compose up -d postgres redis minio app
# mit Mailhog (Dev): docker compose --profile dev up -d
# Worker (aktuell NICHT lauffähig, s. §6): docker compose --profile worker up -d worker
```
App danach unter `AUTH_URL` (Port 3000) erreichbar.
---
## 4. ⚠️ Datenbank-Migrationen & Bootstrap (kritisch)
**Der App-Container führt KEINE Migrationen beim Start aus** (CMD ist `node server.js`). Migrationen und das erste Provisioning sind ein **separater Deploy-Schritt**:
1. **Migrationen anwenden:** `npx prisma migrate deploy` gegen die Ziel-DB.
- Die `runner`-Stage enthält Prisma-CLI/`tsx` **nicht** (nur Runtime-Trace). Migrationen daher aus der **`builder`-Stage** (voller `node_modules`) oder aus einem eigenen **Migrations-Job/CI-Step** fahren. → **Designentscheidung mit DevOps** (z. B. Init-Container `command: npx prisma migrate deploy` mit builder-Image, `restart: "no"`).
- Die Init-Migration legt `CREATE EXTENSION IF NOT EXISTS "vector"` an (pgvector) — das Postgres-Image bringt die Extension mit.
2. **Erster Mandant / Superadmin (Prod):** Der Demo-Seed (`prisma/seed.ts`) ist **nur für Entwicklung** (Demo-Mandant + Testnutzer) — **nicht in Produktion ausführen**. In Prod erfolgt das Anlegen von Kunden über die **Admin-Konsole** (`provisionTenant`). **Offen:** Es gibt aktuell **kein Bootstrap-Skript** für den allerersten Plattform-Admin — dieser muss initial angelegt werden (Skript/One-Off gegen `provisionTenant` mit `isPlatformAdmin: true`, oder manuell). → **Mit App-Entwickler abstimmen** (kleiner Task).
---
## 5. Persistenz, Backup & Restore
- **Volumes:** `pgdata` (kritisch), `miniodata` (künftig Uploads), `redisdata` (unkritisch, Cache).
- **Backups Prod:** regelmäßiger `pg_dump` (logisch) oder Volume-/Snapshot-Backup; MinIO-Bucket-Backup, sobald Uploads aktiv. Aufbewahrung + Restore-Test einplanen (DSGVO-Löschkonzept ist app-seitig noch offen).
- Mandantentrennung ist **logisch** (eine DB, `tenant_id` + Postgres-RLS + App-Guard) — Backups umfassen alle Mandanten gemeinsam.
---
## 6. Bekannte Lücken / To-dos für DevOps
1. **`worker`-Service nicht lauffähig:** Es existiert **kein `npm run worker`**-Script (BullMQ-Scheduler ist app-seitig noch nicht implementiert). Profil `worker` bis dahin **nicht** starten.
2. **Migrations-/Bootstrap-Strategie** festlegen (§4) — Migrations-Job + Erst-Superadmin.
3. **MinIO-Env** in `.env` für Prod ergänzen; MinIO wird erst mit dem kommenden Logo-/Datei-Upload wirklich genutzt (Bucket-Präfix je Mandant vorgesehen).
4. **Reverse-Proxy + TLS** vor der App (Port 3000 nicht direkt exponieren): Traefik/Caddy/nginx mit HTTPS; `AUTH_URL` auf die öffentliche `https://`-Adresse setzen. Rate-Limiting/IP-Härtung für Login/Admin einplanen.
5. **Ressourcen/Skalierung:** `app` ist zustandslos → mehrere Replicas möglich; Sticky-Sessions nicht nötig (JWT). Postgres/Redis als Singleton bzw. Managed-Service.
6. **Health/Observability:** Postgres-Healthcheck vorhanden; für `app` einen HTTP-Healthcheck/Readiness ergänzen (derzeit keiner definiert). Log-Aggregation + Alerting einrichten.
7. **`AUTH_SECRET`** je Umgebung eindeutig & stark; bei Rotation invalidieren alle Sessions.
---
## 7. Test- vs. Produktivumgebung — Unterschiede
| Aspekt | Test (Remote) | Produktiv |
|--------|---------------|-----------|
| Daten | ggf. Demo-Seed erlaubt | **kein Demo-Seed**; nur echtes Provisioning |
| Secrets | Test-Werte | echte Secrets aus Secret-Store |
| Mail | Mailhog (Profil `dev`) | echtes SMTP-Relay |
| TLS | optional/self-signed | verpflichtend, gültiges Zertifikat |
| Backups | optional | verpflichtend + Restore-Test |
| Skalierung | 1 Replica | ≥ 2 App-Replicas hinter Proxy |
---
## 8. Deploy-Checkliste (Kurz)
**Testserver:**
1. Repo klonen/pullen (Gitea, Branch `main`).
2. `.env` aus `.env.example` mit Test-Werten (inkl. `MINIO_*`).
3. `docker compose build app`.
4. `docker compose up -d postgres redis minio`.
5. **Migrationen:** `prisma migrate deploy` (builder-Image/Job).
6. **Erst-Superadmin** anlegen (One-Off, s. §4) — für Test ggf. Demo-Seed ok.
7. `docker compose up -d app`; Reverse-Proxy/TLS davor; Smoke-Test (Login, Admin-Konsole, Modul-Seite).
**Produktivserver:** wie oben, aber Secret-Store, **kein** Demo-Seed, TLS verpflichtend, Backups + Monitoring aktiv, ≥ 2 App-Replicas, Migrations-/Bootstrap-Schritt in die Deploy-Pipeline integriert.
---
## 9. Referenzen im Repo
`Dockerfile`, `docker-compose.yml`, `.env.example`, `next.config.*` (`output: standalone`), `prisma/schema.prisma` + `prisma/migrations/**` (inkl. RLS-Policies & pgvector), `prisma/seed.ts` (nur Dev), `src/server/provision.ts` (Provisioning-Logik für Prod-Onboarding).