# 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): ```http Authorization: Bearer {token} ``` `/printers/register`, `/printers/:printerId/deactivate`, `/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) ```http POST /api/label-print-agent/jobs Content-Type: application/json ``` ### Request Body ```json { "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 ```http 201 Created ``` ```json { "jobId": "42" } ``` ## 2. Vorschau-Bild rendern (kein Job, keine Nummer-Reservierung) ```http 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 ```http 200 OK Content-Type: image/png ``` Body: binäres PNG-Bild. ## 3. Drucker aktivieren/deaktivieren (Benutzeraktion in den Agent-Einstellungen) Der Agent ruft diesen Endpunkt nicht automatisch beim Start auf. Der Benutzer aktiviert lokale Windows-Drucker bewusst über die Agent-Einstellungen. ```http POST /api/label-print-agent/printers/register Content-Type: application/json ``` ```json { "printerId": "PC-BUERO_ZEBRA_GK420D", "agentId": "PC-BUERO", "name": "Zebra GK420 Büro", "windowsPrinterName": "Zebra GK420d", "dpi": 203, "defaultWidthMm": 101, "defaultHeightMm": 76, "active": true } ``` ### Antwort ```http 200 OK ``` ```json { "ok": true } ``` Zum Deaktivieren entfernt der Benutzer den Haken `Aktiv`; der Agent ruft standardmäßig folgenden Endpunkt auf: ```http POST /api/label-print-agent/printers/{printerId}/deactivate Content-Type: application/json ``` Der Request Body entspricht dem Aktivieren, aber mit `"active": false`. ## 4. Nächsten Druckjob abrufen (Agent-Polling) ```http 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 ```http 204 No Content ``` ### Antwort – Job vorhanden ```http 200 OK Content-Type: application/json ``` ```json { "jobId": 42, "printerId": "PC-BUERO_ZEBRA_GK420D", "labelType": "artikel", "windowsPrinterName": "Zebra GK420d", "labelImageBase64": "iVBORw0KGgoAAAANSUhEUgAA...", "labelImageContentType": "image/png", "labelWidthMm": 57, "labelHeightMm": 32 } ``` | Feld | Beschreibung | | --- | --- | | `jobId` | Job-ID für Rückmeldungen | | `printerId` | Backend-ID des Zieldruckers | | `labelType` | Etikettart, z. B. `artikel` oder `text` | | `windowsPrinterName` | Exakter lokaler Windows-Druckername, auf den der Agent drucken soll | | `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. ## 5. Etikettbild separat abrufen Alternativ zum Base64-Feld in `jobs/next`. ```http GET /api/label-print-agent/jobs/{jobId}/image ``` ### Antwort ```http 200 OK Content-Type: image/png ``` Body: binäres PNG-Bild. ```http 404 Not Found ``` Job oder Bild nicht vorhanden. ## 6. Erfolgreichen Druck melden ```http POST /api/label-print-agent/jobs/{jobId}/printed Content-Type: application/json ``` ### Request Body ```json { "agentId": "PC-BUERO", "printerName": "DYMO LabelWriter 450" } ``` Alle Felder optional; Fallback jeweils `""` / `unknown`. ### Antwort ```http 200 OK ``` ```json { "ok": true } ``` Das Backend setzt den Job auf `printed`, speichert Zeitstempel und ruft die konfigurierte `LabelPrintedUrl` des Templates auf (`POST`). ## 7. Druckfehler melden ```http POST /api/label-print-agent/jobs/{jobId}/error Content-Type: application/json ``` ### Request Body ```json { "agentId": "PC-BUERO", "printerName": "DYMO LabelWriter 450", "errorMessage": "Drucker nicht verfügbar." } ``` ### Antwort ```http 200 OK ``` ```json { "ok": true } ``` Das Backend setzt den Job auf `error` und ruft die konfigurierte `LabelReleaseUrl` des Templates auf (`POST`). ## Job-Lebenszyklus ```text createJob() | v pending ---- jobs/next ---- Lock (5 Min TTL) | Agent druckt | +-------+-------+ printed error (PrintedUrl) (ReleaseUrl) ``` ## 8. Server-Sent Events – neue Druckaufträge (Push) ```http 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: ```text 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` |