Skip to content

⚠️ 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.

Krisenmanagement — Technische Architektur

Plugin-Einordnung

Das Krisenmanagement ist als reines Plugin im Prilog-Modulsystem implementiert. Es folgt der 3-Stufen-Aktivierung (Registry → Installation → Aktivierung) und nutzt die bestehende Infrastruktur.

prilog-backend-api/src/modules/crisis-management/
├── prilog-module.json              # Manifest (featureFlag: crisis-management)
├── index.ts                        # register/unregister/cleanup + Fastify-Plugin
├── types.ts                        # TypeScript-Typen + DTOs
├── crisis.router.ts                # Szenarien + Workflow Endpoints
├── n8n-callback.router.ts          # n8n Callback-Endpoints
├── n8n-workflow.service.ts         # n8n-Integration (ersetzt WorkflowService)
├── n8n-client.ts                   # HTTP-Client fuer n8n API
├── matrix-crisis.service.ts        # Matrix-Raum-Erstellung + Nachrichten
├── report-pdf.service.ts           # PDF-Generierung (pdfkit)
├── school-trip.router.ts           # Schulreise-Endpoints
├── child-protection.router.ts      # Kinderschutz-Endpoints
├── integrations.router.ts          # Export-Endpoints
└── integrations/
    ├── index.ts                    # Adapter-Initialisierung
    ├── types.ts                    # ExportAdapter Interface
    ├── adapter-registry.ts         # Zentrale Registry
    ├── pdf-a.adapter.ts            # PDF/A-Langzeitarchivierung
    ├── youth-office.adapter.ts     # Jugendamt §8a SGB VIII
    ├── police.adapter.ts           # Polizei-Berichte
    └── data-protection.adapter.ts  # DSGVO Art. 33

Datenmodell

Entity-Relationship

CrisisScenario (1) ──→ (*) CrisisEvent
                            ├──→ (*) CrisisTask
                            ├──→ (1) CrisisReport
                            └──→ (*) CrisisAuditEntry

SchoolTripEvent (standalone, tenantId-scoped)
ChildProtectionCase (standalone, tenantId-scoped)

Prisma-Models

CrisisScenario

Versioniertes Konfigurationsobjekt. Jede Bearbeitung erstellt eine neue Version; die alte wird deaktiviert (isActive: false). Ohne Freigabe (approvedBy) nicht im Workflow-Tab sichtbar.

FeldTypBeschreibung
idString (cuid)Primaerschluessel
tenantIdStringMulti-Tenancy-Scope
nameStringAnzeigename
nameSlugStringURL-freundlicher Name
severityStringCRITICAL / HIGH / MEDIUM
typeStringGENERAL / CHILD_PROTECTION / SCHOOL_TRIP
targetResponseMsIntSoll-Reaktionszeit in ms
versionIntVersionsnummer (auto-increment)
isActiveBooleanNur die neueste Version ist aktiv
approvedByString?User-ID des Freigebenden
checklistItemsJsonChecklistItem[]
externalContactsJsonExternalContact[]
escalationRulesJsonEscalationRule[]

Unique Constraint: (tenantId, nameSlug, version)

CrisisEvent

Repraesentiert eine aktive oder abgeschlossene Krise.

FeldTypBeschreibung
statusStringACTIVE → RESOLVED / FALSE_ALARM / ARCHIVED
matrixRoomIdString?ID des automatisch erstellten Matrix-Raums
activationNoteString?Freitext bei Aktivierung

CrisisTask

Einzelne Checklisten-Aufgabe, erstellt bei Krisenaktivierung.

FeldTypBeschreibung
statusStringOPEN → IN_PROGRESS → DONE / ESCALATED
escalationLevelIntAktuelle Eskalationsstufe (0 = keine)
checklistItemIdStringVerknuepfung zum Template

CrisisAuditEntry

Lueckenlose Protokollierung aller Aktionen.

