Der Import-Wizard ist für verarbeitete E-Mails gesperrt. Damit ließ sich
ein fehlerhaft abgeschlossener Vorgang bisher nicht korrigieren.
Administratoren können eine E-Mail in der Detailansicht nun wieder
freigeben (POST /api/emails/:id/reimport, MANAGE_ALL). Die Anhänge aus
der Datenbank werden weiterverwendet; ein erneuter Abruf vom IMAP-Server
findet nicht statt.
Die Freigabe setzt Status 4 ("Zur Nachbearbeitung") statt Status 0:
check-attachments prüft Mails mit Status 0, findet die Anhänge per
Checksumme in Paperless – dort liegen sie ja bereits – und würde die
Freigabe beim nächsten Lauf sofort wieder auf "Verarbeitet" zurückdrehen.
Status 4 bleibt davon unberührt. Da Status ein freies int ist, ist dafür
keine Migration nötig.
Erlaubt sind nur die Status 1, 2 und 3; liegt die E-Mail ohnehin im
Arbeitsvorrat, antwortet der Endpunkt mit 400, statt den Zustand still zu
überschreiben. Wer die Freigabe ausgelöst hat, steht im Log.
Der neue Status erscheint als eigener Tag sowie in beiden Filtern der
Mailpostfach-Übersicht, damit die freigegebenen Mails auffindbar bleiben.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Die tägliche E-Mail-Zusammenfassung zeigte Nutzern Bereiche, für die sie
keine Berechtigung haben. Zwei unabhängige Ursachen:
- Das Backend prüfte weiterhin die Altgruppe PM_Belege. Die Umbenennung
zu PM_Buchhaltung (ca1d371) war nur im Frontend angekommen, weshalb
der Digest "Manuell bearbeiten" und "In Agrarmonitor" anbot, während
die Oberfläche beide Bereiche sperrte.
- Der Cron-Versand wertet die Gruppen aus user_settings aus. Diese Spalte
wurde nur beim Aufruf der Benutzereinstellungen gefüllt; entzogene
Berechtigungen erreichten den Digest daher unter Umständen nie.
Behoben durch Angleichen des Gruppen-Mappings und den neuen
UserIdentitySyncService, der E-Mail, Benutzername und Gruppen bei jedem
authentifizierten Request aus dem Token spiegelt – ohne den Request zu
blockieren und ohne DB-Zugriff, solange sich das Token nicht ändert. Die
doppelte Identitätspflege im UserSettingsService entfällt.
WebDAV wird nicht eingesetzt und ist entfernt; Export-Ziele bieten nur
noch FTP. Damit verschwindet das ESM-Paket webdav, an dem zwei
Jest-Suites bereits beim Parsen scheiterten.
Veraltete Tests instand gesetzt: email.controller und settings.controller
mockten weniger Abhängigkeiten, als die Klassen inzwischen haben;
postprocessing.service.spec beschrieb noch das alte Regelmodell mit
Einzelfeldern statt FilterJson und ist gegen die heutige Filter-Engine
neu geschrieben (AND/OR, verschachtelte Gruppen, Fehlerprotokollierung).
Enthält außerdem den Arbeitsstand der E-Rechnungs-Mandantenzuordnung, da
sich beide Änderungen dieselben Dateien teilen (SettingsPage, package.json).
98 Tests in 12 Suites grün, Backend- und Frontend-Build sauber.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Alle Seiten werden per React.lazy als eigene Chunks nachgeladen. Schlug ein
Import fehl (Safari: "Importing a module script failed" — z.B. nach einem
Deployment mit neuen Chunk-Namen oder bei beschädigtem, wegen
"Cache-Control: immutable" nie revalidiertem Browser-Cache), riss der Fehler
mangels ErrorBoundary den kompletten React-Baum in eine weiße Seite.
- main.tsx: Bei 'vite:preloadError' automatisch neu laden (max. 1×/Minute,
sessionStorage-Guard gegen Reload-Schleifen)
- AppErrorBoundary (neu): Fehlermeldung mit "Seite neu laden"-Button statt
weißer Seite; bei Chunk-Ladefehlern mit Hinweis auf Cache-Leeren
- App.tsx: ErrorBoundary um alle Routen gelegt
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Im "Manuell bearbeiten"-Dialog (DocumentEditModal, isPosteingang=false) kann
jetzt trotz leerer Pflichtfelder gespeichert werden: Schlägt die Formular-
Validierung fehl, erscheint ein Bestätigungsdialog, der die fehlenden Pflicht-
felder auflistet; per "Trotzdem speichern" wird ohne erneute Validierung
gespeichert. Der Posteingang (isPosteingang=true) blockiert wie bisher.
Die Kontonummer-Logik wurde in runSave() ausgelagert und von beiden Pfaden
(normal + "trotzdem speichern") wiederverwendet.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- New useIsMobile hook and MobileCardList component
- AppLayout: hamburger menu + Drawer navigation on mobile
- All list pages (Inbox, Posteingang, Manuell, Mail, Freigabe, Zahlung, TaskLog)
show card layout on mobile instead of tables
- CSS: responsive modal height, horizontal table scroll, text-size-adjust
- Backend: Agrarmonitor polling fixes, Zahlung service improvements,
IMAP folder service extended, misc controller fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Belege, die per E-Mail an Agrarmonitor gesendet werden, brauchen bis zu
10 Minuten bis zum Import in den Dateieingang. Bisher wurden sie im
Upload-Check sofort als "Manuell bearbeiten" + Tag 19 markiert, wenn sie
weder verbucht noch im Dateieingang waren – auch mitten im Import-Fenster.
Jetzt wird vor dem Markieren geprüft, ob die jüngste Notiz mit dem
konfigurierbaren Marker-Text jünger als die Wartezeit ist; falls ja, wird
der Beleg übersprungen und beim nächsten Lauf erneut geprüft. Wartezeit
(agrarmonitor_import_wartezeit_minuten, Standard 10) und Marker
(agrarmonitor_notiz_marker, Standard "Agrarmonitor") sind als Settings
konfigurierbar und in der Settings-Seite editierbar.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Zwei Lücken behoben, die bei abgelaufenem Access-Token (v.a. nach inaktivem
Tab, dessen Renew-Timer gedrosselt wurde) zu vollständigen Neuanmeldungen
führten:
- getAccessToken erneuert das Token jetzt proaktiv (signinSilent), wenn es
abgelaufen ist, statt ein abgelaufenes Token zu senden. Profitiert auch den
direkten fetch-Aufrufen (Bilder/PDFs).
- Der 401-Interceptor versucht zuerst einen stillen Refresh und wiederholt die
Anfrage einmal; erst wenn das scheitert (Refresh-Token ungültig), erfolgt der
Login-Redirect.
Gleichzeitige Refreshes werden dedupliziert (renewToken), um invalid_grant bei
Refresh-Token-Rotation zu vermeiden.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fontFamily-Token im ConfigProvider auf denselben Inter-Stack wie der Body
gesetzt. Zuvor fehlte das Token, sodass AntD-Eingaben (z.B. das Select-
Suchfeld) im AntD-Default-Stack abwichen, während der angezeigte Wert die
Body-Schrift (Inter) nutzte.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Webhook reiht eingehende Dokument-IDs nur noch in eine Warteschlange ein
und antwortet sofort (status "queued"). Ein separater Intervall-Prozess
(WebhookQueueService) arbeitet die IDs nacheinander ab – ohne Überschneidung,
falls ein Dokument mehrfach kurz hintereinander gespeichert wird:
- Jede ID kommt nur einmal in der Liste vor (Dedup).
- Beim Verarbeitungsstart wird die ID sofort entfernt; ein erneutes Feuern
während der Verarbeitung reiht sie wieder ein (ein weiterer Lauf folgt).
- Es läuft immer nur eine Verarbeitung gleichzeitig (isProcessing-Guard).
- Prüfintervall sehr kurz (WEBHOOK_QUEUE_INTERVAL_MS, Default 1000 ms).
Status-Recording (last_webhook_call) + GET /api/webhook/status wandern in den
Queue-Service und liefern zusätzlich die aktuelle Warteschlangen-Größe.
Frontend-Tab zeigt Status "In Warteschlange" und die Queue-Größe an.
Unit-Test deckt Dedup, Remove-on-start, Re-Enqueue und No-Parallel ab.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer Tab "Webhook" in der SettingsPage zeigt den letzten Paperless-
Webhook-Aufruf (Zeitpunkt, Dokument-ID, Aktion, Ergebnis) über
GET /api/webhook/status an. Neue API-Datei src/api/webhook.ts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a payment step after document approval: PM_Freigabe approves
(Field 15 = "freigegeben"), then PM_Zahlung can mark as paid (Field 16).
- Backend: VIEW_ZAHLUNG permission mapped to PM_Zahlung OIDC group
- Backend: ZahlungModule with endpoints to list documents by filter
(ausstehend/freigegeben/alle), set Field 16, fetch options from Paperless
- Backend: setZahlung() throws ForbiddenException if Field 15 ≠ "freigegeben"
- Frontend: /zahlung route with 3-way filter, two status columns (Freigabe + Zahlung)
- Frontend: "Zahlung verbuchen" button disabled with tooltip for non-approved docs
- Frontend: Zahlung menu item with EuroOutlined icon
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Cleanup-Cron von EmailDownloadService in ImapFolderService verschoben,
damit er auch aus EmailController aufrufbar ist (zirkuläre Abhängigkeit vermieden)
- Beim Klick auf „Anhänge prüfen" wird der IMAP-Cleanup fire-and-forget gestartet
- Beim Klick auf „Bereits verarbeitete Anhänge prüfen" werden zusätzlich alle
E-Mails im IMAP-Posteingang, die in der DB als verarbeitet (Status 1) oder
ignoriert (Status 3) markiert sind, in den Ordner „importiert" verschoben
- Erfolgsmeldung zeigt Anzahl verschobener E-Mails an
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New steuertag_ids setting to mark tags as workflow-only (not editable)
- DocumentEditModal shows only content tags (non-Steuertags) as editable chips
- Backend preserves Steuertags when saving document tag changes
- ManuellBearbeitenPage renders content tag chips under document title
- New Steuertags settings tab with multi-select and color preview
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Store UserGroups from OIDC in UserSettings entity, sync on each request
- Filter daily digest tiles based on user's permission groups
- Add in-memory job status tracking to EmailImportService
- Poll import job status in MailImportWizard and show progress in Spin tip
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New DailyDigestModule with scheduled summary email for open dashboard items
- Extract StatsService from StatsController for reuse in digest
- Add DailyDigestEnabled, UserEmail, UserPreferredUsername to UserSettings entity
- Sync email/username from OIDC token on each get/update call
- Add dailyDigestEnabled to UserSettingsDto and update API
- Notifications tab in UserSettingsPage with enable toggle and "Jetzt senden" button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Renamed setting agrarmonitor_tag_posteingang → agrarmonitor_tag_manuell
- Documents not found in AM are now tagged as "Manuell bearbeiten"
instead of being moved back to Posteingang
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add agrarmonitor_tag_posteingang setting (default empty)
- When a document is not found in Agrarmonitor, move it back to Posteingang
tag instead of skipping (if tagPosteingang is configured)
- Expose tagPosteingang in polling config API and settings UI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Paperless may return extra_data.select_options as an array of objects
{id, label} instead of plain strings. This caused React error #31
when Ant Design tried to render an object as a child in the Select and
Table components.
- Backend: coerce option items to {id: string, label: string} regardless
of whether Paperless returns strings or objects
- Frontend: normalize cf.value to a plain string before rendering or
storing in state, guarding against object-typed values
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a dedicated approval view for PM_Freigabe users to release documents
for payment by setting Paperless custom field 15 to a predefined value.
- Backend: VIEW_FREIGABE permission mapped to PM_Freigabe OIDC group
- Backend: FreigabeErforderlich flag on DocumentType entity (auto-migrated)
- Backend: FreigabeModule with endpoints to list documents, fetch field
options dynamically from Paperless, and set the approval custom field
- Frontend: /freigabe route with filter (default: nicht freigegeben),
paginated table, and modal to select approval value
- Frontend: Settings checkbox to mark document types as requiring approval
- Frontend: Freigabe menu item visible only to PM_Freigabe/PM_Admin users
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add onSuccess prop to MailImportWizard, called instead of onClose on success
- MailDetailPage navigates to /mailpostfach after import completes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Detect duplicates after sync (same AgrarmonitorId, multiple correspondents)
- Auto-merge duplicates with identical names (delete empty, move docs to larger)
- Expose conflicts with different names for manual resolution
- New mergeCorrespondents endpoint + service method
- Conflict resolution modal in SettingsPage with radio selection per conflict
- deleteCorrespondent added to PaperlessService
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extract getOrCreateCorrespondent helper to deduplicate logic
- Add syncCorrespondentIds to match Paperless correspondents to
Agrarmonitor IDs via Lieferantennummer and persist in CorrespondentSetting
- New POST /api/agrarmonitor/sync-correspondents endpoint
- "Agrarmonitor-Abgleich" button in Correspondents settings tab
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Set autoRetry: false and timeoutMs: 10000 in AgrarmonitorService
- Show specific error message on timeout or backend error in frontend
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New backend module (agrarmonitor) with status check and device registration
- Frontend settings tab with connection status display and registration form
- Environment variables for base URLs, credentials, cookie path and encryption key
- Docker Compose env passthrough for agrarmonitor config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Pass initialContent prop to WysiwygEditor instead of imperative setContent
to ensure mail signature loads correctly on mount
- Rewrite README to reflect full project scope (scanner inbox, email import,
postprocessing rules, label printing, OIDC auth)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Show confirmation dialog to delete document after download or email send
- Auto-refresh inbox list every 30 seconds
- Rename "Vorschau" button to "Weiterverarbeiten"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace div with semantic button elements in AppLayout for accessibility
- Use Ant Design theme tokens instead of hardcoded colors in MailDetailPage
- Add loading state to refresh buttons and pagination info
- Add German empty state messages to tables
- Clean up unnecessary ConfigProvider wrappers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>