L10b Betrieb & Aufräumen: Deploy – craftvia-worker, CI-Testjob, DEPLOY.md, Certvia-Doku archiviert
- docker-compose.coolify(.prebuilt).yml: Service craftvia-worker (Target worker, Chromium, shm_size 1gb, gleiche Härtung), Craftvia-Variablen für app und worker. - Dockerfile: worker-Stage mit HOME=/home/app (Chromium-Profil für non-root); lokaler docker build der Targets runner und worker erfolgreich, PDF-Erzeugung im Image geprüft. - .env.example/.env.prod.example/.env.coolify.example: alle Craftvia-Variablen inkl. RLS, KI-Provider, PDF_CHROMIUM_PATH, OFFLINE_MAX_DAYS, API_RATE_LIMIT_*, AI_GENERATION_RETENTION_DAYS, AI_MONTHLY_TOKEN_LIMIT. - CI (.github, .gitea): Job gate mit Postgres (pgvector) und Redis als Service: migrate deploy, seed, Passwort für craftvia_app, tsc, lint, build, npm run test. - docs/craftvia/DEPLOY.md (aus den Certvia-Deploy-Docs abgeleitet): Architektur, Domains, Secrets, Worker, Migrationen, RLS-Aktivierung, Backup/Restore, KI, Rate Limits, Aufbewahrung, Smoke, Update/Rollback. build-and-push-images.sh baut craftvia-worker. - Certvia-/ISMS-Dokumente aus docs/ nach docs/_certvia-archiv/ (mit README); Verweise in README.md und Skript-Kommentaren angepasst. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+106
-3
@@ -4,7 +4,10 @@
|
||||
# - Konfiguration über Coolify-Env-Variablen statt env_file: .env
|
||||
# - Service "migrate": Init-Job (prisma migrate deploy + Rollen-Rechte-Sync), läuft einmalig VOR app
|
||||
# - kein mailhog (Dev); Service "worker" = SEC1 Mail-Worker (BullMQ/Redis-Queue)
|
||||
# - Service "craftvia-worker" = Craftvia-Job-Worker (Import-Extraktion, Transkription,
|
||||
# Berichts-PDF mit Chromium, Bild-Derivate) aus der Dockerfile-Stage "worker"
|
||||
# In Coolify als "Docker Compose Location" -> docker-compose.coolify.yml setzen.
|
||||
# Betriebsdoku: docs/craftvia/DEPLOY.md
|
||||
#
|
||||
# Härtung (F-11/F-18):
|
||||
# - F-11: migrate nutzt die schlanke "migrate"-Stage (kein Next-Build), Images gepinnt.
|
||||
@@ -97,13 +100,36 @@ services:
|
||||
# wählt bzw. als Env-Fallback. Muss auf das gemountete `backups`-Volume zeigen,
|
||||
# sonst sind Sicherungen beim Redeploy flüchtig. DB-Config hat Vorrang vor dieser Var.
|
||||
BACKUP_LOCAL_DIR: ${BACKUP_LOCAL_DIR:-/app/.backups}
|
||||
AI_PROVIDER: ${AI_PROVIDER}
|
||||
AI_API_KEY: ${AI_API_KEY}
|
||||
SMTP_HOST: ${SMTP_HOST}
|
||||
SMTP_PORT: ${SMTP_PORT}
|
||||
SMTP_SECURE: ${SMTP_SECURE:-}
|
||||
SMTP_USER: ${SMTP_USER}
|
||||
SMTP_PASSWORD: ${SMTP_PASSWORD}
|
||||
SMTP_FROM: ${SMTP_FROM}
|
||||
MAIL_FROM_NAME: ${MAIL_FROM_NAME:-}
|
||||
MAIL_REPLY_TO: ${MAIL_REPLY_TO:-}
|
||||
# Basis für absolute Links (Mails, PDFs); leer = Fallback AUTH_URL.
|
||||
APP_BASE_URL: ${APP_BASE_URL:-}
|
||||
# Craftvia-KI (ARCHITEKTUR §4.5). Ohne ANTHROPIC_API_KEY bzw. TRANSCRIPTION_API_KEY
|
||||
# graceful degradation (Status "disabled", manuelle Eingabe).
|
||||
AI_EXTRACTION_PROVIDER: ${AI_EXTRACTION_PROVIDER:-anthropic}
|
||||
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
|
||||
ANTHROPIC_MODEL: ${ANTHROPIC_MODEL:-}
|
||||
TRANSCRIPTION_PROVIDER: ${TRANSCRIPTION_PROVIDER:-openai-compatible}
|
||||
TRANSCRIPTION_API_URL: ${TRANSCRIPTION_API_URL:-}
|
||||
TRANSCRIPTION_API_KEY: ${TRANSCRIPTION_API_KEY:-}
|
||||
TRANSCRIPTION_MODEL: ${TRANSCRIPTION_MODEL:-}
|
||||
# Tokenbudget je Mandant je Kalendermonat (ein+aus); 0 = unbegrenzt.
|
||||
AI_MONTHLY_TOKEN_LIMIT: ${AI_MONTHLY_TOKEN_LIMIT:-0}
|
||||
# Optionaler Malware-Scan der Uploads (clamd INSTREAM); leer = nur Typ-/Magic-Byte-Prüfung.
|
||||
CLAMAV_HOST: ${CLAMAV_HOST:-}
|
||||
CLAMAV_PORT: ${CLAMAV_PORT:-3310}
|
||||
# PWA: ab wie vielen Tagen ein Offline-Bundle als veraltet gilt (1–365, Default 7).
|
||||
OFFLINE_MAX_DAYS: ${OFFLINE_MAX_DAYS:-7}
|
||||
# Rate Limits je Nutzer/Minute: /api/v1/** allgemein bzw. Einsatz-/Sync-Endpunkte
|
||||
# (/api/v1/sync, /api/v1/uploads, /api/v1/field/**).
|
||||
API_RATE_LIMIT_PER_MINUTE: ${API_RATE_LIMIT_PER_MINUTE:-300}
|
||||
API_FIELD_RATE_LIMIT_PER_MINUTE: ${API_FIELD_RATE_LIMIT_PER_MINUTE:-1200}
|
||||
# Persistenter lokaler Backup-Zielspeicher (überlebt Redeploys).
|
||||
volumes:
|
||||
- backups:/app/.backups
|
||||
@@ -242,6 +268,83 @@ services:
|
||||
condition: service_completed_successfully
|
||||
restart: unless-stopped
|
||||
|
||||
# Craftvia-Job-Worker (ARCHITEKTUR §4.4, scripts/craftvia-worker.ts): je BullMQ-Queue ein
|
||||
# Worker für import-extraction, transcription, report-pdf, image-derivatives.
|
||||
# OHNE diesen Dienst bleiben Import-Extraktion, Transkription, Berichts-PDFs und
|
||||
# Bild-Derivate in der Queue liegen (die App reiht bei gesetztem REDIS_URL nur ein).
|
||||
# Eigene Dockerfile-Stage "worker": tsx + src + Prisma-Client + Debian-Chromium und
|
||||
# Schriften (fonts-dejavu-core, fonts-liberation) — HTML→PDF läuft NUR hier, nie in app.
|
||||
# Processors greifen über dbForTenant zu → bei RLS_ENFORCED=true wie app über
|
||||
# RLS_DATABASE_URL (Rolle craftvia_app). Egress (default-Netz) für Anthropic-/
|
||||
# Transkriptions-API und SMTP. Kein Port, kein Traefik.
|
||||
craftvia-worker:
|
||||
build:
|
||||
context: .
|
||||
target: worker
|
||||
command: ["npx", "tsx", "scripts/craftvia-worker.ts"]
|
||||
environment:
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
RLS_ENFORCED: ${RLS_ENFORCED:-false}
|
||||
RLS_DATABASE_URL: ${RLS_DATABASE_URL}
|
||||
REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379
|
||||
AUTH_SECRET: ${AUTH_SECRET}
|
||||
MFA_ENC_KEY: ${MFA_ENC_KEY:-}
|
||||
AUTH_URL: ${AUTH_URL}
|
||||
APP_BASE_URL: ${APP_BASE_URL:-}
|
||||
# Objektspeicher (Garage): Import-PDFs/Sprachnotizen lesen, PDFs/Derivate schreiben.
|
||||
S3_ENDPOINT: ${S3_ENDPOINT}
|
||||
S3_ACCESS_KEY: ${S3_ACCESS_KEY}
|
||||
S3_SECRET_KEY: ${S3_SECRET_KEY}
|
||||
S3_BUCKET: ${S3_BUCKET}
|
||||
S3_REGION: ${S3_REGION:-us-east-1}
|
||||
# KI-Provider (siehe app). Ohne Key: Jobs enden mit Status "disabled".
|
||||
AI_EXTRACTION_PROVIDER: ${AI_EXTRACTION_PROVIDER:-anthropic}
|
||||
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
|
||||
ANTHROPIC_MODEL: ${ANTHROPIC_MODEL:-}
|
||||
TRANSCRIPTION_PROVIDER: ${TRANSCRIPTION_PROVIDER:-openai-compatible}
|
||||
TRANSCRIPTION_API_URL: ${TRANSCRIPTION_API_URL:-}
|
||||
TRANSCRIPTION_API_KEY: ${TRANSCRIPTION_API_KEY:-}
|
||||
TRANSCRIPTION_MODEL: ${TRANSCRIPTION_MODEL:-}
|
||||
AI_MONTHLY_TOKEN_LIMIT: ${AI_MONTHLY_TOKEN_LIMIT:-0}
|
||||
# Aufbewahrung KI-Protokoll (AiGeneration): Ein-/Ausgaben älter als N Tage leeren.
|
||||
AI_GENERATION_RETENTION_DAYS: ${AI_GENERATION_RETENTION_DAYS:-180}
|
||||
# Chromium aus dem Debian-Paket (im Image bereits gesetzt, hier explizit).
|
||||
PDF_CHROMIUM_PATH: /usr/bin/chromium
|
||||
SMTP_HOST: ${SMTP_HOST}
|
||||
SMTP_PORT: ${SMTP_PORT}
|
||||
SMTP_SECURE: ${SMTP_SECURE:-}
|
||||
SMTP_USER: ${SMTP_USER}
|
||||
SMTP_PASSWORD: ${SMTP_PASSWORD}
|
||||
SMTP_FROM: ${SMTP_FROM}
|
||||
MAIL_FROM_NAME: ${MAIL_FROM_NAME:-}
|
||||
MAIL_REPLY_TO: ${MAIL_REPLY_TO:-}
|
||||
# Chromium nutzt /dev/shm für Renderer-Speicher; render.ts setzt zusätzlich
|
||||
# --disable-dev-shm-usage, 1 GB schützt dennoch vor Abstürzen bei Fotoberichten.
|
||||
shm_size: "1gb"
|
||||
networks:
|
||||
- backend
|
||||
- default
|
||||
security_opt:
|
||||
- "no-new-privileges:true"
|
||||
cap_drop:
|
||||
- ALL
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: "1.0"
|
||||
memory: 1536M
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_started
|
||||
garage:
|
||||
condition: service_healthy
|
||||
garage-provision:
|
||||
condition: service_completed_successfully
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
restart: unless-stopped
|
||||
|
||||
postgres:
|
||||
image: pgvector/pgvector:0.8.0-pg16
|
||||
@@ -301,7 +404,7 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
# Objektspeicher: Garage (S3-kompatibel) — ersetzt den früheren minio-Service
|
||||
# (MinIO Community EOL/Maintenance-Mode). Konzept: docs/KONZEPT-garage-migration.md.
|
||||
# (MinIO Community EOL/Maintenance-Mode). Konzept: docs/_certvia-archiv/KONZEPT-garage-migration.md.
|
||||
# Buckets/Keys werden NICHT über die S3-API angelegt, sondern vom Init-Job
|
||||
# "garage-provision" (Admin-API). Nichts nach außen (kein Traefik/ports:) —
|
||||
# rein clusterintern, wie minio zuvor. Version gepinnt (kein latest).
|
||||
|
||||
Reference in New Issue
Block a user