Briefe (Letter)
Zweck
Letter modelliert in SpeamCore physische Briefe — sowohl ausgehende (über ePost gedruckt und versendet) als auch eingehende (gescannt und mit KI klassifiziert). Im Unterschied zum Mail-Modul (digitale E-Mail über Microsoft 365) geht es hier um Papier-Post: Briefkopf mit Adressfenster, DIN-A4-konformer Druck, Einschreiben mit Rückschein, Zustellungs-Tracking — und beim Eingang die automatische KI-Erkennung von Absender, Betreff und passendem Kunden/Lieferanten/Hersteller.
Drei Verarbeitungs-Pfade:
- Ausgehend — Innendienst erstellt einen Brief, lässt ihn per ePost (DocuGuide) versenden. Optional Einschreiben mit Tracking + Rückschein.
- Eingehend (manuell) — Sekretariat scannt eingehende Post, lädt die PDFs in den SpeamCore-Posteingang. KI analysiert automatisch.
- Eingehend (Mail-Scan-to-Inbox) — eingehende E-Mails mit PDF-Anhängen (z. B. vom Anwalt, Steuerberater, Sachverständigen) werden automatisch in den Brief-Posteingang überführt.
Voraussetzungen
Berechtigungen (CASL)
| Action | Subject | Wirkung |
|---|---|---|
view | FE_Letter, Letter | Brief-Liste + Detail aufrufbar (eigene Briefe) |
create | Letter | Neuen Brief anlegen |
update | Letter | Felder ändern (blockiert wenn isLocked = true) |
delete | Letter | Soft-Delete (blockiert wenn isLocked = true) |
do | ViewDepartmentLetters | Briefe der eigenen Abteilung sehen (Department-Lead) |
do | ViewAllLetters | Briefe aller Abteilungen sehen (Admin) |
view / create | LetterSubmission | ePost-Submission-Liste sehen / anlegen |
do | SubmitLetter | Versand via DocuGuide auslösen |
Row-Level-Scope (Department-Truth-Source)
Drei-Stufen-Modell — wer welche Briefe sieht:
| User-Rolle | Filter |
|---|---|
| Standard | WHERE employeeId = current_employee — nur eigene Briefe |
| Department-Lead | WHERE (employeeId IN colleagues OR departmentId = my_dept) — eigene + Abteilungs-Briefe |
| Admin | WHERE 1=1 — alles |
Wichtig: Mail-Scan-to-Inbox-Briefe haben employeeId = NULL und nur departmentId gesetzt — sie sind also nur über den Department-Lead-Scope sichtbar, nicht über Standard. Das ist gewollt: herrenlose Inbox gehört zentral der Abteilung.
Datenmodell
Letter
| Feld | Pflicht | Typ | Wirkung |
|---|---|---|---|
type | ja | ENUM in | out | out für ausgehende, in für eingehende Briefe. Default out. |
status | ja | ENUM | draft / sent / received / open / in_progress / done / archived |
branchId | nein | UUID → Branch | Niederlassungs-Zuordnung (für Briefkopf-Anschrift) |
employeeId | nein | UUID → Employee | Erstellender Mitarbeiter (bei Mail-Scan-to-Inbox null) |
departmentId | nein | UUID → Department | Abteilungs-Scope (Truth-Source für Row-Level-Sichtbarkeit) |
parentType | nein | ENUM | Customer / Supplier / Manufacturer / Location / Employee |
parentId | nein | UUID | Verknüpftes Stammdaten-Objekt |
locationId | nein | UUID → Location | Bei parentType = Customer optional eine spezifische Standort-Adresse |
parentName / parentStreet / parentZip / parentCity / parentCountryId | auto | Snapshot | Wird beim Anlegen aus dem Parent gezogen und eingefroren — Adressänderungen am Stamm wirken nicht rückwirkend |
documentDate | ja | DateOnly | Brief-Datum (Default: heute) |
title | nein | String | Interner Titel (für die Liste) |
subject | nein | String | Betreff im PDF-Header (bei eingehend von KI gesetzt) |
body | nein | TEXT | Brief-Text (HTML). Bei eingehend von KI als Zusammenfassung gesetzt. |
qrLinkId | nein | UUID → QrLink | Optional ein QR-Link, der unten rechts auf dem Briefpapier gedruckt wird |
qrCodePng | nein | String (Base64) | Vom FE generiertes QR-Code-Bild für die PDF-Engine |
isLocked | auto | Boolean | true sobald aktive LetterSubmission läuft — Felder werden read-only |
activeSubmissionId | auto | UUID → LetterSubmission | Verweis auf laufende Submission |
aiAnalysisStatus | auto | ENUM | pending / analyzing / done / failed (nur bei type = in) |
aiAnalysisError | auto | TEXT | Fehlertext, wenn KI-Analyse scheiterte |
aiAnalyzedAt | auto | DateTime | Zeitstempel der KI-Analyse |
customHeaderInfo | nein | JSON {label,value}[] | Custom-Header-Felder im Briefkopf |
Lock-Verhalten
Sobald eine LetterSubmission für einen Brief läuft, wird isLocked = true. Im beforeUpdate-Hook prüft der Service, dass dann nur isLocked, activeSubmissionId und status geändert werden dürfen — alle anderen Felder sind eingefroren. So bleibt der versendete PDF-Inhalt nachträglich nicht manipulierbar.
Schritt-für-Schritt-Anleitung
Ausgehender Brief
- Briefe (
/letters) → + Neu. - Empfänger wählen — über
parentType+parentIdeinen Kunden, Lieferanten, Hersteller oder Mitarbeiter auswählen. Bei Kunde optional spezifische Filiale (locationId). - Pflichtfelder pflegen:
documentDate,title,subject,body. - Optional: einen QR-Link hinterlegen — z. B. zur Wartungs-Portal-Seite oder zur Buchungsseite.
- PDF-Vorschau öffnen (Brief-PDF mit Briefpapier, Adressfenster, QR-Code) — visuell prüfen.
- „via ePost versenden" klicken → öffnet den Versand-Dialog (SpeamPost-Submit) mit Farbe, Duplexdruck, Einschreiben-Option.
- Bestätigen — der Brief wird
locked, eineLetterSubmissionläuft asynchron über DocuGuide.
Eingehender Brief (manueller Upload)
- Briefe (
/letters) → Tab Posteingang → + Upload. - Drag & Drop ein oder mehrere PDFs ins Modal (max. 3 parallel).
- SpeamCore antwortet sofort mit
202(kein Warten) — der KI-Worker läuft im Hintergrund. - Beobachten: jede Letter-Zeile zeigt
aiAnalysisStatus = pending(Spinner) →analyzing→doneoderfailed. - Sobald
done: Brief hat automatisch Absender, Betreff, Datum, Priorität und ist mit dem richtigen Kunden/Lieferanten/Hersteller verknüpft. - Status weiter pflegen:
received→open→in_progress→done(manuell oder automatisch bei beantwortetem ausgehenden Folge-Brief).
Eingehender Brief (Mail-Scan-to-Inbox)
- Im Postfach-Setup (siehe Mail-Konten) den Toggle Scan-to-Inbox aktivieren setzen.
- Optional pflegen: Absender-Whitelist / -Blocklist, Subject-Filter, „nur PDFs importieren".
- Sobald eine E-Mail mit PDF-Anhang in dieses Postfach kommt, wird der Anhang automatisch als
Letterin den Posteingang gelegt —employeeId = null,departmentId = <Postfach-Department>. KI-Analyse läuft analog zum manuellen Upload.
QR-Code-Druck (Welle 137 + 148)
Wenn ein Brief mit einem QR-Link versehen wird, druckt SpeamCore unten rechts auf dem Briefpapier automatisch den QR-Code. Anwendungsfälle:
- Wartungsprotokoll mit QR zur Anlage-Dokumentation
- Rechnung mit QR zum Online-Zahlungs-Portal
- Kundenbrief mit QR zur Visitenkarte des Sachbearbeiters
- Mahnung mit QR zur Buchungsseite für ein Klärungsgespräch
Konfiguration des Codes (Style, Logo, Farben) läuft über das QR-Link-Modul.
Per-Mail senden (seit Juni 2026)
Ein Brief lässt sich – alternativ zum physischen Versand per ePost – auch direkt per E-Mail verschicken: Der Button Per Mail senden stellt das gerenderte Brief-PDF als Mail-Anhang bereit (GET /letters/:id/mail-attachment, CASL create:Mail) und übergibt es an den Mail-Verfassen-Dialog. So geht derselbe Brief wahlweise als Post oder als Mail raus.
Beim Druck mehrerer Briefe in einem Vorgang steuert das Flag split, ob das Ergebnis als ein gemeinsames PDF oder als getrennte PDFs je Brief ausgegeben wird.
Verknüpfungen zu anderen Modulen
- ePost-Versand (Letter Submissions) — der eigentliche Versand-Lifecycle (DocuGuide-Integration)
- Brief vs. Mail vs. ePost (Konzept) — die drei Welten klar abgegrenzt
- Mail — E-Mail-Modul; Schnittstelle Mail-Scan-to-Inbox
- Mail-Konten — Postfach mit Scan-to-Inbox-Konfig
- QR-Links — QR-Code-Druck auf Briefpapier
- Customization / Allgemein — Briefpapier-Layout (Logo, Header, Footer, Farben)
- Kunden, Lieferanten, Hersteller — Parent für Briefe; jeweils Sub-Listen
/post
Sub-Listen pro Stammdatum
Jedes Stammdaten-Objekt (Kunde, Lieferant, Hersteller) hat eine Sub-Liste /post:
/customers/:id/post— alle Briefe an / von diesem Kunden/suppliers/:id/post— analog/manufacturers/:id/post— analog
Damit sehen Sie auf der Stammdaten-Detail-Seite die vollständige Brief-Korrespondenz, ohne erst in die globale Liste zu wechseln.
Häufige Fehler und Lösungen
| Fehler | Lösung |
|---|---|
| Brief lässt sich nicht editieren | isLocked = true — eine LetterSubmission läuft. Submission-Status prüfen (Letter-Submissions). Bei failed oder cancelled wird wieder editierbar. |
KI-Analyse hängt auf pending | Worker-Status im Admin-Bereich prüfen. Bei Hängenbleiben: BullMQ-Job neu starten. |
| KI weist falschen Kunden zu | Detail-Sicht öffnen, parentType/parentId manuell korrigieren. Beim nächsten ähnlichen Absender lernt die KI nicht automatisch — daher saubere Absender-Stammdaten pflegen. |
| Mail-Scan-Briefe sind nicht sichtbar | Standard-User sieht nur eigene Briefe (employeeId). Mail-Scan setzt nur departmentId. Nur Department-Lead und Admin sehen das. |
| PDF-Vorschau ist leer | Letterhead-Shell-Konfig fehlt — in Customization → Allgemein das Briefpapier konfigurieren. |
| ePost-Versand schlägt fehl | DocuGuide-Token abgelaufen oder Konfiguration fehlt. Admin-Modul prüfen. Bei errorDetail in der Submission steht die DocuGuide-API-Antwort. |
| Adresse im PDF stimmt nicht | Snapshot — beim Anlegen wurde die damalige Adresse eingefroren. Brief löschen und neu anlegen (oder Adresse manuell überschreiben — parentStreet/Zip/City sind editierbar bei nicht-locked Briefen). |
API/Schnittstellen
CRUD
| Methode | Endpoint | Zweck | CASL |
|---|---|---|---|
GET | /api/letters | Liste (mit Row-Level-Scope) | view Letter |
POST | /api/letters | Brief anlegen | create Letter |
GET | /api/letters/:id | Detail | view Letter |
PUT | /api/letters/:id | Update (blockiert bei isLocked) | update Letter |
DELETE | /api/letters/:id | Soft-Delete (blockiert bei isLocked) | delete Letter |
PDF + Upload
| Methode | Endpoint | Zweck | CASL |
|---|---|---|---|
GET | /api/letters/:id/pdf | PDF/A-1b für DocuGuide-Versand | view Letter |
GET | /api/letters/:id/inbox-pdf | Scan-PDF (eingehend) | view Letter |
POST | /api/letters/upload-inbox | Multi-File-Upload Posteingang | create Letter |
GET | /api/letters/own-address | Absender-Adresse aus Mandanten-Setup | view Letter |
Submissions (ePost)
| Methode | Endpoint | Zweck | CASL |
|---|---|---|---|
POST | /api/letters/:id/submit | Versand starten — 202 Accepted | do SubmitLetter |
GET | /api/letters/:id/submissions | Submission-Historie | view LetterSubmission |
GET | /api/letters/:id/submissions/:submitId | Detail einer Submission | view LetterSubmission |
POST | /api/letters/:id/submissions/:submitId/cancel | Abbrechen (vor sent) | do SubmitLetter |
GET | /api/letters/:id/mail-attachment | Brief-PDF als Mail-Anhang (Per Mail senden) | create Mail |
Versionshinweise
- 2026-06-12: Per Mail senden (
/letters/:id/mail-attachment) und Druck-split-Flag (gemeinsames vs. getrenntes PDF je Brief) dokumentiert. Verifiziert anletter.router.ts. - 2026-05-26 (Welle 148): Initiale Veröffentlichung. Quelle: BE-Commits
68248ac5(Brief + Briefpapier + PDF),5de6fbb3(DocuGuide-Integration),b8096e48(Status-Normalisierung),34487c76(Posteingang-KI + Mail-Scan-to-Inbox),ae114638(Row-Level-Scope + Department-Truth-Source). FE-Commitsc513dcbd(Post-Modul + Customization-Print),d5bdc79f(FE-ePost),aefa838f(Lock-Banner-Fix),f73f6286(Posteingang-UI),b7225bdd(Filter-Panel + Multi-Upload + KI-Status-Spinner + Dashboard-Badge). Drei BE-Worker:epost-submit-worker,letter-inbox-worker,microsoft-subscription-renewal.worker. Komplett neues Modul, eigene Sub-Listen pro Stammdatum.