Files
2026-05-09 09:04:20 +02:00

249 lines
4.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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}
```
`/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)
```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. 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",
"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`.
```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
```
---
## 5. 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`).
---
## 6. 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
```
createJob()
pending ──── jobs/next ──── Lock (5 Min TTL)
Agent druckt
┌───────┴───────┐
printed error
(PrintedUrl) (ReleaseUrl)
```
## 7. 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:
```
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` |