Commit Graph

180 Commits

Author SHA1 Message Date
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
sysops 4583262ea4 feat(PROJ-28): Self-Service Onboarding — Signup, Verify, Password Reset, Invites
- internal/mailer: SMTP-Out via net/smtp (TLS + STARTTLS), HTML+Text-Templates
- internal/tokenstore: auth_tokens Tabelle, SHA-256-Hash, TTL, einmalig verwendbar
- userstore: CreateInactive(), Activate(), GetByEmail(), SetPassword()
- API: POST /signup, GET /verify, POST /forgot-password, POST /reset-password
- API: POST /admin/invite (domain_admin+), GET /auth/invite?token (check)
- Login-Seite: Links zu "Passwort vergessen" und "Registrieren"
- Frontend: /signup, /verify, /forgot-password, /reset-password Seiten
- server.fqdn nicht konfiguriert → Startup-Warnung, Self-Service deaktiviert
- LDAP-Nutzer: Passwort-Reset abgewiesen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 21:54:11 +02:00
sysops 7930b85cde feat(PROJ-29): Tenant-Quotas & Usage-Limits
- DB: max_storage_bytes, max_users, max_emails per Tenant (NULL = unlimited)
- storage/quota.go: CheckQuota() mit 60s-Cache, ErrQuotaExceeded
- Save() prüft Quota vor dem Schreiben — Ablehnung bei Hard-Limit
- tenantstore/quota.go: SetQuota(), GetQuota(), GetUsage()
- API: GET/PUT /api/admin/tenant/{id}/quota, GET /api/admin/quotas
- QuotaTab: Usage-Balken (Speicher/Nutzer/Mails), Edit-Dialog, Warnung ab 80%
- InvalidateQuotaCache() nach Quota-Änderung für sofortige Wirkung

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 21:21:11 +02:00
sysops ebc9e278ea fix(PROJ-34): Mandanten-Retention ist Opt-in — kein globaler Lock für Mandanten
storage.Save(): retention_days eines Mandanten muss explizit > 0 sein.
Globale config greift nie automatisch auf Mandanten-Mails.
Mails ohne Mandant: globale config als Fallback (unveraendert).
Frontend: Hinweis und Labels klargestellt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 10:50:54 +02:00
sysops 4aadf7a4d2 fix: retention_handlers.go — getSession/audlog.Log-Signatur korrigiert
Ersetzt nicht-existente getSession(r) durch sessionFromCtx(r.Context()) und
passt den audlog.Log-Aufruf auf die korrekte audit.Entry-Struct-Signatur an.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 10:47:18 +02:00
sysops 58bcfb1586 feat: Dashboard-Metriken nach Mailpiler-Vorbild (Uptime, Aktivität, Prognose)
- storage_stats.go (neu): MailActivityStats (60min/24h/7d/30d), StorageEstimateStats
- dashboard_handlers.go: Uptime (/proc/uptime), activity + estimate in System-Stats-Response
- DashboardTab: Uptime in API-Kachel, neue Kacheln "Mail-Eingang" + "Speicherprognose"
- Warnung (Badge "Knapp!") wenn Partition in <90 Tagen voll

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 10:44:02 +02:00
sysops 5bbf6d0ff3 feat(PROJ-34): Retention-Tab + pro-Mandant Aufbewahrungsfristen
- tenantstore: retention_days Spalte, GetRetentionDays/SetRetentionDays
- storage.Save(): per-tenant retention überschreibt globale config
- API: GET /api/admin/retention, PUT /api/admin/tenant/{id}/retention
- Frontend: RetentionTab mit globaler Policy-Anzeige, Mandanten-Tabelle,
  Bearbeiten-Dialog und Purge-Button (superadmin only)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 10:37:15 +02:00
sysops 5f0c7a7e6d feat(PROJ-27): Docker-Support + install.sh v2.0 (native + Docker-Modus)
Adds multi-stage Dockerfiles (Go+Xapian CGO, Next.js standalone),
docker-compose.yml, webhook-basierter Deploy-Flow und erweitertes
install.sh mit interaktiver Modus-Auswahl.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 10:18:11 +02:00
sysops 842640c3aa fix: Superadmin wird direkt zu /admin weitergeleitet
- Login: superadmin → /admin, alle anderen → /search
- Cached-Session: superadmin → /admin
- Search-Seite: superadmin wird sofort zu /admin umgeleitet

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 10:05:08 +02:00
sysops 27040ffcb1 feat(PROJ-28): FQDN + smtp_out Konfiguration
- config: server.fqdn, SMTPOutConfig, smtp_out Abschnitt
- config: IMAPServerConfig.FQDN (runtime-gesetzt)
- main: FQDN-Fallback für SMTP EHLO, FQDN an IMAP-Server
- imapserver: Greeting nutzt server.fqdn (RFC 3501)
- smtpd/imapserver Modulversion 1.3

