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>
Der Mindest-Wartezeit-Check verglich Date.now() (Node-Uhr) mit dem aus der DB
gelesenen createdAt. Ohne gesetzte timezone (mysql2-Default 'local') wird
createdAt bei abweichender DB-Zeitzone als zukünftig interpretiert → Alter
negativ → jeder Eintrag galt als "zu jung" und wurde nie verarbeitet.
Der Vergleich läuft jetzt in der DB (createdAt <= NOW(6) - INTERVAL 5s via
TypeORM Raw), unabhängig von Zeitzone/Uhr des Node-Prozesses. Bereits
wartende Einträge werden dadurch nach dem Deploy sofort abgearbeitet.
Test-Mock bildet den DB-Alters-Filter nach.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Anhänge mit '/' im Dateinamen (z.B. "Rechnung - 2026/002650322.PDF")
führten zu einem Fehler, weil '/' als Verzeichnistrenner interpretiert
wurde und der temp. Pfad nicht existierte.
- sanitizeFilename() ersetzt '/' und '\' durch '-', entfernt '..' und Null-Bytes
- Wird beim Speichern in die DB (email-download) und beim Aufbau des
temp. Pfads (email-import) angewendet (defense-in-depth)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
processQueue verarbeitet den ältesten Warteschlangen-Eintrag erst, wenn er
mindestens MIN_QUEUE_AGE_MS (Default 5000 ms, ENV WEBHOOK_QUEUE_MIN_AGE_MS)
in der Tabelle lag. Ist der älteste Eintrag (FIFO) noch zu jung, bricht der
Tick ab und prüft beim nächsten Intervall erneut. Unit-Test ergänzt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
E-Mail-Import und External-Upload setzen ASN, Custom Fields (CF3/CF7/CF9),
Dokumenttyp, Tags, Owner und Belegdatum jetzt bereits beim post_document,
statt erst nachträglich über den Task-Processor-Cron (30 s + PATCH).
- Neu: deriveTaskMetadata() in task-metadata.util.ts als gemeinsame
Ableitung (Task-Felder → Paperless-Metadaten) für beide Upload-Pfade
und den Task-Processor – identische Parsing-Regeln, kein Copy-Paste
- Task-Processor nutzt den Helper (verhaltensidentischer Refactor) und
patcht weiterhin idempotent nach; zuständig bleibt er für alles
ID-Abhängige (CF8-Verknüpfungen, Anlage-Titel, Owner-Entfernung, Notizen)
- FAILURE-Zweig loggt Paperless-Fehlertext und Belegnummer vor dem
Löschen des Tasks (ASN-Kollision kann jetzt den Consume scheitern lassen)
- Tests: 18 Unit-Tests für deriveTaskMetadata, 3 Charakterisierungstests
pinnen den PATCH-Payload von processSuccessfulTask
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>
Beim JWT-Ablauf fällt der JwtOrApiKeyGuard auf den ApiKeyGuard zurück. Dieser
nahm bisher jedes Authorization-Bearer-Token als API-Key-Kandidaten – also auch
das (abgelaufene) JWT – und loggte eine irreführende "Invalid API Key"-Warnung
(samt JWT-Präfix). Der Bearer-Fallback akzeptiert nun nur noch Token mit dem
API-Key-Präfix "pm_"; ein JWT wird ignoriert. Ergebnis bleibt 401 (Frontend
re-authentifiziert), aber ohne irreführenden Log.
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>
Die Warteschlange liegt nicht mehr im Speicher, sondern in der neuen Tabelle
webhook_queue (Entity WebhookQueueItem, documentId als Primärschlüssel). So
überstehen ausstehende IDs einen Neustart und werden nach dem Boot
weiterverarbeitet.
- Neue Entity + Migration (CreateWebhookQueue); in data-source.ts/Barrel
registriert. Dev: synchronize legt die Tabelle an; Prod: migrationsRun.
- enqueue nutzt INSERT IGNORE (atomar, race-sicher) -> Dedup über den PK.
- processQueue holt FIFO (createdAt ASC), entfernt die Zeile vor der
Verarbeitung, arbeitet sequenziell (isProcessing-Guard).
- getStatus/queueSize lesen die DB-Anzahl. Controller awaitet enqueue.
- Unit-Test mit simuliertem FIFO-Repo: Dedup, Remove-on-start, Re-Enqueue,
No-Parallel (deterministisch).
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>
processDocumentById verarbeitet nun jedes vom Paperless-Webhook gemeldete
Dokument, unabhängig vom Tag "paperlessmanager" (ID 16). Die Tag-Vorprüfung
(skipped/tag-missing) entfällt. Die Konstante PAPERLESSMANAGER_TAG_ID bleibt
für den manuellen Batch-Lauf processDocuments erhalten.
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>
Pro Webhook-Aufruf wird ein Status in der settings-Tabelle gepflegt
(Tag "last_webhook_call", JSON mit Zeitpunkt, Dokument, action, Ergebnis).
Neuer Endpunkt GET /api/webhook/status liefert den letzten Aufruf zum
Auslesen (JWT oder API-Key). Persistent über Neustarts, anders als die
Container-Logs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Statt stündlichem Cron ruft Paperless-NGX nun per Webhook das Backend auf,
sobald ein Dokument bearbeitet wurde. Der Endpunkt verarbeitet ein einzelnes
Dokument (per doc_url/document_id), prüft weiterhin den Tag "paperlessmanager"
(ID 16) und ist per API-Key (X-API-Key) abgesichert, sodass nur Paperless ihn
aufrufen kann.
- paperless-processor.service.ts: @Cron entfernt; neue Methode
processDocumentById; Tag-16 als Konstante; gemeinsamer Helper
processAndEvaluate (Batch + Webhook)
- paperless.module.ts: PaperlessProcessorService exportiert
- webhook.controller.ts: Route auf api/webhook (erreichbar via /api-Proxy);
@Public() -> @UseGuards(ApiKeyGuard); ID-Extraktion aus {{doc_url}}
- webhook.module.ts: PaperlessModule + AuthModule importiert
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>
NODE_ENV=production deaktiviert synchronize (zerstörerischer ADD/DROP-COLUMN-
Churn auf MariaDB, der die 8126-Byte-Zeilengröße sprengte) und aktiviert
migrationsRun. Neue data-source.ts als einzige Konfigquelle (Laufzeit + CLI),
Migrations-Workflow (generate/run/revert) inkl. dotenv ergänzt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Neuer ImapFolderService verschiebt E-Mails nach erfolgreichem Import in den
konfigurierbaren Ordner "importiert" (wird bei Bedarf automatisch erstellt)
- Täglicher Cron um 03:00 Uhr verschiebt E-Mails älter als 90 Tage in den
Papierkorb und leert ihn anschließend
- createImapClient()-Hilfsmethode im EmailDownloadService ausgelagert
- IMAP_IMPORTED_FOLDER und IMAP_TRASH_FOLDER in docker-compose ergänzt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New workflow_dispatch workflow to build & push backend/frontend images
with a manually chosen tag and service selection (both/backend/frontend).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- New ImapFolderService moves emails to configurable "importiert" folder
after successful import, creating the folder if it doesn't exist
- Daily cron at 03:00 moves emails older than 90 days to trash and empties it
- Extract createImapClient() helper in EmailDownloadService
- Add ensurePageCache() with in-flight deduplication to BarcodeScannerService
- InboxService regenerates page cache on-demand when image file is missing
- IMAP_IMPORTED_FOLDER and IMAP_TRASH_FOLDER added to .env.example and docker-compose
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>
Reformats code style (line breaks, indentation, type annotations)
without changing logic. Also includes minor feature additions bundled
in the same lint run (stats service, user-settings groups, agrarmonitor
polling improvements).
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>
- Replace table layout with modern card-based design per dashboard area
- Add icon, color accent, badge and "Öffnen" link per card
- Show summary bar with total open items count
- Fix cron timezone to Europe/Berlin
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Read APP_URL and AGRARMONITOR_BASE_URL from config
- Render dashboard entries as clickable links in HTML digest email
- Add APP_URL and DAILY_DIGEST_CRON to .env.example and docker-compose.yml
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>
- Before moving a document back to Posteingang, check if it's still
waiting in the Agrarmonitor Dateieingang
- If yes: skip silently (upload is pending processing)
- If no: move to Posteingang tag as before
- Handle 401/403 by clearing the session and aborting the check
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>
- Only set eingangsDatum when belegNummer is present
- Import documents when buchungsDatum is set (revert inverted condition)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Raised page_size from 100 to 9999 on GET /api/paperless/correspondents
so the FreigabePage can resolve all correspondent IDs to names.
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>
- getOrCreateCorrespondent first checks CorrespondentSetting by kundenId
- Falls back to name search only when no mapping exists
- Saves the mapping after creation for future polling runs
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>
- 400 on Korrespondenten-Sync: getCorrespondentByName was called with
searchName "(12345)" but checked exact match against full displayName
"Firma (12345)". Always returned null → duplicate addCorrespondent on
every run → Paperless 400. Fix: search by displayName directly.
- 403 on Livesearch: cached Agrarmonitor session expired. Fix: detect
401/403 from connector, call clearClient() to invalidate cache, break
out of the polling loop so next cron run re-authenticates.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET /api/settings/clients — list all Betriebe ordered by name
PUT /api/settings/clients/:id — update AgrarmonitorBetriebId
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET /api/agrarmonitor/polling-config
PUT /api/agrarmonitor/polling-config
POST /api/agrarmonitor/run-polling
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>
- Trigger build on all branches (not only main)
- Tag image as 'latest' for main, branch name otherwise
- Sanitize branch name for Docker tag (slashes → dashes, lowercase)
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>