⚠️ Veraltet (Stand 2026-04-30)
Diese Dokumentation beschreibt das alte System vor dem Process-Engine-Refactor (Phase 4.7). Die zugrundeliegenden Tabellen (cascade_*, concept_instances/bausteine, crisis_scenarios/events/tasks, workflow_*) wurden gedroppt. Die hier dokumentierten Routen und Models existieren so nicht mehr.
Aktuelle Architektur: Process-Engine API — eine Engine, mehrere Apps (flow.*, concept.*, crisis.*).
Diese Datei bleibt als historische Referenz erhalten.
Kaskaden-Modul — Technische Dokumentation
Ueberblick
Das Kaskaden-Modul ist eine visuelle Kommandozentrale fuer koordinierte Kommunikation. Ein 2D-Topologie-Graph zeigt Knoten (Gruppen/Spaces) und Kanten (Informationsfluss). Jede Kante hat konfigurierbare Linsen: Filter, Form und Gate — plus einen Automatisch/Manuell-Schalter.
Das Modul lebt als eigenstaendiger Hub in der Navigation.
Das Linsen-Prinzip
Jede Verbindung zwischen zwei Knoten hat drei Regler plus einen Auto-Forward-Schalter:
Information kommt rein
|
[AUTO/MANUELL] Automatisch oder per Klick?
|
┌────┴────┐
| FILTER | Was darf durch?
└────┬────┘
┌────┴────┐
| FORM | Wie wird es formuliert?
└────┬────┘
┌────┴────┐
| GATE | Wann darf es durch?
└────┬────┘
|
Information geht rausAuto-Forward
| Modus | Verhalten |
|---|---|
autoForward: true | Nachrichten fliessen automatisch durch die Kante (via Matrix-Connector Hook) |
autoForward: false | Manuell per "Weiter"-Button im Chat (Standard) |
Filter
| Modus | Verhalten |
|---|---|
all | Jede Nachricht fliesst weiter (Standard) |
marked | Nur Nachrichten die explizit als "weiterleiten" markiert wurden (nur bei manuell) |
keyword | Nur wenn bestimmte Stichwoerter im Text vorkommen |
Form
| Modus | Verhalten |
|---|---|
verbatim | Exakt wie im Original (Standard) |
brief | Erster Satz + "Weitere Informationen folgen." |
formal | Umformulierung in offizielle Sprache mit Anrede und Grussformel |
clearance | Feste Entwarnungs-Vorlage |
custom | Freitext-Template mit {nachricht} als Platzhalter |
Gate
| Modus | Verhalten |
|---|---|
open | Sofort, automatisch (Standard) |
manual | Jemand muss in der Spalte auf "Weiterleiten" klicken |
delayed | Automatisch nach X Minuten (5, 10, 15, 30, 60) |
approval | Bestimmte Person muss die Nachricht freigeben — mit Bearbeitungsmoeglichkeit |
Datenmodell
CascadeBoard
| Feld | Typ | Beschreibung |
|---|---|---|
| id | cuid | Primary Key |
| tenantId | string | Tenant-Zuordnung |
| spaceId | string | Besitzer-Space |
| name | string | Anzeigename |
| description | string? | Optionale Beschreibung |
| createdBy | string | Matrix-User-ID des Erstellers |
CascadeColumn (Knoten)
| Feld | Typ | Beschreibung |
|---|---|---|
| id | cuid | Primary Key |
| boardId | string | Zuordnung zum Board |
| title | string | Knotenname |
| color | string? | Farbcode |
| posX | int | Horizontale Position im Graph (Grid-Einheit) |
| posY | int | Vertikale Position (0 = oben, hoeher = abhaengig) |
| filterMode | string | Filter-Linse |
| filterKeywords | string? | Komma-getrennte Stichwoerter |
| formMode | string | Form-Linse |
| formTemplate | string? | Eigene Vorlage mit |
| gateMode | string | Gate-Linse |
| gateDelayMin | int | Verzoegerung in Minuten |
| gateApprover | string? | Freigabe-Person |
CascadeEdge (Kante)
| Feld | Typ | Beschreibung |
|---|---|---|
| id | cuid | Primary Key |
| boardId | string | Zuordnung zum Board |
| sourceColumnId | string | Von welchem Knoten |
| targetColumnId | string | Zu welchem Knoten |
| direction | string | 'one-way', 'two-way', 'confirm' |
| autoForward | boolean | true = automatisch, false = manuell (Standard) |
CascadeColumn.nodeConfig (JSON)
Jeder Knoten speichert seine Elemente und Design-Informationen als JSON:
{
design?: {
heading?: string; // Ueberschrift im Player
body?: string; // Beschreibungstext
};
elements?: ElementConfig[]; // Array von Elementen
}Jedes Element im Array:
{
type: string; // 'decision' | 'dropdown' | 'checklist' | ...
question?: string; // Fragetext / Bezeichnung
label?: string; // Label (bei checklist, radio, button, ...)
options?: Array<{ id: string; label: string }>; // Fuer dropdown/checklist/radio
visibleWhen?: { elementIdx: number; branch: string }; // Bedingte Sichtbarkeit
thenGoTo?: string; // Knoten-ID bei "Weiter"
thenGoToYes?: string; // Knoten-ID bei "Ja" (nur decision)
thenGoToNo?: string; // Knoten-ID bei "Nein" (nur decision)
sourceElement?: number; // Referenz auf anderes Element (condition)
sourceSpaceElement?: number; // Referenz auf createSpace-Element (createTasks, space)
autoExecute?: boolean; // Automatisch ausfuehren ohne Klick
// ... weitere typ-spezifische Felder
}CascadeColumnSpace
| Feld | Typ | Beschreibung |
|---|---|---|
| id | cuid | Primary Key |
| columnId | string | Zuordnung zum Knoten |
| spaceId | string | Der verknuepfte Chat-Space |
CascadeFlowLog
Protokolliert jeden Schritt jedes Player-Durchlaufs:
| Feld | Typ | Beschreibung |
|---|---|---|
| id | cuid | Primary Key |
| boardId | string | Zuordnung zum Board |
| sessionId | string | Eindeutige Session-ID (pro Player-Durchlauf) |
| userId | string | Matrix-User-ID |
| userName | string | Anzeigename des Nutzers |
| columnId | string | Aktueller Knoten |
| columnTitle | string | Knoten-Titel (denormalisiert) |
| action | string | 'start', 'navigate', 'answer_yes', 'answer_no', 'select_option', 'finish' |
| detail | string? | Zusatz-Info (z.B. gewaehlte Option) |
| createdAt | datetime | Zeitstempel |
CascadePendingMessage
Nachrichten die am Gate warten (manual, delayed, approval).
CascadeNodeStatus
Live-Status jedes Knotens: idle, active, confirmed, pending.
Auto-Forward-System
Architektur
Nachricht in Space → Matrix Synapse → on_new_event (Python Connector)
→ POST /cascade-forward-hook (Backend)
→ roomId → spaceId aufloesen
→ Alle ausgehenden Kanten mit autoForward=true finden
→ Filter → Form → Gate → Senden an Ziel-SpacesMatrix-Connector Integration
Der prilog-matrix-connector (Python Synapse-Modul) hat einen on_new_event Hook der bei jeder m.text Nachricht:
- Prüeft ob die Nachricht eine Kaskaden-Nachricht ist (
org.prilog.cascadeMetadata) → wenn ja, ignorieren (Endlosschleifen-Schutz) cascade_forward()am Backend aufruft (fire-and-forget)- Das Backend loest die Matrix-Room-ID zum Prilog-Space auf
- Findet alle Kaskaden-Kanten mit
autoForward: true - Wendet Filter/Form/Gate an und sendet an die Ziel-Spaces
Shared Secret Auth
Der Connector authentifiziert sich mit X-Matrix-Connector-Secret Header. Das Secret muss in der Synapse-Homeserver-Config UND in der Backend-.env identisch sein.
Gemeinsamer Text (CollabDocument)
Ueberblick
Echtzeit-kollaborativer Texteditor basierend auf Y.js (CRDT) + Tiptap + WebSocket.
Datenmodell
| Feld | Typ | Beschreibung |
|---|---|---|
| id | cuid | Primary Key |
| tenantId | string | Tenant-Zuordnung |
| boardId | string? | Kaskaden-Board (optional) |
| columnId | string? | Kaskaden-Knoten (optional) |
| spaceId | string? | Space (fuer Space-basierte Dokumente) |
| title | string | Anzeigename |
| yjsState | bytes? | Y.js Dokument-State als Binary |
| status | string | 'draft', 'sent', 'archived' |
| createdBy | string | Ersteller |
WebSocket-Server
- Endpoint:
GET /api/platform/v1/collab/:documentId/ws?token=<jwt> - Protokoll: Y.js Sync + Awareness (MSG_SYNC=0, MSG_AWARENESS=1)
- In-Memory: Y.Doc pro Dokument, mit Awareness fuer Cursor-Positionen
- Persistence: Debounced (2s) in DB als
yjsStateBinary - Cleanup: 30s nach letztem Disconnect wird das Dokument aus dem Speicher entfernt
API-Endpoints
| Endpoint | Methode | Beschreibung |
|---|---|---|
/spaces/:spaceId/collab-doc | POST | Draft erstellen oder existierenden zurueckgeben |
/spaces/:spaceId/collab-doc | GET | Aktiven Draft fuer Space holen |
/spaces/:spaceId/collab-docs | GET | Alle Dokumente eines Space listen |
/spaces/:spaceId/cascade-targets | GET | Ausgehende Kaskaden-Kanten fuer diesen Space |
/collab-docs/:docId/save | POST | Text als .md Dokument im Space-DMS speichern |
/collab-docs/:docId/send-to-targets | POST | An ausgewaehlte Kaskaden-Ziele senden |
/collab-docs/:docId/send-to-space | POST | Direkt in den eigenen Space senden |
/collab-docs/from-document/:documentId | POST | Neuen Draft aus bestehendem DMS-Dokument erstellen |
/collab-docs/:docId | DELETE | Draft loeschen |
Senden an Kaskaden-Ziele
Der /send-to-targets Endpoint akzeptiert ein Array von Edge-IDs (oder __space__ fuer den eigenen Space). Fuer jede Kaskaden-Kante wird der Text durch die Linsen des Ziel-Knotens geschickt (Filter/Form/Gate). Der Status des Dokuments wechselt auf 'sent'.
Nginx WebSocket Config
Auf Kundenservern (die API ueber den zentralen Server proxyen) muss eine spezielle Location fuer den Collab-WebSocket konfiguriert sein:
location /api/platform/v1/collab/ {
proxy_pass https://api.prilog.chat/api/platform/v1/collab/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 24h;
proxy_send_timeout 24h;
}Frontend
Hub (/kaskaden)
Eigenstaendiger Hub in der Navigation. Zeigt:
- Alle Kaskaden-Boards als Karten
- "Neue Kaskade" mit Vorlagen-Auswahl
- Klick oeffnet Board in voller Breite
Graph-Ansicht (TopologyCanvas — React Flow)
Basiert auf @xyflow/react v12 (React Flow). Ersetzt den frueheren custom SVG-Canvas:
- Zoom/Pan: Built-in via React Flow (Mausrad, Trackpad, Touch)
- MiniMap + Controls: React Flow Controls-Widget unten rechts
- Edge-Routing:
smoothstepEdges mitpathOptions: { borderRadius: 12, offset: 20 } - Custom Nodes:
CascadeNodeComponent mit foreignObject fuer volle React-Interaktivitaet - Handle-System: Top=Input (Kreis), Bottom=Output (Dreieck), Right=Ja/Nein (Dreiecke)
- Edge-Interaktion: Klick → rot markiert → nochmal klicken → loescht
- Undo-System:
pushUndo()vor destruktiven Aktionen, Wiederherstellung ueber API
CSS-Hinweis: Tailwind v4 resettet SVG-Styles. Die React-Flow-Edge-Pfade benoetigen !important Overrides in styles.css:
.react-flow__edge-path { stroke-width: 2 !important; stroke: ... !important; }Element-Registry (cascade-elements.tsx)
Alle interaktiven Elemente in Knoten werden ueber eine zentrale Registry definiert. Jeder ElementDef hat:
interface ElementDef {
type: string; // Eindeutiger Typname
label: string; // Anzeigename im + Menue
icon: JSX.Element; // Icon im + Menue
color: string; // Tailwind hover-class
defaultConfig: () => ElementConfig;
heightRows: (el: ElementConfig) => number; // Graph-Hoehe
renderGraph: (props) => JSX.Element; // Kleine Darstellung in der Box
renderDesigner: (props) => JSX.Element; // Editor-Felder im Designer
renderPlayer: (props) => JSX.Element; // Vollbild im Player
}Aktuell 11 Elementtypen: decision, dropdown, checklist, radio, condition, textfield, link, space (oeffnen), createSpace, createTasks, button.
Neuen Typ hinzufuegen: Nur eine Definition in cascade-elements.tsx ergaenzen und zu ELEMENT_TYPES hinzufuegen. Kein anderer Code muss angepasst werden.
Visibility-System: Elemente koennen eine visibleWhen-Eigenschaft haben:
{ elementIdx: number, branch: 'then' | 'else' | 'yes' | 'no' | optionId }isElementVisible() prueft zur Laufzeit ob das Element sichtbar ist, basierend auf dem State des referenzierten Elements.
Cross-Element-Referenzen: Das createTasks-Element referenziert ein createSpace-Element ueber sourceSpaceElement (Index im Elements-Array), um die Space-ID des gerade erstellten Space als Ziel zu verwenden.
Designer + Player (cascade-designer.tsx)
Drei Komponenten in einer Datei:
CascadeDesigner: Bearbeitungsansicht fuer einzelne Knoten
- Heading, Body-Text, Element-Editoren aus der Registry
- Sichtbar-wenn-Dropdowns und Dann-weiter-zu-Dropdowns pro Element
- Live-Vorschau des Player-Layouts oben
CascadePlayer: Fullscreen Mobile-First Ablauf-Ansicht
- Navigiert durch den Graphen ueber
navigateFlow() - Unterstuetzt thenGoTo / thenGoToYes / thenGoToNo Routing
- Sendet jeden Schritt als Log-Eintrag an das Backend (fire-and-forget)
- State wird pro Knoten zurueckgesetzt (
setElState({})bei Navigation)
CascadeFlowLog: Echtzeit-Protokoll aller Durchlaeufe
- Pollt alle 3 Sekunden
GET /cascade-boards/:id/flow-log - Gruppiert nach Session (jeder Player-Durchlauf = eine Session)
- Zeigt Zeitstempel, User, Aktion, Knoten, Detail
Gemeinsamer Text (CollabPanel)
Rechtes Detailpanel mit zwei Modi:
- Listen-Ansicht: Gespeicherte Dokumente, "Neu"-Button
- Editor-Ansicht: Tiptap v2 + Y.js Collaboration + CollaborationCursor
Verfuegbar in jedem Mitarbeiter-Space (ohne Schueler/Eltern) mit >1 Mitglied. Zugang ueber das "+" Menue im Chat-Eingabefeld.
Wichtig: Tiptap Collaboration v2.27.2 (nicht v3). V3 mischt @tiptap/y-tiptap mit y-prosemirror → Crash. Beide Extensions muessen dieselbe Bridge (y-prosemirror) nutzen.
Dateien
Backend
| Datei | Beschreibung |
|---|---|
src/modules/cascade/cascade-logic.ts | Filter/Form/Gate Logik + 8 Krisen-Vorlagen |
src/modules/cascade/cascade.router.ts | Board/Column/Edge API + Flow-Log Endpoints |
src/modules/cascade/cascade-auto-forward.ts | Auto-Forward Engine |
src/modules/cascade/cascade-send-helper.ts | Matrix-Sende-Helper |
src/modules/cascade/collab-ws.router.ts | Y.js WebSocket Server |
src/routes/platform-v1/collab.router.ts | Space-basierte Collab REST-API |
src/modules/cascade/index.ts | Modul-Registrierung |
Frontend
| Datei | Beschreibung |
|---|---|
src/features/cascade/cascade-hub.tsx | Hub-Ansicht (Board-Liste) |
src/features/cascade/cascade-panel.tsx | Board-Ansicht mit Graph + Chat + Undo |
src/features/cascade/topology-canvas.tsx | React Flow Graph-Editor mit Custom Nodes |
src/features/cascade/cascade-elements.tsx | Element-Registry (11 Typen, renderGraph/Designer/Player) |
src/features/cascade/cascade-designer.tsx | Designer + Player + FlowLog Komponenten |
src/features/cascade/collab-editor.tsx | CollabPanel + CollabEditor (Y.js + Tiptap v2) |