FeldTypBeschreibung
actionStringACTIVATE / DEACTIVATE / FALSE_ALARM / TASK_DONE / ESCALATE / EXPORT / CONFIG_CHANGE
actorIdStringUser-ID oder "system"
metadataJson?Zusaetzliche Kontextdaten

JSON-Feld-Typen

typescript
interface ChecklistItem {
  id: string;
  order: number;
  title: string;
  description?: string;
  assignedRole: string;
  escalateAfterMs: number;
  isMandatory: boolean;
}

interface ExternalContact {
  label: string;
  phone: string;
  address?: string;
  notes?: string;
}

interface EscalationRule {
  level: number;
  afterMs: number;
  escalateTo: string[];
  message: string;
}

Services

N8nWorkflowService

Ersetzt den frueheren WorkflowService. Orchestriert Prisma-Transaktionen und delegiert Workflow-Logik (Aufgabenerstellung, Eskalation, Benachrichtigungen) an n8n.

Methoden:

  • activate(dto, actorId, tenantId) — Idempotenzpruefung → Event erstellen → n8n-Workflow triggern
  • deactivate(eventId, actorId, tenantId) — Status RESOLVED → Nachbericht → n8n benachrichtigen
  • markFalseAlarm(eventId, actorId, tenantId, note) — Status FALSE_ALARM → Matrix-Entwarnung
  • updateTaskStatus(eventId, taskId, status, actorId, tenantId) — Status setzen + Audit + Matrix-Update
  • generateReport(eventId, actorId, tenantId) — ReportContent aus Event + Tasks + Audit zusammenbauen

n8n-Integration: Bei Aktivierung wird der verknuepfte n8n-Workflow via n8n-client.ts getriggert. Der Workflow uebernimmt Aufgabenerstellung, Eskalationsueberwachung und Benachrichtigungen ueber Callback-Endpoints.

Idempotenz: assertNoDuplicate() prueft ob fuer das gleiche Szenario bereits ein ACTIVE Event existiert. Gibt 409 zurueck.

MatrixCrisisService

Erstellt Krisenraeume und postet Nachrichten via synapseAdminFetch().

Methoden:

  • createCrisisRoom(tenantId, eventId, scenario, activatedAt) — Raum erstellen, Checkliste anpinnen, Kontakte posten
  • postTaskUpdate(tenantId, roomId, task, actorName) — "Erledigt: [Aufgabe]"
  • postEscalationNotice(tenantId, roomId, task, level) — "Eskalation Stufe X"
  • postFalseAlarmNotice(tenantId, roomId, note) — "ENTWARNUNG"
  • postDeactivationNotice(tenantId, roomId, actorId) — "Krise beendet"

Matrix-Zugang: Nutzt ServerOrder.synapseAdminToken mit Auto-Refresh bei 401. Die Synapse-URL wird aus order.subdomain konstruiert: http://prilog-{subdomain}:8008.

n8n-Integration

Die Eskalationslogik wurde vom Backend in n8n-Workflows ausgelagert. Die frueheren Dateien escalation.service.ts und workflow.service.ts sind entfernt.

Komponenten:

  • n8n-client.ts — HTTP-Client fuer die n8n REST API. Triggert Workflows und uebergibt Event-Kontext (eventId, tenantId, scenarioId).
  • n8n-callback.router.ts — Callback-Endpoints die vom n8n-Workflow aufgerufen werden (Aufgaben erstellen, Matrix-Raum erstellen, Eskalation, Benachrichtigung, Report-Generierung).
  • N8nWorkflowService — Ersetzt WorkflowService. Erstellt Events in der DB und delegiert die Workflow-Ausfuehrung an n8n.

Ablauf:

  1. Bei Krisenaktivierung wird der n8n-Workflow getriggert
  2. n8n ruft Callback-Endpoints auf um Aufgaben zu erstellen, Matrix-Raeume zu oeffnen, etc.
  3. n8n ueberwacht Zeitlimits und ruft den Eskalations-Callback bei Ueberschreitung
  4. Bei Krisenbeendigung wird n8n ueber einen Webhook informiert