fix: Superadmin sieht keine Suche/IMAP/POP3 Nav-Links

- Navbar: Suche, IMAP Import, POP3 Import nur für non-superadmin
- Superadmin landet direkt auf Admin-Dashboard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 09:51:41 +02:00
sysops 8d0f685fc9 feat(PROJ-33): IMAP UID-Stabilität + Shared/Personal-Modus
Backend:
- storage: uid BIGSERIAL Migration, MailWithUID, GetMailsWithUID, GetMailsByRecipient
- tenantstore: imap_mode Spalte, GetIMAPMode, SetIMAPMode
- imapserver: stable UIDs aus DB, personal/shared Modus, userEmail in session
- api: GET/PUT /api/admin/settings/imap-mode (domain_admin only, double opt-in)

Frontend:
- IMAPSettingsTab: Modus-Anzeige + Toggle mit Double-Opt-In Dialog
- Admin-Panel: IMAP-Tab für domain_admin

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 09:46:52 +02:00
sysops b6856af2eb feat(PROJ-32): Message-ID-basierte Duplikatserkennung
- message_id Spalte + UNIQUE-Index in emails-Tabelle
- Save() prüft Message-ID vor SHA-256-Flow (kein Disk-I/O bei Duplikat)
- lookupByMessageID() als private Hilfsfunktion
- insertMeta() schreibt message_id, gibt error zurück (Race-safe)
- SaveMeta() schreibt message_id idempotent (Backfill)

feat(PROJ-34): Retention-Policy + Löschsperre (GoBD)

- retain_until TIMESTAMPTZ Spalte in emails-Tabelle
- ErrRetentionLock typed error
- Delete() prüft Retention-Frist vor Löschung
- Purge() löscht alle Mails mit abgelaufener Retention
- POST /api/admin/purge Endpunkt (superadmin only)
- config: storage.retention_days

fix: Superadmin-Benutzerübersicht zeigt Mandant-Spalte

- UsersTab: Mandant-Spalte wenn isSuperAdmin
- domain_auditor Rolle im Create-Dialog ergänzt
- storage Modulversion → 1.6

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 01:29:25 +02:00
sysops cb31c48ce8 fix: version → AppVersion in cmd_import.go (Build-Fehler nach 0.9.1-Umbenennung)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 01:14:27 +02:00
sysops 4f7a7d6946 feat: App-Version 0.9.1 + Modulversionsnummern
- version.go: AppVersion + Modules-Map (pro Modul interne Versionsnummer)
- GET /api/version: liefert App- und Modulversionen (ohne Auth)
- archivmail version: zeigt App- und Modulversionen in CLI
- version-Konstante aus cmd_import.go entfernt (war falsche Stelle)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 01:12:51 +02:00
sysops 64433aa847 fix(SEC-29): Rollen-Trennung Admins/Auditoren, domain_auditor Rolle
- superadmin + domain_admin haben keinen Mail-Zugriff mehr (requireMailAccess)
- Neue Rolle domain_auditor: alle Tenant-Mails, kein Admin-Zugriff
- auditor + user: nur eigene Mails
- ZIP-Export: kein separates Attachment-Entpacken mehr, nur EML
- roleLevel() um domain_auditor (Level 3) erweitert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 01:09:19 +02:00
sysops e0f6a818eb feat: LDAP-Test zeigt klickbare Filter-Vorschläge (UCS/AD-Erkennung)
Nach erfolgreichem Verbindungstest werden passende Filter-Vorschläge
angezeigt. Erkennt automatisch Univention UCS (posixAccount) vs.
Active Directory (sAMAccountName). Klick übernimmt den Filter direkt
ins Formular. Vorschläge berücksichtigen mailPrimaryAddress (UCS).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 14:50:20 +01:00
sysops 2fa7104605 fix: User-Struct JSON-Tags ergänzen (active/source/id etc. waren Großbuchstaben)
Frontend erhielt 'Active'/'Source' statt 'active'/'source' →
Inaktiv-Badge und local-Badge zeigten falsche Werte.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 13:46:47 +01:00
sysops 0b435d8d1a fix: LDAP FetchUsers Filter ohne Klammern erzeugt Compile Error
UserFilter wie 'uid=%s' wurde zu 'uid=*' — kein gültiger LDAP-Filter.
Fix: Klammern ergänzen wenn der Filter nicht mit '(' beginnt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 13:38:19 +01:00
sysops a6a66beaa8 chore: weitere Code-Aufteilung (api.ts, hooks, ldap_sync)
- src/lib/api.ts (1085 Zeilen) → 5 thematische Module unter src/lib/api/
  (core, users, ldap, tenants, mail, system) + index.ts Re-Export
