Freigabe → main: Mobile UI, Webhook, IMAP, Zahlung-Workflow und weitere Features #5

Merged
bjoernpoettker merged 16 commits from Freigabe into main 2026-07-14 07:44:32 +00:00
Owner

Zusammenfassung

  • Mobile-Responsive UI: Drawer-Navigation, Kartenansicht auf allen Listenseiten, useIsMobile-Hook, MobileCardList-Komponente
  • Paperless-Webhook: Echtzeit-Dokumentenverarbeitung ersetzt Tag-16-Cron; persistente, deduplizierte Warteschlange; Status-Tab in Einstellungen
  • Freigabe → Zahlung: Zweistufiger Workflow mit eigenem Zahlung-Modul
  • IMAP-Ordnerverwaltung: Importierte E-Mails automatisch verschieben; 90-Tage-Bereinigung
  • Auth-Fix: JWT wird nicht mehr fälschlicherweise als API-Key geprüft
  • Agrarmonitor: Karenzzeit vor "Von AM zurück"-Markierung; diverse Polling-Fixes
  • Steuertags: Trennung von Workflow-Tags und inhaltlichen Tags
  • Daily Digest: Tägliche E-Mail-Zusammenfassung mit Card-Layout und Permission-Filterung
  • Diverse Bugfixes: TypeORM-synchronize-Crash in Produktion, stiller Token-Refresh, einheitliche Schriftart

Testplan

  • Mobile-Ansicht auf Smartphone/DevTools prüfen (Inbox, Mail, Freigabe, Zahlung)
  • Paperless-Webhook manuell auslösen und Status in Einstellungen beobachten
  • Freigabe-Dokument genehmigen → erscheint in Zahlung
  • E-Mail importieren → landet im IMAP-Ordner "importiert"
  • Login mit JWT-Bearer-Token → kein ungewollter API-Key-Fallback

🤖 Generated with Claude Code

## Zusammenfassung - **Mobile-Responsive UI**: Drawer-Navigation, Kartenansicht auf allen Listenseiten, `useIsMobile`-Hook, `MobileCardList`-Komponente - **Paperless-Webhook**: Echtzeit-Dokumentenverarbeitung ersetzt Tag-16-Cron; persistente, deduplizierte Warteschlange; Status-Tab in Einstellungen - **Freigabe → Zahlung**: Zweistufiger Workflow mit eigenem Zahlung-Modul - **IMAP-Ordnerverwaltung**: Importierte E-Mails automatisch verschieben; 90-Tage-Bereinigung - **Auth-Fix**: JWT wird nicht mehr fälschlicherweise als API-Key geprüft - **Agrarmonitor**: Karenzzeit vor "Von AM zurück"-Markierung; diverse Polling-Fixes - **Steuertags**: Trennung von Workflow-Tags und inhaltlichen Tags - **Daily Digest**: Tägliche E-Mail-Zusammenfassung mit Card-Layout und Permission-Filterung - **Diverse Bugfixes**: TypeORM-synchronize-Crash in Produktion, stiller Token-Refresh, einheitliche Schriftart ## Testplan - [x] Mobile-Ansicht auf Smartphone/DevTools prüfen (Inbox, Mail, Freigabe, Zahlung) - [x] Paperless-Webhook manuell auslösen und Status in Einstellungen beobachten - [x] Freigabe-Dokument genehmigen → erscheint in Zahlung - [x] E-Mail importieren → landet im IMAP-Ordner "importiert" - [x] Login mit JWT-Bearer-Token → kein ungewollter API-Key-Fallback 🤖 Generated with [Claude Code](https://claude.ai/claude-code)
bjoernpoettker added 15 commits 2026-07-14 07:43:50 +00:00
feat: importierte E-Mails automatisch in IMAP-Ordner verschieben und nach 90 Tagen löschen
Build and Push Multi-Platform Images / build-and-push (push) Successful in 31s
ed57477324
- 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>
fix: Produktions-Crash durch TypeORM-synchronize beheben
Build and Push Multi-Platform Images / build-and-push (push) Successful in 44s
41eed1871e
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>
feat: verarbeitete/ignorierte E-Mails beim Prüfen in IMAP-Ordner verschieben
Build and Push Multi-Platform Images / build-and-push (push) Successful in 38s
969f0ae0b1
- 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>
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>
feat: Paperless-Webhook ersetzt Tag-16-Cron-Job durch Echtzeit-Verarbeitung
Build and Push Multi-Platform Images / build-and-push (push) Successful in 42s
56596d4482
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>
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>
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>
feat: Webhook verarbeitet jedes Dokument ohne Tag-16-Vorprüfung
Build and Push Multi-Platform Images / build-and-push (push) Successful in 38s
b77a283ab2
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>
feat: Webhook-Warteschlange für sequenzielle, deduplizierte Verarbeitung
Build and Push Multi-Platform Images / build-and-push (push) Successful in 37s
66a2cccd20
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>
feat: Webhook-Warteschlange in Datenbank persistieren
Build and Push Multi-Platform Images / build-and-push (push) Successful in 31s
9718d6888a
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>
fix(frontend): einheitliche Schriftart in AntD-Komponenten
Build and Push Multi-Platform Images / build-and-push (push) Successful in 17s
e50111a731
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>
fix(auth): JWT nicht als API-Key prüfen (Bearer-Fallback nur für pm_-Keys)
Build and Push Multi-Platform Images / build-and-push (push) Successful in 30s
156b0401b3
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>
fix(frontend): seltener Relogin durch stillen Token-Refresh
Build and Push Multi-Platform Images / build-and-push (push) Successful in 17s
8fda248683
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>
fix(agrarmonitor): Karenzzeit vor "Von AM zurück"-Markierung
Build and Push Multi-Platform Images / build-and-push (push) Successful in 39s
0765d14d3b
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>
feat: add mobile-responsive layout and card views across all pages
Build and Push Multi-Platform Images / build-and-push (push) Successful in 39s
7076eef57b
- 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>
bjoernpoettker added 1 commit 2026-07-14 07:43:54 +00:00
chore: add .gitea_token to .gitignore
Build and Push Multi-Platform Images / build-and-push (push) Successful in 10s
3cbb64686a
bjoernpoettker merged commit 8390d03869 into main 2026-07-14 07:44:32 +00:00
bjoernpoettker deleted branch Freigabe 2026-07-14 07:44:39 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bjoernpoettker/paperlessmanager#5