Szenarien verknuepfen: Jedes CrisisScenario kann ein n8nWorkflowId enthalten, das auf den zugehoerigen n8n-Workflow verweist.

Adapter-Architektur

ExportAdapter Interface

typescript
interface ExportAdapter {
  id: string;
  type: AdapterType;
  name: string;
  description: string;
  validate(config: AdapterConfig): { valid: boolean; errors: string[] };
  exportCrisisReport(content: unknown, context: ExportContext): Promise<ExportResult>;
  exportChildProtectionCase?(data: unknown, context: ExportContext): Promise<ExportResult>;
}

Registry-Pattern

Adapter registrieren sich beim Modulstart via registerAdapter(). Die initializeIntegrations() Funktion wird in onStartup() aufgerufen.

Adapter-Kaskade

Die Behoerden-Adapter (Jugendamt, Polizei, Datenschutz) nutzen intern den PDF/A-Adapter fuer die Dokumenten-Generierung und fuegen strukturierte JSON-Metadaten hinzu. So entsteht ein duales Format: lesbares PDF + maschinenlesbares JSON.

police.adapter → pdfAAdapter.exportCrisisReport() + strukturiertes JSON

                 ExportResult { data: Buffer(PDF), metadata: { structuredReport: {...} } }

Erweiterbarkeit

Neue Adapter koennen hinzugefuegt werden durch:

  1. Datei in integrations/ erstellen die ExportAdapter implementiert
  2. In integrations/index.ts importieren und registerAdapter() aufrufen
  3. Keine Aenderungen an Routern oder UI noetig — der Adapter erscheint automatisch

Sicherheit

Zugriffskontrolle

BereichErlaubte Rollen
Workflow (Aktivierung)SCHOOL_PRINCIPAL, SCHOOL_ADMIN, SCHOOL_SECRETARY, CUSTODIAN
Workflow (Deaktivierung)SCHOOL_PRINCIPAL, SCHOOL_ADMIN
Szenario-ManagerSCHOOL_PRINCIPAL, SCHOOL_ADMIN
KinderschutzSCHOOL_PRINCIPAL, SCHOOL_ADMIN
Audit-LogSCHOOL_PRINCIPAL, SCHOOL_ADMIN

Tenant-Isolation

Alle Queries sind auf tenantId gefiltert (aus JWT). Cross-Tenant-Zugriff ist auf Datenbankebene ausgeschlossen.

Kinderschutz-Besonderheiten

  • Jeder Zugriff auf einen Fall wird im accessLog protokolliert
  • Meldungen ans Jugendamt erfordern Vier-Augen-Prinzip (2 verschiedene User)
  • Aufbewahrungsfrist: 10 Jahre nach Schliessung (retainUntil)
  • ChildProtectionCase wird bei Modul-Deaktivierung nicht automatisch geloescht

Portal-UI

Komponenten-Struktur

prilog-portal/src/components/spaces/crisis/
├── CrisisModule.tsx          # 5-Tab-Controller
├── crisis-api.ts             # API-Client (alle Endpoints)
├── store.ts                  # Zustand Store
├── workflow/                 # Workflow-Tab
├── szenarien/                # Szenario-Manager
├── school-trips/             # Schulreise-Tab
├── child-protection/         # Kinderschutz-Tab
└── integrations/             # Integrationen-Tab

State Management

Zustand Store (store.ts) mit:

  • Szenarien-Laden (mit approved-Filter)
  • Active Events Polling (10s)
  • Task-Aktualisierung
  • Aktivierung/Deaktivierung
  • Archiv-Laden

Polling

  • Aktive Events: 10s Intervall im WorkflowTab
  • Tasks: 10s Intervall im CrisisDetail
  • Beide Polls stoppen beim Unmount via useEffect Cleanup