- useLDAPConfig / useTenantLDAPConfig / useTenantUsers Hooks extrahiert;
  admin/page.tsx nutzt diese statt roher useState-Blöcke
- handleSyncTenantLDAP, handleAdminSyncTenantLDAP, doSyncTenantLDAP,
  buildTenantTestConfig, syncResult aus ldap_tenants.go in ldap_sync.go verschoben

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 13:05:19 +01:00
sysops bc4a98de0d chore: admin/page.tsx in Einzelkomponenten aufteilen (3917 → 1304 Zeilen)
- Tab-Sektionen → src/components/admin/tabs/ (11 Dateien)
- Dialoge → src/components/admin/ (TenantLDAPDialog, UserDialogs)
- Keine Verhaltensänderungen, TypeScript fehlerfrei

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 12:30:16 +01:00
sysops 38f8cdddc7 fix: TypeScript-Fehler bei tenantUsersSyncResult errors-Pruefung
Optional chaining auf errors.length fuehrt zu 'possibly undefined'
in strict mode -- explizite null-Guard + nullish coalescing fix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 11:36:35 +01:00
sysops 72b023b598 feat: LDAP-User-Sync in Mandanten-Benutzerliste
Neuer Endpoint POST /api/admin/tenants/{id}/ldap/sync importiert alle
LDAP-User (source=ldap) per UpsertLDAPUser in die Tenant-Benutzerliste.
Im Nutzer-Dialog erscheint ein "LDAP-Benutzer synchronisieren"-Button
wenn LDAP für den Mandanten aktiv ist. Unterstützt Univention UCS
(mailPrimaryAddress, inetOrgPerson). Benutzertabelle zeigt jetzt auch
die Quelle (local/ldap).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 11:35:02 +01:00
sysops 2da61689ea feat: LDAP-Test zeigt User-Tabelle mit Univention-UCS-Support
Nach erfolgreichem Verbindungstest werden bis zu 50 Benutzer (UID,
Name, E-Mail) in einer scrollbaren Tabelle angezeigt. Unterstützt
mailPrimaryAddress (Univention UCS) als Fallback für mail sowie
inetOrgPerson objectClass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 11:23:12 +01:00
sysops 30c6694dff feat(PROJ-24): Mandanten-Logo Upload
- DB: logo_data (BYTEA) + logo_content_type Spalten in tenants-Tabelle
- Backend: SetLogo/GetLogo/DeleteLogo im tenantstore
- API: Logo-Endpunkte für superadmin (beliebiger Mandant) und
  domain_admin (eigener Mandant), max. 2 MB, PNG/JPEG/GIF/WebP/SVG
- Frontend: Logo-Dialog in Mandantentabelle (superadmin),
  Logo-Upload-Sektion im LDAP-Tab (domain_admin)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 03:15:34 +01:00
sysops cd2781bdff fix: Mandanten-Nutzerdialog Fehlerhandling + LDAP-Hinweis
- Fehlerstate für Nutzer-Dialog: API-Fehler werden jetzt angezeigt statt silent ignoriert
- LDAP-Hinweis: wenn LDAP aktiv aber keine lokalen User da sind, erklärender Text
  "LDAP ist aktiv — Benutzer erscheinen hier nach ihrem ersten Login"
- tenantUsersDialogLdap State: speichert ob Tenant LDAP aktiviert hat

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 02:18:41 +01:00
sysops 9db433c4c1 fix: Mandantenverwaltung LDAP-Status und Nutzer-Listing
- tenantstore.List(): LEFT JOIN tenant_ldap hinzugefügt — ldap_enabled + ldap_url
  werden jetzt im GET /api/tenants Response mitgeliefert
- Tenant-Struct: Felder LDAPEnabled *bool + LDAPURL string ergänzt
- Neuer Endpunkt GET /api/tenants/{id}/users → listet Nutzer eines Mandanten
- api.ts: getTenantUsers() Funktion + tenant_id Feld im User Interface
- Admin-Panel: "Nutzer"-Button im Mandanten-Tab öffnet Dialog mit Nutzerliste

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 02:01:12 +01:00
sysops b3074b303e fix: LDAP leere BindPassword schlägt Login fehl + install.sh Passwort-Extraktion
- auth.Manager.Login: LDAP-Fallback überspringen wenn URL oder BindPassword leer
  (verhindert go-ldap ErrorEmptyPassword Code 206 bei fehlerhaftem LDAP-Config-Eintrag)
