CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
144 lines
5.9 KiB
Markdown
144 lines
5.9 KiB
Markdown
# 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:
|
|
|
|
```json
|
|
{"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:
|
|
|
|
```example
|
|
POST /uploads -> 201
|
|
capture sessionId=sessionId
|
|
{"filename":"beleg.txt","mimeType":"text/plain","totalSize":16}
|
|
```
|
|
|
|
Datenblock senden (fortsetzbar über `offset`):
|
|
|
|
```example
|
|
PUT /uploads/{sessionId}/chunk?offset=0 -> 200
|
|
Rechnung 4711 ok
|
|
```
|
|
|
|
Stand abfragen:
|
|
|
|
```example
|
|
GET /uploads/{sessionId} -> 200
|
|
```
|
|
|
|
Abschließen, Dokument und erste Revision entstehen:
|
|
|
|
```example
|
|
POST /uploads/{sessionId}/complete -> 200
|
|
capture documentId=documentId
|
|
```
|
|
|
|
Dokument lesen:
|
|
|
|
```example
|
|
GET /documents/{documentId} -> 200
|
|
```
|
|
|
|
```example
|
|
GET /documents/{documentId}/content -> 200
|
|
```
|
|
|
|
```example
|
|
GET /documents/{documentId}/revisions -> 200
|
|
```
|
|
|
|
Tags und Metadaten:
|
|
|
|
```example
|
|
GET /documents/{documentId}/tags -> 200
|
|
```
|
|
|
|
```example
|
|
GET /documents/{documentId}/metadata -> 200
|
|
```
|
|
|
|
```example
|
|
GET /metadata-fields -> 200
|
|
```
|
|
|
|
Ordner und Papierkorb:
|
|
|
|
```example
|
|
GET /folders/children -> 200
|
|
```
|
|
|
|
```example
|
|
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:
|
|
|
|
```example
|
|
POST /trash -> 200
|
|
{"document_ids":["{documentId}"]}
|
|
```
|
|
|
|
```example
|
|
POST /trash/restore -> 200
|
|
{"document_ids":["{documentId}"]}
|
|
```
|
|
|
|
Signierte Download-URL anfordern:
|
|
|
|
```example
|
|
GET /documents/{documentId}/download-url -> 200
|
|
```
|
|
|
|
Fehlerformat bei unbekanntem Dokument:
|
|
|
|
```example
|
|
GET /documents/00000000-0000-0000-0000-000000000000/tags -> 403
|
|
```
|
|
|
|
Schnittstellenbeschreibung (ohne Anmeldung):
|
|
|
|
```example
|
|
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](CMIS.md).
|