# TESM

Verwaltung von PoE-Geraeten und Aruba-Switchen: Inventar, Zustandsueberwachung,
Portsteuerung, Neustart (PoE, SSH, RPC), DHCP ueber Kea, Dateifreigaben,
Wartung ueber SSH, Protokolle, Papierkorb, verschluesselte Ein- und Ausfuhr und
ein SSH-Terminal im Browser.

**Dieses Repository enthaelt genau das, was zum Installieren und Betreiben von
TESM gebraucht wird** -- nichts darueber hinaus:

```
apps/tesm                   die Anwendung
packages/tesm-core          gemeinsamer Kern (Anmeldung, Rechte, Sicherung, nginx, ...)
packages/tesm-licensing     Lizenzprotokoll, Clientseite
deploy/                     install.sh, update.sh, release.sh, systemd, privilegierter Helfer
docs/                       Betrieb und Sicherheit
```

Die Serverhaelfte des Lizenzprotokolls (`tesm-licensing-server`: ausstellen,
erneuern, Antworten signieren) liegt **nicht** hier. TESM verifiziert Lizenzen
und stellt Anfragen; den Code zum Ausstellen soll ein Client nicht einmal
mitbringen.

| Wo sonst noch | |
|---|---|
| [alientim/tesm-license](https://gitea.int.eertmoed.net/alientim/tesm-license) | der Lizenzserver |
| [alientim/TESM-DEV](https://gitea.int.eertmoed.net/alientim/TESM-DEV) | Entwicklung: beide Anwendungen, Tests, Architekturdoku |

## Zweige

| Zweig | Inhalt |
|---|---|
| `main` | dieser Neubau (Version 2.0.0) |
| `SONNET5` | der Stand davor, unveraendert aufbewahrt |

---

## Installation

```bash
sudo bash deploy/install.sh --app tesm --https
sudo -u tesm tesm-admin create-admin
```

Danach `https://<host>/`. Ohne `--domain` entsteht ein selbstsigniertes
Zertifikat; der Browser warnt einmal, die Verbindung ist verschluesselt.

Mit oeffentlichem Namen und Let's Encrypt stattdessen:

```bash
sudo bash deploy/install.sh --app tesm --https --domain tesm.firma.de --acme-email it@firma.de
```

Zielzustand: **Port 443 mit TLS, Port 80 leitet dorthin um** -- ausser dem
ACME-Pfad, der erreichbar bleiben muss, sonst kann Let's Encrypt nie erneuern.

Sitzt ein eigener Reverse Proxy davor, der TLS beendet, laeuft TESM ohne
`--https` schlicht auf Port 80.

Eine zweite Installation zum Testen stoert die laufende nicht:

```bash
sudo bash deploy/install.sh --app tesm --instance test --port 5100 --http-port 8080
```

Jede Instanz bekommt eigene Datenbank, eigene Schluessel, eigene nginx-Site und
ein eigenes Sitzungscookie.

### Aktualisieren

```bash
sudo bash deploy/update.sh --app tesm
```

Das laedt ein Release, entpackt es und ruft dessen `install.sh` auf. Vor jedem
Update entsteht ein vollstaendiges Backup -- unabhaengig davon, ob sich das
Schema geaendert hat -- und danach laeuft ein Health-Check mit automatischem
Rollback.

---

## Betrieb von der Kommandozeile

```bash
sudo -u tesm tesm-admin status              # Zustand der Installation
sudo -u tesm tesm-admin create-admin        # Konto anlegen oder zuruecksetzen
sudo -u tesm tesm-admin check-now           # Ueberwachungsdurchlauf sofort
sudo -u tesm tesm-admin housekeeping        # Sitzungen und Protokolle aufraeumen
sudo -u tesm tesm-admin web-setup --https   # nginx und TLS einrichten
```

### Umzug aus dem alten TESM

Ein Export des Vorgaengers laesst sich uebersetzen und dann ueber den normalen
Import einlesen -- Clients, Switche, Zugangsdaten und die DHCP-Konfiguration:

```bash
sudo -u tesm tesm-admin convert-legacy tesm_export_20260813_195455.json --dry-run
```

`--dry-run` zeigt nur den Bericht. Ohne die Option entsteht eine Datei im
neuen Format, die unter *Verwaltung -> Sicherung* eingelesen wird. Der Bericht
nennt ausdruecklich, was **nicht** uebersetzt werden kann (lokale Konten,
Rechte, Verzeichnisdienst, Webserver) -- das ist von Hand nachzuziehen.

Die Passphrase gehoert an die verdeckte Eingabeaufforderung. `--passphrase`
existiert nur fuer Automatisierung: es schreibt sie in Shell-Historie und
Prozessliste.

---

## Release bauen

```bash
git tag -a v2.0.0 -m "TESM 2.0.0" && git push origin v2.0.0
bash deploy/release.sh v2.0.0
```

Heraus kommt `tesm-v2.0.0.tar.gz` samt SHA-256. Der Name kommt aus dem
Repository, nicht aus einer festen Zeichenkette.

---

## Dokumentation

| | |
|---|---|
| [docs/BETRIEB.md](docs/BETRIEB.md) | Installation, Update, HTTPS, Sicherung, Fehlersuche |
| [docs/SICHERHEIT.md](docs/SICHERHEIT.md) | Anmeldung, Sitzungen, CSRF, Geheimnisse, Rechtetrennung |

Aufbau und Entwurfsentscheidungen stehen in `docs/ARCHITEKTUR.md` im
Entwicklungsrepository, ebenso die Tests.

---

## Was diese Fassung anders macht

Ein Neubau. Die Fehler des Vorgaengers sind bekannt; an den Stellen, an denen
sie entstanden sind, steht jetzt ein Kommentar, der erklaert, warum es hier
anders geloest ist. Die wichtigsten:

* **Kein root fuer die Anwendung.** Ein einziger allowlisted Helfer mit
  Argumentpruefung statt eines Webprozesses als `root`.
* **CSRF-Schutz ueberhaupt.** Der Vorgaenger hatte keinen.
* **Rechte werden serverseitig geprueft**, nicht nur im Template ausgeblendet.
* **Die nginx-Site wird bei jedem Lauf inhaltlich verglichen und erneuert.** Ein
  falscher `alias`-Pfad ueberlebte im Vorgaenger jahrelang jedes Update.
* **Jede erzeugte Konfiguration wird vor dem Uebernehmen geprueft** -- nginx wie
  Kea. Eine fehlerhafte Datei faellt beim Schreiben auf, nicht erst beim
  naechsten Start des Dienstes.
* **Kein Hostname im Lizenz-Fingerabdruck.** Umbenennen brach die Bindung.
* **Zwei Installationen stoeren sich nicht** -- eigener `SITE_KEY` fuer
  nginx-Site, netplan, logrotate, Zertifikate und Sitzungscookie.
* **Verschachtelte Datenbankverbindungen sind ein Fehler**, kein Deadlock.
