Commit Graph

171 Commits

Author SHA1 Message Date
sysops 88e9d0c08c docs(PROJ-35): Status auf Deployed + Bekannte Pitfalls dokumentiert
- 132 + 131 deployed
- hashMailID-Bit-Mask-Fix dokumentiert (negative IDs Problem)
- OCR-Tempo-Constraint (CPU-bound) erklärt
- Boot-Resume-Loop als bekannter, unkritischer Bug vermerkt
2026-05-08 23:10:59 +02:00
sysops d71d20d869 fix(PROJ-35): hashMailID maskiert Top-Bit für positive int64
Vorheriger Fix (int64-Cast) erzeugte für die obere uint64-Hälfte negative
Werte. Manticore weist negative IDs beim INSERT/REPLACE zurück
("Negative document ids are not allowed"), nur SELECT akzeptiert sie.

Lösung: Bit-Mask 0x7FFFFFFFFFFFFFFF — Top-Bit immer 0, Result in
[0, 2^63-1]. 63-Bit-Hash-Space reicht für jede realistische Mail-Anzahl.
2026-05-08 22:53:20 +02:00
sysops 7ba677e4b5 fix(PROJ-35): hashMailID liefert int64 statt uint64
Manticore akzeptiert in `id`-bigint nur signed int64. Der mysql-Treiber
serialisiert Parameter als Dezimal-String → uint64-Werte > int64.MaxValue
führten zu "number ... is out of range". Fix: int64(h.Sum64())
verlustfreier Bit-Cast — bestehende Dokumente bleiben erreichbar.

Auch: PROJ-35-Spec auf In Progress + Implementation Notes/Pitfalls/QA-Block,
INDEX.md-Status-Update.
2026-05-08 22:40:25 +02:00
sysops 6d835aefac fix(PROJ-35): OCR Tempdir auf storage_dir umleiten
Mit systemd ProtectSystem=strict ist /tmp fuer den Service read-only.
ocr.SetTempDir(storage_path/ocr-tmp) nutzt einen RW-Pfad innerhalb der
ohnehin freigegebenen ReadWritePaths.
2026-05-08 22:19:20 +02:00
sysops a252ad6f0e fix(PROJ-35): OCR Boot-Resume drosselt nach Queue-Kapazitaet 2026-05-08 22:15:20 +02:00
sysops 0bda21033e feat(PROJ-35): OCR & Anhang-Volltext-Indexierung
Asynchrone OCR fuer PDF- und Bild-Anhaenge via tesseract + poppler-utils.
Extrahierter Text wird in Manticore (attachment_text) gespeichert und ist
ueber die normale Volltextsuche auffindbar.

- internal/ocr: ExtractText + Worker (queue + drain)
- internal/storage/ocr.go: SetOCRStatus, OCREnabled, GetMailsByOCRStatus
- emails.ocr_status (pending|done|failed|skipped|disabled)
- tenants.ocr_enabled (Default TRUE, opt-out)
- Manticore: attachment_text-Feld + UpdateAttachmentText
- Boot-resume: pending Jobs nach Restart automatisch in die Queue
- CLI: archivmail ocr-reprocess --tenant N --status pending|failed|all
- update.sh: tesseract-ocr + poppler-utils optional installieren
2026-05-08 22:11:17 +02:00
sysops 2a91f6e249 fix: IMAP-Serveradresse dynamisch aus Backend laden
Hardcodierte 192.168.1.131 in settings/page.tsx ersetzt durch
dynamischen API-Call GET /api/system/info → {fqdn, imap_port}.
Fallback auf window.location.hostname wenn API nicht antwortet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 11:06:58 +02:00
sysops 3b05e949dd feat(PROJ-13,PROJ-42): REST API v1 + Gespeicherte Suchanfragen
PROJ-13: Externe REST API für CRM/ERP-Anbindung
- API-Key Middleware mit SHA-256-Hash-Lookup + Token-Bucket Rate-Limiter
- GET /api/v1/mails — Suche mit Paginierung (max 100/Seite)
- GET /api/v1/mails/{id} — Mail-Metadaten als JSON
- GET /api/v1/mails/{id}/raw — Original-EML Download
- Admin-Endpoints: POST/GET/DELETE /api/admin/apikeys
- Tenant-Isolation, Audit-Log, 405 für non-GET Methoden

