REST-API-Referenz

DocPlatform stellt eine RESTful-JSON-API unter /api/v1/ bereit. Alle Endpunkte erfordern Authentifizierung, sofern nicht anders angegeben.

Basis-URL

http://localhost:3000/api/v1

Authentifizierung

Die meisten Endpunkte erfordern einen JWT-Access-Token im Authorization-Header:

Authorization: Bearer eyJhbGciOiJSUzI1NiIs...

Token erhalten Sie über die Login- oder OIDC-Endpunkte.

Token-Lebenszyklus

Token Lebensdauer Zweck
Access-Token 15 Minuten API-Authentifizierung
Refresh-Token 30 Tage Neue Access-Token erhalten

Auth-Endpunkte

Registrieren

POST /api/v1/auth/register

Erstellt ein neues Benutzerkonto. Der erste Benutzer wird zum Super Admin.

Anfrage:

{
  "name": "Jane Smith",
  "email": "[email protected]",
  "password": "secure-password-here"
}

Antwort: 201 Created

{
  "user": {
    "id": "01HJK...",
    "name": "Jane Smith",
    "email": "[email protected]",
    "role": "superadmin"
  },
  "access_token": "eyJhbG...",
  "refresh_token": "eyJhbG...",
  "expires_in": 900
}

Anmelden

POST /api/v1/auth/login

Authentifizierung mit E-Mail und Passwort.

Anfrage:

{
  "email": "[email protected]",
  "password": "secure-password-here"
}

Antwort: 200 OK

{
  "access_token": "eyJhbG...",
  "refresh_token": "eyJhbG...",
  "expires_in": 900
}

Fehler:

Code Beschreibung
401 Ungültige Anmeldedaten
429 Zu viele Anmeldeversuche (Rate-Limit)

Token aktualisieren

POST /api/v1/auth/refresh

Tauscht einen Refresh-Token gegen einen neuen Access-Token. Der Refresh-Token wird rotiert (alter wird invalidiert).

Anfrage:

{
  "refresh_token": "eyJhbG..."
}

Antwort: 200 OK

{
  "access_token": "eyJhbG...",
  "refresh_token": "eyJhbG...",
  "expires_in": 900
}

Passwort-Zurücksetzung anfordern

POST /api/v1/auth/password-reset

Fordert einen Token zur Passwort-Zurücksetzung an. Mit konfiguriertem SMTP wird eine E-Mail gesendet. Ohne SMTP wird der Token auf stdout geloggt.

Anfrage:

{
  "email": "[email protected]"
}

Antwort: 200 OK (immer, unabhängig davon, ob die E-Mail existiert — verhindert Enumeration)

Passwort-Zurücksetzung bestätigen

POST /api/v1/auth/password-reset/confirm

Setzt ein neues Passwort mit einem Reset-Token.

Anfrage:

{
  "token": "reset-token-here",
  "new_password": "new-secure-password"
}

Antwort: 200 OK


Inhalts-Endpunkte

Alle Inhalts-Endpunkte sind einem Workspace zugeordnet.

Seiten auflisten

GET /api/v1/workspaces/{workspace_id}/pages

Gibt alle Seiten zurück, für die der aktuelle Benutzer Leserechte hat.

Query-Parameter:

Parameter Typ Beschreibung
parent_id string Nach übergeordneter Seite filtern (für Baumnavigation)
tag string Nach Tag filtern
published boolean Nach Veröffentlichungsstatus filtern
limit int Maximale Ergebnisse (Standard: 100)
offset int Paginierungsoffset

Antwort: 200 OK

{
  "pages": [
    {
      "id": "01HJK...",
      "title": "Getting Started",
      "slug": "getting-started",
      "description": "Install and configure DocPlatform.",
      "path": "getting-started.md",
      "tags": ["guide"],
      "published": true,
      "access": "public",
      "created_at": "2026-03-08T10:00:00Z",
      "updated_at": "2025-01-16T14:30:00Z",
      "author_id": "01HJK..."
    }
  ],
  "total": 42,
  "limit": 100,
  "offset": 0
}

Seite abrufen

GET /api/v1/workspaces/{workspace_id}/pages/{page_id}

Antwort: 200 OK

{
  "id": "01HJK...",
  "title": "Getting Started",
  "slug": "getting-started",
  "description": "Install and configure DocPlatform.",
  "path": "getting-started.md",
  "content": "# Getting Started\n\nThis guide walks you through...",
  "content_hash": "sha256:abc123...",
  "tags": ["guide"],
  "published": true,
  "access": "public",
  "parent_id": null,
  "created_at": "2026-03-08T10:00:00Z",
  "updated_at": "2025-01-16T14:30:00Z",
  "author_id": "01HJK..."
}

Fehler:

Code Beschreibung
403 Unzureichende Berechtigungen
404 Seite nicht gefunden

