Files
craftvia/.env.prod.example
T
msolarczekandClaude Opus 5 4d5be72ebb Website und App auf getrennten Domains (craftvia.de / app.craftvia.de)
Der Proxy trennt nach Host, sobald MARKETING_HOST gesetzt ist: craftvia.de zeigt nur die
Produktseiten und leitet Login, Testphase, App und API auf die App-Domain aus AUTH_URL um;
www leitet auf die Hauptdomain; auf der App-Domain landet / ohne Sitzung beim Login und
Produktseiten gehen zurück zur Website. Interne Aufrufe (Healthcheck) bleiben unverändert.
Links bleiben relativ, damit keine Domain im Image steckt.

Dazu Test scripts/test-host-routing.ts, Env-Vorlagen mit MARKETING_HOST und Registry,
scripts/generate-coolify-env.sh für lokal erzeugte Geheimnisse und DEPLOY.md §2.1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 09:08:47 +02:00

144 lines
6.6 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Referenz für die PRODUKTIV-Env-Variablen (Coolify, docker-compose.coolify[.prebuilt].yml).
# ECHTE Secrets NUR in Coolify eintragen – diese Datei enthält nur Platzhalter.
# Unterschiede zum Testserver: HTTPS-AUTH_URL, KEIN Demo-Seed, stattdessen Bootstrap-Admin,
# RLS scharf. Betriebsdoku: docs/craftvia/DEPLOY.md
# --- Datenbank (Service "postgres") ---
POSTGRES_USER=craftvia
POSTGRES_PASSWORD=CHANGE_ME_starkes_db_passwort
POSTGRES_DB=craftvia
DATABASE_URL=postgresql://craftvia:CHANGE_ME_starkes_db_passwort@postgres:5432/craftvia?schema=public
# --- Row Level Security scharfschalten (F-04) ---
# RLS_ENFORCED=true – app und craftvia-worker verbinden sich als eingeschränkte Rolle
# craftvia_app (NOBYPASSRLS) und setzen app.tenant_id pro Transaktion; FORCE ROW LEVEL
# SECURITY macht die Policies dann scharf. Ist der Kontext nicht gesetzt, sieht craftvia_app
# NULL Zeilen – daher NUR mit korrekt gesetztem RLS_DATABASE_URL einschalten (sonst
# bricht die App beim Start bewusst ab).
# WICHTIG: Die Owner-/Migrate-Rolle in DATABASE_URL MUSS BYPASSRLS/Superuser sein
# (Migrationen, Seed, Mail-/Backup-Worker und der mandantenübergreifende Login-Lookup
# laufen darüber). craftvia_app wird von der Baseline-Migration NOLOGIN angelegt und in
# Prod EINMALIG mit LOGIN + starkem Passwort versehen:
# ALTER ROLE craftvia_app WITH LOGIN PASSWORD '<stark>';
RLS_ENFORCED=true
RLS_DATABASE_URL=postgresql://craftvia_app:CHANGE_ME_starkes_craftvia_app_passwort@postgres:5432/craftvia?schema=public
# --- Redis (Service "redis") ---
# F-18: Redis läuft mit requirepass. NUR REDIS_PASSWORD setzen – REDIS_URL wird in den
# Coolify-Compose-Dateien daraus abgeleitet (redis://:${REDIS_PASSWORD}@redis:6379).
REDIS_PASSWORD=CHANGE_ME_starkes_redis_passwort
# --- Objektspeicher (Service "garage", S3-kompatibel) ---
# Bucket/Key legt der Init-Job "garage-provision" an (Admin-API). Format erzwungen:
# S3_ACCESS_KEY = "GK" + 24 Hex -> echo "GK$(openssl rand -hex 12)"
# S3_SECRET_KEY = 64 Hex -> openssl rand -hex 32
S3_ENDPOINT=http://garage:3900
S3_ACCESS_KEY=GK000000000000000000000000
S3_SECRET_KEY=CHANGE_ME_openssl_rand_hex_32
S3_BUCKET=craftvia-documents
S3_REGION=us-east-1
# Garage-Daemon-Secrets (LITERAL in Coolify setzen, nicht via ${...}).
GARAGE_RPC_SECRET=CHANGE_ME_openssl_rand_hex_32
GARAGE_ADMIN_TOKEN=CHANGE_ME_openssl_rand_hex_32
# GARAGE_ZONE=dc1
# GARAGE_CAPACITY_BYTES=100000000000
# --- Backup-Zielspeicher (optional) ---
# Ziel der Backup-/DSGVO-Artefakte ist im Betreiber-Portal (/admin/backup) waehlbar
# (Lokal/S3) und wird verschluesselt in der DB gehalten. Praezedenz: DB-Config →
# Env (S3_*/BACKUP_LOCAL_DIR) → lokaler Default. Fuer „Lokal" mountet die Compose-Datei
# das persistente Volume `backups` auf /app/.backups (app + backup-worker).
BACKUP_LOCAL_DIR=/app/.backups
# Optionaler eigener Backup-Bucket (nur wenn der Backup-Store auf S3 laeuft).
# BACKUP_S3_BUCKET=
# Verschluesselung der Backup-Artefakte (AES-256-GCM); leer = AUTH_SECRET. Je Umgebung
# eigener Wert, alte Keys bis Retention-Ende aufbewahren.
BACKUP_ENC_KEY=CHANGE_ME_openssl_rand_hex_32
# --- Auth (Auth.js v5) – Produktiv über HTTPS ---
# AUTH_SECRET: openssl rand -base64 32 (frisch, NICHT der Testwert)
AUTH_SECRET=CHANGE_ME_openssl_rand_base64_32
# PASSWORD_PEPPER (Härtung §1): openssl rand -hex 32 — frisch je Umgebung, NICHT rotierbar, nie ins Artefakt.
PASSWORD_PEPPER=CHANGE_ME_openssl_rand_hex_32
# MFA_ENC_KEY: TOTP-Secrets at-rest (leer = aus AUTH_SECRET). ⚠ Nach dem Setzen nicht mehr ändern.
MFA_ENC_KEY=CHANGE_ME_openssl_rand_hex_32
AUTH_URL=https://app.craftvia.example
# Website und App auf getrennten Domains (src/lib/marketing/hosts.ts): craftvia.de zeigt nur die
# Produktseiten, AUTH_URL-Domain die App. Beide Domains in Coolify beim Service "app" eintragen.
# Leer = alles auf einer Domain.
MARKETING_HOST=craftvia.example
# AUTH_TRUST_HOST ist im Compose fest auf true (hinter dem Coolify-Proxy) – nicht nötig.
# Passkeys/WebAuthn: leer = aus AUTH_URL abgeleitet.
# WEBAUTHN_ORIGIN=https://app.craftvia.example
# WEBAUTHN_RP_ID=app.craftvia.example
# --- E-Mail (produktives SMTP-Relay; SPF/DKIM/DMARC der Absenderdomain vorher einrichten) ---
SMTP_HOST=
SMTP_PORT=587
# true = implizites TLS (465), false = STARTTLS (587); leer = aus Port abgeleitet.
SMTP_SECURE=
SMTP_USER=
SMTP_PASSWORD=
SMTP_FROM=no-reply@craftvia.example
MAIL_FROM_NAME=Craftvia
MAIL_REPLY_TO=
# Basis für absolute Links in Mails/PDFs; leer = AUTH_URL.
APP_BASE_URL=https://app.craftvia.example
# --- KI: Auftragsimport-Extraktion & Lotse (Anthropic) ---
# Ohne ANTHROPIC_API_KEY: graceful degradation (manuelle Erfassung, kein Lotse-Entwurf).
AI_EXTRACTION_PROVIDER=anthropic
ANTHROPIC_API_KEY=
# Leer = Default-Modell aus src/server/ai/client.ts
ANTHROPIC_MODEL=
# --- KI: 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
# --- KI: Kostenbremse & Aufbewahrung ---
# Tokens (ein + aus) je Mandant je Kalendermonat; darüber lehnen Lotse und
# Import-Extraktion ab. 0 = unbegrenzt.
AI_MONTHLY_TOKEN_LIMIT=0
# --- Craftvia: Testphase (L15, docs/craftvia/TESTPHASE.md) ---
# Längste selbst gewählte Testphase in Tagen (1–365); Vorbelegung im Wizard heute + 14.
TRIAL_MAX_DAYS=30
# Kontakt in Banner und Testphasen-Mails (Vollversion/Verlängerung); leer = allgemeiner Hinweis.
TRIAL_CONTACT_EMAIL=
# Nach N Tagen leert/pseudonymisiert ein Worker-Job Ein-/Ausgaben im KI-Protokoll
# (AiGeneration). Frist mit dem DSB abstimmen.
AI_GENERATION_RETENTION_DAYS=180
# --- Craftvia: API-Rate-Limits (je Nutzer, Anfragen pro Minute) ---
API_RATE_LIMIT_PER_MINUTE=300
# /api/v1/sync, /api/v1/uploads, /api/v1/field/**
API_FIELD_RATE_LIMIT_PER_MINUTE=1200
# --- Craftvia: Offline/PWA ---
OFFLINE_MAX_DAYS=7
# --- Craftvia: optionaler Malware-Scan (ClamAV clamd) ---
CLAMAV_HOST=
CLAMAV_PORT=3310
# PDF_CHROMIUM_PATH ist im Worker-Image/Compose fest /usr/bin/chromium – nicht setzen.
# --- Demo-Seed: in PROD AUS lassen! ---
RUN_DEMO_SEED=false
# --- Erst-Admin-Bootstrap (statt Demo-Seed) ---
# Beim ersten Deploy true setzen -> migrate-Job legt Plattform-Admin + ersten Mandanten an
# (idempotent). Danach auf false setzen oder stehen lassen (No-op, wenn vorhanden).
BOOTSTRAP_ADMIN=true
BOOTSTRAP_ADMIN_EMAIL=admin@craftvia.example
BOOTSTRAP_ADMIN_PASSWORD=CHANGE_ME_initiales_admin_passwort
BOOTSTRAP_ADMIN_NAME=Craftvia Admin
BOOTSTRAP_TENANT_NAME=Musterbetrieb GmbH
BOOTSTRAP_TENANT_SLUG=musterbetrieb
BOOTSTRAP_TENANT_SHORT=Musterbetrieb
BOOTSTRAP_TENANT_SECTOR=