Files
craftvia/.env.example
msolarczekandClaude Opus 5 d9290a187c L15 Testphase & Onboarding: Selbstanmeldung mit Double-Opt-in, Plattform-Wizard, Nur-Lesen-Sperre, Export, Lebenszyklus-Job
- Datenmodell: Testphasen-Lebenszyklus am Mandanten (plan, trialEndsAt, readOnlySince, deletionDueAt,
  Versandmarker), TrialSignup (Plattform, Hashes statt Klartext), TenantExport (RLS), Onboarding-Status
- /testen: 5-Schritte-Wizard (Betrieb, Admin-Konto, Enddatum, Einrichtung, Zusammenfassung),
  Bestätigung per POST, direkte Anmeldung über login-ticket; Rate-Limit je IP/E-Mail, Honeypot,
  Enumeration-Schutz, Slug-Kollisionen
- Plattform: Wizard „Testmandant anlegen“ mit Einladung, Badges/Filter, Enddatum ändern,
  umwandeln, beenden, Löschung vormerken/abbrechen (Bestätigung + Audit)
- Schreibsperre nach Ablauf zentral in moduleGuard und requireApiContext (non-GET über withApi),
  Upload-Routen, Einstellungen/Nutzerverwaltung, Worker-Jobs; Banner Backoffice + mobil
- Datenexport (ZIP mit CSV/JSON + Dateien) als Worker-Job, auch im Nur-Lesen-Zustand
- Täglicher Job trial-lifecycle: Erinnerungen 7/3/1, Ablauf, Löschhinweis, Löschung über das Offboarding
- Erste-Schritte-Checkliste im Dashboard, Mail-Vorlagen de/en, Tests + Smoke, Betriebsdoku

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

163 lines
7.8 KiB
Bash
Raw Permalink 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.
# --- 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://:<pw>@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/<key>). 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
# --- 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=
# --- Craftvia: Planung – Karten & Geocoding (L13) ---
# Adresse → Koordinaten nur serverseitig im Worker (Job geocode-site, max. 1 Anfrage/s),
# Ergebnis wird am Objekt gespeichert. nominatim | none (none = keine Verortung, Objekte
# erscheinen „ohne Ortsangabe“). Für Produktion eigenen/vertraglichen Dienst verwenden.
GEOCODING_PROVIDER=nominatim
# GEOCODING_URL=https://nominatim.openstreetmap.org
# Eindeutiger User-Agent (Nominatim-Richtlinie); leer = "Craftvia/<version> (+APP_BASE_URL)".
# GEOCODING_USER_AGENT=
# Kartenkacheln der Live-Lage; der Host wird beim Build in die CSP (img-src) übernommen.
# MAP_TILE_URL=https://tile.openstreetmap.org/{z}/{x}/{y}.png
# MAP_ATTRIBUTION=© OpenStreetMap-Mitwirkende
# --- 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