PROJ-42: Gespeicherte Suchanfragen
- Tabelle saved_searches (user_id, tenant_id, name, query_json)
- GET/POST/DELETE /api/searches/saved mit Ownership-Check
- Frontend: "Suche speichern"-Button + Popover mit gespeicherten Suchen
- shadcn/ui Komponenten, Loading/Empty States

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 10:54:26 +02:00
sysops 9298216ce0 feat(PROJ-40,PROJ-41): Prometheus Metriken + Dashboard Zeitreihe
- PROJ-40: /api/health mit Version+Uptime, /metrics Prometheus-Format
  (mails_last_60min/24h/7d/30d, mails_total, storage_bytes, tenants_total,
   users_total, uptime_seconds) — Token-Schutz optional konfigurierbar
- PROJ-41: GET /api/admin/stats/timeseries (30-Tage tagesgenau, Tenant-scoped)
  + SVG-Balkendiagramm im Dashboard (Mail-Eingang letzte 30 Tage)
- storage.DBQueryRow() Helper für Metrics-Queries ohne Pool-Exposition
- config.MetricsConfig (enabled, token) in config.go

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 21:10:42 +02:00
sysops 4f366a3634 fix(PROJ-39): exportEDiscovery in api/index.ts re-exportieren
exportEDiscovery war in mail.ts definiert, aber fehlte im Re-Export-Block
von index.ts — Frontend-Build schlug mit "Export doesn't exist" fehl.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 20:57:32 +02:00
sysops 963a324476 fix(PROJ-39): sanitizeFilename-Konflikt beheben — in ediscovery.go umbenannt
sanitizeFilename war doppelt deklariert (server.go + ediscovery.go).
Funktion in ediscovery.go zu sanitizeExportFilename umbenannt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 20:56:27 +02:00
sysops a82e854cfc feat(PROJ-39): eDiscovery Export + Feature-Specs PROJ-40–43
- Neuer POST /api/export/ediscovery Handler (internal/api/ediscovery.go)
- Route in server.go registriert
- Feature-Specs PROJ-39 bis PROJ-43 angelegt
- INDEX.md aktualisiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 20:55:37 +02:00
sysops 2bab61209c chore: Modulname github.com/archivmail → archivmail
Go-Modul in go.mod und allen 45 Go-Dateien umbenannt.
2026-04-05 20:37:35 +02:00
sysops eb48081c5e feat(PROJ-38): rethread — rückwirkendes Mail-Threading 2026-04-05 20:28:50 +02:00
sysops 887548a9c7 fix(PROJ-38): getThread + ThreadMail/ThreadResponse in api/index.ts re-exportieren 2026-04-05 20:19:36 +02:00
sysops b252172cc7 feat(PROJ-26,PROJ-38): IMAP LDAP-Auth + Mail-Threading 2026-04-05 20:17:41 +02:00
sysops 956b5b6d5f feat(PROJ-36): archivmail recompress — Nachkomprimierung bestehender Mails
Neuer CLI-Subcommand: archivmail recompress [--dry-run]
Komprimiert alle unkomprimierten Dateien im Store atomisch (temp + rename).
Überspringt bereits komprimierte Dateien (Magic-Byte 0x01).
Aktualisiert storage_objects und emails.storage_id in der DB.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 01:30:42 +02:00
sysops 27d45f58e8 feat(PROJ-36,PROJ-37): gzip-Kompression + Attachment-Deduplication
Sprint 1: Emails werden vor AES-256-GCM optional gzip-komprimiert (compress: true).
Magic-Byte 0x01 als Prefix ermöglicht backward-kompatibles Load() für Legacy-Dateien.
Neue DB-Tabelle storage_objects trackt Kompressions-Metadaten.

Sprint 2: Attachments werden via SHA-256 dedupliziert — gleicher Anhang in N Mails
wird nur einmal gespeichert. Neue Tabellen: attachments, email_attachments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 01:19:51 +02:00
sysops fdb25cb16a feat: Labels-Feature vollständig entfernen (PROJ-9)
Backend:
- internal/labelstore/ gelöscht (Store, Schema, CRUD)
- internal/api/label_handlers.go gelöscht (alle Label-Routen)
- internal/api/server.go: labels-Feld + SetLabels() entfernt
- internal/api/search_handlers.go: label_id-Filter + Enrichment entfernt
- internal/index/index.go: LabelID aus SearchRequest entfernt
- internal/imapserver/server.go: labels-Feld + labelbasierte Mailboxen entfernt
- cmd/archivmail/main.go: labelstore-Init + SetLabels() entfernt
- cmd/archivmail/version.go: labelstore-Modul entfernt, index-Kommentar korrigiert

