# FlorianNetz — Design-Spezifikation

**Datum:** 2026-06-08
**Status:** Entwurf (zur Freigabe)
**Sprache der Anwendung:** Deutsch (österreichischer Feuerwehr-Standard, ÖBFV)

---

## 1. Zweck

FlorianNetz ist eine **ausschließlich für authentifizierte Benutzer zugängliche** Web-Plattform, auf der österreichische Freiwillige Feuerwehren ihre **Fahrzeuge** und **Geräte/Ausrüstung** erfassen. Andere Wehren können diese durchsuchen, um für die überörtliche Hilfe die **am schnellsten eintreffende** Ressource zu finden.

**Oberstes Prinzip:** Kein anonymer Zugriff — *kein einziger* Seiten- oder API-Endpunkt ist ohne gültige Sitzung erreichbar (default-deny, serverseitig erzwungen).

### Nicht-Ziele (vorerst)
- Kein In-App-Ausleih-/Anfrage-Workflow (nur Kontaktaufnahme out-of-band; für später vorgesehen, Datenmodell offen halten).
- Keine 2-Faktor-Authentifizierung in v1 (später leicht ergänzbar).
- Keine Kopplung mit `feuerwehr_dashboard` in v1 (Architektur hält die spätere Kopplung offen).
- Kein Mehrmandanten-SaaS — eine selbst gehostete Instanz mit vielen Wehren.

---

## 2. Rollen & Zugriff

| Rolle | Login über | Berechtigungen |
|---|---|---|
| **Platform-Admin** | Authentik SSO (OIDC) | Verwaltet die Taxonomie (Merkmal-Katalog, Fahrzeug-Vorlagen inkl. zugeordneter Merkmale & Auswahloptionen, Geräte-Kategorien); gibt von Wehren vorgeschlagene Merkmale frei; legt Wehren an und stellt den ersten Wehr-Admin-Login bereit; sieht Audit-Log |
| **Wehr-Admin** | App-Konto (erster Login vom Platform-Admin bereitgestellt) | Verwaltet das eigene Wehr-Profil, eigene Fahrzeuge & Geräte (Werte, Zuordnung, Status); **legt weitere Wehr-Admins und Lese-Benutzer der eigenen Wehr selbst an** |
| **Lese-Benutzer** | App-Konto (vom Wehr-Admin angelegt) | Durchsucht und sieht alle Wehren-Daten inkl. Kontaktinfo; **keine** Bearbeitung |

- Zwei Authentifizierungswege, **eine** einheitliche Sitzung mit `role` + `brigadeId`.
- Autorisierung serverseitig: Schreibzugriffe sind auf die eigene Wehr beschränkt; Lesezugriff über alle Wehren (offenes Verzeichnis).
- **Login-Seite zeigt ausschließlich den Login** — keine weiteren Inhalte.

---

## 3. Informationsarchitektur

