46 lines
3.9 KiB
Markdown
46 lines
3.9 KiB
Markdown
# 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 `<data-dir>/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.
|