# Changelog
Alle nennenswerten Änderungen an FLORIAN. Format nach
[Keep a Changelog](https://keepachangelog.com/de/1.1.0/), Versionierung nach
[Semantic Versioning](https://semver.org/lang/de/).
Die Regeln dazu stehen in [docs/VERSIONIERUNG.md](docs/VERSIONIERUNG.md).
## [Unveröffentlicht]
Aufräumarbeiten vor Phase 9. Drei Punkte, die sich über mehrere Phasen
angesammelt hatten und in jeder Phase Zeit gekostet haben.
### Hinzugefügt
- **ESLint** hat endlich eine Konfiguration (`eslint.config.mjs`, Flat Config).
Bis dahin gab es das Skript `npm run lint`, aber nichts, was es hätte prüfen
können — ein Werkzeug, das aussieht, als prüfe es etwas, und nichts prüft,
ist schlechter als gar keines. Bewusst **ohne** Formatierungsregeln: die
macht Prettier. Dazu `npm run lint:fix`.
- **Eine eigene Wehr für die E2E-Tests.** `npm run db:test-reset` legt
`ff-teststelle` neu an — vollständig, mit denselben Beispieldaten, aber unter
eigener Kennung. Ein Riegel im Skript bricht ab, wenn die Testkennung mit der
der Beispielwehr übereinstimmt.
- `tests/e2e/wehr.ts` — Zugangsdaten und Anmeldung an einer Stelle statt
achtmal wortgleich in acht Dateien. Schlägt die Anmeldung fehl, sagt die
Meldung, dass die Testwehr fehlt, statt zweihundertmal „Timeout".
### Behoben
- **Die E2E-Tests schrieben in die Beispielwehr.** Nach fünf Phasen standen
dort 120 Atemschutz-Überwachungen statt einer, 115 Geräte statt 45 und
39 Einsätze statt 8. Zweimal fielen Tests aus, weil ein gesuchter Eintrag von
Seite 1 gerutscht war; bei jedem Lauf unterschieden sich alle 72
Bildschirmfotos. Der Bestand ist einmal zurückgesetzt, die Tests laufen
jetzt gegen die eigene Wehr.
- **`
` in einem `
` auf der Einsatzseite** — die Meldung stand seit
Phase 3 in der Konsole und ist der klassische Auslöser für einen
Hydration-Fehler. Die Wurzel war das `Badge`: es rendert jetzt ein ``
statt eines ``. Ein Abzeichen ist Fließtext-Inhalt, und die Darstellung
ändert sich dadurch nicht.
- **Die Fehlerfläche der Karte konnte nie etwas anzeigen** — der Zustand
dahinter wurde nirgends gesetzt. Eine gescheiterte Abfrage sah damit aus wie
„keine Hydranten vorhanden". Gefunden hat das der neue Linter.
- **Die Lagekarte rechnete bei jedem Rendern neu.** Ein `?? []` erzeugte jedes
Mal ein neues leeres Feld und machte damit zwei `useMemo` wirkungslos — bei
einer Karte mit dreißig Elementen und einem Ereignisstrom im Zwei-Sekunden-
Takt kein akademischer Punkt.
- Deutsche Anführungszeichen in vier Ansichten schlossen mit einem geraden
Zoll-Zeichen statt mit dem typografischen.
- Unbenutzte Importe in fünf Dateien.
### Geändert
- `npm run lint` ruft jetzt `eslint .` statt des in Next 15.5 abgekündigten
`next lint`.
- **`tests/e2e` ist nicht mehr vom Typecheck ausgenommen.** Die Ausnahme hat
beim Umbau einen doppelt deklarierten Bezeichner durchgelassen, den erst der
Testlauf gemeldet hat — `npx tsc --noEmit` hatte geschwiegen.
---
## [0.9.0] — 2026-09-04
Phase 8: Lokale KI. Ein Wiki mit semantischer Suche, Diktat, Berichtsassistent
und Belegerfassung — alles gegen selbst betriebene Modelle.
**Nichts, was ein Modell erzeugt, gelangt ungeprüft in einen Nachweis.** Jede
KI-Ausgabe ist zuerst ein eigener Datensatz und nicht ein Feld im
Zieldokument. Sie ist gekennzeichnet, sie steht daneben statt mittendrin, und
sie braucht zwei gleich große Knöpfe, bevor etwas mit ihr geschieht.
**Es läuft alles im Haus.** Ollama und faster-whisper als Container daneben,
kein Anbieter, kein Schlüssel. Es gibt keinen Rückfall auf einen Cloud-Dienst:
fehlen die Container, fehlt die Funktion.
### Hinzugefügt
**Datenmodell**
- `KiVorgang` — jede Befragung eines Modells mit Eingabe, Ausgabe, Modell,
Dauer und der Entscheidung darüber. Auch Fehlschläge: ein Modell, das
dreimal am Tag in eine Zeitüberschreitung läuft, ist eine Information.
- `Wikiseite`, `Wikiabschnitt` (mit `vector(768)`) und `Wikiversion`.
- `Diktat` mit Aufnahme in MinIO, `Belegentwurf` mit allen Feldern optional —
ein Modell, das den Betrag nicht findet, soll nichts erfinden.
**Postgres mit pgvector**
- Eigenes Image (`docker/postgres/Dockerfile`), weil FLORIAN PostGIS **und**
pgvector braucht und es kein offizielles Image mit beidem gibt.
- HNSW-Index statt IVFFlat: IVFFlat muss auf gefülltem Bestand trainiert
werden, HNSW ist ab der ersten Zeile brauchbar. Ein Wiki wächst Seite für
Seite — es gibt nie den Moment, an dem man den Index einmal aufbaut.
**Wiki**
- Markdown, selbst gerendert **ohne HTML**: der Text kommt von Anwendern, und
jeder Weg über `dangerouslySetInnerHTML` wäre ein Weg für ein `