Seite erstellen

POST /api/v1/workspaces/{workspace_id}/pages

Anfrage:

{
  "title": "New Page",
  "slug": "new-page",
  "content": "# New Page\n\nContent here...",
  "description": "Description for search and SEO.",
  "tags": ["guide"],
  "published": false,
  "parent_id": null
}

Antwort: 201 Created — gibt das vollständige Seitenobjekt zurück.

Seite aktualisieren

PUT /api/v1/workspaces/{workspace_id}/pages/{page_id}

Anfrage:

{
  "title": "Updated Title",
  "content": "# Updated Title\n\nUpdated content...",
  "content_hash": "sha256:abc123..."
}

Das Feld content_hash ermöglicht optimistische Nebenläufigkeit. Wenn der Hash nicht mit der aktuellen Version übereinstimmt, gibt der Server 409 Conflict zurück.

Antwort: 200 OK — gibt das aktualisierte Seitenobjekt zurück.

Fehler:

Code Beschreibung
409 Content-Hash-Abweichung (gleichzeitige Bearbeitung erkannt)

Seite löschen

DELETE /api/v1/workspaces/{workspace_id}/pages/{page_id}

Antwort: 204 No Content


Workspace-Endpunkte

Workspaces auflisten

GET /api/v1/workspaces

Gibt Workspaces zurück, in denen der aktuelle Benutzer Mitglied ist.

Workspace erstellen

POST /api/v1/workspaces

Erfordert die Super Admin-Rolle.

Anfrage:

{
  "name": "API Docs",
  "slug": "api-docs",
  "git_remote": "[email protected]:org/api-docs.git",
  "git_branch": "main"
}

Workspace-Mitglieder

GET /api/v1/workspaces/{workspace_id}/members
POST /api/v1/workspaces/{workspace_id}/invitations
DELETE /api/v1/workspaces/{workspace_id}/members/{user_id}
PUT /api/v1/workspaces/{workspace_id}/members/{user_id}/role

Suche

GET /api/v1/workspaces/{workspace_id}/search?q={query}

Query-Parameter:

Parameter Typ Beschreibung
q string Suchabfrage (erforderlich)
tag string Nach Tag filtern
limit int Maximale Ergebnisse (Standard: 20)

Antwort: 200 OK

{
  "results": [
    {
      "page_id": "01HJK...",
      "title": "Git Integration",
      "description": "Bidirectional git sync...",
      "path": "guides/git-integration.md",
      "score": 0.95,
      "highlights": [
        "...bidirectional <mark>git sync</mark> lets your team..."
      ]
    }
  ],
  "total": 5,
  "query": "git sync",
  "took_ms": 12
}

Ergebnisse werden nach Berechtigungen gefiltert — Benutzer sehen nur Seiten, auf die sie Zugriff haben.


Git-Synchronisation

Synchronisation auslösen

POST /api/v1/workspaces/{workspace_id}/sync

Löst manuell einen Git-Pull + Reconciliation aus. Erfordert die Admin-Rolle.

Antwort: 200 OK

{
  "status": "completed",
  "changes": {
    "added": 2,
    "updated": 1,
    "deleted": 0
  }
}

Webhook-Endpunkte

POST /api/v1/webhooks/github
POST /api/v1/webhooks/gitlab
POST /api/v1/webhooks/bitbucket

Diese Endpunkte empfangen Push-Event-Payloads von Git-Hosting-Anbietern. Kein Authentication-Header erforderlich — sie validieren über das GIT_WEBHOOK_SECRET-Shared-Secret.


Health

Diese Endpunkte erfordern keine Authentifizierung.

GET /health    → 200 OK { "status": "ok" }
GET /ready     → 200 OK { "status": "ready", "db": "ok", "search": "ok" }

Fehlerformat

Alle Fehlerantworten verwenden ein einheitliches Format:

{
  "error": {
    "code": "CONFLICT",
    "message": "Content hash mismatch. The page was modified by another user.",
    "details": {
      "current_hash": "sha256:def456...",
      "provided_hash": "sha256:abc123..."
    }
  }
}

Häufige Fehlercodes

HTTP Code Beschreibung
400 BAD_REQUEST Ungültiger Anfragekörper oder Parameter
401 UNAUTHORIZED Fehlende oder ungültige Authentifizierung
403 FORBIDDEN Unzureichende Berechtigungen
404 NOT_FOUND Ressource nicht gefunden
409 CONFLICT Gleichzeitige Modifikation erkannt
429 RATE_LIMITED Zu viele Anfragen
500 INTERNAL_ERROR Serverfehler (Logs prüfen)

Paginierung

Inhaltsauflistungs-Endpunkte verwenden Cursor-basierte Paginierung mit ULIDs für stabile Ergebnisse, auch wenn Inhalte hinzugefügt oder gelöscht werden.

