Files
Laufzettel/docs/betrieb/README.md
T
Florian WildeandClaude Opus 5 fcd67018b8
Prüfung / pruefung (push) Canceled after 0s
Prüfung / e2e (push) Canceled after 0s
feat(verzeichnis): SCIM-Endpunkt als dritte Quellenart (#029)
Bisher holt Laufzettel Personen aus dem Verzeichnis. Das setzt Lesezugriff und
einen Netzweg dorthin voraus, und beides ist nicht ueberall gegeben. Mit der Art
SCIM ruft stattdessen der Anbieter an — sofort, nicht beim naechsten Intervall.

Umgesetzt ist, was authentik, Entra ID und Okta wirklich schicken: Users mit dem
Filter userName eq, POST/GET/PUT/PATCH/DELETE, dazu ServiceProviderConfig,
Schemas und ResourceTypes. Jeder Handler prueft sein Token selbst.

Ein Token je Quelle, argon2-gehasht, einmal angezeigt — es ist der einzige
Mandantenbeweis, den eine Zustellung mitbringt. DELETE deaktiviert und loescht
nichts. Eine SCIM-Quelle wird nicht abgeglichen, an zwei Stellen gehalten: ein
Abgleich, der dort nichts liest und ERFOLG meldet, haette ueber die
Abschaltregel die ganze Belegschaft deaktiviert.

Zwei Befunde kamen aus Gegenproben, nicht aus Tests:

- PATCH remove wirkte gar nicht. Der Schalter nurGesetzte las bei PATCH jedes
  null als "nicht mitgeschickt"; eine beim Anbieter entfernte Abteilung stand
  hier weiter. Noetig war er nie — patchAnwenden liefert immer den
  vollstaendigen Zielzustand.
- Entra ID schickt active als "True"/"False". Beim Deaktivieren kommt mit einem
  reinen value === true zufaellig das Richtige heraus, beim Aktivieren nicht:
  ein wieder freigeschaltetes Konto waere fuer immer inaktiv geblieben.

Dazu ein Fehler aus #028: in verbindungTestenAktion stand zweimal dieselbe
Bedingung, der zweite Zweig war seit dem ersten Tag unerreichbar.

1432 Tests (vorher 1373). Klickprobe am gebauten Stand mit einer echten
Zustellung. Gegen echte Mandanten ist nichts gelaufen — die Anfrageformen
stammen aus der Dokumentation, und das steht so in der Testdatei.

Closes #49

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-10 19:50:54 +02:00

74 lines
4.8 KiB
Markdown

# Laufzettel betreiben
Diese Sammlung richtet sich an den, der Laufzettel betreibt, aber nicht gebaut hat. Sie führt von
einem leeren Server bis zur ersten Anmeldung, und danach durch Aktualisierung, Sicherung und
Fehlersuche. Wer die Anwendung *benutzen* will, liest stattdessen die
[Anleitung](../anleitung/README.md).
Es gibt zwei Wege in den Betrieb. Beide sind gleichwertig und führen zum selben Stand.
| Weg | Für wen | Was du mitbringen musst |
|---|---|---|
| **[Docker Compose](inbetriebnahme.md)** | Es gibt schon einen Docker-Host, und weitere Dienste laufen dort ebenso. Aktualisieren heißt neu bauen. | Docker mit Compose-Plugin |
| **[Nativ im Proxmox-LXC](proxmox.md)** | Es gibt einen Proxmox-Host und keinen Docker. Ein Skript legt den Container an und installiert darin alles — PostgreSQL, Node, die Anwendung, einen systemd-Dienst. | Proxmox VE 8 oder 9, oder ein leeres Debian 13 |
Nimm den Compose-Weg, wenn du schwankst: er ist der Weg, gegen den hier entwickelt und getestet
wird. Der `pct`-Teil des Proxmox-Skripts ist ungetestet — das steht so, und warum, in
[`proxmox.md`](proxmox.md).
## Was auf beiden Wegen gilt
Vier Dinge sind keine Empfehlung, sondern Teil des Aufbaus. Sie zu übergehen heißt, einen anderen
Stand zu betreiben als den beschriebenen.
**Die Datenbank ist von außen nicht erreichbar.** Im Compose-Stand hat `postgres` kein
`ports:`-Mapping und hängt nur im Netz `intern`, das `internal: true` ist — ein Netz ohne Gateway.
Nativ läuft PostgreSQL mit `listen_addresses = ''`, also nur am Unix-Socket. Dieselbe Regel, zwei
Mittel. Daraus folgt, dass jede Sicherung und jeder Blick in die Daten über den Dienstnamen
beziehungsweise den Socket läuft, nie über `psql -h localhost`. `tests/betriebsstand.test.ts` hält
das für den Compose-Stand fest, damit ein `ports:`-Mapping nicht versehentlich zurückkommt.
**Die Anwendung bindet auf `127.0.0.1`** und spricht kein HTTPS. Davor gehört ein Reverse Proxy, der
das Zertifikat hält — siehe [`reverse-proxy.md`](reverse-proxy.md). Ohne Proxy erreicht die
Anwendung niemand außer dem Host selbst, und das ist die richtige Voreinstellung: ein Dienst, der
aus Versehen im LAN steht, fällt keinem auf.
**`APP_URL` ist die öffentliche Adresse und wird nicht geraten.** Aus ihr entstehen die QR-Adressen
auf den gedruckten Aufklebern und die OIDC-Rücksprungadresse. Sie später zu ändern ist möglich, aber
teuer — der Grund steht am Anfang von [`reverse-proxy.md`](reverse-proxy.md). Leg die Adresse fest,
bevor der erste Aufkleber gedruckt wird.
**Geheimnisse entstehen im Zielsystem.** `APP_SECRET`, das Datenbank-Passwort und das erste
Admin-Passwort werden dort erzeugt, wo sie gelten, und stehen in keinem Repository und in keiner
Vorlage. `APP_SECRET` gehört mit in die Sicherung: ohne ihn sind nach dem Zurückspielen alle
Sitzungen ungültig *und* die verschlüsselt gespeicherten LDAP-Bind-Passwörter unlesbar. Siehe
[`sicherung.md`](sicherung.md).
## Die Kapitel
- **[Inbetriebnahme mit Docker Compose](inbetriebnahme.md)** — von null bis zur ersten Anmeldung,
mit der vollständigen Tabelle der Umgebungsvariablen, dem Seed und der Aktualisierung
- **[Der native Weg im Proxmox-LXC](proxmox.md)** — `deploy/proxmox/laufzettel.sh` und
`deploy/install.sh`, was sie anlegen, wie ein zweiter Aufruf aktualisiert, und die Prüfliste für
den ersten echten Lauf
- **[Reverse Proxy](reverse-proxy.md)** — Caddy und nginx als vollständiges Beispiel, TLS,
Weiterleitungen, welche Kopfzeilen nötig sind und welche schaden
- **[Anmeldung über authentik](authentik.md)** — OIDC-Provider, Gruppen auf Rollen, Notfallzugang
- **[Sichern und Zurückspielen](sicherung.md)** — auf beiden Wegen, was in die Sicherung gehört und
was nicht, und wie du prüfst, dass das Zurückspielen wirklich funktioniert
- **[Entra ID als Verzeichnisquelle](entra-id.md)** — App-Registrierung, `User.Read.All`,
Administratoreinwilligung, und was anders ist als bei einem lokalen AD
- **[Benachrichtigungen](benachrichtigungen.md)** — SMTP einrichten, den Webhook prüfen, die
Signatur nachrechnen, und wo man nachsieht, wenn keine Mail mehr ankommt
- **[SCIM-Endpunkt](scim.md)** — die einzige Stelle, an der ein fremder Dienst von außen schreibend
zugreift: das Token, was nicht unterstützt wird, und was der Reverse Proxy durchlassen muss
## Wo sonst noch etwas steht
- [`../../README.md`](../../README.md) — Kurzfassung für Entwickler, Betriebsmodi, Seed-Inhalt
- [`../../.env.example`](../../.env.example) — jede Umgebungsvariable mit Kommentar, zum Kopieren
- [`../architektur.md`](../architektur.md) — warum es so gebaut ist; Abschnitt 6 fasst die
Betriebsregel zusammen
- [`../anleitung/08-fehlerbehebung.md`](../anleitung/08-fehlerbehebung.md) — Fehlermeldungen der
Oberfläche. Wer eine Meldung im Browser sieht, ist dort besser bedient als hier