4.7 KiB
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 |