Query-Parameter:

Parameter Typ Standard Beschreibung
cursor string ULID des letzten Elements der vorherigen Seite. Weglassen für die erste Seite.
limit int 20 Anzahl der Ergebnisse pro Seite (max: 100)

Antwort-Metadaten:

{
  "data": [...],
  "next_cursor": "01HJK...",
  "has_more": true
}

Übergeben Sie next_cursor als cursor-Parameter in der nächsten Anfrage. Wenn has_more den Wert false hat, haben Sie das Ende erreicht.


Asset-Uploads

POST /api/v1/workspaces/{workspace_id}/assets

Laden Sie Bilder und Dateien in einen Workspace hoch. Assets werden im assets/-Verzeichnis des Workspace gespeichert und in Git committet, wenn die Synchronisation aktiviert ist.

Anfrage: multipart/form-data mit einem file-Feld.

Limits:

Einschränkung Wert
Maximale Dateigröße 10 MB
Akzeptierte Typen PNG, JPG, GIF, SVG, WebP, PDF

Antwort: 201 Created

{
  "path": "assets/screenshot-2025-01-15.png",
  "url": "/api/v1/workspaces/{workspace_id}/assets/screenshot-2025-01-15.png",
  "size": 245760,
  "content_type": "image/png"
}

Konfliktauflösung

Konflikte auflisten

GET /api/v1/workspaces/{workspace_id}/conflicts

Antwort: 200 OK

{
  "workspace_id": "01HJK...",
  "sync_status": "conflict",
  "conflicts": [
    {
      "path": "guides/editor.md",
      "ours_hash": "abc123...",
      "theirs_hash": "def456...",
      "page_id": "01HJK...",
      "timestamp": "20250115T103045Z"
    }
  ]
}

Konfliktversion herunterladen

GET /api/v1/conflicts/{page_id}/{timestamp}/{version}

Der version-Parameter ist entweder ours (lokal) oder theirs (remote).

Antwort: 200 OK mit Content-Type: text/markdown — roher Dateiinhalt.

Konflikt auflösen

POST /api/v1/conflicts/{page_id}/{timestamp}/resolve

Entfernt Konflikt-Artefakte nach manueller Auflösung.

Antwort: 200 OK

{
  "message": "Conflict resolved",
  "page_id": "01HJK..."
}

WebSocket

Verbindungs-Ticket erhalten

POST /api/v1/auth/ws-ticket

WebSocket-Verbindungen verwenden ein Einmal-Ticket-Verfahren, um zu vermeiden, dass JWT-Token in URLs offengelegt werden.

Antwort: 200 OK

{
  "ticket": "random-ticket-value",
  "expires_in": 30
}

Das Ticket ist 30 Sekunden gültig und kann nur einmal verwendet werden. Verbinden Sie sich über:

ws://localhost:3000/ws?ticket={ticket}

Server-Events

Event-Typ Payload Wann
page-created {workspace_id, path, actor} Eine neue Seite wird erstellt
page-updated {workspace_id, path, actor} Eine Seite wird geändert
page-deleted {workspace_id, path, actor} Eine Seite wird gelöscht
presence-join {workspace_id, user_id} Ein Benutzer verbindet sich
presence-leave {workspace_id, user_id} Ein Benutzer trennt sich (90s Timeout)
sync-status {workspace_id, status} Git-Synchronisationsstatus ändert sich
conflict-detected {workspace_id, path} Git-Merge-Konflikt gefunden
bulk-sync {workspace_id, changed_count, paths[]} Mehrere Dateien synchronisiert (>20 Dateien)

Client-Nachrichten

{"type": "subscribe", "workspace_id": "01HJK..."}
{"type": "unsubscribe", "workspace_id": "01HJK..."}

Sicherheits-Header

DocPlatform setzt folgende Header auf allen Antworten:

Header Wert
X-Content-Type-Options nosniff
X-Frame-Options DENY
Content-Security-Policy default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
X-Request-ID ULID (eindeutig pro Anfrage, in Fehlerantworten und Logs enthalten)

Veröffentlichte Dokumentation setzt zusätzlich:

Header Wert
Cache-Control public, max-age=300
ETag Content-Hash der gerenderten Seite

Rate-Limiting

Endpunkt-Kategorie Community Edition
Leseoperationen 100 / Minute pro Benutzer
Schreiboperationen 20 / Minute pro Benutzer
Suche 30 / Minute pro Benutzer
Auth (Login, Registrierung, Zurücksetzung) 5 / Minute pro IP
Git-Webhooks 10 / Minute pro Workspace
Veröffentlichte Dokumentation (öffentlich) 1.000 / Minute pro IP

Rate-Limit-Antworten enthalten Retry-After (Sekunden) und X-RateLimit-Reset (Unix-Zeitstempel) Header.