- install.sh: grep-Muster von variablenbreitem Lookbehind auf \K umgestellt
  (PCRE unterstützt keine variablen Lookbehinds — Passwörter wurden nie korrekt extrahiert)
- install.sh: Wartezeit auf Backend-Start erhöht (bis zu 15s statt 2s)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 01:47:48 +01:00
sysops fd46f0de9a fix: superadmin beim ersten Start anlegen + Installer zeigt echte Passwörter
- seedDefaultUsers: superadmin (Rolle superadmin) zu Default-Usern hinzugefügt
  → wird beim ersten Backend-Start mit Zufallspasswort angelegt
- Installer: Passwörter werden nach dem Deployment aus dem Journal gelesen
  (journalctl -u archivmail) statt falschen Platzhalter 'archivmailrockz'

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 01:23:33 +01:00
sysops 32032b49d2 fix(installer): echte Web-Passwörter aus Journal lesen statt Platzhalter
Der Backend generiert beim ersten Start zufällige Passwörter und gibt
sie im Journal aus. Der Installer liest sie nun nach dem Deployment
und trägt sie korrekt in install-summary.txt und Terminal-Output ein.
Zuvor wurden fälschlicherweise 'archivmailrockz' als Passwörter angezeigt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 01:22:50 +01:00
sysops 33eafc1624 feat(installer): Zusammenfassung aller angelegten User & Passwörter
- Abschlussbericht zeigt alle Credentials in übersichtlicher Tabelle:
  DB-Passwort, API-Secret, Web-Logins (superadmin/admin/auditor)
- Speichert vollständige Zusammenfassung als /etc/archivmail/install-summary.txt
  (chmod 600, nur root lesbar) mit allen Pfaden, Diensten und Hinweisen
- Tabelle im Terminal-Output mit allen wichtigen Zugangsdaten auf einen Blick

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 01:10:19 +01:00
sysops d262253faf fix(installer): DB-Passwort-Mismatch bei Re-Install verhindern
Bei vorhandener config.yml wird das DB-Passwort daraus gelesen und
PostgreSQL entsprechend aktualisiert — verhindert Auth-Fehler beim
zweiten Installer-Durchlauf auf demselben Server.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 01:05:51 +01:00
sysops 48e04f36fd fix(installer): Lücken aus Gap-Report geschlossen
- rsync zum apt-Paket-Block hinzugefügt
- DEBIAN_FRONTEND=noninteractive gesetzt (keine debconf-Interaktion)
- go PATH-Fix: Debian-spezifische Pfade in /usr/lib/go-*/bin ergänzen
  (update.sh + install.sh symlink-Fallback)
- TLS-Zertifikat: selbstsigniertes RSA-4096 Cert via hostname -f,
  /etc/ssl/archivmail/ anlegen + Permissions (640, root:archivmail)
- nginx: HTTPS von Anfang an (HTTP→HTTPS Redirect + TLS-Block statt HTTP-only)
- config.yml-Template vollständig:
  - smtp.enabled, smtp.domain (hostname -f), smtp.tls_cert/tls_key
  - imap_server (enabled, bind :993, tls_cert/tls_key)
  - api.trusted_proxies, api.secure_cookies: true
  - Vorhandenes config.yml wird nicht überschrieben
- systemd archivmail.service: AmbientCapabilities=CAP_NET_BIND_SERVICE
  (für privilegierten Port 993 als non-root User)
  NoNewPrivileges=false (erforderlich für AmbientCapabilities)
  ReadOnlyPaths um /etc/ssl/archivmail ergänzt
- systemctl enable am Ende des Installers (ohne --now)
- update.sh nach /opt/archivmail/ kopieren + erstes Deployment direkt anstoßen
- Abschlussbericht: FQDN, HTTPS/IMAP/SMTP URLs, TLS-Hinweis

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 01:03:57 +01:00
sysops c59cad92be fix: IMAP-Konto bearbeiten + Löschen auch bei sync_running
- Store: UpdateCredentials() — Zugangsdaten + Passwort neu verschlüsseln,
  setzt status='idle', error_msg='', sync_running=false zurück
- Handler: PATCH /api/imap/{id} unterstützt nun Credential-Update
  (name/host/username vorhanden = Credential-Update, sonst sync_interval)
