Files
paperlessmanager/docs/BACKEND_API.md
T
2026-05-09 09:04:20 +02:00

4.7 KiB
Raw Blame History

Backend API LabelPrintAgent

Diese Datei beschreibt die Endpunkte des PaperlessManager-Backends für den LabelPrintAgent.

Das Backend rendert das fertige Etikettbild (SVG → PNG via resvg-js). Der Agent ist nur lokaler Druck-Connector.

Authentifizierung

Alle Endpunkte erfordern einen Bearer Token (JWT oder API-Key):

Authorization: Bearer {token}

/jobs/next, /jobs/:id/image, /jobs/:id/printed und /jobs/:id/error benötigen keine spezifische Permission (nur gültigen Token). POST /jobs und POST /preview erfordern VIEW_SCANNER.


1. Job manuell anlegen (Frontend → Backend)

POST /api/label-print-agent/jobs
Content-Type: application/json

Request Body

{
  "templateId": 3,
  "fieldValues": {
    "datum": "2026-05-09"
  }
}
Feld Pflicht Beschreibung
templateId ja ID des BarcodeTemplates
fieldValues nein Feldwerte für Platzhalter; Datumsfelder im Format YYYY-MM-DD

Antwort

201 Created
{ "jobId": "42" }

2. Vorschau-Bild rendern (kein Job, keine Nummer-Reservierung)

POST /api/label-print-agent/preview
Content-Type: application/json

Request Body

Identisch mit POST /jobs. {number} wird immer als 1 gerendert — die GET-URL wird nicht aufgerufen.

Antwort

200 OK
Content-Type: image/png

Body: binäres PNG-Bild.


3. Nächsten Druckjob abrufen (Agent-Polling)

GET /api/label-print-agent/jobs/next?agentId={agentId}
Parameter Pflicht Beschreibung
agentId nein Eindeutige Agent-ID (z. B. Rechnername); Fallback: "unknown"

Antwort kein Job vorhanden

204 No Content

Antwort Job vorhanden

200 OK
Content-Type: application/json
{
  "jobId": "42",
  "labelImageBase64": "iVBORw0KGgoAAAANSUhEUgAA...",
  "labelImageContentType": "image/png",
  "labelWidthMm": 57,
  "labelHeightMm": 32
}
Feld Beschreibung
jobId Job-ID für Rückmeldungen
labelImageBase64 Base64-PNG; null wenn Rendering fehlgeschlagen
labelImageContentType Immer "image/png"
labelWidthMm / labelHeightMm Etikettenmaß in mm

Das Backend setzt beim Ausliefern einen Lock (5-Minuten-TTL). Jobs mit abgelaufenem Lock werden erneut angeboten.


4. Etikettbild separat abrufen

Alternativ zum Base64-Feld in jobs/next.

GET /api/label-print-agent/jobs/{jobId}/image

Antwort

200 OK
Content-Type: image/png

Body: binäres PNG-Bild.

404 Not Found   Job oder Bild nicht vorhanden

5. Erfolgreichen Druck melden

POST /api/label-print-agent/jobs/{jobId}/printed
Content-Type: application/json

Request Body

{
  "agentId": "PC-BUERO",
  "printerName": "DYMO LabelWriter 450"
}

Alle Felder optional; Fallback jeweils "" / "unknown".

Antwort

200 OK
{ "ok": true }

Das Backend setzt den Job auf printed, speichert Zeitstempel und ruft die konfigurierte LabelPrintedUrl des Templates auf (POST).


6. Druckfehler melden

POST /api/label-print-agent/jobs/{jobId}/error
Content-Type: application/json

Request Body

{
  "agentId": "PC-BUERO",
  "printerName": "DYMO LabelWriter 450",
  "errorMessage": "Drucker nicht verfügbar."
}

Antwort

200 OK
{ "ok": true }

Das Backend setzt den Job auf error und ruft die konfigurierte LabelReleaseUrl des Templates auf (POST).


Job-Lebenszyklus

createJob()
    │
    ▼
 pending ──── jobs/next ──── Lock (5 Min TTL)
                │
         Agent druckt
                │
        ┌───────┴───────┐
      printed          error
   (PrintedUrl)    (ReleaseUrl)

7. Server-Sent Events neue Druckaufträge (Push)

GET /api/label-print-agent/events
Authorization: Bearer {token}
Accept: text/event-stream

Der Agent verbindet sich einmalig. Sobald ein neuer Druckauftrag erstellt wird, sendet das Backend:

data: {"type":"label-job-available"}

Der Agent ruft daraufhin sofort GET /jobs/next auf. Polling bleibt als Fallback sinnvoll (z. B. alle 30 s), falls die SSE-Verbindung unterbrochen wurde.

Es werden keine agentId-Parameter ausgewertet alle verbundenen Agents erhalten das Event.


Statuscodes

Situation Status
Kein Job vorhanden 204 No Content
Job / Bild vorhanden 200 OK
Job erstellt 201 Created
Token fehlt / ungültig 401 Unauthorized
Fehlende Permission 403 Forbidden
Job-ID unbekannt 404 Not Found
Backend-Fehler 500 Internal Server Error