Frontend:
- LabelList.tsx, LabelPicker.tsx, LabelsTab.tsx gelöscht
- src/lib/api/system.ts: MailLabel/LabelRule-Typen + alle Label-Funktionen entfernt
- src/lib/api/index.ts: Label-Exports entfernt
- src/app/search/page.tsx: LabelList + selectedLabelId State entfernt
- src/app/mail/[id]/page.tsx: LabelPicker + Labels-State entfernt
- src/app/admin/page.tsx: LabelsTab + alle Label-Handler/State entfernt

Docs:
- features/PROJ-9: Status auf Removed gesetzt
- features/INDEX.md: PROJ-9 auf Removed gesetzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:32:13 +02:00
sysops 4d1bdb6e8b fix(ui): rollenbasierte Navigation + domain_auditor-Support
- useAuth.ts: domain_auditor (Level 3) in roleLevels ergänzt
- navbar.tsx: IMAP/POP3-Links nur noch für user + domain_admin;
  domain_auditor bekommt Zugang zum Admin-Bereich
- UserNav.tsx: Rollenbezeichnung deutsch + leserlich (domain_auditor →
  "Domain-Auditor"); Badge ausgeblendet wenn Username = Rollenname

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:16:53 +02:00
sysops 0db2324c8b fix(ui): Label-Sidebar für auditor/domain_auditor ausblenden
Auditoren haben keine eigenen Mails — Labels machen für sie keinen Sinn.
Die Sidebar (inkl. "+ Neues Label") wird jetzt nur noch für Rollen
mit eigenen Mails angezeigt (user, domain_admin, superadmin).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:13:46 +02:00
sysops 23dbab1f47 chore: überflüssigen REPO_URL-Guard im Docker-Installer entfernen
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:00:49 +02:00
sysops 2900187a0d chore: Xapian/Bleve-Reste aus install.sh, setup.sh und smoke_test.sh entfernen
- install.sh: REPO_URL auf Gitea gesetzt, libxapian-dev entfernt, xapian-
  Verzeichnis entfernt, config.yml-Template auf Manticore umgestellt,
  Manticore-Installationsschritt ergänzt, systemd-Unit auf manticore.service
  als Abhängigkeit, GitHub-URL-Sonderbehandlung entfernt
- setup.sh: "Bleve backend" und "build with Xapian" Hinweise entfernt,
  Projektname von mailarchive auf archivmail korrigiert
- smoke_test.sh: Binary-Namen auf aktuelles CLI-Format korrigiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:00:06 +02:00
sysops bde291901a fix: Manticore als Standard-Backend, Xapian-Cleanup in update.sh
- main.go: Default-Backend von "xapian" auf "manticore" geändert
- index.go: Kommentar und Fehlermeldung aktualisiert
- update.sh: Xapian-Verzeichnis wird nach erfolgreichem Manticore-Reindex
  automatisch entfernt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 20:42:58 +02:00
sysops 48cfb7cfa6 fix: auditor immer globalen Index nutzen, tenant_id ignorieren
auditor-Rolle hat evtl. tenant_id gesetzt (historisch), soll aber
trotzdem immer den globalen Index durchsuchen und nur No-Tenant-Mails
sehen. tenant_id auf auditor-User per DB-Migration auf NULL gesetzt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 19:51:42 +02:00
sysops 994e5d16fc feat: auditor sieht Mails ohne Tenant-Zuordnung
- auditor-Rolle sieht jetzt Mails wo tenant_id IS NULL und kein
  email_refs-Eintrag existiert (statt nur eigene Mails)
- Neues storage.IsWithoutTenant() für effizienten Direktzugriff
- Neues storage.GetAllIDsWithoutTenant() für Suche + ZIP-Export
- Konsistente Prüfung in Search, GetMail, GetAttachment, GetRaw, Export

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 19:34:45 +02:00
sysops c8ab4afef0 chore: PROJ-9 als Deployed markiert
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 10:44:28 +02:00
sysops 030752157b fix(PROJ-9): Superadmin-Tenant-NULL, GET admin/labels, from_domain-Allowlist
- labelTenantID() returns *int64 (nil for superadmin) statt int64(0)
  → verhindert FK-Constraint-Fehler bei tenant_id = 0
