Infra: Worker/Garage/Test-Runner

- docker-compose.yml: explizite Build-Targets (runner/migrate) — Ursache für
  "npx not found" bei garage-provision war das Default-Target (letzte Stage =
  Garage-Image ohne Node); worker startet npm run worker:mail; Defaults craftvia
- Coolify-Compose: incident-inbound-worker und sync-policy-templates entfernt,
  Rollen-/Bucket-/Image-Namen auf craftvia
- Dockerfile: seed/ und docs/wizard-uebergabe entfernt, messages/ im Runner
- npm: Name craftvia, Scripts test (scripts/run-tests.ts) und gate, ISMS-Pakete
  entfernt (handlebars, marked, sanitize-html, @xyflow/react, @dagrejs/dagre,
  html-to-image, imapflow, mailparser, exceljs, @dnd-kit/core)
- .env-Beispiele, launch.json (craftvia-dev), CI-Kommentare umbenannt

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-14 11:44:58 +02:00
co-authored by Claude Opus 5
parent 6f3f5a5947
commit ba7d6ac3ed
45 changed files with 167 additions and 7932 deletions
+3 -46
View File
@@ -23,7 +23,7 @@ services:
build:
context: .
target: migrate
command: sh -c "npx prisma migrate deploy && echo '>> Rollen-Rechte-Sync läuft…' && npx tsx scripts/sync-role-permissions.ts && echo '>> Vorlagen-Sync läuft…' && npx tsx scripts/sync-policy-templates.ts && if [ \"$$RUN_DEMO_SEED\" = \"true\" ]; then echo '>> Demo-Seed läuft…'; npx tsx prisma/seed.ts; fi && if [ \"$$BOOTSTRAP_ADMIN\" = \"true\" ]; then echo '>> Bootstrap-Admin läuft…'; npx tsx scripts/bootstrap-admin.ts; fi"
command: sh -c "npx prisma migrate deploy && echo '>> Rollen-Rechte-Sync läuft…' && npx tsx scripts/sync-role-permissions.ts && if [ \"$$RUN_DEMO_SEED\" = \"true\" ]; then echo '>> Demo-Seed läuft…'; npx tsx prisma/seed.ts; fi && if [ \"$$BOOTSTRAP_ADMIN\" = \"true\" ]; then echo '>> Bootstrap-Admin läuft…'; npx tsx scripts/bootstrap-admin.ts; fi"
environment:
DATABASE_URL: ${DATABASE_URL}
# Härtung §1: Passwort-Pepper (Argon2 `secret`). Seed/Bootstrap hashen Passwörter
@@ -64,7 +64,7 @@ services:
DATABASE_URL: ${DATABASE_URL}
# F-04: Row Level Security scharf. Der migrate-Job oben läuft bewusst
# weiter mit der Owner-DATABASE_URL (BYPASSRLS). Nur der App-Prozess
# verbindet als eingeschränkte Rolle isms_app (NOBYPASSRLS) über
# verbindet als eingeschränkte Rolle craftvia_app (NOBYPASSRLS) über
# RLS_DATABASE_URL und setzt app.tenant_id pro Transaktion.
RLS_ENFORCED: ${RLS_ENFORCED:-false}
RLS_DATABASE_URL: ${RLS_DATABASE_URL}
@@ -242,49 +242,6 @@ services:
condition: service_completed_successfully
restart: unless-stopped
# IM-D — Inbound-Mail-Worker (E-Mail-to-Ticket). Holt Mails vom Catch-all-Postfach
# (vorfall-<token>@in.certvia.de) per IMAP ab und legt daraus Vorfälle an bzw. reiht
# unklare Mails in die Betreiber-Review. Kein Redis nötig (IMAP-Poller, keine Queue).
# Ohne INCIDENT_IMAP_* beendet sich der Prozess sauber („nicht konfiguriert").
incident-inbound-worker:
build:
context: .
target: migrate
command: ["npx", "tsx", "scripts/incident-inbound-worker.ts"]
environment:
DATABASE_URL: ${DATABASE_URL}
AUTH_SECRET: ${AUTH_SECRET}
# Pepper wird von der Fail-Secure-Startprüfung erwartet (assertSecureEnv).
PASSWORD_PEPPER: ${PASSWORD_PEPPER}
# IMAP-Zugang des Catch-all-Postfachs. Fehlt es, beendet sich der Worker sauber.
INCIDENT_IMAP_HOST: ${INCIDENT_IMAP_HOST:-}
INCIDENT_IMAP_PORT: ${INCIDENT_IMAP_PORT:-993}
INCIDENT_IMAP_USER: ${INCIDENT_IMAP_USER:-}
INCIDENT_IMAP_PASSWORD: ${INCIDENT_IMAP_PASSWORD:-}
INCIDENT_IMAP_TLS: ${INCIDENT_IMAP_TLS:-true}
INCIDENT_IMAP_MAILBOX: ${INCIDENT_IMAP_MAILBOX:-INBOX}
INCIDENT_IMAP_POLL_MS: ${INCIDENT_IMAP_POLL_MS:-60000}
# Muss zur Catch-all-Subdomain passen (Ableitung der Intake-Adressen).
INCIDENT_INTAKE_DOMAIN: ${INCIDENT_INTAKE_DOMAIN:-in.certvia.de}
AUTH_URL: ${AUTH_URL}
networks:
- backend
- default
security_opt:
- "no-new-privileges:true"
cap_drop:
- ALL
deploy:
resources:
limits:
cpus: "0.5"
memory: 512M
depends_on:
postgres:
condition: service_healthy
migrate:
condition: service_completed_successfully
restart: unless-stopped
postgres:
image: pgvector/pgvector:0.8.0-pg16
@@ -401,7 +358,7 @@ services:
# Der zu importierende Garage-Key = App-Key (App-Env und Garage synchron).
S3_ACCESS_KEY: ${S3_ACCESS_KEY}
S3_SECRET_KEY: ${S3_SECRET_KEY}
S3_BUCKET: ${S3_BUCKET:-isms-documents}
S3_BUCKET: ${S3_BUCKET:-craftvia-documents}
# Optionaler separater Backup-Bucket (nur falls Backup-Store auf S3 statt lokal).
BACKUP_S3_BUCKET: ${BACKUP_S3_BUCKET:-}
# Single-Node-Layout (nominale Kapazität/Zone; für Prod ggf. anheben).