# MailAdmin MVP Erste Version einer Admin-Webapp für dein DMS/SES/S3/SQS/DynamoDB-Mail-System. Die App ist bewusst **node-orientiert** gebaut: Sie läuft auf `node1`, `node2`, usw. und entdeckt die Domains dynamisch aus dem lokalen Docker Mailserver. Dadurch ist sie geeignet für dein Szenario, bei dem Domains neu hinzukommen oder zwischen Nodes umziehen. ## Was diese Version bereits kann - Login mit eigenem Admin-User - PostgreSQL als Admin-Datenbank - dynamische Domain-Erkennung über `docker exec mailserver setup email list` - Domains pro Node speichern: `node1`, `node2`, ... - Mailboxen anzeigen - Mailbox anlegen - Mailbox löschen - Passwort zurücksetzen - Speicherverbrauch pro Inbox scannen - Forward- und Auto-Reply-Regeln in DynamoDB bearbeiten - Blocklisten in DynamoDB bearbeiten - Audit Log für Admin-Aktionen - Frontend wird vom Backend direkt ausgeliefert - Docker Compose Deployment auf dem Mailserver ## Warum dynamische Domains berücksichtigt sind Die Domainliste ist **nicht hart codiert**. Beim Start und bei jedem manuellen Resync liest die App die DMS-Accounts aus: ```bash docker exec mailserver setup email list ``` Daraus werden Domains und Mailboxen abgeleitet und in Postgres gespiegelt. Wenn eine Domain später auf einen anderen Node umzieht, passiert Folgendes: - auf dem alten Node werden die lokalen Mailboxen nach einem Resync als `missing_on_node` markiert - auf dem neuen Node wird dieselbe Domain beim Resync als `active` mit `current_node=node2` erkannt - die App-Codebasis bleibt identisch; nur `.env` unterscheidet `NODE_NAME=node1` oder `NODE_NAME=node2` ## Struktur ```text mailadmin-mvp/ backend/ src/ server.ts Express App, API, static frontend config.ts zentrale Konfiguration über Env Vars db.ts Postgres Pool + Migration + Initial Admin routes/ auth.ts Login/Logout/Me domains.ts Domains dynamisch vom DMS syncen/anzeigen mailboxes.ts Mailbox CRUD, Usage, Rules, Blocklist audit.ts Audit Log API services/ dms.ts DMS Docker Integration + Usage Scan sync.ts Sync DMS -> Postgres dynamodb.ts email-rules + email-blocked-senders audit.ts Audit helper utils/ email.ts Email/domain/local-part helpers shell.ts sicherer execFile wrapper migrations/001_init.sql PostgreSQL Schema Dockerfile Backend + Frontend Image frontend/ index.html Single Page App app.js UI Logik ohne Build-Step styles.css einfache Admin-Oberfläche deploy/ caddy/ Caddy-Hinweise scripts/ Snippet-Hilfe für update-caddy-certs.sh docker-compose.yml App + Postgres .env.example Beispiel-Konfiguration ``` ## Installation auf node1 ```bash cd /home/aknuth/git/email-amazon unzip mailadmin-mvp.zip cd mailadmin-mvp cp .env.example .env nano .env ``` Wichtige Werte in `.env`: ```env MAILADMIN_DB_PASSWORD=ein-sicheres-passwort MAILADMIN_JWT_SECRET=sehr-langes-random-secret MAILADMIN_ADMIN_EMAIL=admin@bayarea-cc.com MAILADMIN_ADMIN_PASSWORD=StartPassword123! NODE_NAME=node1 NODE_HOSTNAME=node1.email-srvr.com DMS_CONTAINER=mailserver AWS_REGION=us-east-2 AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... ``` Start: ```bash docker compose up -d --build ``` Logs: ```bash docker logs -f mailadmin ``` ## Installation auf node2 Gleicher Code, andere `.env`: ```env NODE_NAME=node2 NODE_HOSTNAME=node2.email-srvr.com ``` Die Domainliste wird auch dort aus dem lokalen DMS gelesen. ## Caddy: mailadmin.{DOMAIN} Dein bestehendes `update-caddy-certs.sh` generiert bereits dynamisch Domain-Blöcke. Ergänze im Domain-Loop zusätzlich diesen Block: ```caddy # MailAdmin UI mailadmin.DOMAIN_HERE { encode gzip reverse_proxy mailadmin:3000 } ``` Im Script sieht das ungefähr so aus: ```bash OUTPUT="${OUTPUT}# MailAdmin UI\n" OUTPUT="${OUTPUT}mailadmin.${domain} {\n" OUTPUT="${OUTPUT} encode gzip\n" OUTPUT="${OUTPUT} reverse_proxy mailadmin:3000\n" OUTPUT="${OUTPUT}}\n\n" ``` Danach: ```bash cd /home/aknuth/git/email-amazon/caddy ./update-caddy-certs.sh docker exec caddy caddy reload --config /etc/caddy/Caddyfile ``` ## Wichtige Sicherheitshinweise Diese MVP-Version mountet `/var/run/docker.sock`, damit der Backend-Container `docker exec mailserver ...` ausführen kann. Das ist praktisch, aber mächtig. Für die nächste Version wäre ein kleiner dedizierter Local-Agent mit begrenzten Operationen sicherer. Das Admin-Passwort wird nur beim ersten Start erstellt. Wenn du `MAILADMIN_ADMIN_PASSWORD` später änderst, wird der vorhandene User nicht überschrieben. Das ist Absicht. ## API Kurzüberblick ```text POST /api/auth/login POST /api/auth/logout GET /api/auth/me GET /api/domains?resync=true POST /api/domains/resync GET /api/mailboxes?domain=example.com POST /api/mailboxes DELETE /api/mailboxes/:email POST /api/mailboxes/:email/password POST /api/mailboxes/usage/rescan GET /api/mailboxes/:email/rules PUT /api/mailboxes/:email/rules GET /api/mailboxes/:email/blocklist PUT /api/mailboxes/:email/blocklist GET /api/audit ``` ## Nächste sinnvolle Ausbaustufen 1. Domain-Detailseite mit DNS/SES/S3/SQS/Caddy Status 2. Admin-User Verwaltung im UI 3. Quotas pro Mailbox 4. Soft-Delete mit Retention statt hartem Löschen 5. Outbound Reporting über Postfix Logs und später SES Events 6. Node-Migration Workflow: Domain gezielt von node1 auf node2 markieren und prüfen