- CreateAdminLabel/CreateLabelRule: nil-Check, 400 wenn kein Tenant
- GET /api/admin/labels Route + handleGetAdminLabels Handler ergänzt
- from_domain in condition_field Allowlist für Label-Regeln hinzugefügt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 10:42:06 +02:00
sysops 7e1e58e1e4 feat(PROJ-35): Spec — OCR & Anhang-Volltext-Indexierung 2026-04-04 02:06:30 +02:00
sysops e1f25f2287 fix(security): emailsFromHeader fail-closed, domain_auditor-Block, Manticore-Tabellenvalidierung
- emailsFromHeader gibt bei Parse-Fehler nil zurück (fail-closed) statt raw-Header-String;
  verhindert Authorization-Bypass via malformiertem From-Header
- mailBelongsToUser: strings.Contains-Fallback entfernt (war dead code nach dem fix-closed-Fix)
- handleSearch: domain_auditor ohne TenantID wird mit 403 abgewiesen, bevor der globale Index
  abgefragt wird
- manticoreTableName: Regex-Validierung ^emails_(global|tenant_\d+)$ mit panic bei Abweichung

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 02:01:50 +02:00
sysops 896f8dceb9 chore: PROJ-29 + PROJ-30 als Deployed markiert 2026-04-04 01:54:29 +02:00
sysops ab7d6aded2 fix: Datumsparser — mehr RFC-2822-Varianten, kein time.Now() Fallback 2026-04-04 01:47:12 +02:00
sysops ecd5ed361b fix(PROJ-30): cmd import-piler — Manticore-Backend support 2026-04-04 01:38:59 +02:00
sysops 44bff147ba fix(PROJ-30): cmd import — Manticore-Backend support (wie cmd_reindex) 2026-04-04 01:38:25 +02:00
sysops 4ef5897e68 feat(PROJ-29): Tenant-Quotas & Usage-Limits vollständig implementiert
- storage/quota.go: SQL-Bug gefixt (emails.size → size_bytes, email_refs JOIN)
- tenantstore/quota.go: GetUsage nutzt jetzt email_refs JOIN für korrekte Tenant-Isolation
- smtpd: ErrQuotaExceeded → SMTP 452 statt 554 (MTA-retry statt permanent reject)
- admin_handlers: handleCreateUser prüft max_users-Quota → HTTP 402 bei Überschreitung
- quota_handlers: handleGetTenantUsage gibt jetzt warnings-Feld mit soft-limit-Prozenten zurück
- server.go: spec-konforme Alias-Route GET /api/admin/tenants/{id}/usage registriert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 01:27:59 +02:00
sysops 22cbfb5df6 fix(security): Email-Matching, LDAP-Validierung, Auditor-Isolation
- mailBelongsToUser: net/mail.ParseAddressList statt strings.Contains
  verhindert False-Positives durch Display-Namen in Mail-Headern
- LDAP mail-Attribut: net/mail.ParseAddress-Validierung vor Übernahme,
  Fallback auf username / username@ldap.local bei ungültiger Adresse
