Commit Graph
193 Commits
Author SHA1 Message Date
bjoernpoettkerandClaude Opus 5.5 c28475f71f fix(security): JWT-Audience gegen OIDC_CLIENT_ID prüfen
Bisher prüfte das Backend nur Issuer und Signatur. Ein Access-Token, das
derselbe Authentik-Provider für eine andere Anwendung ausgestellt hat,
wurde ebenfalls akzeptiert.

- JwtStrategy verlangt aud == OIDC_CLIENT_ID (jwt-optionen.ts, getestet
  mit echten RS256-Tokens). Ohne OIDC_CLIENT_ID bleibt die Prüfung aus,
  mit Warnung beim Start.
- docker-compose.yml übergibt OIDC_CLIENT_ID jetzt ans Backend, Standard:
  dieselbe Client-ID wie das Frontend (VITE_OIDC_CLIENT_ID).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 10:46:57 +01:00
bjoernpoettkerandClaude Opus 5.5 b11294ec10 fix(security): Path-Traversal in den Mail-Vorschau-Routen
attachments/:attachmentId/pages/:page/{thumb,preview} übernahm die ID
ungeprüft in den Dateipfad – mit `..%2Finbox%2F<uuid>` ließen sich
Scanner-Vorschauen anderer Benutzer aus /mnt/data/inbox lesen.

- Routen wandeln attachmentId und page per ParseIntPipe in Zahlen um.
- EmailPageCacheService nimmt nur positive ganze Zahlen als Anhang-ID und
  Seite an, PageCacheService (Scanner) nur UUIDs als Dokument-ID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 10:46:57 +01:00
bjoernpoettkerandClaude Opus 5.5 e0a6598b35 refactor: Paperless-Dokumentrouten unter /api/paperless/documents/:id
„inbox“ war doppelt belegt (/api/inbox = Scanner, /api/paperless/inbox =
Paperless-Posteingang) und passte nicht zur Manuell-Seite, die dieselben
Routen nutzt. Umbenannt (ohne Alias, nur das eigene Frontend nutzt sie):

  PUT  paperless/inbox/:id            → PUT  paperless/documents/:id
  GET  paperless/inbox/pdf/:id        → GET  paperless/documents/:id/pdf
  GET  paperless/inbox/preview/:id    → GET  paperless/documents/:id/preview
  GET  paperless/inbox/:id/erechnung  → GET  paperless/documents/:id/erechnung

Dabei:
- Dokumentsuche (GET documents) wieder für den Posteingang (VIEW_INBOX)
  statt nur Admin – die Verknüpfungssuche im Bearbeiten-Dialog nutzt sie;
  die Einschränkung aus dem vorigen Commit hatte sie gebrochen.
- Suche und GET documents/:id liefern nur noch id, Titel, ASN, Datum
  (kein OCR-Volltext, keine Statusfelder).
- documents/:id/pdf auch für VIEW_SCANNER (Duplikatvergleich im Scanner).
- E-Rechnungs-Vorschlag prüft wie das Speichern pro Dokument (Tag 1 bzw.
  Manuell-Tag); Vorschau/PDF bewusst nicht (Suchergebnisse, Duplikate).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 10:46:57 +01:00
bjoernpoettkerandClaude Opus 5.5 04fca933ee fix(auth): PM_Buchhaltung umfasst den Posteingang
Der Posteingang ist eine abgespeckte Buchhaltung. Bisher bekam
PM_Buchhaltung nur PROCESS_MANUALLY; die Seite „Manuell bearbeiten“
nutzt für Vorschau, PDF, E-Rechnung und Speichern aber Routen mit
VIEW_INBOX – reine Buchhaltungsnutzer konnten dort nichts speichern.

PM_Buchhaltung bekommt jetzt zusätzlich VIEW_INBOX (Backend und Frontend).
permissions.enum.spec.ts vergleicht künftig nicht nur die Gruppennamen,
sondern auch die Berechtigungen pro Gruppe zwischen beiden Kopien.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 10:46:43 +01:00
bjoernpoettkerandClaude Opus 5.5 cedd7c78f4 fix(security): Posteingangs-Maske nur für Dokumente im eigenen Arbeitsbereich
PUT paperless/inbox/:id prüft jetzt pro Dokument: Posteingang-Rolle nur
für Dokumente mit Tag 1 (Posteingang), Buchhaltung nur für Dokumente mit
MANUELL_BEARBEITEN_TAG, Admins immer. Bisher ließen sich Mandant (Owner),
Felder und Titel beliebiger Paperless-Dokumente ändern, weil das Backend
mit dem Service-Token arbeitet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 10:46:43 +01:00
bjoernpoettkerandClaude Opus 5.5 3f98dfd98f fix(security): Rechteprüfung deny by default, API-Keys nur auf freigegebenen Routen
- PermissionsGuard lehnt Routen ohne @RequirePermissions/@AllowAnyAuthenticated
  ab. API-Keys umgehen keine Rechteprüfung mehr, sondern gelten nur auf
  Routen mit @AllowApiKey (Paperless-Webhook, externer Upload, checksum,
  Agent-Routen des Etikettendrucks).
