Postfach & Kommunikation
Jeder Kundenbetrieb bekommt ein eigenes, zentral verwaltetes Postfach — Zugangsdaten laufen nie roh durchs System.
Zentrales Kunden-Postfach
Ein Kundenbetrieb bindet sein bestehendes IMAP/SMTP-Postfach ein; Zugangsdaten werden AES-256-GCM-verschlüsselt gespeichert, nie im Klartext gehalten.
Mehrere Zugänge pro Kunde
Kundenbetriebe verwalten ihr Team selbst — Kolleg:innen einladen, Zugänge entfernen. Ein Schutzmechanismus verhindert, dass der letzte Zugang gelöscht wird.
IMAP-IDLE Push
Eine dauerhafte IDLE-Verbindung je Zentralkonto meldet neue Nachrichten innerhalb von Sekunden per WebSocket-Push an den Client — kein Warten auf den nächsten Poll-Zyklus.
Nachrichten-Reservierung
Claim/Release-Mechanismus verhindert, dass zwei Teammitglieder gleichzeitig an derselben Anfrage arbeiten.
Zuständigkeiten & Abwesenheit
Routing-Regeln je Zuständigkeitsbereich, inklusive automatischer Vertretung während einer aktiven Abwesenheit — auch offen-endig.
Geschäftszeiten-Warteschlange
Antworten, die außerhalb der Geschäftszeiten entstehen, werden geparkt und automatisch verschickt, sobald das Zeitfenster wieder offen ist.
Zentrale Antwort-Idempotenz
Eine State Machine über jeden ausgehenden Reply schließt die Doppelversand-Lücke — ein Retry nach Teilfehler erzeugt nie eine zweite Mail.
Mail-Flood-Schutz
Obergrenze für Anhang-Größen und für die Anzahl Nachrichten je Sync-Durchlauf — verhindert, dass ein einzelner Sync-Zyklus den Server überlastet.
SLA-Wächter
Prüft alle 15 Minuten auf unbeantwortete Nachrichten jenseits einer Frist und eskaliert je Nachricht genau einmal per E-Mail an die zuständige Stelle.
Sicherheit & Compliance
Der Teil des Produkts, der Kunden in regulierten Branchen überhaupt erst überzeugt.
Anonymer Hinweisgeber-Kanal
Hybrides Ende-zu-Ende-Schema: der Client erzeugt einmalig einen symmetrischen Schlüssel, verpackt ihn per RSA-OAEP und nutzt ihn für den gesamten weiteren Nachrichtenwechsel. Der Fall-Schlüssel geht nie über die Leitung; strikte Mandantentrennung zwischen Kundenbetrieben.
Betroffenenanfragen-Selbstbedienung
Anfragen nach Art. 15 ff. DSGVO mit eingebautem Fristen-Tracking und stündlicher Erinnerung, sobald eine Frist auf drei Tage schrumpft.
Automatische Löschfristen
Ein täglicher Sweep löscht abgeschlossene DSGVO-Anfragen und geschlossene Hinweisgeber-Fälle nach Ablauf ihrer Frist — automatisch, protokolliert im Audit-Log (Art. 5 Abs. 1 lit. e).
Kunden-Löschung mit Abhängigkeitsprüfung
Ein Kunde lässt sich erst löschen, wenn alle produktiven CASCADE-Abhängigkeiten geprüft sind — keine stillen Kollateralschäden an Postfächern, Team-Zugängen oder Onboardings.
Security Center
Laufende Prüfung: Secret-Scanning (gitleaks), Abhängigkeits-Audit, Repository-Hygiene, Sicherheitssignale aus dem selbst gehosteten Forgejo — ein Statusbild statt Blindflug.
Passkeys & Geräte-Alarme
Passkey-Anmeldung als phishing-resistenter Standard; automatische E-Mail bei Login von einem neuen Gerät. Für Inhaber- und Admin-Konten ist ein Passkey Pflicht für jede schreibende Aktion.
Self-Service-Passwort-Reset
Kundenkonten setzen ihr Passwort selbst zurück. Bewusst nicht für Inhaber- und Admin-Konten — dort bleibt der Reset ein bewusster, geschützter Vorgang.
AES-256 für Zugangsdaten
Mail-Zugangsdaten werden ausschließlich AES-256-GCM-versiegelt abgelegt; der Entschlüsselungs-Schlüssel liegt nur im Serverprozess und wird nie an einen Client gesendet oder geloggt.
Unveränderbares Audit-Log
Jede Rechteänderung, jeder Jarvis-Befehl, jeder sicherheitsrelevante Vorgang landet in einer append-only-Tabelle — ein Datenbank-Trigger weist UPDATE und DELETE hart ab.
Jarvis — Sprachsteuerung fürs HQ
Eine Betriebsassistenz, die den Server per Sprache oder Text abfragen und steuern kann — mit fest verdrahteten Sicherheitsklassen statt frei interpretierter Befehle.
Intent-Engine
Erkannter Text wird auf einen festen Intent abgebildet; unbekannte Eingaben enden sauber als UNKNOWN_INTENT statt in einer geratenen Aktion.
Action Registry
Jede Aktion ist einzeln registriert und einer Sicherheitsklasse zugeordnet: read_only, local_control, confirm_required oder restricted.
System-Check-Aggregator
Bündelt Ressourcen, Security Center, Client-Releases, Deployment-Status, SLA, Backups, Pipeline, Mailkonten und Voice zu einer einzigen gesprochenen Lagemeldung.
Voice-Host-Registry
Ein WebSocket-Kanal verbindet den späteren Electron Voice Host; fehlt er, degradieren die betroffenen Routen sauber auf 503 statt zu blockieren.
Strukturiertes Befehls-Log
Jeder Befehl landet mit Intent, Ergebnisstatus, Dauer und Quelle (voice/text) in einer eigenen indexierten Tabelle — auswertbar, nicht nur ein JSON-Klumpen.
Host-Steuerung
Stop, Aktivieren/Deaktivieren und Push-to-Talk laufen über einen einzigen, spät gebundenen Steuer-Kanal — dieselbe Instanz für Admin-Board-Testeingabe und echtes Voice.
Kunden-Self-Service & Onboarding
Vom ersten Formular bis zum aktiven Postfach, ohne dass jemand manuell etwas einträgt.
Direktes Kunden-Onboarding
Signierter HTTPS-Fastpath vom Marketing-Formular direkt zum Server, mit E-Mail-Relay als Fallback, falls der direkte Weg einmal nicht erreichbar ist.
Wiederverwendbares Einladungssystem
Ein gemeinsamer Token-Mechanismus für Personal- und Kunden-Team-Einladungen — ein Weg für beide Fälle.
Onboarding-Checkliste
Sichtbarer Fortschritt im Kundenportal, statt eines Postfachs, bei dem unklar bleibt, was als Nächstes zu tun ist.
Kontaktformular-Fastpath
Direkter, authentifizierter HTTPS-Weg vom öffentlichen Kontaktformular zum Server — bei fehlendem Token fällt die Website auf ihre normale Zustellung zurück.
Admin & Betrieb
Werkzeuge für den laufenden Betrieb — nicht kundensichtbar, aber jeden Tag im Einsatz.
„Jetzt deployen“-Knopf
Git Pull, Neu-Build und der dokumentierte WinSW-Selbstneustart des Windows-Diensts — ein Klick im Admin Board statt manueller Terminal-Befehle.
Client-Releases-Übersicht
Version, Branch und Tag-Status des Desktop-Clients auf einen Blick, gespeist aus Forgejo, inklusive Steuerung des Release-Vorgangs.
Pipeline-Report-Dashboard
Builds, Tests und Deployments aus allen Repos laufen über einen Einzweck-Token in einem gemeinsamen Statusbild im Admin Board zusammen.
Voice-Channel
LiveKit-gestützte Sprachräume für interne Team-Abstimmung, direkt im HQ integriert.
Server-Ressourcen & Backups
CPU, Speicher, Plattenplatz und der Stand der verschlüsselten Backups als eigene Admin-Screens — Grundlage auch für Jarvis' Lagemeldung.
Client-Update-Feed
electron-updater-Artefakte werden über einen separaten Bearer-Token hochgeladen und unauthentifiziert ausgeliefert — vom übrigen Auth-Modell entkoppelt.
Architektur im Detail
Drei eigenständige Repositories, ein einzelner Node-Prozess, strikte Mandantentrennung auf Datenbankebene — und eine Request-Pipeline, die man Zeile für Zeile lesen kann.
Systemgrenzen: die Desktop-App spricht ausschließlich die dokumentierte HTTPS-API; Datenbank- und Mailzugänge bleiben im Serverprozess.
01 Prozess & Laufzeit
Der gesamte Server ist ein einziger Node-Prozess (src/index.ts), ohne Framework — roher node:http/node:https. Kein Application-Server, kein Container in Produktion: ein nativer Windows-Dienst über WinSW.
Alle Dienste teilen sich denselben Connection-Pool; die Scheduler starten nach listen() und werden bei SIGINT/SIGTERM sauber gestoppt.
02 Request-Pipeline
Eine einzige listener-Funktion in src/app.ts ruft die Route-Gruppen der Reihe nach auf. Jede Gruppe prüft Pfad und Methode selbst; die erste, die zuständig ist, antwortet und bricht die Kette ab. Kein Router-Framework, keine Middleware-Magie — die Reihenfolge ist der Code.
- system —
/health,/ready(DB-Ping), keine Auth - auth — Better-Auth-Handler, Login-Seiten, Passkey-Setup, Account-Setup
- admin — Team-/Board-Verwaltung, hinter
manage_users+ Passkey - customers / onboarding-mail / customer-onboarding-direct — Kundenregistrierung, signierter Onboarding-Payload (Relay + direkter HTTPS-Pfad)
- invite — Token-Einlösung über eine separate, signup-fähige Auth-Instanz
- customer-mailbox / mailbox-widget — Kundenportal, hart über
customer_idgefiltert; öffentliches Antwortzeit-Widget - secure-messages / whistleblower / gdpr-requests — je eigener Rate-Limiter, eigenes Browser-Client-Skript
- customer-team — Team-Selbstverwaltung des Kundenbetriebs
- mail-accounts / mail-messages — Zentralkonten, Ordner, Nachrichten, Senden, Reply-Idempotenz
- infrastructure — Deployment-, Backup-, Ressourcen-, Security-Center-, SLA-, Pipeline-Status
- projects / workspaces / contact-forms / contact-form-fast-path — Projektfreigaben, gehostete Formulare, Website-Fastpath
- conversations / voice / jarvis — Konversations-Sicht, LiveKit-Räume, Sprachbefehle
- updates — electron-updater-Feed (Download offen, Upload per Token)
- kein Treffer → 404 { error: "not_found" }
03 Autorisierung — eine Grenze für alles
src/authorization.ts ist die gemeinsame Sicherheitsgrenze. Jede geschützte Route ruft dieselbe Funktion mit ihrer konkreten Aktion auf; UI-Ausblendungen zählen nie als Schutz.
- 01
- Gültige Better-Auth-Sitzung — sonst 401.
- 02
- Verknüpftes, aktives HQ-Profil in
users(auth_user_id). Gesperrte Konten verlieren sofort jeden Zugriff, auch mit noch gültiger Sitzung. - 03
- Feste Rolle erlaubt die Aktion —
owner · admin · support · viewer · customer_owner, jede mit einer festen Aktionsmenge. Ein Kunden-Login bekommt ausschließlichview_own_mailbox. - 04
- Bei projektbezogenen Daten die konkrete Freigabe (
user_product_access). Nicht freigegebene und unbekannte Projekte liefern beide dieselbe neutrale 404.
owner/admin verlangt jede Aktion außer read einen registrierten Passkey — ein Passwort-Login allein reicht dort nicht. Rechteänderungen beenden alle Sitzungen des betroffenen Kontos und landen im unveränderbaren Audit-Log.
04 Datenmodell & Mandantentrennung
45 nummerierte, ausschließlich vorwärts gerichtete SQL-Migrationen. Ein Startup-Guard verweigert den Start, wenn eine fehlt — es gibt keine automatische Migration beim Hochfahren.
/api/customer/*-Route filtert strikt über mail_accounts.customer_id, nie über eine einzelne user_id. Dadurch funktionierten mehrere Team-Zugänge pro Kunde, sobald zusätzliche users-Zeilen existierten — ganz ohne Änderung am Autorisierungsmodell.
Fundament
products, users, user_product_access, sessions, audit_log (append-only-Trigger), Better-Auth-Tabellen, Geräteautorisierung.
Kundenmodul
customers, members, products, domains, E-Mail-User, Onboardings mit fixer URL, Formularzweck.
mail_accounts (versiegelte Credentials), Sync-State, Reservierungen, Send-Schedule, In-Reply-To, Signaturen, Reply-Idempotenz.
Voice & CI/CD
voice_rooms, Pipeline-Runs, Security-Center-History, Findings ↔ Issues, Codex-Automation.
Sichere Kanäle
Mailbox-Secure-Messages, Hinweisgeber-Kanal, SLA-Wächter, DSGVO-Anfragen, Data-Retention, bekannte Login-Geräte.
Jarvis
jarvis_command_log — indexiert nach Zeit, Actor und Intent, mit Dauer und Ergebnisstatus.
05 Secrets & Ausfallverhalten
Jedes Geheimnis hat genau einen Zweck. Fehlt ein optionales, fällt nur das eine Feature sauber aus (503) — statt den ganzen Server zu reißen. Nur BETTER_AUTH_SECRET ist beim Start Pflicht.
MAIL_CREDENTIALS_ENCRYPTION_KEY
Versiegelt IMAP/SMTP-Zugangsdaten. Fehlt er, scheitern nur die Credential-Operationen — sonst nichts.
ONBOARDING_MAIL_SIGNING_SECRET
Nur zwischen Server und nachgedacht-studio geteilt. Ohne ihn ist Onboarding schlicht aus.
CICD_REPORT_TOKEN
Einzweck: ein geleaktes CI-Secret kann nur Pipeline-Läufe schreiben, sonst nichts.
UPDATE_UPLOAD_TOKEN
Gate nur für den PUT-Upload des Update-Feeds — vom übrigen Auth-Modell entkoppelt.
CONTACT_FORM_WEBHOOK_TOKEN
Fehlt er, liefert der Fastpath 503 und die Website nutzt ihre normale Zustellung.
LIVEKIT_KEYS
Ohne sie sind die Voice-Räume deaktiviert, der Rest läuft normal weiter.
06 Öffentliche Onboarding-Subdomain
Ist ONBOARDING_PUBLIC_BASE_URL gesetzt, prüft der Server bei jeder Anfrage serverseitig den Host-Header.
/admin und jede interne /api/admin/*-Route liefern dort eine neutrale 404 — keine Weiterleitung ins interne HQ, kein Informationsleck über die Existenz des Admin-Bereichs.
07 Betrieb & Deployment
Getrennter Runtime-Checkout
Der laufende Dienst zieht per git pull --ff-only in ein eigenes Arbeitsverzeichnis, gebaut wird dort, nicht im Entwicklungs-Repo.
WinSW-Selbstneustart
Der „Jetzt deployen“-Knopf triggert den dokumentierten restart!-Befehl des Service-Wrappers — kein manuelles Restart-Service nötig.
Tailscale-Overlay
Privates Netz zwischen Server, Windows-PC und MacBook; TLS-Zertifikat via tailscale cert, damit der Server auch außerhalb von localhost erreichbar ist.
Migrations-Startsperre
Fehlt eine Migration in der Datenbank, startet der Prozess gar nicht erst — ein Deploy mit vergessener Migration fällt sofort auf.
| Komponente | Technologie | Rolle |
|---|---|---|
| nachgedacht-hq-server | Node.js, TypeScript, PostgreSQL | Zentraler Server — Auth, Postfach-Verwaltung, Compliance-Automatisierung, Jarvis, Admin Board |
| nachgedacht-hq | Electron, React | Desktop-Mailclient für Mitarbeiter:innen, plus Kunden-Rolle und späterer Voice Host |
| nachgedacht-studio | Next.js | Marketing-Website + Onboarding-Formular, signiert den Onboarding-Payload |
| Authentifizierung | better-auth + Passkey-Plugin | Sessions, WebAuthn-Passkeys, feste Rollen (owner · admin · support · viewer · customer_owner) |
| imapflow, nodemailer, mailparser | Server-eigene IMAP/SMTP-Anbindung je Zentralkonto, persistentes IDLE | |
| Sprachkanal | LiveKit | Interne Voice-Räume; Jarvis-Audio über den Electron Voice Host |
| Netzwerk | Tailscale | Privates Overlay-Netz zwischen Server, Windows-PC und MacBook |
| Dienstbetrieb | WinSW (Windows-Dienst) | Nativer Dienst mit dokumentiertem Selbstneustart für den Deploy-Knopf |
CI/CD-Infrastruktur
Die komplette Build- und Release-Pipeline läuft auf eigener Infrastruktur — GitHub dient nur noch als automatisch synchronisierter Backup-Spiegel.
Auslöser war eine wiederholt erschöpfte GitHub-Actions-Kontingentgrenze, die einen Client-Release blockierte. Statt eine Zahlungsmethode bei einem weiteren US-Anbieter zu hinterlegen, wurde die komplette Git- und CI/CD-Kette selbst gehostet: Forgejo für Git-Hosting, Woodpecker CI für Build/Test/Release. Security Center und die Client-Releases-Übersicht im Admin Board beziehen ihre Signale seitdem aus Forgejo.
Docker-Agent
Lint, Build, Unit- und Integrationstests (inklusive echtem Postgres-Service), Secret-Scanning — für beide Repositories.
Windows-Agent
Baut den Windows-Installer — native Kompilierung (electron-rebuild, NSIS) braucht eine echte Windows-Umgebung, kein Container.
MacBook-Agent
Baut, signiert (Developer-ID) und notarisiert den macOS-Build — beides nur mit echtem macOS möglich.