Import/Export-Standard — Konzept
Ein einheitlicher Standard für den Import und Export von Prilog-Daten. Beginnt mit Aufgaben (WorkItem), wächst Schritt für Schritt zu Kontakten, Dokumenten, Briefen, Kalender-Einträgen.
Ziele
- Schul-IT-tauglich: Sekretariat soll mit Excel oder einem Texteditor einen Import vorbereiten können.
- Versionssicher: alte Exports lassen sich auch in 5 Jahren noch importieren — Schema-Version steht im Datei-Header.
- Wachstumsfähig: neue Entitäten kommen einfach dazu, ohne den Standard zu ändern.
- DSGVO-tauglich: jeder Import/Export wird im Activity-Log dokumentiert (wer, wann, wieviele Items).
- Kein Vendor-Lock: Daten gehören dem Kunden — Export liefert lesbares JSON, niemand braucht Prilog um die Daten zu verstehen.
Format-Familie
Zwei Formate werden unterstützt, beide bauen auf demselben Datenmodell:
JSON (Hauptformat)
Strukturiert, hierarchisch, mit Sub-Entitäten (Checklisten, Kommentare). Default für Export. Eingabeformat für API-zu-API-Migration.
CSV (Sekundärformat)
Tabellarisch, ohne Sub-Entitäten. Excel-kompatibel. Default für manuellen Import durch Sekretariat. Nur Top-Level-Felder, Sub-Entitäten werden weggelassen oder per Spalten-Konvention serialisiert (z.B. assignee_emails: "anna@…|lee@…").
JSON-Schema v1 — Container
Jede JSON-Datei beginnt mit einem festen Container:
{
"$schema": "https://docs.prilog.chat/schema/import-v1.json",
"schema_version": 1,
"entity_type": "tasks",
"exported_at": "2026-05-10T08:00:00Z",
"exported_by": "@lee:weser.prilog.team",
"tenant_slug": "weser",
"items": [ /* Entity-spezifische Objekte */ ]
}Pflichtfelder:
| Feld | Bedeutung |
|---|---|
schema_version | Integer. Aktuell 1. Beim Import abgelehnt wenn unbekannt. |
entity_type | String. Welche Art Daten? tasks, contacts, documents, … |
items | Array. Die eigentlichen Daten-Objekte. |
Optional:
| Feld | Bedeutung |
|---|---|
exported_at | ISO-8601 — wann wurde exportiert. |
exported_by | Matrix-User-ID des Exporteurs (Audit). |
tenant_slug | Quell-Tenant — Hinweis bei Cross-Tenant-Import (z.B. zwischen Prilog-Instanzen). |
default_space_id | Wenn ein Item space_id weglässt, wird dieser Wert verwendet. Praktisch beim Bulk-Import in einen einzelnen Space. |
notes | Freitext-Beschreibung des Exports. |
Entity-Schema v1 — tasks
{
"_import_id": "extern-1234",
"title": "Klassenrats-Beschluss umsetzen",
"description": "Beschluss vom 12.4. — Theaterprojekt für 2026/27",
"status": "in_progress",
"priority": "high",
"due_date": "2026-05-15T00:00:00Z",
"start_date": null,
"space_id": "space-xyz",
"board_name": "Aufgaben",
"assignee_emails": ["anna@weser-schule.de", "lee@weser-schule.de"],
"responsible_email": "lee@weser-schule.de",
"checklists": [
{
"title": "Vorbereitung",
"items": [
{ "title": "Klassenrat informieren", "checked": true },
{ "title": "Eltern anschreiben", "checked": false }
]
}
],
"comments": [
{
"content": "Schulleitung hat zugestimmt.",
"created_by_email": "anna@weser-schule.de",
"created_at": "2026-04-15T10:00:00Z"
}
],
"completion": {
"type": "decision",
"note": "Klassenrat einstimmig — Aufführung am 17.6.",
"completed_at": "2026-05-09T14:30:00Z",
"completed_by_email": "anna@weser-schule.de"
}
}Feld-Referenz
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
_import_id | String | nein | Externe ID aus dem Quell-System (Excel-Zeilennummer, Trello-ID …). Wird im Activity-Log mitgeführt; nicht in der Prilog-DB als Primärschlüssel verwendet. |
title | String | ja | Aufgaben-Titel, max 500 Zeichen. |
description | String oder null | nein | Längere Beschreibung. |
status | Enum | nein | todo (Default), in_progress, review, done. |
priority | Enum | nein | low, medium (Default), high, critical. |
due_date | ISO-8601 oder null | nein | Fälligkeit. |
start_date | ISO-8601 oder null | nein | Startdatum. |
space_id | String oder null | nein | Ziel-Space. Wenn null, wird default_space_id aus dem Container verwendet. |
board_name | String oder null | nein | Wenn das Board mit dem Namen nicht existiert, wird das Default-Board des Spaces verwendet. |
assignee_emails | Array<String> | nein | Bearbeiter — werden über Email zur Matrix-User-ID aufgelöst (UserDirectoryEntry-Lookup im Tenant). Unbekannte Emails werden weggelassen + im Result-Report aufgelistet. |
responsible_email | String oder null | nein | Verantwortliche Person. |
checklists | Array<Checklist> | nein | Sub-Entität (siehe unten). |
comments | Array<Comment> | nein | Sub-Entität (siehe unten). |
completion | Object oder null | nein | Beim Status done: Resultat-Doku (Phase F). |
Sub-Schema Checklist
{ "title": "...", "items": [{ "title": "...", "checked": true }] }Sub-Schema Comment
{ "content": "...", "created_by_email": "...", "created_at": "ISO-8601" }Sub-Schema Completion
{
"type": "decision" | "letter" | "note" | "snoozed" | "other",
"note": "...",
"completed_at": "ISO-8601",
"completed_by_email": "..."
}Beim Import wird beim Setzen von status: 'done' die Resultat-Validierung wie im normalen Done-Flow angewandt — fehlt completion.type, schlägt der Import für dieses Item fehl (mit klarer Fehlermeldung im Result-Report).
CSV-Schema v1 — tasks
Eine Zeile pro Aufgabe. Sub-Entitäten werden weggelassen (Excel kann Hierarchie nicht darstellen). Kommentare/Checklisten können nachträglich im UI ergänzt werden.
Header:
title,description,status,priority,due_date,start_date,space_id,board_name,assignee_emails,responsible_email,completion_type,completion_noteBeispiel-Zeile:
"Klassenrats-Beschluss umsetzen","Theater 2026/27","in_progress","high","2026-05-15","","space-xyz","Aufgaben","anna@weser-schule.de|lee@weser-schule.de","lee@weser-schule.de","",""- Multi-Wert-Felder (
assignee_emails): pipe-getrenntemail1|email2|email3. - Datum:
YYYY-MM-DDreicht; Zeit-Komponente optional. - Leere Felder: einfach leer, nicht
null. - Anführungszeichen doppeln (Excel-Konvention) wenn der Wert ein Komma enthält.
CSV-Import liefert dieselben Result-Reports wie JSON-Import (siehe unten).
Result-Report
Jeder Import-Endpoint liefert ein strukturiertes Ergebnis:
{
"schema_version": 1,
"entity_type": "tasks",
"imported": 23,
"failed": 2,
"warnings": [
{ "_import_id": "extern-1234", "field": "assignee_emails", "message": "Email anna@weser-schule.de nicht im Verzeichnis gefunden — Bearbeiter wurde weggelassen" }
],
"errors": [
{ "_import_id": "extern-1240", "message": "title fehlt — Pflichtfeld" }
],
"items": [
{ "_import_id": "extern-1234", "id": "cuid-...", "status": "imported" }
]
}- Imported: Anzahl erfolgreich angelegter Items.
- Failed: Anzahl Items mit harten Fehlern (Pflichtfeld fehlt, ungültige Enum-Werte, …).
- Warnings: Items wurden angelegt, aber nicht alles war perfekt (z.B. unbekannte Email).
- Items: Mapping
_import_id → erzeugte Prilog-IDfür nachgelagerte Verknüpfungen.
Backwards-Compatibility-Strategie
Wenn schema_version erhöht wird (z.B. auf 2), gelten folgende Regeln:
- Alte Exports bleiben importierbar — der Import-Endpoint kennt v1 + v2.
- Neue Felder in v2 sind optional bei v1-Daten (
undefinedist OK). - Umbenennungen / Entfernungen brauchen einen expliziten Migration-Pfad — der wird im Konzept-Doc-Update dokumentiert, bevor v2 ausgerollt wird.
- Drei Versionen rückwärts werden mindestens unterstützt (v1, v2, v3 wenn v4 kommt).
Activity-Log-Integration
Pro Import wird ein Activity-Eintrag mit contentType: 'import.batch' geschrieben:
{
"title": "23 Aufgaben importiert (2 Warnungen)",
"metadata": {
"entity_type": "tasks",
"imported": 23,
"failed": 2,
"source": "json|csv|api",
"actor": "..."
}
}Pro fehlgeschlagenem Import-Item wird kein einzelner Eintrag geschrieben (sonst Spam) — die Fehler stehen im Result-Report, der im Frontend angezeigt wird und im Backend für 7 Tage zur Nachschau gecached werden kann (Phase 2).
Permission-Model
| Aktion | Wer darf? |
|---|---|
| Export aller Tasks aus einem Space | Mitglied des Spaces (task:read) |
| Export tenant-weit aller Tasks | Schul-Admin |
| Import in einen Space | Mitglied mit file:upload (kann auch Tasks erzeugen) |
| Import tenant-weit (Bulk-Provisioning) | Schul-Admin |
Beim Import gilt die normale Schreibberechtigung für jedes erzeugte WorkItem. Email-Lookups sind tenant-isoliert: anna@weser-schule.de wird nur unter weser-Tenant aufgelöst.
Roadmap
| Phase | Inhalt | Aufwand |
|---|---|---|
| 1 | Backend: Tasks-Export (JSON+CSV) + Tasks-Import (JSON+CSV) | ~6h |
| 2 | Frontend: Hub-Page mit Tasks Export/Import + File-Upload + Vorschau | ~4h |
| 3 | Result-Report-Cache + Activity-Log-Integration | ~2h |
| 4 | Kontakte-Export/Import (Phase 2 der App) | später |
| 5 | Dokumente-Export (DMS-Bulk-Download als ZIP) | später |
| 6 | Briefe / Kalender / Checklisten-Templates | später |
Phasen 1+2+3 werden in der ersten Implementations-Welle gebaut. Phase 4 startet, sobald Phase 1–3 produktiv getestet sind.
Konvention für JSON-Schema-Dateien
Die formalen JSON-Schema-Definitionen liegen unter prilog_docs/public/schema/import-v1.json und werden über https://docs.prilog.chat/schema/import-v1.json ausgeliefert. Damit kann jeder externe Tool (z.B. Excel-Validator, JSON-Editor) gegen das Schema prüfen.
Was wir nicht tun
- Kein binäres Format (Excel
.xlsxdirekt) — wir nehmen CSV. Wer xlsx will, exportiert aus Excel als CSV. - Kein Round-Trip-ID-Garant — beim Import werden frische Prilog-IDs vergeben. Externe IDs landen in
_import_idzur späteren Verknüpfung, nicht als Primärschlüssel. - Keine selektiven Feld-Updates beim Import — Import erzeugt neue WorkItems. Updates auf bestehende WorkItems gehen über die normale
PATCH-API. (Phase 2 könnte Update-by-_import_idergänzen.) - Keine automatische Konflikt-Auflösung — wenn
_import_idbereits importiert wurde, wird das Item beim Re-Import als Duplikat angelegt. Frontend zeigt eine Vorschau mit Duplikat-Warnung.