- Rechte für 24 bisher offene Routen ergänzt, u.a. paperless/documents
  (nur Admin), paperless/documents/:id und Kontonummern (Posteingang/
  manuell), webhook/status (Admin). routen-rechte.spec.ts prüft alle Routen.
- Etiketten-Agent: printed/error nur für abgeholte, offene Jobs (bedingtes
  Update, sonst 409) – ein gedruckter Job kann seine Nummer nicht mehr
  freigeben. Feldwerte nur aus den Eingabefeldern der Vorlage ({number}
  nicht vorgebbar) und URL-kodiert in GET-/Callback-URLs.
- PUT paperless/inbox/:id ignoriert Freigabe (CF15) und Zahlung (CF16)
  ohne die jeweilige Rolle (Funktionstrennung).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 10:46:43 +01:00
bjoernpoettkerandClaude Opus 5.5 de9cb09bcd fix(security): Ghostscript mit -dSAFER, Schutz vor PDF-Dekompressionsbomben
- Ghostscript läuft auf PDFs aus Mails und vom Scanner jetzt mit -dSAFER
  statt -dNOSAFER (kein Datei-/Prozesszugriff aus PostScript), mit
  Timeout (60 s je Seite, 10 min je Dokument, SIGKILL) und höchstens
  500 gerenderten Seiten. Temp-Dateien werden auch im Fehlerfall
  entfernt. Ungenutztes getPageCount (brauchte Dateizugriff) entfernt.
- Neuer Vorab-Check ueberschreitetDekompressionsLimit (256 MB, streamend,
  erkennt auch Deflate-Ketten und abgeschnittene Streams). Fingerprint
  (pdf.js) und E-Rechnungs-Extraktion (pdf-lib) laden Bomben nicht mehr;
  eine einzelne Mail konnte das Backend sonst per OOM dauerhaft lahmlegen.
- Verschlüsselte PDFs bekommen keinen Inhalts-Fingerprint mehr ('' =
  nicht vergleichbar), weil pdf.js sie erst intern entschlüsselt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 10:46:43 +01:00
bjoernpoettkerandClaude Opus 5.5 bb8bf3714f fix(security): API-Keys nur für Admins, Mailversand ohne Datei-/URL-Zugriff
- ApiKeysController verlangt MANAGE_SETTINGS. Bisher konnte jeder
  OIDC-Benutzer einen API-Key erzeugen, der im PermissionsGuard jede
  Rechteprüfung umgeht (Rechteausweitung zum Admin).
- MailService setzt disableFileAccess/disableUrlAccess für jede Mail.
- send-email im Posteingang prüft den Body streng auf Strings/Zahlen.
  Bisher liest nodemailer bei html: { path: '/proc/self/environ' }
  beliebige Serverdateien ein und verschickt sie.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 10:46:43 +01:00
