Files
tesm-license/srv
alientimandClaude Sonnet 5 cee5311b1d Ticketverwaltung, Kundenstammdaten, Kundenportal, Lifetime-Lizenzen, Dashboard-Kacheln (v1.2.0)
Reaktion auf mehrere Bug-Reports und Feature-Wuensche zum bestehenden
Ticket-System (v1.1.0): 'Logs gehen nicht', 'Ticketverwaltung fehlt',
'Lizenzen koennen nicht vom Dashboard geloescht werden', plus eine Reihe
konkreter neuer Anforderungen.

## Bugfixes

- /logs: behob einen Absturz (jinja2.exceptions.UndefinedError:
  'global_check_interval' is undefined) UND die eigentliche Ursache
  dahinter -- logs.html war unveraendert aus dem TESM-Fork uebernommen
  (PoE-Geraete-Polling-Text/-Farblogik, ein Template-Feld, das app.py nie
  befuellt hat) und ausserdem schrieb auf diesem Server ueberhaupt nichts
  in live.log (kein poe.sh-Aequivalent vorhanden). Live-Log zeigt jetzt
  echte Ticket-/Lizenzaktionen, mit passendem Hinweistext und Faerbung.
- Lizenz-Loeschung war bereits vorhanden, aber nur ueber Ticket- ->
  Lizenz-Detailseite erreichbar -- jetzt zusaetzlich inline in der
  Lizenzhistorie jedes Tickets.

## Ticketverwaltung (neu: eigene Seite /tickets)

- Volle CRUD: Liste mit Suche, Bearbeiten (Typ/Module/Laufzeit/Lifetime,
  wirkt nur auf die naechste Ausstellung), Loeschen (nur wenn keine
  offene Lizenz mehr besteht, dann inkl. Historie).
- Dashboard (/) zeigt seitdem NICHT mehr die Ticket-Tabelle, sondern eine
  rein informative Kachel-Uebersicht der aktuell AKTIVEN Lizenzen, exakt
  im Kachel-Stil von TESMs eigenem Geraete-Dashboard: Ampelfarben (gruen
  >90 Tage, orange 30-90, rot <30/abgelaufen), gruppiert, Firma + Hostname
  der Kundeninstanz. Hostname kommt neu vom TESM-Client per Activate/
  Heartbeat (srv/tesm/licensing.py, abwaerts-kompatibel: alte Clients ohne
  das Feld ueberschreiben nie einen bereits bekannten Hostnamen).

## Kundenstammdaten

- Neue Felder: Strasse/Hausnummer/PLZ/Ort/Ansprechpartner. E-Mail ist beim
  Anlegen jetzt Pflicht; beim Bearbeiten bewusst nur validiert, wenn
  ausgefuellt (sonst waeren Bestandskunden aus der Zeit vor dieser
  Umstellung fuer JEDE Aenderung blockiert gewesen).

## Kundenportal (neu, per Magic-Link, kein Login)

- /portal/<token>: zeigt einem Kunden ALLE seine Tickets/Lizenzen auf
  einen Blick (ergaenzt den bestehenden Pro-Ticket-Link
  /self-service/<ticket_id>) und erlaubt ihm, seine eigenen Kontakt-/
  Anschriftdaten selbst zu pflegen -- Firmenname und kommerzielle
  Ticket-Eckdaten bleiben bewusst admin-verwaltet. token = eigene Spalte
  license_customers.portal_token, rueckwirkend fuer Bestandskunden erzeugt.

## Lifetime-Lizenzen

- Neues Ticket-Flag 'Lifetime': ignoriert die Laufzeit fuer jede REGULAERE
  Ausstellung (Sentinel-Ablaufdatum 2099-12-31, licensing.
  LIFETIME_EXPIRES_AT) -- eine zusaetzlich erzeugte Trial-Lizenz aus
  demselben Ticket bleibt immer die normale 30-Tage-Variante. Trial ALS
  TICKET-GRUNDTYP + Lifetime wird serverseitig verhindert (haette eine
  dauerhafte, nie ablaufende Lizenz ganz ohne Module ergeben).

## Absicherung nach Review

Ein Adversarial-Review-Durchlauf ueber den kompletten Diff deckte vor dem
Deploy zusaetzlich auf und wurde behoben:
- TOCTOU-Race: zwei nahezu gleichzeitige 'Lizenz erstellen'-Anfragen fuer
  dasselbe Ticket (z.B. Doppelklick im Self-Service) konnten beide
  durchkommen. Jetzt durch einen partiellen Unique-Index
  (idx_one_open_license_per_ticket) auf DB-Ebene ausgeschlossen; die
  zweite Anfrage bekommt sauber die bereits erstellte Lizenz zurueck statt
  eine zweite zu erzeugen.
- Analoger Unique-Index auf license_customers.portal_token als Backstop
  fuer den neuen Magic-Link.
- tickets.html nutzte noch die alte, feste '<=30 Tage'-Schwelle statt der
  gemeinsamen Ampelfarbe -- Lizenzen im 30-90-Tage-Bereich blieben dort
  unmarkiert, obwohl das Dashboard sie schon als orange zeigte.

SCHEMA_VERSION 2 -> 3 (neue Spalten/Tabellen, ueber install.sh mit
Backup+Health-Check abgesichert).

Verifiziert: vollstaendige Migration gegen eine echte Kopie der
Live-Datenbank, anschliessend 22 Funktionstests direkt gegen die echten
Routen (Validierung, Lifetime-Ausstellung, Sperr-/Kaskadenregeln bei
Loeschungen, Kundenportal inkl. ungueltiger Eingaben) sowie ein Playwright-
Seitenladetest ohne Konsolenfehler -- beides nach den Review-Fixes erneut
komplett durchlaufen, inkl. direktem Nachweis, dass der neue Unique-Index
eine doppelte offene Lizenz pro Ticket tatsaechlich auf DB-Ebene ablehnt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 15:51:20 +02:00
..