Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
5.9 KiB
DMS-API v1
Schnittstellenbeschreibung: GET /api/dms/v1/openapi.json (OpenAPI 3.0, Quelle internal/openapi/openapi.json). Die Oberfläche nutzt ausschließlich diese Schnittstelle.
Versionierung und Routen
Alle Endpunkte liegen unter /api/dms/v1 (Registerpräfix aus deploy/routes.tsv, wie /api/core/v1). Es gibt keine DMS-eigene Versionierung: eine neue Version ist ein neues Präfix des zentralen Schemas, bestehende Pfade bleiben unberührt.
Authentifizierung
Authorization: Bearer <Core-Modul-JWT> (EdDSA, kid-Header, Claims sub und tenant; Schlüssel per JWKS von Core, NEXARCH_DMS_APP_CORE_JWKS_URL). Der Mandant im Token muss dem Mandanten der Instanz (NEXARCH_DMS_APP_TENANT_SLUG) entsprechen. Die Identität kommt ausschließlich aus dem Token; ein mitgeschickter caller-Parameter oder X-User-Id-Header wird überschrieben.
Ohne Token: 401. Ohne Erreichbarkeit von Core und ohne bekannten Schlüsselsatz: 503. Bereits bekannte Schlüssel gelten bei einem Core-Ausfall weiter.
Ausnahmen ohne Nutzeridentität: GET /download (Signatur der zuvor angeforderten URL), POST /retention/destroy-callback (Archive, Dienst-zu-Dienst) und GET /openapi.json.
Übergangsmodus: mit NEXARCH_DMS_APP_ALLOW_CALLER_IDENTITY=true gilt ohne Token der Parameter caller als Identität (nicht authentifiziert, nur für Entwicklung). Ohne JWKS-URL und ohne diesen Schalter startet der Dienst nicht.
Rechte
Objektzugriff (Eigentümer, Admin, Prüfer) erzwingt der Guard vor jedem Handler. Dokumentlisten eines Ordners (GET /folders/documents, GET /folders/{id}/documents) enthalten nur Dokumente des Aufrufers und verlangen eine Identität (401 ohne). Mit NEXARCH_DMS_APP_POLICY_URL fragt das DMS zusätzlich je Route Core (POST /authorize, Header X-Service-Token) nach dem in der OpenAPI-Beschreibung als x-permission deklarierten Recht. Die Rolle stammt aus dem Token-Claim role, sonst gilt NEXARCH_DMS_APP_POLICY_DEFAULT_ROLE (Standard user), Admin-IDs erhalten tenant_admin. Fehler oder Ausfall von Core lehnen die Anfrage ab (503, nie stillschweigend erlaubt).
Fehlerformat
Jede Fehlerantwort (>= 400, auch 404/405 des Routers) hat das Core-Schema:
{"error": {"code": "not_found", "message": "dokument nicht gefunden"}}
code ist stabil und maschinenlesbar (invalid_request, unauthenticated, forbidden, not_found, method_not_allowed, conflict, unprocessable, payload_too_large, locked, unavailable, internal_error). Zusatzfelder (z. B. documentId beim Duplikat) stehen daneben.
Beispiele
Die folgenden Blöcke werden von TestDocumentationExamples gegen die verdrahtete Anwendung ausgeführt. capture name=schluessel merkt sich einen Wert der JSON-Antwort für spätere {name}-Platzhalter.
Upload-Sitzung starten:
POST /uploads -> 201
capture sessionId=sessionId
{"filename":"beleg.txt","mimeType":"text/plain","totalSize":16}
Datenblock senden (fortsetzbar über offset):
PUT /uploads/{sessionId}/chunk?offset=0 -> 200
Rechnung 4711 ok
Stand abfragen:
GET /uploads/{sessionId} -> 200
Abschließen, Dokument und erste Revision entstehen:
POST /uploads/{sessionId}/complete -> 200
capture documentId=documentId
Dokument lesen:
GET /documents/{documentId} -> 200
GET /documents/{documentId}/content -> 200
GET /documents/{documentId}/revisions -> 200
Tags und Metadaten:
GET /documents/{documentId}/tags -> 200
GET /documents/{documentId}/metadata -> 200
GET /metadata-fields -> 200
Ordner und Papierkorb:
GET /folders/children -> 200
GET /trash -> 200
Dokument in den Papierkorb verschieben (Auswahl von document_ids und/oder folder_ids; Antwort mit trashed_*_ids und failed je ID, ein von anderen ausgeliehenes Dokument und ein Ordner mit Dokumenten anderer Nutzer werden abgelehnt) und wiederherstellen:
POST /trash -> 200
{"document_ids":["{documentId}"]}
POST /trash/restore -> 200
{"document_ids":["{documentId}"]}
Signierte Download-URL anfordern:
GET /documents/{documentId}/download-url -> 200
Fehlerformat bei unbekanntem Dokument:
GET /documents/00000000-0000-0000-0000-000000000000/tags -> 403
Schnittstellenbeschreibung (ohne Anmeldung):
GET /openapi.json -> 200 anonymous
Freigabelinks (DOC-22)
Ein Dokument lässt sich ohne DMS-Konto teilen: POST /documents/{id}/share-links (nur der Eigentümer, Rechte dms.sharelink.write) legt einen Link mit Pflichtablauf, optionalem Passwort und optionalem Download-Limit an; die Antwort enthält den Token nur dieses eine Mal in der URL. GET /documents/{id}/share-links (Rechte dms.sharelink.read) listet bestehende Links ohne Token/Passwort, DELETE /documents/{id}/share-links/{linkID} widerruft sofort.
Der Abruf läuft ohne Anmeldung über GET /share/{token} bzw. POST /share/{token} (Passwort im JSON-Body, nie in der URL oder im Query-String) und ist in der OpenAPI-Beschreibung als "security": [] markiert. Jeder nicht nutzbare Ausgang (unbekannt, abgelaufen, widerrufen, Limit erreicht) liefert einheitlich 404; ein gesetztes Passwort liefert ohne Angabe 401 password_required, nach zu vielen Fehlversuchen 423 locked.
Konfiguration per Umgebungsvariable (siehe BETRIEB-UMGEBUNGSVARIABLEN.md): NEXARCH_DMS_APP_SHARE_LINKS_ENABLED (Mandanten-Schalter), NEXARCH_DMS_APP_SHARE_LINK_DEFAULT_TTL_SECONDS, NEXARCH_DMS_APP_SHARE_LINK_MAX_TTL_SECONDS, NEXARCH_DMS_APP_SHARE_LINK_MAX_ATTEMPTS, NEXARCH_DMS_APP_SHARE_LINK_LOCKOUT_SECONDS.
Optionale CMIS-Schnittstelle
Neben der REST-API gibt es eine abschaltbare CMIS-1.1-Schnittstelle (Browser Binding) unter /api/dms/v1/cmis/browser. Sie nutzt intern diese REST-API und damit dieselben Rechte- und Mandantenregeln; Einzelheiten in CMIS.md.