# --- Datenbank --- POSTGRES_USER=craftvia POSTGRES_PASSWORD=craftvia POSTGRES_DB=craftvia DATABASE_URL=postgresql://craftvia:craftvia@localhost:5432/craftvia?schema=public # --- Row Level Security (F-04) –€” lokal AUS (Owner-Betrieb) --- # Lokal bleibt RLS aus: Der Owner craftvia ist Superuser/BYPASSRLS und sieht trotz # FORCE alle Daten. Zum scharfen Testen die beiden Zeilen aktivieren (die Rolle # craftvia_app zuvor mit LOGIN+Passwort versehen, s. scripts/test-rls-enforcement.ts): # RLS_ENFORCED=true # RLS_DATABASE_URL=postgresql://craftvia_app:craftvia_app_local@localhost:5432/craftvia?schema=public # --- Redis (BullMQ) --- # F-18: Redis läuft mit requirepass. REDIS_PASSWORD muss zum docker-compose-Default # passen; das Passwort steht zusätzlich in der REDIS_URL (redis://:@host:port). REDIS_PASSWORD=craftvia-redis REDIS_URL=redis://:craftvia-redis@localhost:6379 # --- Objektspeicher (Garage / S3-kompatibel) --- # Sind alle vier S3_*-Pflichtvariablen gesetzt, nutzt der Storage-Adapter das echte # S3-Backend (Byte-Speicherung + Download-Route /files/). Fehlt eine davon, faellt # der Adapter auf den Stub zurueck (nur Metadaten, keine Bytes) - kein Crash. # Der Bucket wird NICHT automatisch angelegt (Garage bedient kein S3-CreateBucket): er # muss vorab provisioniert sein (Compose-Service "garage-provision"). Fehlt er, wirft der # Adapter einen sprechenden Konfigurationsfehler. # Garage erzwingt das Key-Format: S3_ACCESS_KEY = "GK" + 24 Hex, S3_SECRET_KEY = 64 Hex. S3_ENDPOINT=http://localhost:3900 S3_ACCESS_KEY=GKdead0000beef0000cafe0000 S3_SECRET_KEY=0000000000000000000000000000000000000000000000000000000000000001 S3_BUCKET=craftvia-documents # Region beidseitig us-east-1 (deckt sich mit garage.toml s3_region). forcePathStyle ist # im Code fest gesetzt - Garage bedient ausschliesslich Path-Style. S3_REGION=us-east-1 # Garage-Daemon-Secrets (der Daemon liest sie aus der Env, NICHT aus deploy/garage.toml). # Lokale Dev-Werte (unkritisch, nur localhost). Fuer eigene Stacks frisch erzeugen: # openssl rand -hex 32 GARAGE_RPC_SECRET=0000000000000000000000000000000000000000000000000000000000000002 GARAGE_ADMIN_TOKEN=0000000000000000000000000000000000000000000000000000000000000003 # --- Backup-Zielspeicher (optional) --- # Lane „Konfigurierbarer Backup-Zielspeicher": das Ziel der Backup-/DSGVO-Artefakte ist # jetzt im Betreiber-Portal (/admin/backup) waehlbar (Lokal/S3) und wird in der DB # gespeichert. Praezedenz zur Laufzeit: DB-Config → diese Env-Vars → lokaler Default. # Ohne DB-Config gelten weiter S3_* (siehe oben) bzw. — falls unvollstaendig — der # lokale Ordner unten. HINWEIS: sobald im Portal ein Ziel gespeichert wird, hat die # DB-Config Vorrang vor S3_*/BACKUP_LOCAL_DIR. # Lokaler Ordner fuer Backup-Artefakte (Dev: relativ zum cwd). In Prod auf ein # gemountetes, persistentes Volume zeigen lassen (sonst beim Redeploy fluechtig). BACKUP_LOCAL_DIR=.backups # --- Auth --- AUTH_SECRET=change-me-generate-with-openssl-rand-base64-32 # PASSWORD_PEPPER (Härtung §1): 32-Byte hex, pro Umgebung eindeutig. openssl rand -hex 32 # ⚠ NICHT rotierbar ohne Passwort-Reset für alle; NICHT aus AUTH_SECRET ableiten; NICHT ins Backup-Artefakt. PASSWORD_PEPPER=change-me-openssl-rand-hex-32 AUTH_URL=http://localhost:3000 # --- KI-Provider (anthropic | openai) --- AI_PROVIDER=anthropic AI_API_KEY= # --- Anthropic (Lotse KI-Assistent, Auftragsimport) --- # Ohne ANTHROPIC_API_KEY ist die KI-Anbindung deaktiviert (graceful degradation): # kein Entwurf, Status bleibt –€žmanuell zu erfassen", die UI funktioniert weiter. ANTHROPIC_API_KEY= # Optionale Modell-ID; Default: claude-opus-5 ANTHROPIC_MODEL=claude-opus-5 # --- E-Mail / SMTP (SEC1) --- # Dev: Mailpit oder Mailhog (docker-compose Service `mailhog`, SMTP auf 1025, # Weboberflaeche auf 8025). Gegen localhost wird TLS bewusst nicht erzwungen. # Prod: dedizierte Absenderdomain mit SPF, DKIM und DMARC –€” Vorbedingung vor # dem ersten Produktivversand. Secrets ausschliesslich aus dem Secret-Store. SMTP_HOST=localhost SMTP_PORT=1025 # true = implizites TLS (Port 465), false = STARTTLS (587). Ohne Angabe wird # aus dem Port abgeleitet. SMTP_SECURE=false SMTP_USER= SMTP_PASSWORD= # Absenderadresse und Anzeigename. MAIL_FROM/MAIL_FROM_NAME werden als Alias # ebenfalls akzeptiert. SMTP_FROM=no-reply@craftvia.de MAIL_FROM_NAME=Craftvia # Optionale Antwortadresse (sonst keine Reply-To-Kopfzeile). MAIL_REPLY_TO= # Basis fuer absolute Links in Mails. Faellt auf AUTH_URL zurueck. APP_BASE_URL=http://localhost:3000 # --- Craftvia: KI-Extraktion (Auftragsimport) & Lotse --- # Nutzt ANTHROPIC_API_KEY / ANTHROPIC_MODEL (s. oben). Ohne Key: manuelle Erfassung. AI_EXTRACTION_PROVIDER=anthropic # --- Craftvia: Transkription von Sprachnotizen (Whisper-kompatible API) --- # Ohne TRANSCRIPTION_API_KEY bleibt die Transkription deaktiviert (Status "disabled"). TRANSCRIPTION_PROVIDER=openai-compatible TRANSCRIPTION_API_URL=https://api.openai.com/v1/audio/transcriptions TRANSCRIPTION_API_KEY= TRANSCRIPTION_MODEL=whisper-1 # --- Craftvia: optionaler Malware-Scan für Uploads (ClamAV clamd) --- # Leer = nur Allowlist/Magic-Byte-Prüfung; gesetzt = zusätzlich clamd INSTREAM. CLAMAV_HOST= CLAMAV_PORT=3310 # --- Craftvia: Berichts-PDF (Worker, playwright-core + Chromium) --- # Leer = Playwright-Chromium bzw. lokal installiertes Google Chrome (Entwicklerrechner). # Im Docker-Worker-Image fest /usr/bin/chromium. PDF_CHROMIUM_PATH= # --- Craftvia: Offline/PWA --- # Ab wie vielen Tagen ein lokal gespeichertes Auftragsbundle als veraltet gilt (1–365). OFFLINE_MAX_DAYS=7 # --- Craftvia: Rate Limits der REST-API (je Nutzer, Anfragen pro Minute) --- # Allgemein für /api/v1/**. API_RATE_LIMIT_PER_MINUTE=300 # Einsatz-/Sync-Endpunkte (/api/v1/sync, /api/v1/uploads, /api/v1/field/**) – höher, weil # die PWA nach Offline-Phasen Outbox und Fotos in Schüben nachsendet. API_FIELD_RATE_LIMIT_PER_MINUTE=1200 # --- Craftvia: KI-Protokoll & Kostenbremse --- # Nach N Tagen leert/pseudonymisiert ein Worker-Job Ein-/Ausgaben im KI-Protokoll # (AiGeneration); Metadaten (Art, Modell, Tokens, Zeitpunkt) bleiben erhalten. AI_GENERATION_RETENTION_DAYS=180 # Tokens (ein + aus) je Mandant je Kalendermonat; darüber lehnen Lotse und # Import-Extraktion ab. 0 = unbegrenzt. AI_MONTHLY_TOKEN_LIMIT=0 # --- Optionale Fundament-Variablen (Default leer) --- # MFA_ENC_KEY: Schlüssel für TOTP-Secrets at-rest (leer = aus AUTH_SECRET abgeleitet). # ⚠ Nach dem Setzen nicht mehr ändern. # MFA_ENC_KEY= # BACKUP_ENC_KEY: Verschlüsselung der Backup-Artefakte (leer = AUTH_SECRET). # BACKUP_ENC_KEY= # WebAuthn/Passkeys: Origin und RP-ID (leer = aus AUTH_URL abgeleitet). # WEBAUTHN_ORIGIN=http://localhost:3000 # WEBAUTHN_RP_ID=localhost # Demo-Seed-Passwort (Default Demo1234!). # SEED_PASSWORD= # RLS-Test hart statt Skip, wenn craftvia_app kein LOGIN hat (CI). # RLS_TEST_REQUIRED=true