- handleSearch: Auditor-Rolle in userEmailFilter-Check eingeschlossen,
  sodass Auditoren im Search-Pfad dieselbe Mail-Isolation erhalten wie User

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 01:18:34 +02:00
sysops 36d8db1574 chore: go.sum für go-sql-driver/mysql aktualisiert 2026-04-03 21:35:33 +02:00
sysops 7efccda864 chore: Manticore als Standard — Xapian-Referenzen entfernt
- CLAUDE.md: Manticore statt Xapian, CGO_ENABLED=0, /var/lib/manticore/
- .claude/agents/manticore-admin.md: Neuer Projekt-Agent (Security, Backup, Reindex)
- .claude/agents/mailarchiv-architect.md: Xapian → Manticore Search

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 21:29:12 +02:00
sysops b568c73887 fix(PROJ-30): Stemmer stem_de → lemmatize_de_all (Manticore 25.0.0 MySQL-Protokoll)
stem_de wird vom nativen MySQL-Handler in Manticore 25.0.0 nicht erkannt.
lemmatize_de_all nutzt das mitgelieferte de.pak und funktioniert korrekt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 21:26:06 +02:00
sysops 825e4db7c1 fix(PROJ-30): ListFolders — c.Client statt c uebergeben (imap.Conn vs *imapclient.Client)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 21:21:20 +02:00
sysops 0969f76da6 fix(PROJ-30): imapclient.New — Rueckgabewert an go-imap/v2 beta.8 API anpassen
imapclient.New gibt in beta.8 nur *Client zurueck (kein error).
Alle drei Aufrufe in Connect() korrigiert.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 21:21:03 +02:00
sysops a93a843506 feat(PROJ-30): Xapian → Manticore Search Migration
- internal/index/manticore.go: ManticoreTenantManager + manticoreIndex (RT-Indizes, CGO-frei)
- internal/index/index.go: TenantIndexer Interface (Xapian + Manticore)
- internal/index/tenant_worker.go: mgr-Typ auf TenantIndexer Interface
- internal/api/server.go: idxMgr auf TenantIndexer Interface
- config/config.go: IndexConfig.ManticoreDSN Feld
- cmd/archivmail/cmd_reindex.go: reindex Subkommando
- cmd/archivmail/main.go: Manticore-Branch + reindex Case
- go.mod: github.com/go-sql-driver/mysql v1.8.1
- update.sh: Manticore auto-install, CGO_ENABLED=0, config.yml migration, auto-reindex

fix(IMAP): TCP-Deadline-Wrapper für steckengebliebene Imports
fix(auth): Email-Claim in JWT für User-Isolation
fix(search): User-Isolation via sess.Email (fail-safe)
fix(ui): Admin-Login Auth-Cache, Logout-Redirect, IMAP-Polling-Resilienz

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 21:19:36 +02:00
sysops e90d588e30 fix: UpsertLDAPUser — email-basierter Match vor Insert
Verhindert duplicate-key-Fehler wenn LDAP-uid (z.B. "patrick") vom
gespeicherten username ("patrick@perlbach24.de") abweicht. Erst per
Email matchen und updaten, dann neu anlegen falls nicht vorhanden.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 00:41:19 +02:00
sysops d01df2a810 fix: Debug-Logging entfernt, tenant_domains auf 132 wiederhergestellt 2026-04-02 00:22:06 +02:00
sysops caac522e3c debug: erweitertes LDAP-Logging (upsert + success) 2026-04-01 00:26:08 +02:00
sysops 5c3a9b55ff debug: temporäres LDAP-Logging für Fehlerdiagnose 2026-04-01 00:05:35 +02:00
sysops d7b01504aa fix(ui): Mandanten-Tabelle — Slug unter Name, LDAP-Host anzeigen, Slug-Spalte entfernt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 23:54:50 +02:00
sysops acc0d93318 feat: getrennte Login-Seiten für User (/), Admins (/admin/login)
- /admin/login: neue Login-Seite nur für auditor, admin, domain_admin, superadmin
- /: blockiert Admin-Rollen mit Hinweis auf /admin
- useAuth: neuer loginPage-Parameter für flexiblen Unauthentifiziert-Redirect
- /admin: leitet bei Nicht-Auth zu /admin/login statt /

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 23:47:41 +02:00
sysops c1a9004720 feat(PROJ-28): SMTP-Out Relay — DB-Konfiguration + Admin-Tab
- smtpoutconfig.Store: AES-256-GCM verschlüsseltes Passwort in DB (id=1 Singleton)
- Mailer: Reload() für Runtime-Konfigurationswechsel (sync.RWMutex)
- API: GET/PUT/DELETE /api/admin/smtp-out + POST /api/admin/smtp-out/test
- Admin-Tab: Host, Port, User, Passwort, TLS-Switch, From, Test-Button, Status-Badge
- Startup: Lädt DB-Konfiguration und aktiviert Mailer ohne Restart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 22:36:57 +02:00
sysops 7371a73b3e fix(SEC): Signup-Enumeration durch Always-Send-Email schließen
Bei doppeltem Signup wird eine "bereits registriert"-Mail gesendet,
sodass jeder Signup-Versuch eine ausgehende E-Mail erzeugt.
Side-Channel-Angriff zur Account-Enumeration nicht mehr möglich.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 22:00:43 +02:00