Files
2026-05-20 09:24:11 +02:00

94 lines
2.7 KiB
Markdown

# Serienbrief-Backend
Node.js/Express-Backend für das Serienbrief-System auf Basis von **Directus** (Adressdatenbank) und **Gotenberg/Carbone** (PDF-Rendering).
## Voraussetzungen
- Docker Engine 27.x, Docker Compose V2
- Laufende Directus-Instanz mit:
- Collection `sb_templates` (siehe Konzept-Dokument)
- Service-Account-Token mit Lesezugriff auf Kontakt-Collections und `sb_templates`
- Gotenberg v8 (oder Carbone, via `RENDERER=carbone`)
- PostgreSQL-Instanz für Audit-Log
## Schnellstart (Entwicklung)
```bash
cp .env.example .env
# .env anpassen (DIRECTUS_TOKEN, AUDIT_DB_* etc.)
npm install
npm run dev
```
## Umgebungsvariablen
Alle Optionen: siehe `.env.example`
## API-Endpunkte
| Methode | Pfad | Auth | Beschreibung |
|---|---|---|---|
| `GET` | `/health` | nein | Healthcheck |
| `GET` | `/api/sb/templates` | Bearer | Aktive Templates |
| `GET` | `/api/sb/recipients` | Bearer | Empfängerliste |
| `POST` | `/api/sb/render` | Bearer | PDF generieren |
| `GET` | `/api/sb/audit` | Bearer (Admin) | Audit-Log |
| `POST` | `/admin/reload-templates` | intern | Template-Cache leeren |
## Render-Request
```json
POST /api/sb/render
Authorization: Bearer <directus-user-token>
{
"templateId": "uuid-aus-sb_templates",
"collection": "kontakte",
"recipientIds": [42, 87, 133],
"extraFields": { "betreff": "Wichtige Information" }
}
```
Response: `application/pdf` (Datei-Download)
## Template-Syntax (Carbone)
Templates sind ODT- oder DOCX-Dateien mit Carbone-Platzhaltern:
```
{d.empfaenger[i].vorname} {d.empfaenger[i].nachname}
{d.empfaenger[i].adresse}
{d.empfaenger[i].plz} {d.empfaenger[i].ort}
Datum: {d.meta.datum}
Betreff: {d.meta.betreff}
```
## Sicherheit
- Service-Account-Token wird als Docker Secret geliefert (`/run/secrets/directus_token`)
- User-Bearer-Token wird gegen Directus `/users/me` validiert
- Generierte PDFs werden nur im RAM gehalten und direkt gestreamt (keine Persistenz)
- Audit-Log: INSERT-only (DB-User hat kein UPDATE/DELETE)
- Container läuft als non-root (UID 1001), `read_only: true`, `cap_drop: ALL`
## Renderer-Auswahl
| Variable | Wert | Beschreibung |
|---|---|---|
| `RENDERER` | `gotenberg` (default) | Carbone merged Template + Daten → Gotenberg konvertiert nach PDF |
| `RENDERER` | `carbone` | Carbone merged + konvertiert direkt (LibreOffice im Container nötig) |
## Direktus-Collection `sb_templates`
| Feld | Typ | Beschreibung |
|---|---|---|
| `id` | UUID | Primärschlüssel |
| `name` | String | Anzeigename |
| `description` | String | Beschreibung |
| `version` | String | z.B. `2.1` |
| `file_id` | FK → directus_files | Template-Datei |
| `active` | Boolean | Nur aktive werden angezeigt |
| `allowed_fields` | String | Kommagetrennte Felder-Allowlist |