- **Startseite (nach Login):** eine globale Suche mit prominentem „Meinen Standort verwenden" (GPS). Tabs: **Fahrzeuge · Geräte · Wehren**.
- **Pro Tab:** Namens-/Funkrufnamen-Suche + **dynamisch aus dem Merkmal-Katalog erzeugte Filter** (typabhängig: Schieberegler / Dropdown / Ja-Nein-Schalter) + Status-Filter („nur einsatzbereit").
- **Trefferliste:** sortiert nach **Eintreffzeit (Fahrzeit-ETA)**; jede Zeile zeigt Wehr, Eckdaten, ETA/Entfernung, Status und **📞 Kontakt** (Telefonnummer der Wehr).
- **Detailseiten:**
  - *Fahrzeug:* Eckdaten-Raster (aus Merkmalwerten) · **Beladung** als verlinkte Geräteliste · Wehr-Karte · expliziter Button **„Wehr kontaktieren"**.
  - *Gerät:* Merkmale · zugeordnetes Fahrzeug **oder** „im Gerätehaus" · Wehr-Karte · Kontakt.
  - *Wehr:* Profil (Adresse, Kontakt, Funkrufnamen-Schema), eigener Fuhrpark, Kontakt.

### Design / Corporate Identity
- Richtung **„Amtlich"**: seriös, behördlich, ruhig. Navy-Primärfarbe, Signalrot als Akzent/Signal, Serifen-Überschriften, viel Weißraum, tabellarische Ziffern.
- Logo **„Netzknoten"**: vernetzte Wehren-Knoten um einen roten Mittelpunkt (Florian + Netz).
- Palette: Navy `#1B3A5B`, Signalrot `#E2231A`, Anthrazit `#1A2530`, Nebelgrau `#F6F8FA`, Grün/bereit `#1F8F5A`, Bernstein/Wartung `#B5460F`.
- Typografie: Serif-Display (Source Serif / Georgia) für Überschriften, humanistische Sans (Inter / System-UI) für UI, Tabular-Nums für Datenspalten.
- Bewusst **kein** generischer „KI-Look" (keine Verlaufsflächen, nicht alles abgerundet, keine Emoji-Dekoration).

---

## 4. Dynamisches Merkmal-System (Kernstück)

Ein starres Spaltenschema skaliert nicht — die Vielfalt an Fahrzeugen/Geräten ist zu groß. Stattdessen typisierte, vom Admin gepflegte Merkmale.

- **Merkmal-Katalog** (Admin): jedes Merkmal hat Name, Typ (`Zahl` / `Auswahl` / `Ja-Nein` / `Text`), optional Einheit; bei `Auswahl` definiert der Admin die erlaubten Optionen.
- **Fahrzeug-Vorlagen** (Admin): definieren die niederösterreichischen Standard-Bezeichnungen (HLF 1, HLF 1 W, HLF 2, HLF 3, HLF 4 inkl. HLF 4-U, VRF, VF, ALF, SSTF, WLF, MTF) und **pro Vorlage, welche Merkmale gelten** sowie deren Optionen/Vorgabewerte. Inklusive Standard-Beladung. Jede Vorlage führt **Such-Aliasse** (frühere/umgangssprachliche Namen wie RLF/RLFA 2000, KLFA, TLFA …) und eine **Allrad-Namensregel** (Einschub „A" in die Abkürzung, z. B. „HLFA 3" = `Allradantrieb = Ja`, gleiche Vorlage wie „HLF 3"). Seed-Daten siehe `docs/reference/fahrzeug-katalog-noelfv.md`.
- **Geräte-Kategorien** (Admin): je Kategorie ein eigener Merkmal-Satz. Anfangsbestand wird aus den **Beladelisten** der Fahrzeug-Richtlinien abgeleitet (Atemschutz, hydraul. Rettungsgerät, Pumpen, Schläuche/Armaturen, Strom/Licht, Schadstoff/Ölwehr …); per Hybrid-Governance erweiterbar.
- **Anlegen durch die Wehr:** Vorlage wählen (füllt Merkmale & Beladung vor, alles editierbar) **oder** „Eigenes Fahrzeug/Gerät" frei aus dem Katalog zusammenstellen.
- **Hybrid-Governance:** Ein von einer Wehr neu angelegtes Merkmal ist **sofort** am eigenen Objekt nutzbar und auf dessen Detailseite sichtbar; es wird **erst nach Admin-Freigabe** (prüfen / zusammenführen) zu einem **globalen Suchfilter**. Hält die Suche über alle Wehren konsistent.
- **Suche:** Filter werden dynamisch aus dem Katalog erzeugt; der Typ bestimmt das Eingabeelement und die Abfrage (Range / Gleichheit / Boolean).

---

## 5. Geografie & „am schnellsten eintreffend"

- Jede Wehr hat Koordinaten (aus der Adresse geokodiert).
- Suchstandort = Geräte-GPS **oder** eingegebene Adresse (geokodiert).
- Treffer werden nach **Fahrzeit-ETA** von der jeweils besitzenden Wehr zum Suchstandort sortiert.
- **Selbst gehostet** zur Wahrung der Privatsphäre (keine Standortdaten an Dritte):
  - **OSRM** für Fahrzeit/Routing (Österreich-OSM-Extrakt), als Distanz-/Zeit-Matrix.
  - **Nominatim** (oder Photon) für Geokodierung (Österreich-Extrakt).
  - **Fallback:** Luftlinie (Haversine), falls der Routing-Dienst nicht erreichbar ist — klar gekennzeichnet.
- Optionale **MapLibre-GL**-Kartenansicht (Liste bleibt primär).

---

## 6. Datenmodell (PostgreSQL, indikativ)

> Typisierte Merkmalwerte in einer eigenen Wert-Tabelle (EAV mit typisierten Spalten) für saubere Range-/Enum-/Boolean-Indizes.

- **brigades**: `id, name, art (FF), strasse, plz, ort, bundesland, lat, lng, funkrufname_schema, telefon, email, wehrführer, aktiv, erstellt_am`
- **users**: `id, brigade_id (NULL für Platform-Admin), rolle (platform_admin | wehr_admin | wehr_read), auth_typ (authentik | local), email, name, passwort_hash (NULL bei authentik), aktiv, erstellt_von, erstellt_am`
- **merkmale** (Attributdefinitionen): `id, name, typ (number|enum|boolean|text), einheit, geltungsbereich (vehicle|equipment|both), status (active|proposed), vorgeschlagen_von_brigade_id, erstellt_am`
- **merkmal_optionen** (für `enum`): `id, merkmal_id, wert, label, reihenfolge`
- **vehicle_templates** (Vorlagen): `id, code (z. B. "TLFA 4000"), name, beschreibung`
- **vehicle_template_merkmale**: `template_id, merkmal_id, vorgabewert (NULL), pflicht (bool), reihenfolge`
- **equipment_categories**: `id, name`
- **equipment_category_merkmale**: `category_id, merkmal_id, reihenfolge`
- **vehicles**: `id, brigade_id, template_id (NULL bei Eigenbau), name, funkrufname, status (einsatzbereit|wartung|ausser_dienst), notiz, erstellt_am`
- **equipment**: `id, brigade_id, category_id, vehicle_id (NULL = im Gerätehaus), name, status, erstellt_am`
- **merkmal_values**: `id, merkmal_id, entity_typ (vehicle|equipment), entity_id, value_num, value_text, value_bool` — Indizes: `(merkmal_id, value_num)`, `(merkmal_id, value_bool)`, `(merkmal_id, value_text)`; sowie `(entity_typ, entity_id)`
- **audit_log**: `id, actor_user_id, aktion, ziel_typ, ziel_id, details (jsonb), zeitpunkt`

---

## 7. Tech-Stack

- **Next.js (App Router, TypeScript)** — Full-Stack (Server Components + Route Handlers / Server Actions), wenig Boilerplate.
- **PostgreSQL** + **Drizzle ORM** — typsicher und SQL-nah; besser geeignet als Prisma für die dynamischen Merkmal-Abfragen (Range/Enum-Filter).
- **Auth.js (NextAuth v5)** — Authentik-OIDC-Provider (Platform-Admins) + Credentials-Provider mit **argon2id** (Wehr-Konten); **default-deny Middleware** auf allen Routen; einheitliche Session mit `role` + `brigadeId`.
- **Tailwind CSS + Radix-UI-Primitives**, eigens auf die „Amtlich"/Netzknoten-Identität gethemt (volle Kontrolle über den eigenständigen Look; bewusst nicht MUI).
- **Zod** (Validierung), **MapLibre GL** (Karte), **OSRM + Nominatim** (Docker, Österreich-Extrakt).
- **Tests:** **Playwright** (E2E, insbesondere Auth-Gating-Tests) + **Vitest** (Units).

---

## 8. Sicherheit

- **Default-deny** serverseitig auf allen Seiten **und** API-Routen; keine reine Client-Absicherung.
- Rollen- + Wehr-Scoping bei **jedem** Schreibzugriff serverseitig erzwungen.
- **argon2id**-Passwort-Hashing; sichere Cookies (`httpOnly`, `secure`, `sameSite`); CSRF-Schutz; Rate-Limiting am Login; Security-Header.
- **Audit-Log** für Admin- und Bereitstellungsaktionen (Wehr/Benutzer anlegen, Merkmal-Freigaben).
- 2FA für Wehr-Konten als spätere, einfache Erweiterung vorgesehen.

---

## 9. Deployment

- **Docker Compose**: Container für `app` (Next.js), `postgres`, `osrm`, `nominatim`.
- **Reverse Proxy:** vorhandener **Traefik** (extern). Kein gebündelter Proxy. Der App-Container wird per **Traefik-Labels** (Router/Service-Port, TLS, ggf. Middlewares) am externen Traefik-Netzwerk angebunden.
- Die App muss `X-Forwarded-Proto`/`X-Forwarded-Host` von Traefik vertrauen, damit sichere Cookies und Auth.js-Callback-URLs korrekt funktionieren; vertrauenswürdige Hosts konfigurieren.
- **Authentik:** Redirect-URI der App in Authentik registrieren; Client-ID/-Secret + Issuer-URL via Umgebungsvariablen.

---

## 10. Eingaben / Abhängigkeiten

- **Bundesland: Niederösterreich** (bestätigt) — maßgeblich NÖ-LFV-Richtlinien (FA 01–10) + ÖBFV FA 30; relevant fürs Funkrufnamen-Schema.
- **Standarddokumente vorhanden:** 11 Fahrzeug-Richtlinien in `docs/reference/` analysiert; Seed-Katalog (Vorlagen, Merkmal-Katalog, Aliasse) in `docs/reference/fahrzeug-katalog-noelfv.md`.
- **Geräte-Kategorien:** Anfangsbestand aus den Beladelisten abgeleitet (siehe §4); separate Geräte-Standarddokumente können später ergänzt werden.
- **Offen (nicht blockierend):** Bestätigung der noch tentativen Such-Aliasse (KLF/KLFA, TLFA, GTLF, KRF/KRFA, LAST, WLFA, MTFA) — als Aliasse jederzeit im Admin pflegbar.

---

## 11. Zukünftige Kopplung mit `feuerwehr_dashboard`

In v1 eigenständig, aber kopplungsfreundlich: gemeinsamer **Authentik**-Identitätsanbieter, kompatible **PostgreSQL**- und **Docker/Traefik**-Konventionen. Eine spätere Integration (geteilte Identitäten, Querverweise) bleibt dadurch unkompliziert.
