From 9861c25949e08da9c6d3942470b19917bd6a8e22 Mon Sep 17 00:00:00 2001
From: Bjoern Runden
Date: Tue, 29 Sep 2026 22:45:38 +0200
Subject: [PATCH] init des architektur beschreibenden MD... noch kein code, nur
REadme, ai.agent md s
---
.ai/sultan-system-architecture.md | 368 ++++++++++++++++++++++++++++++
CLAUDE.md | 45 ++++
README.md | 78 ++++++-
3 files changed, 488 insertions(+), 3 deletions(-)
create mode 100644 .ai/sultan-system-architecture.md
create mode 100644 CLAUDE.md
diff --git a/.ai/sultan-system-architecture.md b/.ai/sultan-system-architecture.md
new file mode 100644
index 0000000..6c3cf9f
--- /dev/null
+++ b/.ai/sultan-system-architecture.md
@@ -0,0 +1,368 @@
+# CLAUDE.md
+
+
+# Sultan: High-Performance Distributed Ingress & ZeroTrust Service Discovery
+
+Dieses Dokument beschreibt das vollständige Architektur-, Daten-, Netzwerk- und Anwendungsmodell des Projekts **Sultan**. Es dient als Kontext und Referenz für Software-Architekten und AI-gestützte Coding-Agenten (z. B. via Continue in VSCodium).
+
+---
+
+## 1. Executive Summary & Problemstellung
+
+Klassische Ingress-Lösungen wie Nginx Proxy Manager (NPM) erfordern eine manuelle, GUI-basierte Konfiguration des Routings. In verteilten Umgebungen (Mehrere Proxmox-Cluster, Docker-Hosts, Bare-Metal-LAMP/Apache-Server, Kunden-Setups hinter DS-Lite/CGNAT) führt dies zu Dokumentationsbrüchen, toten Routen und hohem Wartungsaufwand.
+
+**Sultan** löst dies durch eine entkoppelte, zweigeteilte Architektur:
+1. **In-Service-Deklaration:** Backends deklarieren ihr Routing direkt am Dienst (native Traefik-Labels in Docker oder Drop-in-Konfigurationen unter `/etc/sultan.d/`).
+2. **Dynamische Registrierung:** Ein leichtgewichtiger Agent überträgt diese Konfiguration kryptografisch gesichert über einen langlebigen, ressourcenschonenden Keepalive-Stream an den zentralen Ingress.
+3. **ZeroTrust & Public Reachability:** Optionale Anbindung über ein WireGuard-Mesh (z. B. NetBird), um auch Hosts ohne statische IPv4/IPv6 oder hinter NAT/Firewalls öffentlich mit TLS bereitzustellen.
+4. **Integrierte Autorisierung & Monetarisierung:** Mandantensichere Capability-Lizenzen via Ed25519-Kryptografie, Lease-System und automatisierte Überwachung von Lizenzfristen.
+
+---
+
+## 2. Netzwerkmodell (Network Model)
+
+### 2.1 Topologie
+
+```text
+[ Öffentliches Internet ]
+ │
+ │ HTTP (80) / HTTPS (443) / TCP-Streams
+ ▼
+┌────────────────────────────────────────────────────────┐
+│ Ingress-Knoten (Zentrales Rechenzentrum / Public IP) │
+│ │
+│ ┌────────────────────────────────────────────────┐ │
+│ │ Traefik v3 (Ingress / ACME DNS-01 Validierung) │ │
+│ └───────────────────────▲────────────────────────┘ │
+│ │ HTTP Poll (:8080) │
+│ │ (/v1/traefik-config) │
+│ ┌───────────────────────┴────────────────────────┐ │
+│ │ Sultan-Server (Registry / Policy Engine) │ │
+│ └───────────────────────▲────────────────────────┘ │
+│ │ │
+│ │ Control Plane: │
+│ │ TLS-Stream (:8443) │
+│ │ (45s Heartbeat, │
+│ │ Instant Event Push) │
+│ │ │
+│ ┌───────────────────────┴────────────────────────┐ │
+│ │ NetBird / WireGuard Gateway (100.64.0.1) │ │
+│ └───────────────────────▲────────────────────────┘ │
+└───────────────────────────┼────────────────────────────┘
+ │
+ ZeroTrust WireGuard Tunnel (Traffic)
+ │
+ ┌──────────────────┴──────────────────┐
+ │ │
+┌────────┴──────────────┐ ┌──────────┴─────────────┐
+│ Client-Host A │ │ Client-Host B │
+│ (Bare-Metal / LAMP) │ │ (Docker-Compose Stack) │
+│ │ │ │
+│ ┌───────────────────┐ │ │ ┌────────────────────┐ │
+│ │ sultan-agent │ │ │ │ sultan-agent │ │
+│ │ (File-Watcher) │ │ │ │ (Docker-Socket) │ │
+│ └───────────────────┘ │ │ └────────────────────┘ │
+│ ┌───────────────────┐ │ │ ┌────────────────────┐ │
+│ │ Apache / VHost │ │ │ │ Web-Container │ │
+│ └───────────────────┘ │ │ └────────────────────┘ │
+└───────────────────────┘ └────────────────────────┘
+
+```
+
+### 2.2 Datenfluss & Verbindungstypen
+
+1. **Control Plane (Agent -> Server):**
+* **Transport:** Ausgehende Verbindung vom Agenten zum Server über TCP `:8443` (TLS).
+* **Firewall-Freundlichkeit:** Reine Outbound-Verbindung; funktioniert hinter DS-Lite, Mobilfunk, Carrier-Grade-NAT und Unternehmens-Firewalls ohne Portweiterleitung.
+* **Keepalive-Mechanik:** Persistenter HTTP/2- oder SSE-Stream. Alle 45 Sekunden wird ein minimales Keepalive-Byte (`:\n\n`) ausgetauscht. Verhindert das Schließen von State-Tables in NAT-Routern (Conntrack Timeout).
+* **Event-Driven Push:** Änderungen an Containern (Start/Stop) oder Notfall-Sperren werden verzögerungsfrei (Latenz < 5 ms) über den bestehenden Stream übertragen.
+
+
+2. **Data Plane (Traffic: Besucher -> Backend):**
+* **Direkt:** Liegen Ingress und Backend im selben VLAN/LAN, routet Traefik direkt auf die interne LAN-IP.
+* **ZeroTrust Overlay (NetBird):** Sitzt das Backend im Fremdnetz/Homelab, routet Traefik auf die WireGuard-Overlay-IP (`100.64.x.y`). End-to-End verschlüsselt.
+
+
+3. **Ingress zu Traefik:**
+* Traefik pollt den lokalen Sultan-Server via HTTP-Provider: `GET http://127.0.0.1:8080/v1/traefik-config`.
+* Intervall: 2–5 Sekunden. Traefik verarbeitet die In-Memory-Konfiguration ohne Neustart und ohne Verbindungsabbrüche.
+
+
+
+---
+
+## 3. Sicherheits- und Vertrauensmodell
+
+### 3.1 Transport-Verschlüsselung (TLS ohne CA-Zirkus)
+
+* **Server-Zertifikat:** Generiert sich beim ersten Start selbst (Self-Signed / Snakeoil ECDSA P-256).
+* **Vertrauensmodell:** Trust-on-First-Use (TOFU) analog zu SSH. Der Agent verifiziert beim ersten Connect den SHA256-Fingerprint des Servers und speichert ihn in `known_servers`.
+* **Optional:** Unterstützung für explizit gemountete Root-CA-Zertifikate.
+
+### 3.2 Authentifizierung & Enrollment (CSR-Handshake)
+
+* Private Keys werden **ausschließlich lokal auf dem Ziel-Host** generiert (Ed25519) und verlassen diesen niemals.
+* **Enrollment:**
+1. Admin erzeugt kurzlebigen Einladungs-Token auf dem Server (`sltn_token_...`).
+2. Agent generiert lokalen Key (`node.key`) und sendet seinen Public Key (`node.pub`) zusammen mit dem Einladungs-Token an den Server (`POST /api/v1/enroll`).
+3. Server speichert den Public Key des Agenten, weist ihm eine Mandanten-ID zu und signiert das initiale Berechtigungszertifikat (Capability Lease).
+4. Der Einladungs-Token wird entwertet; alle künftigen Heartbeats werden kryptografisch vom Agenten mit `node.key` signiert.
+
+
+
+### 3.3 Autorisierung & Domain-Ownership-Schutz
+
+Jeder Payload vom Agenten an den Server muss vom Server gegen die zugewiesene Policy geprüft werden:
+
+* **Domain Spoofing Protection:** Beansprucht ein Agent ein Label `Host('kunde.de')`, prüft der Server, ob `kunde.de` im Feld `allowed_domains` der Mandanten-Lizenz hinterlegt ist. Falls nicht: Ablehnung mit Sicherheits-Audit-Log.
+* **Route Limits:** Übersteigt die Anzahl der deklarierten Routen das Limit (`max_routes`), werden überzählige Routen verworfen.
+
+---
+
+## 4. Datenmodell (Data Specifications)
+
+### 4.1 Lizenz & Capabilities (`license.json`)
+
+```json
+{
+ "$schema": "[http://json-schema.org/draft-07/schema#](http://json-schema.org/draft-07/schema#)",
+ "title": "SultanCapabilities",
+ "type": "object",
+ "properties": {
+ "tenant_id": { "type": "string" },
+ "tier": { "type": "string", "enum": ["community", "pro", "enterprise"] },
+ "max_routes": { "type": "integer", "description": "-1 für unbegrenzt" },
+ "allowed_domains": {
+ "type": "array",
+ "items": { "type": "string" }
+ },
+ "features": {
+ "type": "array",
+ "items": { "type": "string", "enum": ["websockets", "tcp_stream", "custom_middleware"] }
+ },
+ "valid_until": { "type": "string", "format": "date-time" },
+ "signature": { "type": "string", "description": "Ed25519 Signatur des Server-Master-Keys über den Payload" }
+ },
+ "required": ["tenant_id", "tier", "max_routes", "allowed_domains", "valid_until", "signature"]
+}
+
+```
+
+### 4.2 Stream Event Protocol (Agent <-> Server)
+
+Das bidirektionale Streaming-Format nutzt standardisierte JSON-Events:
+
+```json
+{
+ "event_id": "evt_01J8Z9X2Y3...",
+ "timestamp": 1727618531,
+ "type": "service_state | lease_renew | node_command | error",
+ "node_id": "node-proxmox-vm-42",
+ "payload": {}
+}
+
+```
+
+* **Typ `service_state` (Agent -> Server):**
+Enthält die vollständige Liste der aktuell aktiven Traefik-Labels des Knotens.
+* **Typ `node_command` (Server -> Agent):**
+Enthält Aktionen wie `re_enroll`, `drain`, `maintenance`.
+* **Typ `lease_renew` (Server -> Agent):**
+Liefert ein verlängertes Krypto-Lease an den Agenten zurück.
+
+### 4.3 SQLite Datenbankschema (Server State)
+
+Der Server persistiert Mandanten, Tokens und Richtlinien lokal in SQLite (`/var/lib/sultan/sultan.db`):
+
+```sql
+-- Mandanten & Abonnements
+CREATE TABLE tenants (
+ id TEXT PRIMARY KEY,
+ name TEXT NOT NULL,
+ email TEXT NOT NULL,
+ tier TEXT NOT NULL DEFAULT 'community',
+ max_routes INTEGER NOT NULL DEFAULT 5,
+ allowed_domains TEXT NOT NULL, -- JSON-Array: ["*.firma.de", "shop.de"]
+ valid_until DATETIME NOT NULL, -- Ablaufdatum des Vertrags / Abos
+ status TEXT NOT NULL DEFAULT 'active', -- active, suspended_payment, quarantined
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+-- Registrierte Agenten / Knoten
+CREATE TABLE nodes (
+ id TEXT PRIMARY KEY,
+ tenant_id TEXT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
+ hostname TEXT NOT NULL,
+ public_key TEXT NOT NULL UNIQUE, -- Ed25519 Public Key des Agenten
+ last_seen DATETIME NOT NULL,
+ ip_address TEXT NOT NULL,
+ status TEXT NOT NULL DEFAULT 'online', -- online, offline, drained
+ FOREIGN KEY(tenant_id) REFERENCES tenants(id)
+);
+
+-- Einmalige Enrollment-Tokens
+CREATE TABLE enrollment_tokens (
+ token_hash TEXT PRIMARY KEY,
+ tenant_id TEXT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
+ expires_at DATETIME NOT NULL,
+ used INTEGER NOT NULL DEFAULT 0
+);
+
+```
+
+---
+
+## 5. Anwendungsmodell (Application Model)
+
+Das gesamte System ist als **Single-Binary-Architektur** in Go implementiert:
+
+```text
+sultan
+├── server # Führt Registry, Stream-Hub, Policy-Engine & Traefik-Provider aus
+├── agent # Führt Docker-/File-Watcher aus und verbindet sich zum Server
+└── token # CLI-Tools zur Schlüsselverwaltung, Enrollment- & Lizenzausstellung
+
+```
+
+### 5.1 Agenten-Subsysteme
+
+1. **Watcher Engine:**
+* **Docker Engine:** Lauscht am `/var/run/docker.sock` via Docker Events API. Filtert nach Labels mit Präfix `traefik.`.
+* **File Provider:** Überwacht Verzeichnis `/etc/sultan.d/*.conf` via Inotify auf Konfigurationsdateien im INI/YAML-Format.
+
+
+2. **State Serializer:**
+* Extrahiert Services, Host-Ports und Routen.
+* Injiziert automatisch die Ziel-IP (LAN-IP oder NetBird-IP) in die Server-URL-Definitionen für Traefik.
+
+
+3. **Transport Engine:**
+* Verwaltet den permanenten TLS-Stream mit 45s-Keepalive.
+* Führt automatischen Reconnect mit exponentiellem Backoff durch.
+
+
+
+### 5.2 Server-Subsysteme
+
+1. **Stream Hub:**
+* Hält offene Sockets aller Agents im RAM.
+* Verarbeitet State-Pushes und führt Dead-Node-Detection durch (Timeout: 90s).
+
+
+2. **Dynamic Config Aggregator:**
+* Führt die flachen Traefik-Labels aller aktiven Knoten zusammen.
+* Wandelt die Labels in das verschachtelte Traefik-JSON-Format um.
+* Stellt `GET /v1/traefik-config` bereit.
+
+
+3. **Policy & Interception Engine:**
+* **Sperrung bei Zahlungsverzug:** Modifiziert den Traefik-Router auf einen internen Redirect zu einer Bezahlseite (`HTTP 402 / Payment Required`).
+* **Notfall-Wartung:** Schlägt das Backend fehl oder meldet der Agent `service_down`, liefert Traefik eine statische Statusseite mit `Retry-After: 60` (`HTTP 503`).
+
+
+
+---
+
+## 6. Überwachung, Lizenzfristen & Alerting (Checkmk-Integration)
+
+Um zu verhindern, dass Kunden-Instanzen bei Ablauf von Quartals- oder Jahresabonnements unerwartet in den Wartungsmodus fallen, implementiert der Sultan-Server Schnittstellen für **Checkmk** und externe Alerting-Pipelines.
+
+### 6.1 Checkmk Local Check Protocol
+
+Der Server stellt einen internen Management-Endpunkt bereit: `GET /metrics/checkmk` (oder auslesbar über ein lokales Checkmk-Agent-Plugin-Script `/usr/lib/check_mk_agent/local/sultan_licenses`).
+
+Das Ausgabeformat entspricht der nativen Checkmk Local-Check-Syntax:
+
+```text
+# Syntax:
+# 0 = OK, 1 = WARN, 2 = CRIT, 3 = UNKNOWN
+
+0 "Sultan_Tenant_kunde_schmidt" days_left=74;30;14 OK - Abo aktiv bis 2026-12-15 (74 Tage verbleibend)
+1 "Sultan_Tenant_meier_gmbh" days_left=12;30;14 WARN - Abo laeuft in 12 Tagen ab! Verlaengerung erforderlich.
+2 "Sultan_Tenant_alt_ag" days_left=0;30;14 CRITICAL - Abo seit 1 Tagen abgelaufen! Status: suspended_payment
+
+```
+
+### 6.2 Schwellenwerte & Alarmierungskaskade
+
+* **30 Tage vor Ablauf:** Warnung im Checkmk-Dashboard (Monitoring-Status: `WARN`).
+* **14 Tage vor Ablauf:** Kritischer Alert (`CRIT`). Automatischer E-Mail-Dispatch / Ticket-Erstellung an Kunden und Admin: *„Abo-Verlängerung erforderlich – bitte Rechnung begleichen“*.
+* **Tag 0 (Ablaufzeitpunkt):**
+* Status wechselt in SQLite auf `expired`.
+* Traefik leitet Domain auf Informations-Landingpage um.
+* Checkmk triggert Alarm: `CRITICAL - Service offline geschaltet`.
+
+
+
+---
+
+## 7. Referenzkonfigurationen
+
+### 7.1 Compose-Setup: Ingress-Knoten
+
+```yaml
+services:
+ traefik:
+ image: traefik:v3.1
+ container_name: traefik-ingress
+ restart: unless-stopped
+ network_mode: host
+ command:
+ - "--providers.http.endpoint=[http://127.0.0.1:8080/v1/traefik-config](http://127.0.0.1:8080/v1/traefik-config)"
+ - "--providers.http.pollInterval=3s"
+ - "--entrypoints.web.address=:80"
+ - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
+ - "--entrypoints.web.http.redirections.entryPoint.scheme=https"
+ - "--entrypoints.websecure.address=:443"
+ - "--certificatesresolvers.dns-resolver.acme.dnschallenge=true"
+ - "--certificatesresolvers.dns-resolver.acme.dnschallenge.provider=rfc2136"
+ volumes:
+ - ./acme.json:/etc/traefik/acme.json
+
+ sultan-server:
+ image: sultan:latest
+ container_name: sultan-server
+ restart: unless-stopped
+ command: ["sultan", "server", "--data-dir=/var/lib/sultan"]
+ ports:
+ - "8443:8443" # Agent Inbound (TLS Stream)
+ - "127.0.0.1:8080:8080" # Traefik Config Provider & Checkmk Metrics
+ volumes:
+ - ./sultan-data:/var/lib/sultan
+
+```
+
+### 7.2 Compose-Setup: Kunden-Host (Backend mit Docker)
+
+```yaml
+services:
+ sultan-agent:
+ image: sultan:latest
+ container_name: sultan-agent
+ restart: unless-stopped
+ command:
+ - "sultan"
+ - "agent"
+ - "--server=[https://ingress.dein-netz.de:8443](https://ingress.dein-netz.de:8443)"
+ - "--token=sltn_enroll_01J8Z9..."
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock:ro
+ - ./agent-data:/var/lib/sultan
+
+ kunde-wordpress:
+ image: wordpress:latest
+ restart: unless-stopped
+ labels:
+ - "traefik.enable=true"
+ - "traefik.http.routers.wp.rule=Host(`kunde.de`) || Host(`www.kunde.de`)"
+ - "traefik.http.routers.wp.entrypoints=websecure"
+ - "traefik.http.routers.wp.tls=true"
+ - "traefik.http.routers.wp.tls.certresolver=dns-resolver"
+ - "traefik.http.middlewares.wp-www.redirectregex.regex=^https?://kunde\\.de/(.*)"
+ - "traefik.http.middlewares.wp-www.redirectregex.replacement=[https://www.kunde.de/$$](https://www.kunde.de/$$){1}"
+ - "traefik.http.middlewares.wp-www.redirectregex.permanent=true"
+ - "traefik.http.routers.wp.middlewares=wp-www"
+ - "traefik.http.services.wp.loadbalancer.server.port=80"
+
+```
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..a0b5624
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,45 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Instruktionen
+
+Lies die `.ai/*.md` Files. Diese liefern den Context für die App, die hier entstehen soll.
+Maßgeblich ist aktuell [.ai/sultan-system-architecture.md](.ai/sultan-system-architecture.md) (Netzwerk-, Sicherheits-, Daten- und Anwendungsmodell inkl. SQL-Schema, Event-Format und Referenz-Compose-Files). Bei Widersprüchen zwischen diesem File und der Spec gilt die Spec.
+
+## Projektstatus
+
+Greenfield: Es existiert noch kein Go-Code, kein `go.mod`, keine Build-/Test-Toolchain. Build-, Lint- und Test-Befehle hier ergänzen, sobald sie existieren.
+
+## Big Picture
+
+Sultan ersetzt manuell gepflegtes Ingress-Routing (z. B. Nginx Proxy Manager): Backends deklarieren ihr Routing selbst (Traefik-Labels an Docker-Containern oder Drop-ins in `/etc/sultan.d/*.conf` für Bare-Metal/LAMP), ein Agent meldet das an einen zentralen Server, und Traefik auf dem Ingress-Knoten pollt daraus seine Konfiguration.
+
+**Single Binary in Go** mit drei Subcommands:
+- `sultan server` – Registry, Stream-Hub (hält Agent-Verbindungen im RAM, Dead-Node-Timeout 90s), Policy-Engine, Traefik-HTTP-Provider
+- `sultan agent` – Watcher (Docker Events API auf `traefik.*`-Labels bzw. inotify auf `/etc/sultan.d`), State-Serializer (injiziert LAN- oder NetBird-IP `100.64.x.y` als Backend-Ziel), Transport mit Reconnect + exponentiellem Backoff
+- `sultan token` – CLI für Schlüssel, Enrollment-Tokens, Lizenzausstellung
+
+**Ports / Endpunkte des Servers:**
+- `:8443` (TLS) – Control Plane, ausschließlich *ausgehend* vom Agent (NAT/CGNAT/DS-Lite-tauglich). Persistenter Stream (HTTP/2 oder SSE), 45s-Keepalive, Events werden sofort gepusht. Enrollment: `POST /api/v1/enroll`.
+- `127.0.0.1:8080` – `GET /v1/traefik-config` (Traefik pollt alle 2–5s; flache Labels aller aktiven Nodes → verschachteltes Traefik-JSON) und `GET /metrics/checkmk` (Checkmk Local-Check-Format).
+
+**Sicherheitsmodell (Kerninvarianten):**
+- Server-TLS-Zertifikat self-signed (ECDSA P-256), Agent pinnt den SHA256-Fingerprint per TOFU in `known_servers`.
+- Agent-Keys (Ed25519) werden nur lokal erzeugt und verlassen den Host nie; Enrollment tauscht Public Key + einmaligen Token gegen Mandanten-Zuordnung und signierten Capability-Lease. Danach ist jeder Heartbeat mit `node.key` signiert.
+- Jeder Agent-Payload wird serverseitig gegen die Mandanten-Policy geprüft: Hosts in `Host(...)`-Regeln müssen in `allowed_domains` stehen (sonst ablehnen + Audit-Log), Routen über `max_routes` werden verworfen.
+- Lizenzen (`license.json`) sind mit dem Ed25519-Server-Master-Key signiert.
+
+**Stream-Events** (JSON: `event_id`, `timestamp`, `type`, `node_id`, `payload`): `service_state` (Agent→Server, vollständiger Label-Snapshot, nicht Delta), `node_command` (`re_enroll`/`drain`/`maintenance`), `lease_renew`, `error`.
+
+**Persistenz:** SQLite unter `/sultan.db` (Default `/var/lib/sultan`), Tabellen `tenants`, `nodes`, `enrollment_tokens` (Tokens nur als Hash gespeichert).
+
+**Policy/Lizenzablauf:** Mandanten-Status steuert das generierte Routing – Zahlungsverzug → Router auf Bezahlseite (402), Backend down/`service_down` → Statusseite 503 mit `Retry-After: 60`. Checkmk-Schwellen: WARN bei 30, CRIT bei 14 Tagen Restlaufzeit, bei Ablauf Umleitung auf Landingpage.
+
+## Bekannte Unstimmigkeiten in der Spec
+
+Vor der Implementierung mit dem User klären statt raten:
+- Token-Präfix: `sltn_token_...` (Abschnitt 3.2) vs. `sltn_enroll_...` (Compose-Beispiel 7.2).
+- Tenant-Status: Schema kennt `active`/`suspended_payment`/`quarantined`, Abschnitt 6.2 setzt `expired`.
+- Stream-Transport ist offen: HTTP/2 *oder* SSE (SSE wäre nur Server→Agent; bidirektionale Events brauchen dann einen Rückkanal).
+- Einige URLs in JSON/YAML-Blöcken der Spec sind durch Copy-Paste als Markdown-Links verstümmelt (`"[http://...](http://...)"`) – die nackte URL ist gemeint.
diff --git a/README.md b/README.md
index 11e02e1..2d389f8 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,76 @@
-# sultan
+# 👑 sultan
-sultan service + agent in GO
-Target: a Traefik label registry docker host over span
\ No newline at end of file
+**Verteiltes Ingress-Routing mit ZeroTrust-Service-Discovery – geschrieben in Go.**
+
+Schluss mit Klick-Konfiguration im Proxy-GUI und toten Routen 🪦: Bei Sultan sagen deine Dienste selbst, wie sie erreichbar sein wollen. Ob Docker-Container mit Traefik-Labels 🐳 oder klassischer Bare-Metal-/LAMP-Server mit Drop-in-Config 🖥️ – ein kleiner Agent meldet das Routing sicher an den zentralen Sultan-Server, und Traefik holt sich daraus live seine Konfiguration. Ohne Neustart, ohne Portweiterleitung.
+
+## ✨ Was Sultan kann
+
+- 🏷️ **Routing am Dienst deklarieren** – native `traefik.*`-Labels in Docker oder Dateien unter `/etc/sultan.d/`
+- 📡 **Firewall-freundlich** – der Agent baut nur *ausgehende* Verbindungen auf; funktioniert hinter NAT, CGNAT und DS-Lite
+- ⚡ **Echtzeit-Updates** – Container starten oder stoppen, Traefik weiß es sofort
+- 🔐 **Sicher von Haus aus** – TLS mit Fingerprint-Pinning (wie bei SSH), Ed25519-Schlüssel, die den Host nie verlassen
+- 🛡️ **Mandantenfähig** – jeder Mandant darf nur seine eigenen Domains beanspruchen
+- 🌐 **ZeroTrust-Overlay** – optional über ein WireGuard-Mesh (z. B. NetBird), auch für Hosts ohne öffentliche IP
+- 📊 **Monitoring** – Checkmk-Integration für Knoten- und Lizenzstatus
+
+## 🧭 So funktioniert's
+
+```text
+Internet ──▶ Traefik ──(pollt)──▶ sultan server ◀──(TLS-Stream)── sultan agent (Docker / Bare-Metal)
+```
+
+Ein einziges Binary, drei Rollen:
+
+| Befehl | Aufgabe |
+|-----------------|----------------------------------------------------------------|
+| `sultan server` | Registry, Policy-Engine und Konfigurationsquelle für Traefik |
+| `sultan agent` | Beobachtet Docker bzw. `/etc/sultan.d/` und meldet an den Server |
+| `sultan token` | Schlüssel, Einladungs-Tokens und Lizenzen verwalten |
+
+Die ausführliche Architektur steht in [.ai/sultan-system-architecture.md](.ai/sultan-system-architecture.md).
+
+## 🚀 Installation
+
+> 🚧 **Hinweis:** Sultan befindet sich noch am Anfang der Entwicklung. Die folgenden Schritte zeigen, wie die Installation aussehen *wird* – Befehle und Flags können sich noch ändern.
+
+### Voraussetzungen
+
+- Go (aktuelle stabile Version)
+- Für den Ingress-Knoten: Traefik v3
+- Für Docker-Hosts: Zugriff auf `/var/run/docker.sock`
+
+### Binary bauen
+
+```bash
+git clone ssh://git@git.everdc.eu:10022/chmln-app-dev/sultan.git
+cd sultan
+go build -o sultan .
+sudo install -m 0755 sultan /usr/local/bin/sultan
+```
+
+### Server starten (Ingress-Knoten)
+
+```bash
+sultan server --data-dir=/var/lib/sultan
+```
+
+Der Server lauscht auf `:8443` für Agents und auf `127.0.0.1:8080` für Traefik. Traefik bindest du über den HTTP-Provider an:
+
+```bash
+--providers.http.endpoint=http://127.0.0.1:8080/v1/traefik-config
+--providers.http.pollInterval=3s
+```
+
+### Agent verbinden (Backend-Host)
+
+1. Auf dem Server mit `sultan token` einen Einladungs-Token erzeugen 🎟️
+2. Auf dem Backend-Host den Agent starten:
+
+```bash
+sultan agent --server=https://ingress.example.com:8443 --token=
+```
+
+Beim ersten Verbinden merkt sich der Agent den Fingerprint des Servers – ab dann läuft alles automatisch. 🎉
+
+Fertige Docker-Compose-Beispiele für Ingress und Backend-Host findest du in der [Architektur-Doku](.ai/sultan-system-architecture.md#7-referenzkonfigurationen).