bjoernpoettker 0406354b8b Merge pull request 'feat: Duplikate im Import als neue Version behandeln' (#6) from feat/duplikat-neue-version into main
Build and Push Multi-Platform Images / build-and-push (push) Successful in 10s
Reviewed-on: #6
2026-11-02 13:31:04 +00:00
bjoernpoettkerandClaude Opus 5.5 c1afa02ee2 fix: Duplikatprüfung immer gegen die ASN, die das Dokument beim Upload bekäme
Build and Push Multi-Platform Images / build-and-push (push) Successful in 39s
Im Posteingang kann das ASN-Feld der Aktion von der Belegnummer abweichen.
Prüfung, Versions-Upload und normaler Upload nutzen jetzt dieselbe ASN.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 14:27:21 +01:00
bjoernpoettkerandClaude Opus 5.5 79dadb9c93 fix: Kennzahlen mit Timeout laden, ungültige Seitenbereiche als 400 melden
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 14:22:44 +01:00
bjoernpoettkerandClaude Opus 5.5 32b5228f68 fix: Zieldokument prüfen, Versions-Verarbeitung abwarten, Abschnittsseiten vom Backend
- Neue Version nur, wenn die Belegnummer in Paperless eindeutig zu genau
  diesem Dokument gehört (serverseitig geprüft)
- Auf die Paperless-Task der Version warten; Ablehnung → Fehler, Tag 21 weg
- Entscheidung im Posteingang nur zusammen mit processOnlyOne
- Vergleichsdialog im Posteingang zeigt die Seiten, die tatsächlich
  hochgeladen werden

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 14:14:01 +01:00
bjoernpoettkerandClaude Opus 5.5 98021fdcbf docs: offene Punkte zu Versionen und Task-Bearbeitung
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 14:04:58 +01:00
bjoernpoettkerandClaude Opus 5.5 fffbf692b2 feat(frontend): Vergleichsdialog für Duplikate mit neuer Version
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 14:04:42 +01:00
bjoernpoettkerandClaude Opus 5.5 21a447e915 feat(mail): Beleg beim Import als neue Version anhängen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 14:01:47 +01:00
bjoernpoettkerandClaude Opus 5.5 bdc85f5f1f feat(posteingang): Duplikat als neue Version oder verwerfen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 13:58:31 +01:00
bjoernpoettkerandClaude Opus 5.5 170eb72c70 feat(paperless): Belege als neue Version anhängen und mit Tag 21 markieren
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 13:57:02 +01:00
bjoernpoettkerandClaude Opus 5.5 8e0c609802 feat: Seiten- und Wortzahl für den Duplikatvergleich
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 13:55:51 +01:00
bjoernpoettkerandClaude Opus 5.5 57a460ffa2 feat(paperless): Belegnummer gegen Paperless prüfen (CF7 + ASN)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 13:53:50 +01:00
bjoernpoettkerandClaude Opus 5.5 da02baa2b9 docs: Ergebnisse der Live-Prüfung Paperless-Versionen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 13:52:23 +01:00
bjoernpoettkerandClaude Opus 5.5 62d81dc25f docs: Design und Plan „Duplikat → neue Version“
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 13:52:04 +01:00
bjoernpoettkerandClaude Opus 5.5 bc2d1cd4b7 fix(agrarmonitor): gebuchte Belege wieder erkennen, Titel per Template
Build and Push Multi-Platform Images / build-and-push (push) Successful in 18s
- Connector auf 9bda65e: Buchungsstatus aus #bookedStatus lesen. AM zeigt
  hinter dem Status jetzt „Zahlung erfassen“, dadurch war buchungsDatum
  immer leer und das Polling hat keinen Beleg als verbucht markiert.
- Polling: Schritt-Logging pro Dokument über AGRARMONITOR_POLLING_DEBUG,
  Abschlusszeile zählt „noch nicht gebucht“ mit.
- Upload-Check: Titel über das Titel-Template des Dokumenttyps, Fallback
  auf ERG/EGU <Belegnr>. Template-Auflösung als resolveTitelTemplate()
  ausgelagert und im Processor wiederverwendet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:03:27 +01:00
bjoernpoettkerandClaude Opus 5.5 df50470e53 fix(paperless): documents.checksum für SHA-256 verbreitern
Build and Push Multi-Platform Images / build-and-push (push) Successful in 28s
Paperless-NGX ≥ 3.0 liefert original_checksum als SHA-256 (64 Zeichen).
Die lokale Spiegeltabelle documents hatte nur varchar(32), wodurch die
Nachbearbeitung mit „Data too long for column 'checksum'“ abbrach – nach
dem Setzen von Notizen, aber vor Fertig=1. Der Task wurde dadurch jede
Minute erneut verarbeitet und erzeugte doppelte Notizen.

- documents.checksum auf varchar(64) (Entity + Migration)
- Sync der Spiegeltabelle ist nicht mehr fatal: Fehler werden als
  Warnung geloggt, der Task wird trotzdem abgeschlossen

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 13:35:45 +01:00
bjoernpoettkerandClaude Opus 5.5 4f34855c12 fix(paperless): Anpassung an Paperless-NGX 3.4 (API v10)
Build and Push Multi-Platform Images / build-and-push (push) Successful in 31s
- Task-Status: getTask() normalisiert die paginierte v10-Antwort
  (status klein, result_data, related_document_ids). Bisher wurde jede
  Task als „nicht gefunden“ gelöscht, ohne Nachbearbeitung.
- Checksummen: Paperless ≥ 3.0 nutzt SHA-256 statt MD5. Duplikatprüfung
  umgestellt; Migration verbreitert Attachments.Checksum und berechnet
  Bestandswerte per SHA2() neu.
- Custom-Field-Suche über custom_field_query, der alte Filter wurde von
  Paperless ignoriert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 20:15:01 +01:00
bjoernpoettkerandClaude Opus 5.5 33457c19c2 chore(docker): Node.js 20 → 24 LTS
Build and Push Multi-Platform Images / build-and-push (push) Successful in 1m22s
Node 20 ist seit April 2026 End-of-Life. Backend- und Frontend-Images
laufen jetzt auf node:24-alpine; @types/node im Backend auf ^24 angehoben.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 10:00:57 +01:00
bjoernpoettkerandClaude Opus 5.5 cdcee29c5b fix(agrarmonitor): Connector-Update – Lieferscheinnummer bei gebuchten Rechnungen
Build and Push Multi-Platform Images / build-and-push (push) Successful in 1m4s
Connector e6ce1d2 schickt die disabled-Felder aus editForm.php mit an
update.php. Bisher schlug „Lieferscheinnummer setzen“ bei gebuchten
Rechnungen mit HTTP 422 fehl (typ, firma_id, Adressfelder fehlten).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 15:55:36 +02:00
bjoernpoettkerandClaude Opus 5.5 0ff78707d1 feat(agrarmonitor): Cookies in den Einstellungen zurücksetzen
Build and Push Multi-Platform Images / build-and-push (push) Successful in 42s
Neuer Button „Cookies zurücksetzen“ neben „Status abrufen“. Er löscht
die gespeicherte Agrarmonitor-Session samt Cookie-Datei; beim nächsten
Zugriff meldet sich der Manager neu an.

Eine laufende Connector-Instanz wird über clearSession() zurückgesetzt
und verworfen, damit sie ihren alten Cookie-Jar nicht wieder in die
Datei schreibt. Während einer Lieferantennummern-Vergabe ist das
Zurücksetzen gesperrt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 09:53:47 +02:00
bjoernpoettkerandClaude Opus 5.5 549948913a fix(agrarmonitor): Lieferanten-Detailseite ohne AJAX-Header laden
Build and Push Multi-Platform Images / build-and-push (push) Successful in 38s
Im Einzeltest fehlte auf /kunden/detail/<id> das Feld
#lieferantennummer, obwohl die Liste kurz vorher mit derselben Session
geladen wurde. Die Detailseite wird jetzt wie eine normale
Browser-Navigation ohne X-Requested-With geladen (wie im Connector
bei den Eingangsrechnungen).

Fehlt das Feld trotzdem, nennt der Fehler HTTP-Status, Ziel-URL,
Seitentitel und Feldnamen – ohne Feldwerte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 09:34:49 +02:00
bjoernpoettkerandClaude Opus 5.5 3d4125b29a feat(agrarmonitor): fehlende Lieferantennummern vergeben
Build and Push Multi-Platform Images / build-and-push (push) Successful in 1m1s
Neuer Bereich „Lieferantennummern überprüfen“ in den Agrarmonitor-
Einstellungen. Er vergibt allen aktiven Lieferanten ohne
Lieferantennummer eine fortlaufende Nummer im Schema 1555xxxx, ab der
höchsten vergebenen Nummer (Inaktive zählen mit, Altlasten werden
ignoriert).

- Vorschau „Lieferant → neue Nummer“, geschrieben wird erst nach
  Bestätigung; Einzelmodus zum Testen an einem Lieferanten
- formData wird wie in der Weboberfläche aus #form_detail aufgebaut,
  nur die Lieferantennummer ändert sich
- Dublettencheck über vorhanden.php, Erfolgskontrolle durch Neuladen
  des Details, Abbruch beim ersten Fehler
- Lauf im Hintergrund mit Status-Abfrage (wegen Proxy-Timeouts),
  Listenfilter werden danach zurückgesetzt
- HTML-Parsing mit cheerio, Unit-Tests für Parser und Vergabe-Ablauf

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 08:51:13 +02:00
bjoernpoettkerandClaude Opus 5.5 029009182a fix(agrarmonitor): Fehlergrund beim Speichern in Agrarmonitor loggen
Build and Push Multi-Platform Images / build-and-push (push) Successful in 50s
Connector-Update: Bei HTTP 422 von update.php steht jetzt die
Begründung von Agrarmonitor in der Warnung „Lieferscheinnummer setzen
fehlgeschlagen“.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:22:28 +02:00
bjoernpoettkerandClaude Opus 5.5 79ab3da2c2 fix(agrarmonitor): Connector mit neuen Eingangsrechnungs-Endpunkten
Build and Push Multi-Platform Images / build-and-push (push) Failing after 19s
Agrarmonitor hat eingangsrechnungen.php entfernt, dadurch schlug die
Livesearch im Upload-Check mit 404 fehl. Der Connector nutzt jetzt
editForm.php zum Laden und update.php zum Speichern.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 14:18:40 +02:00
bjoernpoettkerandClaude Opus 5.5 d2236368be fix(agrarmonitor): aufgerufene Seite bei HTTP-Fehlern mitloggen
Build and Push Multi-Platform Images / build-and-push (push) Successful in 43s
Fehlermeldungen im Polling enthielten nur den Status (z. B. „Request
failed with status code 404“), nicht aber die aufgerufene URL. Die neue
Hilfsfunktion fehlerText() hängt bei Axios-Fehlern Methode und
vollständige URL an, damit sich z. B. der Livesearch-404 einer
konkreten Seite zuordnen lässt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 14:02:59 +02:00
bjoernpoettkerandClaude Opus 5.5 a72e41611d feat(mail): E-Mail ignorieren, wenn im Import-Wizard alles ignoriert wird
Build and Push Multi-Platform Images / build-and-push (push) Successful in 23s
Stehen im Wizard alle Dokumente auf „Ignorieren“ (durch die
Duplikatprüfung oder vom Benutzer gewählt), gibt es nichts zu
importieren. „Weiter“ markiert die E-Mail dann als ignoriert, informiert
den Benutzer und schließt den Wizard.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 14:04:23 +02:00
bjoernpoettkerandClaude Opus 5.5 acb9076944 fix(mail): „Anhänge prüfen“ erkennt Duplikate auch über den Inhalt
Build and Push Multi-Platform Images / build-and-push (push) Successful in 32s
check-attachments fragte nur die Checksumme bei Paperless ab. Neu
erzeugte PDFs mit gleichem Inhalt wie ein bereits importierter Anhang
blieben dadurch auf „Neu“. Findet Paperless die Checksumme nicht, wird
jetzt per Text-Fingerprint nach einem importierten Anhang gesucht; die
Mail wird dann als verarbeitet markiert und die Paperless-ID übernommen.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 12:42:02 +02:00
bjoernpoettkerandClaude Opus 5.5 797cbb9b71 fix(mail): Duplikate auch bei neu erzeugten PDFs erkennen
Build and Push Multi-Platform Images / build-and-push (push) Successful in 45s
Absender erzeugen PDFs beim erneuten Versand oft neu (andere
Erstellungszeit/Dokument-ID), dadurch unterscheidet sich die Checksumme
und die Duplikatprüfung griff nicht (z.B. Mail 7071 vs. 7072).

- Neuer Text-Fingerprint (SHA-256 über normalisierten PDF-Text via
  pdf-parse) in Attachments.ContentFingerprint, inkl. Migration und Index
- Wird beim Mail-Abruf berechnet; Altbestand füllt ein Hintergrund-
  Backfill beim Start auf, fehlende Werte werden bei Bedarf nachberechnet
- Duplikatprüfung und Import-Sperre berücksichtigen Anhänge mit gleichem
  Inhalt, die importiert sind oder gerade importiert werden
- Jest braucht für pdf-parse --experimental-vm-modules (test-Skripte)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 12:27:31 +02:00
bjoernpoettkerandClaude Opus 5.5 534b313054 fix(mail): Duplikate auch bei gerade laufenden Importen erkennen
Build and Push Multi-Platform Images / build-and-push (push) Successful in 39s
Wurde dieselbe Mail zweimal weitergeleitet, erkannte der Import-Assistent
das Duplikat nicht, solange Paperless das erste Dokument noch verarbeitete –
geprüft wurde nur die Checksumme in Paperless.

- checkDuplicate() berücksichtigt zusätzlich offene Paperless-Tasks von
  Anhängen mit gleicher Checksumme (gleicher Seitenbereich)
- Assistent prüft erneut vor dem Abrufen der Belegnummern und vor dem
  Import; Duplikate werden ignoriert, reservierte Nummern freigegeben
- executeImport prüft serverseitig vor Upload und Festlegen der Nummer,
  sperrt laufende Importe gegen parallele Doppelimporte und meldet 409

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 10:29:43 +02:00
bjoernpoettkerandClaude Opus 5.5 3cea3fb239 feat(mail): E-Mails mit Leserecht als ignoriert markieren
Der Button „Als ignoriert markieren“ war für alle mit VIEW_MAIL sichtbar,
der Aufruf (PATCH :id/status) verlangte aber MANAGE_ALL und scheiterte
mit 403. Neuer Endpunkt POST /api/emails/:id/ignore mit VIEW_MAIL, der nur
Status 3 setzen kann; bereits verarbeitete E-Mails werden abgelehnt. Das
allgemeine Statusändern bleibt Admins vorbehalten.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 10:29:43 +02:00
bjoernpoettkerandClaude Opus 5 f97177943d feat(mail): abgeschlossene E-Mails erneut zur Bearbeitung freigeben
Build and Push Multi-Platform Images / build-and-push (push) Successful in 39s
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>
2026-09-02 11:06:08 +02:00
bjoernpoettkerandClaude Opus 5 b7b65c64ae fix: Berechtigungen der Tagesübersicht, WebDAV-Ausbau, Tests instand gesetzt
Build and Push Multi-Platform Images / build-and-push (push) Successful in 55s
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>
2026-09-01 00:06:50 +02:00
bjoernpoettkerandClaude Fable 5 32ba772e4e fix(frontend): weiße Seite bei fehlgeschlagenem Chunk-Import beheben
Build and Push Multi-Platform Images / build-and-push (push) Successful in 18s
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>
2026-07-27 10:20:25 +02:00
bjoernpoettkerandClaude Opus 4.8 095cc4bb02 fix: Warteschlange blieb stehen – Altersvergleich in die DB verlagert
Build and Push Multi-Platform Images / build-and-push (push) Successful in 32s
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>
2026-07-22 12:07:51 +02:00
bjoernpoettkerandClaude Sonnet 4.6 7b2a79be2a fix: Dateinamen mit Pfadtrennzeichen beim Mail-Import absichern
Build and Push Multi-Platform Images / build-and-push (push) Successful in 31s
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>
2026-07-22 11:10:36 +02:00
bjoernpoettkerandClaude Opus 4.8 1c70473cef feat: Mindest-Wartezeit (5000 ms) zwischen Einreihen und Verarbeitung
Build and Push Multi-Platform Images / build-and-push (push) Successful in 33s
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>
2026-07-22 11:03:10 +02:00
bjoernpoettkerandClaude Fable 5 beaa1be4a5 feat(backend): Metadaten direkt beim Paperless-Upload übergeben
Build and Push Multi-Platform Images / build-and-push (push) Successful in 31s
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>
2026-07-14 22:46:42 +02:00
bjoernpoettkerandClaude Opus 4.8 57c8964384 feat(frontend): Manuell bearbeiten – Speichern trotz fehlender Pflichtfelder
Build and Push Multi-Platform Images / build-and-push (push) Successful in 17s
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>
2026-07-14 10:55:04 +02:00
bjoernpoettker 8390d03869 Merge pull request 'Freigabe → main: Mobile UI, Webhook, IMAP, Zahlung-Workflow und weitere Features' (#5) from Freigabe into main
Build and Push Multi-Platform Images / build-and-push (push) Successful in 8s
Reviewed-on: #5
2026-07-14 07:44:32 +00:00
bjoernpoettker 3cbb64686a chore: add .gitea_token to .gitignore
Build and Push Multi-Platform Images / build-and-push (push) Successful in 10s
2026-07-14 09:43:53 +02:00
bjoernpoettkerandClaude Sonnet 4.6 7076eef57b feat: add mobile-responsive layout and card views across all pages
Build and Push Multi-Platform Images / build-and-push (push) Successful in 39s
- 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>
2026-07-14 09:22:58 +02:00
bjoernpoettkerandClaude Opus 4.8 0765d14d3b fix(agrarmonitor): Karenzzeit vor "Von AM zurück"-Markierung
Build and Push Multi-Platform Images / build-and-push (push) Successful in 39s
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>
2026-07-03 12:40:59 +02:00
bjoernpoettkerandClaude Opus 4.8 8fda248683 fix(frontend): seltener Relogin durch stillen Token-Refresh
Build and Push Multi-Platform Images / build-and-push (push) Successful in 17s
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>
2026-06-30 11:53:38 +02:00