ESLint hatte keine Konfiguration — das Skript "npm run lint" pruefte nichts. Jetzt Flat Config ohne Formatierungsregeln, dafuer mit den Regeln, die die Fehler dieses Projekts gemeldet haetten. Er hat gleich zwei gefunden, die niemand gesucht hatte. Das Badge rendert ein span statt eines div. Damit ist die Meldung "div cannot be a descendant of p" weg, die seit Phase 3 auf der Einsatzseite stand — sie ist der klassische Ausloeser fuer einen Hydration-Fehler. Die E2E-Tests laufen gegen eine eigene Wehr. Nach fuenf Phasen standen in der Beispielwehr 120 Atemschutz-Ueberwachungen statt einer und 115 Geraete statt 45; bei jedem Lauf aenderten sich alle Bildschirmfotos. Der Bestand ist einmal zurueckgesetzt, npm run db:test-reset baut die Testwehr neu auf. Behoben nebenbei: - Die Fehlerflaeche der Karte konnte nie etwas anzeigen. - Zwei useMemo der Lagekarte rechneten bei jedem Rendern neu. - tests/e2e war vom Typecheck ausgenommen und liess einen doppelt deklarierten Bezeichner durch. Closes #10 Closes #11 Closes #12 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
440 lines
21 KiB
Bash
440 lines
21 KiB
Bash
# =============================================================================
|
|
# FLORIAN — Feuerwehr-Verwaltungsplattform
|
|
# Kopiere diese Datei nach ".env" und passe die Werte an:
|
|
# cp .env.example .env
|
|
# Alles, was hier steht, wird von docker-compose.yml und von lib/env.ts gelesen.
|
|
# lib/env.ts validiert beim Start mit Zod — fehlt eine Pflichtvariable, startet
|
|
# die App gar nicht erst, statt später halb zu funktionieren.
|
|
# =============================================================================
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Allgemein
|
|
# -----------------------------------------------------------------------------
|
|
# development | production | test — steuert Logging, Fehlerseiten und Caching.
|
|
NODE_ENV=development
|
|
# Öffentliche Basis-URL der Anwendung, ohne abschließenden Schrägstrich.
|
|
# Muss exakt der Adresse entsprechen, unter der Nutzer die App aufrufen —
|
|
# Auth.js baut daraus die OIDC-Redirect-URI.
|
|
APP_URL=http://localhost:3100
|
|
# Zeitzone für alle serverseitigen Fristen- und Terminberechnungen.
|
|
# Nicht ändern, außer die Wehr liegt außerhalb Deutschlands.
|
|
TZ=Europe/Berlin
|
|
# Host-Ports fuer die Entwicklung. Bewusst nicht die Standardports,
|
|
# damit FLORIAN neben anderen lokalen Stacks laufen kann.
|
|
APP_PORT=3100
|
|
GOTENBERG_PORT=3101
|
|
MAILPIT_UI_PORT=8125
|
|
MAILPIT_SMTP_PORT=1125
|
|
ADMINER_PORT=8081
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Traefik / Domains (nur für den Produktionsbetrieb relevant)
|
|
# In der Entwicklung greift docker-compose.override.yml und veröffentlicht die
|
|
# Dienste direkt auf localhost — Traefik wird dort nicht gebraucht.
|
|
# -----------------------------------------------------------------------------
|
|
# Hostname der Anwendung hinter Traefik, z. B. florian.beispielwehr.de
|
|
APP_DOMAIN=florian.localhost
|
|
# Hostname der MinIO-S3-API (Datei-Uploads, presignte URLs).
|
|
MINIO_DOMAIN=s3.florian.localhost
|
|
# Hostname der MinIO-Weboberfläche (Administration der Buckets).
|
|
MINIO_CONSOLE_DOMAIN=minio.florian.localhost
|
|
# Hostname des Traefik-Dashboards. Leer lassen, um es nicht zu veröffentlichen.
|
|
TRAEFIK_DASHBOARD_DOMAIN=traefik.florian.localhost
|
|
# E-Mail-Adresse für die ACME-Zertifikate (Let us Encrypt).
|
|
ACME_EMAIL=kommandant@beispielwehr.de
|
|
# Traefik-Entrypoint für HTTPS. "websecure" ist der Standard aus dieser Datei.
|
|
TRAEFIK_ENTRYPOINT=websecure
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# PostgreSQL 17 + PostGIS
|
|
# -----------------------------------------------------------------------------
|
|
POSTGRES_USER=florian
|
|
# Vor dem ersten Start ersetzen: openssl rand -base64 24
|
|
POSTGRES_PASSWORD=bitte_aendern_postgres
|
|
POSTGRES_DB=florian
|
|
# Port, unter dem Postgres auf dem Host erreichbar ist (nur Entwicklung).
|
|
POSTGRES_PORT=5442
|
|
# Verbindungszeichenfolge der Anwendung. Läuft über den Datenbankbenutzer
|
|
# "florian_app", für den Row Level Security AKTIV ist — dieser Zugang sieht nur
|
|
# Daten der Organisation, die per SET LOCAL app.current_organisation gesetzt
|
|
# wurde (siehe src/lib/db.ts).
|
|
DATABASE_URL=postgresql://florian_app:bitte_aendern_app@postgres:5432/florian?schema=public
|
|
# Passwort des Anwendungsbenutzers. Muss zu DATABASE_URL passen und wird beim
|
|
# ersten Start von docker/postgres/10-init-app-role.sh gesetzt.
|
|
POSTGRES_APP_PASSWORD=bitte_aendern_app
|
|
# Verbindung für Migrationen und Seed. Nutzt den Eigentümer-Zugang, der RLS
|
|
# umgehen darf. Niemals im Anwendungscode verwenden.
|
|
DIRECT_DATABASE_URL=postgresql://florian:bitte_aendern_postgres@postgres:5432/florian?schema=public
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Redis (Warteschlangen für BullMQ, Rate-Limiting)
|
|
# -----------------------------------------------------------------------------
|
|
# Vor dem ersten Start ersetzen: openssl rand -base64 24
|
|
REDIS_PASSWORD=bitte_aendern_redis
|
|
REDIS_URL=redis://:bitte_aendern_redis@redis:6379
|
|
# Port auf dem Host (nur Entwicklung).
|
|
REDIS_PORT=6389
|
|
# Anzahl paralleler Jobs je Worker-Prozess.
|
|
WORKER_CONCURRENCY=5
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# MinIO (S3-kompatibler Objektspeicher — ALLE Dateien liegen hier, nie im FS)
|
|
# -----------------------------------------------------------------------------
|
|
MINIO_ROOT_USER=florian
|
|
# Mindestens 8 Zeichen, vor dem ersten Start ersetzen.
|
|
MINIO_ROOT_PASSWORD=bitte_aendern_minio
|
|
# Endpunkt, den App und Worker intern ansprechen — im Compose-Netz der
|
|
# Dienstname, außerhalb der externe Hostname.
|
|
S3_ENDPOINT=minio
|
|
S3_PORT=9000
|
|
# true, sobald MinIO hinter Traefik mit TLS läuft.
|
|
S3_USE_SSL=false
|
|
S3_ACCESS_KEY=florian
|
|
S3_SECRET_KEY=bitte_aendern_minio
|
|
S3_REGION=eu-central-1
|
|
# Bucket für alle Nutzdateien (Prüfprotokolle, Fotos, Rechnungen, Exporte).
|
|
S3_BUCKET=florian
|
|
# Öffentlich erreichbare Basis-URL für presignte Download-Links. In der
|
|
# Entwicklung http://localhost:9010, in Produktion https://$MINIO_DOMAIN
|
|
S3_PUBLIC_URL=http://localhost:9010
|
|
# Gültigkeitsdauer presignter Links in Sekunden (Standard: 15 Minuten).
|
|
S3_URL_TTL=900
|
|
# Ports auf dem Host (nur Entwicklung): API und Weboberfläche.
|
|
MINIO_API_PORT=9010
|
|
MINIO_CONSOLE_PORT=9011
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Gotenberg (PDF-Erzeugung für Prüfprotokolle, Berichte, Rechnungen)
|
|
# -----------------------------------------------------------------------------
|
|
GOTENBERG_URL=http://gotenberg:3000
|
|
# Zeitlimit je PDF-Auftrag in Sekunden.
|
|
GOTENBERG_TIMEOUT=30
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Auth.js — Sitzungsverwaltung
|
|
# -----------------------------------------------------------------------------
|
|
# Signiert die Sitzungs-Cookies. Zwingend erforderlich, pro Installation neu:
|
|
# openssl rand -base64 32
|
|
AUTH_SECRET=bitte_aendern_mindestens_32_zeichen_lang
|
|
# Muss hinter einem Reverse Proxy (Traefik) auf true stehen, damit Auth.js die
|
|
# X-Forwarded-Header auswertet und korrekte Redirect-URIs erzeugt.
|
|
AUTH_TRUST_HOST=true
|
|
# Lebensdauer einer Sitzung in Sekunden (Standard: 8 Stunden).
|
|
AUTH_SESSION_MAX_AGE=28800
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# OIDC gegen authentik
|
|
# Die authentik-Instanz wird SEPARAT betrieben und ist nicht Teil dieses Stacks.
|
|
# In authentik anzulegen: Provider "OAuth2/OpenID" (Client-Typ: confidential),
|
|
# Redirect-URI exakt $APP_URL/api/auth/callback/authentik
|
|
# Scopes: openid profile email — plus einen Gruppen-Scope, wenn Rollen aus
|
|
# authentik-Gruppen vorbelegt werden sollen (siehe AUTH_OIDC_GROUP_CLAIM).
|
|
# -----------------------------------------------------------------------------
|
|
# false blendet den OIDC-Knopf aus; dann bleibt nur der lokale Login. Sinnvoll
|
|
# für den Erststart, bevor authentik konfiguriert ist.
|
|
AUTH_OIDC_ENABLED=false
|
|
# Issuer-URL des Providers, OHNE /.well-known/openid-configuration.
|
|
# Bei authentik: https://<authentik-host>/application/o/<application-slug>/
|
|
AUTH_OIDC_ISSUER=https://auth.beispiel.de/application/o/florian/
|
|
AUTH_OIDC_CLIENT_ID=
|
|
AUTH_OIDC_CLIENT_SECRET=
|
|
# Beschriftung des Anmeldeknopfes in der Oberfläche.
|
|
AUTH_OIDC_NAME=Anmeldung über authentik
|
|
# Claim, aus dem die Gruppenzugehörigkeit gelesen wird. In authentik über ein
|
|
# Scope-Mapping bereitzustellen. Leer lassen, um das Mapping abzuschalten —
|
|
# dann werden Rollen ausschließlich in FLORIAN gepflegt.
|
|
AUTH_OIDC_GROUP_CLAIM=groups
|
|
# Zuordnung authentik-Gruppe -> FLORIAN-Rolle, kommagetrennt als "gruppe:ROLLE".
|
|
# Wirkt nur als VORBELEGUNG beim ersten Login; danach ist die in FLORIAN
|
|
# gepflegte Rolle führend und wird nicht mehr überschrieben.
|
|
AUTH_OIDC_GROUP_MAPPING=feuerwehr-kommandant:KOMMANDANT,feuerwehr-geraetewart:GERAETEWART,feuerwehr-atemschutz:ATEMSCHUTZGERAETEWART,feuerwehr-kassier:KASSIER,feuerwehr-schriftfuehrer:SCHRIFTFUEHRER,feuerwehr-ausbilder:AUSBILDER,feuerwehr-mitglied:MITGLIED
|
|
# true legt einen in authentik bekannten Nutzer beim ersten Login automatisch
|
|
# als Person an. false verlangt, dass die Person vorher in FLORIAN existiert
|
|
# und über die E-Mail-Adresse verknüpft wird.
|
|
AUTH_OIDC_AUTO_PROVISION=true
|
|
# Organisation (Slug), der automatisch angelegte Personen zugeordnet werden.
|
|
AUTH_OIDC_STANDARD_ORGANISATION=ff-musterhausen
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Lokaler E-Mail/Passwort-Login (Rückfalloption für Erststart und Notbetrieb)
|
|
# -----------------------------------------------------------------------------
|
|
# Nach der Einrichtung von authentik auf false setzen, damit nur noch OIDC geht.
|
|
AUTH_LOCAL_ENABLED=true
|
|
# Zugangsdaten des ersten Administrators, angelegt vom Seed-Skript.
|
|
# Nach dem ersten Login das Passwort in der Oberfläche ändern.
|
|
SEED_ADMIN_EMAIL=admin@beispielwehr.de
|
|
SEED_ADMIN_PASSWORT=Feuerwehr2026
|
|
# bcrypt-Kostenfaktor. 12 ist ein guter Kompromiss aus Sicherheit und Tempo.
|
|
AUTH_BCRYPT_ROUNDS=12
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Terminal-/Kiosk-Anmeldung im Gerätehaus (PIN und RFID)
|
|
# -----------------------------------------------------------------------------
|
|
# Schaltet den Kiosk-Modus samt Terminal-Login frei.
|
|
KIOSK_ENABLED=true
|
|
# Gemeinsames Geheimnis, mit dem sich ein Terminal-Gerät gegenüber dem Server
|
|
# ausweist, bevor überhaupt eine PIN oder ein Token akzeptiert wird:
|
|
# openssl rand -hex 32
|
|
KIOSK_DEVICE_SECRET=bitte_aendern_kiosk_geheimnis
|
|
# Länge der Personen-PIN. 4 ist bequem, 6 ist sicherer.
|
|
KIOSK_PIN_LAENGE=6
|
|
# Nach wie vielen Fehlversuchen eine PIN gesperrt wird.
|
|
KIOSK_MAX_FEHLVERSUCHE=5
|
|
# Sperrdauer nach zu vielen Fehlversuchen, in Sekunden.
|
|
KIOSK_SPERRDAUER=300
|
|
# Automatische Abmeldung am Terminal nach Untätigkeit, in Sekunden.
|
|
KIOSK_IDLE_TIMEOUT=120
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Kartenmodule (Phase 6)
|
|
# -----------------------------------------------------------------------------
|
|
# FLORIAN laedt keine Kacheln aus dem Netz. Wo eine Wehr ausrueckt und wo ihre
|
|
# Hydranten liegen, ist niemandes Geschaeft — der Kartenserver laeuft selbst:
|
|
#
|
|
# docker compose --profile karte up -d
|
|
#
|
|
# Dafuer wird eine MBTiles-Datei des Ausrueckegebiets gebraucht (siehe README).
|
|
# Ohne KARTE_STIL_URL zeigt die Karte einen leeren Hintergrund mit Gitternetz;
|
|
# Hydranten, Objekte und Lagekarte funktionieren trotzdem.
|
|
KARTE_STIL_URL=http://localhost:8085/styles/basic/style.json
|
|
# Kartenmittelpunkt beim Oeffnen (Musterhausen).
|
|
KARTE_BREITENGRAD=48.5
|
|
KARTE_LAENGENGRAD=12.15
|
|
KARTE_ZOOM=13
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Atemschutz nach FwDV 7 (Phase 5)
|
|
# -----------------------------------------------------------------------------
|
|
# Der Sicherheitshinweis ueber jeder Ansicht der Atemschutzueberwachung:
|
|
# "Ergaenzendes System — die analoge Atemschutzueberwachung bleibt fuehrend."
|
|
# Er gehoert dorthin. Auf false setzen darf ihn nur, wer eine schriftliche
|
|
# Freigabe des Kommandanten hat — und deren Fundstelle gehoert in
|
|
# ATEMSCHUTZ_FREIGABE, sonst bleibt der Hinweis stehen.
|
|
ATEMSCHUTZ_HINWEIS=true
|
|
# Aktenzeichen oder Fundstelle der Freigabe, z. B. "Kommandantenbeschluss vom 12.03.2026".
|
|
ATEMSCHUTZ_FREIGABE=
|
|
# Abstand der Druckabfrage in Sekunden. FwDV 7 nennt keinen festen Wert;
|
|
# zehn Minuten sind die uebliche Praxis.
|
|
ATEMSCHUTZ_ABFRAGE_INTERVALL=600
|
|
# Ansprechdruck der Warneinrichtung in bar. Je nach Baujahr 50 bis 60.
|
|
ATEMSCHUTZ_WARNDRUCK=55
|
|
# Sicherheitszuschlag auf den errechneten Rueckzugsdruck, in bar.
|
|
ATEMSCHUTZ_ZUSCHLAG=10
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Wetterwarnungen auf dem Hallenmonitor (optional, DWD)
|
|
# Die einzige Verbindung nach draussen, die FLORIAN von sich aus aufbaut —
|
|
# deshalb standardmaessig aus. Ohne WETTER_ENABLED=true wird nichts abgerufen.
|
|
# -----------------------------------------------------------------------------
|
|
WETTER_ENABLED=false
|
|
# Warnzellen-Nummer der eigenen Gemeinde aus der DWD-Warnzellenliste:
|
|
# https://www.dwd.de/DE/leistungen/opendata/help/warnungen/cap_warncellids_csv.csv
|
|
DWD_WARNCELL=
|
|
DWD_WARNUNGEN_URL=https://www.dwd.de/DWD/warnungen/warnapp/json/warnings.json
|
|
# Zeitlimit fuer den Abruf, in Sekunden. Der Monitor darf davon nicht haengen.
|
|
WETTER_TIMEOUT=5
|
|
# Wie lange eine Antwort gilt, bevor neu gefragt wird, in Sekunden.
|
|
WETTER_ZWISCHENSPEICHER=300
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# E-Mail-Versand (optional, hinter lib/integrations/mail.ts abstrahiert)
|
|
# Ohne MAIL_ENABLED=true wird nur ins Log geschrieben — praktisch für Tests.
|
|
# -----------------------------------------------------------------------------
|
|
MAIL_ENABLED=false
|
|
MAIL_HOST=smtp.beispiel.de
|
|
MAIL_PORT=587
|
|
MAIL_SECURE=false
|
|
MAIL_USER=
|
|
MAIL_PASSWORD=
|
|
MAIL_FROM=FLORIAN <florian@beispielwehr.de>
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Telegram-Benachrichtigungen (optional, abschaltbar)
|
|
# -----------------------------------------------------------------------------
|
|
TELEGRAM_ENABLED=false
|
|
TELEGRAM_BOT_TOKEN=
|
|
TELEGRAM_CHAT_ID=
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Push über ntfy (Phase 7, optional)
|
|
#
|
|
# ntfy ist ein winziger Push-Dienst, den man selbst betreibt: ein Container,
|
|
# eine App im Store, fertig. Man abonniert ein "Thema" (einen frei gewählten
|
|
# Namen) und bekommt Meldungen darauf — ohne Konto, ohne Telefonnummer.
|
|
#
|
|
# Läuft der Server im eigenen Netz, verlässt keine Nachricht das Gerätehaus.
|
|
# Deshalb gilt ntfy in FLORIAN als INTERNER Kanal und bekommt die
|
|
# ausführlichen Texte. Wer stattdessen das öffentliche ntfy.sh einträgt, macht
|
|
# ihn zu einem externen Dienst wie jeden anderen.
|
|
#
|
|
# ACHTUNG: Ein Thema ist nur so geheim wie sein Name. Wer ihn kennt, liest mit.
|
|
# FLORIAN schlägt deshalb Namen mit Zufallsanteil vor.
|
|
# -----------------------------------------------------------------------------
|
|
NTFY_ENABLED=false
|
|
# NTFY_URL=http://ntfy:80
|
|
# Nur nötig, wenn der eigene ntfy Zugriffsschutz eingeschaltet hat.
|
|
NTFY_TOKEN=
|
|
NTFY_TIMEOUT=10
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Web-Push in den Browser (Phase 7, optional)
|
|
#
|
|
# Der Weg, der ohne App auskommt. Die Meldung läuft über den Push-Dienst des
|
|
# Browserherstellers (Mozilla, Google, Apple) — verschlüsselt, aber sie
|
|
# verlässt das Netz der Wehr. Deshalb ist Web-Push ein EXTERNER Kanal und
|
|
# bekommt nur Kurzfassungen: "3 Prüfungen fällig", nicht welche.
|
|
#
|
|
# Schlüsselpaar erzeugen mit: npm run vapid
|
|
#
|
|
# ACHTUNG: Beide Schlüssel gehören ins Backup. Ein neuer öffentlicher Schlüssel
|
|
# macht alle bestehenden Push-Abos wertlos — jeder müsste Push neu erlauben,
|
|
# und niemand merkt es, die Meldungen bleiben einfach aus.
|
|
# -----------------------------------------------------------------------------
|
|
WEBPUSH_ENABLED=false
|
|
WEBPUSH_PUBLIC_KEY=
|
|
WEBPUSH_PRIVATE_KEY=
|
|
# Kontaktweg für den Push-Dienst, "mailto:..." oder eine Adresse.
|
|
WEBPUSH_KONTAKT=
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# WhatsApp: bewusst NICHT.
|
|
#
|
|
# Es gibt keine WHATSAPP_-Variablen, und das ist eine Entscheidung, keine Lücke.
|
|
# Die Begründung steht im README unter "Warum kein WhatsApp" — kurz: die
|
|
# Business-Plattform kostet je Konversation, verlangt einen Vertrag mit Meta
|
|
# als Auftragsverarbeiter, und die App gleicht das Telefonbuch ab. Für eine
|
|
# Wehr, deren Daten im Gerätehaus bleiben sollen, ist das der falsche Weg.
|
|
# -----------------------------------------------------------------------------
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Benachrichtigungen und Termine (Phase 7)
|
|
# -----------------------------------------------------------------------------
|
|
# Wann der Worker die Erinnerungen anlegt und verschickt (cron, Europe/Berlin).
|
|
# Bewusst am frühen Morgen und nicht nachts: eine Push-Meldung um drei Uhr
|
|
# weckt Leute, die am nächsten Tag arbeiten müssen.
|
|
BENACHRICHTIGUNG_LAUF=0 7 * * *
|
|
# Wie viele Tage vor einem Termin erinnert wird (kommagetrennt).
|
|
# "7,1": einmal in der Woche davor, damit man den Abend freihalten kann, und
|
|
# einmal am Vortag, weil man es bis dahin wieder vergessen hat.
|
|
TERMIN_ERINNERUNG_TAGE=7,1
|
|
# Wie oft eine fehlgeschlagene Zustellung wiederholt wird, bevor sie als
|
|
# fehlgeschlagen stehen bleibt. Stehen bleiben ist Absicht: eine still
|
|
# verschluckte Benachrichtigung ist schlimmer als eine sichtbar gescheiterte.
|
|
BENACHRICHTIGUNG_VERSUCHE=3
|
|
# Wie lange ZUGESTELLTE Benachrichtigungen aufgehoben werden.
|
|
# Fehlgeschlagene bleiben — sie zeigen einen kaputten Kanal an.
|
|
BENACHRICHTIGUNG_AUFBEWAHRUNG_TAGE=90
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# LLM-Anbindung (optional; nur selbstgehostete Endpunkte, kein Cloud-Zwang)
|
|
# -----------------------------------------------------------------------------
|
|
# ES GIBT KEINEN RUECKFALL AUF EINEN ANBIETER. Laeuft der eigene Endpunkt
|
|
# nicht, fehlen die KI-Funktionen — sie werden nicht durch einen fremden
|
|
# Dienst ersetzt. Ein Einsatzbericht spricht ueber Menschen in ihrer
|
|
# schlechtesten Stunde; solche Texte gehoeren nirgendwo anders hin.
|
|
#
|
|
# Container starten: docker compose --profile ki up -d
|
|
# Modelle holen: docker compose exec ollama ollama pull <modell>
|
|
LLM_ENABLED=false
|
|
# OpenAI-kompatibler Endpunkt, z. B. eine lokale Ollama- oder vLLM-Instanz.
|
|
LLM_BASE_URL=http://ollama:11434/v1
|
|
LLM_API_KEY=
|
|
LLM_MODELL=qwen2.5:14b
|
|
# Zeitlimit fuer eine Antwort. Ein Bericht darf dauern, aber nicht ewig.
|
|
LLM_TIMEOUT=120
|
|
|
|
# Modell fuer Einbettungen (semantische Suche im Wiki).
|
|
#
|
|
# ACHTUNG: Die Spalte wikiabschnitt.einbettung ist auf 768 Dimensionen
|
|
# festgelegt — das liefert nomic-embed-text. Ein Modell mit anderer Laenge
|
|
# braucht eine Migration; wie, steht im README unter Phase 8.
|
|
LLM_EINBETTUNG_MODELL=nomic-embed-text
|
|
LLM_EINBETTUNG_DIMENSIONEN=768
|
|
|
|
# Modell, das Bilder lesen kann — fuer die Belegerfassung. Ohne dieses Modell
|
|
# werden Belege trotzdem abgelegt, die Angaben nur von Hand eingetragen.
|
|
# LLM_VISION_MODELL=llama3.2-vision
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Spracherkennung fuers Diktat (Phase 8, optional)
|
|
#
|
|
# Selbst betriebener faster-whisper im Compose-Profil "ki". Groesse ueber
|
|
# WHISPER_MODELL: "tiny" laeuft auf jedem Buerorechner, "base" ist der
|
|
# brauchbare Kompromiss, "small" erkennt Fachbegriffe merklich besser und
|
|
# will dafuer Zeit oder eine Grafikkarte.
|
|
# -----------------------------------------------------------------------------
|
|
WHISPER_ENABLED=false
|
|
WHISPER_URL=http://whisper:8000
|
|
WHISPER_MODELL=base
|
|
WHISPER_SPRACHE=de
|
|
# Zeitlimit fuer eine Aufnahme. Zehn Minuten Sprache brauchen Zeit.
|
|
WHISPER_TIMEOUT=300
|
|
# Hoechstlaenge einer Aufnahme in Sekunden.
|
|
DIKTAT_MAX_SEKUNDEN=600
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Einsätze und Übungen (Phase 3)
|
|
# -----------------------------------------------------------------------------
|
|
# Adressen zu Koordinaten auflösen. Vorgesehen ist ein SELBST betriebener
|
|
# Nominatim — Einsatzadressen gehören nicht an einen öffentlichen Dienst, und
|
|
# dessen Nutzungsbedingungen erlauben es ohnehin nicht.
|
|
GEOCODING_ENABLED=false
|
|
# NOMINATIM_URL=http://nominatim:8080
|
|
GEOCODING_TIMEOUT=5
|
|
# Auf welche Länder die Suche eingegrenzt wird (ISO-Codes, kommagetrennt).
|
|
GEOCODING_LAENDER=de,at,ch
|
|
|
|
# Einsatzportal für Fremdwehren: ein signierter Link ohne Anmeldung, über den
|
|
# eine Nachbarwehr den Stand sieht und Lagemeldungen absetzen kann.
|
|
PORTAL_ENABLED=true
|
|
# Wie lange ein neu erzeugter Link gilt.
|
|
PORTAL_GUELTIGKEIT_STUNDEN=24
|
|
# Höchstzahl Zugriffe je Link und Stunde.
|
|
PORTAL_MAX_ZUGRIFFE=120
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Wartung und Prüfung (Phase 2)
|
|
# -----------------------------------------------------------------------------
|
|
# Wann der nächtliche Lauf Prüftermine plant. Cron-Syntax, Zeitzone
|
|
# Europe/Berlin. Der Worker trägt den Zeitplan beim Start je Wehr selbst ein.
|
|
WARTUNG_NACHTLAUF=15 3 * * *
|
|
# Wann die Erinnerungen verschickt werden. Bewusst nach der Planung: sonst
|
|
# erinnert der Lauf an Termine, die es noch gar nicht gibt.
|
|
WARTUNG_ERINNERUNG_LAUF=45 3 * * *
|
|
# Wie weit im Voraus Termine angelegt werden. Ohne Horizont stünden Termine für
|
|
# die nächsten zehn Jahre im Dashboard.
|
|
WARTUNG_PLANUNGSHORIZONT_TAGE=180
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Datenschutz und Aufbewahrung (DSGVO)
|
|
# -----------------------------------------------------------------------------
|
|
# Aufbewahrungsfrist für Einsatz- und Prüfdokumentation in Jahren.
|
|
AUFBEWAHRUNG_JAHRE=10
|
|
# Aufbewahrungsfrist für den Audit-Log in Tagen. Der Log ist append-only;
|
|
# Älteres wird vom Worker exportiert, bevor es entfernt wird.
|
|
AUDIT_AUFBEWAHRUNG_TAGE=3650
|
|
# Frist in Tagen, nach der ein ausgetretenes Mitglied anonymisiert wird.
|
|
PERSON_ANONYMISIERUNG_TAGE=365
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Telemetrie bleibt aus. Nicht ändern.
|
|
# -----------------------------------------------------------------------------
|
|
NEXT_TELEMETRY_DISABLED=1
|
|
CHECKPOINT_DISABLE=1
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Testwehr fuer die E2E-Tests
|
|
#
|
|
# Die Playwright-Tests laufen gegen eine EIGENE Wehr, nicht gegen die
|
|
# Beispielwehr aus der Anleitung. Sonst wachsen deren Listen bei jedem Lauf,
|
|
# und die Bildschirmfotos aendern sich, ohne dass sich die Oberflaeche
|
|
# geaendert haette.
|
|
#
|
|
# Vor dem Lauf einmal: npm run db:test-reset
|
|
# -----------------------------------------------------------------------------
|
|
E2E_SLUG=ff-teststelle
|
|
E2E_NAME=Freiwillige Feuerwehr Teststelle
|
|
E2E_KURZNAME=FF Teststelle
|
|
E2E_ADMIN_EMAIL=e2e@teststelle.de
|
|
E2E_ADMIN_PASSWORT=Feuerwehr2026
|