# kundenplattform Kunden-Web-UI für den Tuxflotte-Auftragskatalog — von `provisioning-server` (anode) bewusst getrennter Dienst, siehe [ADR-0011](https://git.tuxflotte.de/admin/platform-docs/raw/branch/main/adr/0011-kundenplattform-getrennter-dienst.md). ## Architektur - FastAPI + Jinja2 (serverseitig gerendert, kein Frontend-Build). - Eigene Postgres-Datenbank (`benutzer`-Tabelle: E-Mail/Passwort-Hash pro Organisation) — getrennt von provisioning-servers Datenbank, keine Cross-Database-Referenzen. - Spricht mit anode ausschließlich über dessen HTTP-API, authentifiziert mit einem eigenen Service-Token (`TUXFLOTTE_KUNDENPLATTFORM_TOKEN`, getrennt vom Admin-Token). Organisationszugehörigkeits-Prüfung (darf dieser Login auf dieses Gerät zugreifen?) passiert hier in der Anwendung, vor jedem Aufruf gegen anode — siehe `find_device_in_organization()` in `app.py`. ## Setup (lokal) ``` python3 -m venv .venv .venv/bin/pip install -r requirements.txt KUNDENPLATTFORM_DATABASE_URL=postgresql://... .venv/bin/psql ... -f migrations/0001_initial_schema.sql ``` Env-Variablen: - `TUXFLOTTE_ANODE_URL` (Default `http://127.0.0.1:8080`) - `TUXFLOTTE_KUNDENPLATTFORM_TOKEN` — muss mit dem gleichnamigen Wert in provisioning-servers `/etc/tuxflotte/provisioning-server.env` übereinstimmen - `KUNDENPLATTFORM_DATABASE_URL` - `KUNDENPLATTFORM_SESSION_SECRET` — beliebiger zufälliger String zum Signieren der Session-Cookie (z.B. `openssl rand -base64 32`) Start: `.venv/bin/uvicorn app:app --port 8081` ## Konto anlegen Kein Self-Service in v1 (siehe ADR-0011) — Konten werden manuell angelegt: ``` KUNDENPLATTFORM_DATABASE_URL=... .venv/bin/python scripts/create_user.py \ --organization-id \ --email admin@schule-beispiel.de ``` ## Deploy (anode) Wie bei `provisioning-server`, git-basiert statt scp: ``` git pull --ff-only systemctl restart kundenplattform ``` Läuft unter einem eigenen, unprivilegierten System-User `kundenplattform` (nicht root, anders als provisioning-server) — siehe `kundenplattform.service`. Port `8081` (provisioning-server belegt `8080`). **Öffentliche Erreichbarkeit über Pangolin ist nicht Teil dieses Repos** — das ist ein separater Ops/DNS/Reverse-Proxy-Schritt.