CLAUDE.md und README.md verweisen auf docs/, die Dateien lagen aber im Wurzelverzeichnis. Verschoben. docs/13-entscheidungen.md hält fest, wo die Dokumente sich widersprechen und wie es aufgelöst wurde. Der wichtigste Punkt: 04-datenmodell.md verlangt eine Regel, die jedes UPDATE auf CaseEntryVersion verwirft, 05-akten-und-vorlagen.md verlangt, dass eine Umklassifizierung rückwirkend auf alle Versionen wirkt. Beides zusammen geht nicht. Aufgelöst über einen Trigger, der die Tabelle anhängend hält, aber das Anheben von minClearance zulässt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
74 lines
3.2 KiB
Markdown
74 lines
3.2 KiB
Markdown
# Chat und Echtzeit
|
|
|
|
## Zwei Ebenen
|
|
|
|
- **Aktenchat**: hängt an einer Akte, formlos, ausdrücklich kein Aktenbestandteil.
|
|
Optisch klar vom Verlauf abgesetzt (siehe Design-System).
|
|
- **Kanäle**: frei angelegte Räume für allgemeine Absprachen, mit eigener Mindeststufe.
|
|
|
|
## Kernfunktion: „Als Vermerk übernehmen"
|
|
|
|
Eine Chatnachricht wird per Klick zu einem `CaseEntry` mit `type = NOTE`. Der erzeugte
|
|
Eintrag trägt einen Hinweis auf den Ursprung (Autor, Zeitpunkt, Nachrichten-ID). Die
|
|
Chatnachricht bleibt stehen und bekommt eine Markierung „übernommen".
|
|
|
|
Das ist die Brücke zwischen Discord-Gewohnheit und sauberem Aktenbestand und sollte
|
|
prominent sein, nicht in einem Kontextmenü versteckt.
|
|
|
|
## Funktionsumfang
|
|
|
|
- Erwähnungen `@` mit Autovervollständigung aus `User`
|
|
- Antworten auf einzelne Nachrichten (`replyToId`), zitierte Vorschau
|
|
- Reaktionen (kleiner fester Satz, keine freie Emoji-Auswahl)
|
|
- Bearbeiten mit sichtbarem `editedAt`
|
|
- Löschen nur als Zurückziehen: `withdrawnAt` gesetzt, Platzhalter „Nachricht zurückgezogen"
|
|
- Ungelesen-Markierung über `ReadMarker`, Trennlinie „Neu seit deinem letzten Besuch"
|
|
|
|
## Aktenzeichen-Erkennung
|
|
|
|
Text wie `AfiS-2026-0038` wird beim Rendern zu einer Vorschaukarte. **Die Karte wird
|
|
serverseitig aufgelöst und respektiert die Stufe des Lesers.** Wer die Akte nicht sehen darf,
|
|
bekommt eine neutrale Karte ohne Titel und ohne Status. Nie den Titel mitschicken und im
|
|
Client ausblenden.
|
|
|
|
## Echtzeit über SSE
|
|
|
|
Kein WebSocket, kein Redis. Postgres `LISTEN/NOTIFY` plus ein SSE-Endpunkt reicht bei dieser
|
|
Nutzerzahl vollständig.
|
|
|
|
```
|
|
GET /api/stream?topics=case:<id>,notifications
|
|
```
|
|
|
|
- Ein einziger `pg`-Client hält `LISTEN` offen und verteilt an die Verbindungen im Prozess
|
|
- Server sendet alle 25 Sekunden einen Kommentar-Heartbeat gegen Proxy-Timeouts
|
|
- Client nutzt `EventSource` mit `Last-Event-ID`, bei Reconnect werden verpasste Nachrichten
|
|
über `?since=<id>` nachgeladen
|
|
- Reconnect mit exponentiellem Backoff, gedeckelt bei 30 Sekunden
|
|
- Beim Wechsel des Tabs in den Hintergrund wird die Verbindung nach 5 Minuten geschlossen und
|
|
bei Rückkehr neu aufgebaut
|
|
|
|
Ereignistypen: `chat.new`, `chat.edit`, `entry.new`, `entry.updated`, `entry.retracted`,
|
|
`case.update`, `attachment.scanned`, `presence`.
|
|
|
|
`entry.updated` und `entry.retracted` tauschen den Eintrag im offenen Verlauf anhand der ID
|
|
aus. Wer die Akte gerade offen hat, sieht die Änderung sofort und nicht erst beim Neuladen.
|
|
|
|
## Dedupe mit Client-IDs
|
|
|
|
Der Client erzeugt die Nachrichten-ID (UUIDv7) selbst und zeigt die Nachricht sofort an.
|
|
Kommt dieselbe ID über SSE zurück, wird der optimistische Eintrag ersetzt statt verdoppelt.
|
|
Die ID ist gleichzeitig der Idempotenzschlüssel: ein wiederholtes Absenden nach Netzfehler
|
|
erzeugt keine zweite Nachricht (`INSERT ... ON CONFLICT DO NOTHING`).
|
|
|
|
## Discord-Benachrichtigungen
|
|
|
|
Der Worker postet in einen konfigurierbaren Channel und optional als DM an Beteiligte:
|
|
|
|
> Neuer Eintrag in **AfiS-2026-0042** · Insp. Vogel · https://afis.example.de/faelle/AfiS-2026-0042
|
|
|
|
**Niemals Inhalte, niemals Titel bei Akten ab Stufe 3.** Discord kennt eure Klassifizierung
|
|
nicht. Der Link führt zur App, die dann selbst prüft.
|
|
|
|
Konfigurierbar pro Nutzer: alles / nur meine Fälle / nur Erwähnungen / aus.
|