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
Erfüllt die Pflicht aus dem Hinweisgeberschutzgesetz (HinSchG) zu einem sicheren, anonymen Meldekanal. 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
Löscht man einen Kunden, löscht die Datenbank automatisch alles Verknüpfte mit (CASCADE) — Postfächer, Team-Zugänge, Onboardings. Ein Kunde lässt sich deshalb erst löschen, wenn genau diese Kettenreaktion vorher geprüft ist — keine stillen Kollateralschäden.
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.
read_only, läuft ohne Rückfrage. „Jarvis, öffne Security" navigiert im Admin Board dorthin. „Jarvis, stopp" ist die einzige schreibende Aktion, die es aktuell gibt: ein lokaler Kill-Switch für den Voice-Host (local_control). Die Sicherheitsklassen confirm_required und restricted sind im Modell bereits vorgesehen, aber noch an keinen echten Befehl gebunden — es gibt heute schlicht nichts, was Jarvis kaputt machen könnte. Getippt im Admin Board oder gesprochen über den Electron Voice Host — bereits Ende-zu-Ende getestet — derselbe Weg, dasselbe Protokoll, dieselbe Protokollierung.
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 Electron Voice Host (eigenes Repo, mit lokaler Spracherkennung und Sprachausgabe) — der komplette Weg von echtem Sprechen bis zur hörbaren Antwort ist bereits erfolgreich getestet. Fehlt der Host, 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
Ein signierter HTTPS-„Fastpath" — die Formulardaten gehen direkt und authentifiziert an den Server, ohne den Umweg über eine echte E-Mail-Zustellung, die abhängig von Zustellzeiten und potenziell im Spam-Ordner landen kann. Genau dieser E-Mail-Weg bleibt als Fallback bestehen, falls der direkte Pfad 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
Vier 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. Kundenbetriebe erreichen denselben Server über Portal-Login und ihr eigenes IMAP/SMTP-Postfach.
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. Das macht den kompletten Anfrageweg an einer Stelle nachvollziehbar: wer wissen will, was bei einer Anfrage passiert, liest diese Liste von oben nach unten, statt Framework-Konventionen zu erraten.
- 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 — Änderungen am Datenmodell werden nur ergänzt, nie rückgängig gemacht oder überschrieben, damit die Historie nachvollziehbar und ein Rollback nie „stille" Datenverluste erzeugt. Ein Startup-Guard verweigert den Start, wenn eine Migration 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
Ein „Secret" ist ein Passwort- oder Schlüsselwert, den nur der Server selbst kennt — nie ein Client, nie ein Log. Jedes Secret ist für genau eine einzige Aufgabe zuständig. Fehlt eines, das optional ist, schaltet sich nur die eine dazugehörige Funktion sauber ab (die Nutzer bekommen eine klare Fehlermeldung statt einen Absturz) — der Rest des Servers merkt davon nichts. Nur ein einziges Secret ist wirklich zwingend: ohne die Anmelde-Verschlüsselung startet der Server gar nicht erst.
Zugangsdaten-Verschlüsselung
Ohne sie lassen sich keine neuen Postfach-Zugänge anlegen oder ändern — bestehende laufen normal weiter. (MAIL_CREDENTIALS_ENCRYPTION_KEY)
Signatur fürs Kunden-Onboarding
Nur zwischen diesem Server und nachgedacht-studio geteilt. Fehlt sie, ist die automatische Kundenaufnahme komplett abgeschaltet. (ONBOARDING_MAIL_SIGNING_SECRET)
Build-Meldungen entgegennehmen
Einzweck-Zugang: selbst wenn er geleakt würde, könnte damit nur ein falscher Pipeline-Status eingetragen werden — sonst nichts. (CICD_REPORT_TOKEN)
Client-Updates hochladen
Nur fürs Hochladen neuer App-Versionen — komplett losgelöst vom normalen Mitarbeiter-Login. (UPDATE_UPLOAD_TOKEN)
Formular direkt zustellen
Fehlt er, landen Nachrichten trotzdem zu — nur eben über den normalen (etwas langsameren) Zustellweg statt direkt. (CONTACT_FORM_WEBHOOK_TOKEN)
Voice-Channel aktivieren
Ohne ihn sind nur die Sprachräume abgeschaltet — jede andere Funktion läuft unbeeinflusst weiter. (LIVEKIT_KEYS)
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
Läuft nicht in der Cloud, sondern auf Marvins eigener Hardware — mit denselben Sicherheitsmechanismen, die man sonst nur von größeren Hosting-Anbietern kennt.
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 |
| nachgedacht-jarvis-host | Electron | Voice Host für Jarvis, verbindet sich per WebSocket mit dem Server |
| 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.