Files
LabelPrintAgent/BACKEND_API.md
T

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 einen 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()
    |
    v
 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. Ein Poll-Lauf ruft /jobs/next wiederholt auf, bis das Backend 204 No Content zurückgibt. Polling bleibt als Fallback sinnvoll, z. B. alle 30 Sekunden, 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