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:
@@ -1,7 +1,7 @@
|
||||
# Coolify-Deployment (PREBUILT-Variante) — zieht fertige Images aus der Registry
|
||||
# statt auf dem Host zu bauen (Plan B: langsamer/timeoutender Host-Build umgehen).
|
||||
# Images vorher bauen+pushen: scripts/build-and-push-images.sh
|
||||
# Registry/Tag via Coolify-Env: REGISTRY (Default git.certvia.de/msolarczek), IMAGE_TAG (Default main).
|
||||
# Registry/Tag via Coolify-Env: REGISTRY (Default registry.example.com/craftvia), IMAGE_TAG (Default main).
|
||||
# Abgeleitet von docker-compose.coolify.yml.
|
||||
# Unterschiede zum lokalen Dev-Compose:
|
||||
# - keine host "ports": Coolify-Proxy routet die Domain intern auf app:3000
|
||||
@@ -24,8 +24,8 @@ services:
|
||||
# Optionaler Demo-Seed nur, wenn RUN_DEMO_SEED=true (Testserver). Idempotent (upserts).
|
||||
# In Produktion die Variable NICHT setzen; stattdessen BOOTSTRAP_ADMIN.
|
||||
migrate:
|
||||
image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-migrate:${IMAGE_TAG:-main}
|
||||
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"
|
||||
image: ${REGISTRY:-registry.example.com/craftvia}/craftvia-migrate:${IMAGE_TAG:-main}
|
||||
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
|
||||
@@ -59,12 +59,12 @@ services:
|
||||
restart: "no"
|
||||
|
||||
app:
|
||||
image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-app:${IMAGE_TAG:-main}
|
||||
image: ${REGISTRY:-registry.example.com/craftvia}/craftvia-app:${IMAGE_TAG:-main}
|
||||
environment:
|
||||
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}
|
||||
@@ -148,7 +148,7 @@ services:
|
||||
# Owner-DATABASE_URL (kein RLS): der Worker arbeitet mandantenübergreifend.
|
||||
# Im default-Netz (Egress), damit der externe SMTP-Server erreichbar ist.
|
||||
worker:
|
||||
image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-migrate:${IMAGE_TAG:-main}
|
||||
image: ${REGISTRY:-registry.example.com/craftvia}/craftvia-migrate:${IMAGE_TAG:-main}
|
||||
command: ["npx", "tsx", "scripts/mail-worker.ts"]
|
||||
environment:
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
@@ -192,7 +192,7 @@ services:
|
||||
# Braucht das S3/MinIO-Backup-Bucket (S3_*) und den Backup-Schlüssel (BACKUP_ENC_KEY,
|
||||
# Fallback AUTH_SECRET). concurrency ist im Worker seriell (destruktiv).
|
||||
backup-worker:
|
||||
image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-migrate:${IMAGE_TAG:-main}
|
||||
image: ${REGISTRY:-registry.example.com/craftvia}/craftvia-migrate:${IMAGE_TAG:-main}
|
||||
command: ["npx", "tsx", "scripts/backup-worker.ts"]
|
||||
environment:
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
@@ -238,47 +238,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:
|
||||
image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-migrate:${IMAGE_TAG:-main}
|
||||
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
|
||||
@@ -346,7 +305,7 @@ services:
|
||||
# Image mit eingebackener deploy/garage.toml (Dockerfile-Stage „garage"). KEIN
|
||||
# Bind-Mount der Config: Coolify legt relative Bind-Quellen sonst als Verzeichnis an
|
||||
# → Garage bekäme /etc/garage.toml als Ordner („IO error: Is a directory").
|
||||
image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-garage:${IMAGE_TAG:-main}
|
||||
image: ${REGISTRY:-registry.example.com/craftvia}/craftvia-garage:${IMAGE_TAG:-main}
|
||||
# Secrets stehen NICHT in der eingebackenen deploy/garage.toml — der Daemon liest
|
||||
# rpc_secret/admin_token aus der Env (in Coolify literal setzen, nicht via ${…}).
|
||||
environment:
|
||||
@@ -383,7 +342,7 @@ services:
|
||||
# Läuft bei JEDEM Deploy; "already exists" = Erfolg. Ohne GARAGE_ADMIN_TOKEN No-op.
|
||||
# Nutzt das schlanke "migrate"-Image (Node/tsx) — kein Garage-Binary nötig.
|
||||
garage-provision:
|
||||
image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-migrate:${IMAGE_TAG:-main}
|
||||
image: ${REGISTRY:-registry.example.com/craftvia}/craftvia-migrate:${IMAGE_TAG:-main}
|
||||
command: ["npx", "tsx", "scripts/garage-provision.ts"]
|
||||
environment:
|
||||
GARAGE_ADMIN_URL: http://garage:3903
|
||||
@@ -391,7 +350,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).
|
||||
|
||||
Reference in New Issue
Block a user