- Frontend: "Bearbeiten"-Button öffnet Edit-Dialog mit allen Feldern;
  Passwort-Feld leer = unverändertes Passwort
- Frontend: Löschen-Button nicht mehr durch sync_running blockiert
  (nur noch bei status=running gesperrt)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 00:49:37 +01:00
sysops 4a4136e4a6 feat: FQDN-Support, IMAP-TLS und SMTP-TLS via Master-Cert
- config: IMAPServerConfig um TLSCert/TLSKey erweitert
- imapserver: TLS-Support (tls.Listen) mit automatischem Port 993-Default
- Server-Konfiguration: FQDN archivmail.scahome.local
  - nginx server_name auf archivmail.scahome.local gesetzt
  - SMTP domain auf archivmail.scahome.local
  - SMTP TLS aktiviert (/etc/ssl/archivmail/archivmail.crt)
  - IMAP-Server TLS auf Port 993 aktiviert
  - secure_cookies: true (HTTPS)
  - Firewall: Port 993 geöffnet
  - Zertifikat neu ausgestellt (SAN: archivmail.scahome.local + archivmail + 192.168.1.131)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 00:32:25 +01:00
sysops 9e71af104f feat: Dark Mode + Zertifikat-Verwaltung im Superadmin
- Dark Mode: ThemeProvider (next-themes), ThemeToggle in Navbar (Hell/Dunkel/System)
- Zertifikat-Tab (superadmin only): aktuelles Zertifikat anzeigen, Upload (cert+key),
  Self-Signed ausstellen, Let's Encrypt/ACME
- Backend: /api/admin/cert/* Endpunkte (info, upload, self-signed, acme), nginx reload
- HTTPS bereits live auf Server (self-signed RSA-4096, Port 443)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 00:14:43 +01:00
sysops 0e62b10bd4 fix(PROJ-26): IMAP-Löschen-Fehler nicht mehr stumm verschlucken — Fehlermeldung anzeigen 2026-03-18 12:16:32 +01:00
sysops d79e334029 refactor: server.go in separate Handler-Dateien aufgeteilt
server.go (2357 -> 391 Zeilen) enthaelt nur noch Server-Struct,
Konstruktor, Router, Middleware und Hilfsfunktionen.

Neue Dateien:
- auth_handlers.go: Login, Logout, Me
- search_handlers.go: Suche, Mail-Anzeige, Anhaenge, Raw-Download
- admin_handlers.go: User-CRUD, SMTP/Storage-Stats, Services, Security
- import_handlers.go: IMAP + POP3 Account-Verwaltung und Import
- dashboard_handlers.go: System-Stats, Audit-Log

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 11:55:21 +01:00
sysops e7146fdbac fix: ungenutzten pgx/v5 Import in labelstore entfernen 2026-03-18 11:47:10 +01:00
sysops 19a55a3166 feat(PROJ-26): IMAP-Archive-Server Read-Only Zugriff auf archivierte Mails
- Neues Package internal/imapserver: vollständiger IMAP4rev1-Server (~700 Zeilen)
- Auth via bcrypt (userstore.VerifyPassword), Multi-Tenant-Isolation
- INBOX + INBOX/LabelName Ordnerstruktur
- FETCH mit BODY[], ENVELOPE, RFC822.SIZE, INTERNALDATE, FLAGS, UID
- SEARCH: ALL, FROM, TO, SUBJECT, SINCE, BEFORE + UID FETCH/SEARCH
- Read-Only: STORE, DELETE, COPY, MOVE, APPEND → NO [CANNOT]
- \Seen-Flag nicht persistent (GoBD-konform)
- Max 5 gleichzeitige Verbindungen pro User, 30min Idle-Timeout
- Audit-Log: imap_login / imap_login_failed Events
- Config: imap_server.enabled + imap_server.bind (default: 127.0.0.1:1143)
- Externe Ports: 9993 (primär) und 993 (alternativ) via nginx TLS-Terminierung

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 11:42:35 +01:00
sysops 5c25e3a7e7 feat(PROJ-26): IMAP-Verbindungsinfo in User-Settings anzeigen
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 11:36:04 +01:00
sysops dd41e1f00e fix(PROJ-16): LDAP URL-Feld zeigt flexible Port-Hinweise inkl. Univention UCS (7389/7636) 2026-03-18 10:50:34 +01:00
sysops cee75094ad feat(PROJ-9): implement labels frontend - LabelList, LabelPicker, search integration, admin UI 2026-03-18 09:51:10 +01:00