Migration 0079: Setup Mode und Drittanbieter-CA im Hardware-Snapshot,
firmware_* an devices aus dem Agent-Check-in. Gerätelisten und
Hardware-Endpunkt liefern firmware + secure_boot_stufe.
platform-docs roadmap/secure-boot-verschluesselung.md Schritt 3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bisher ließen sich Organisationen gar nicht entfernen. Jetzt archivieren:
nur ohne aktive Geräte; Medien (enrollment_sessions) widerrufen,
Aktivierungscodes deaktiviert, laufende Einladungen zur Personalisierung
zurückgezogen; die Organisation fehlt danach in der Liste und im
Admin-Dashboard. Daten bleiben erhalten (Migration 0076, archived_at).
Endgültiges Löschen später als eigener Punkt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Befund Erstkontakt 25.10.2026: Eine neue Einladung ohne "Bestehenden
Zugang behalten" sperrte das Konto sofort (auch am Bildschirmschoner einer
laufenden Sitzung); Zurückziehen hob die Sperre nicht auf. Jetzt merkt sich
das Konto die sperrende Einladung (Migration 0075, gesperrt_durch). Wird
sie zurückgezogen, ersetzt, läuft ab oder scheitert am Gerät, ist das
Konto wieder frei; eine ersetzende Einladung übernimmt die Sperre. Von
Hand gesperrte Konten bleiben gesperrt. Die Liste meldet
gesperrt_durch_einladung.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Migration 0074: organizations.org_wlan (Optionen der Rolle, Passwort
verschlüsselt). GET/PUT /api/v1/organizations/{id}/org-wlan; im
Auftragskatalog gilt es für org-wlan, solange OE/Gruppe nichts festlegt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Kunden-Admin trägt die Adresse ein (nur mit Merkmal), der Link (7 Tage,
einmalig) führt zu Anmeldename und Passwort; Stand-Seite per abgeleitetem
Token. Migration 0072: Stand eingeladen, Code-Spalten optional, laufende
Codes zurückgezogen. Code-Endpunkte entfernt; Passwort-vergessen-Kiosk
bleibt bis zur Umstellung der Rolle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_geraete_ampel(): rot bei Fehlern im letzten gemeldeten Lauf oder Platte
>= 95 %, gelb bei knappen Ressourcen oder länger/nie nicht gemeldet, mit
Gründen; für Kunden- und Admin-Dashboard. Tabelle plattform_ereignisse:
neue Stände vorab/stabil schreibt der Spiegel-Thread, Deploy/Migration/
Boot-Medium die Wrapper auf anode. Admin-Dashboard liefert die letzten 30.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Der Agent meldet seit 54f76f1, ob er den Ansible-Stand als Archiv von
anode, per Git oder per Git-Rückfall bezogen hat. Nur die drei bekannten
Werte werden gespeichert; Gerätelisten liefern das Feld mit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Check-in liefert persoenliche_konten (anlegen mit Hash, aktiv, sperren,
entfernen). /api/v1/agent/persoenliche-konten nimmt die Ergebnisse an:
angelegt löscht den Hash und merkt ohne "Bestehenden Zugang behalten" die
übrigen Konten zum Entfernen vor. Ein Code ohne Kästchen sperrt bestehende
Konten sofort. Sperren/Entsperren je Konto. Eine Neuinstallation beendet
alle Personalisierungen des Geräts. Migration 0065 um gesperrt, entfernen,
geraet_meldung und Status fehlgeschlagen ergänzt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Code je Gerät (7 Tage, nur Hash gespeichert), Einreichen mit Domänen- und
Anmeldenamenprüfung (Passwort kommt nur als SHA-512-crypt), Bestätigung
binnen einer Stunde, verfallene Vorgänge verlieren Hash und Adresse. Die
Platzhalterseite /personalisierung entfällt, das Formular liegt in der
Kundenplattform.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bauplan Schritt 1 (platform-docs roadmap/veyon-schluesselverteilung-
diskussion-2026-10-14.md). Paar beim ersten Bedarf erzeugt (RSA 4096,
PKCS#8/SPKI-PEM wie veyon-cli), privat Fernet-verschluesselt. Optionen:
veyon_schluesselname, veyon_public_pem, veyon_raum, veyon_lehrer; nur
Lehrergeraete zusaetzlich veyon_private_pem und veyon_rechner
(<hostname>.local, ohne sich selbst). Lehrer = Haekchen veyon_lehrer an
irgendeiner aktiven Gruppe. Fehler brechen den Check-in nicht ab.
Getestet gegen eine Wegwerf-Datenbank mit allen Migrationen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ressourcen (Mail, Nextcloud, ownCloud, WebDAV, SMB, Web-Proxy) gehoeren zur
Organisation und wirken fuer die ganze Org, OEs samt Unter-OEs oder
Geraetegruppen. Keine Zugangsdaten: unbekannte Felder werden verworfen.
Der Check-in schickt die fuer das Geraet geltenden Ressourcen (spezifisch
zuerst) als Auftrag org-ressourcen, vorerst nur fuer Organisationen mit
Ausrollstufe vorab (ORG_RESSOURCEN_NUR_VORAB).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nachtrag zu ADR-0044: Ob ein Gerät die über die Rolle agent freigegebene
Fassung übernommen hat, war aus der Ferne nicht sichtbar. Ältere Agenten
schicken nichts (Wert bleibt stehen), ungültige Werte werden verworfen
statt den Check-in abzulehnen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Der Check-in liefert Organisationen mit Stufe "stabil" die Adresse des
freigegebenen Repos (ansible-content-stabil), "vorab" die von main. Neue
Organisationen sind stabil; Default Lab, Liebherr und WLAN-Test vorab.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vorgabe im Entwurf setzen (Firefox oder ein im Entwurf enthaltener
Browser), wird mit kopiert, faellt beim Entfernen des Browsers zurueck und
steht in der Wirkungsvorschau. Der Check-in liefert sie als eigenen Auftrag
"standardbrowser" (kein Katalog-Merkmal); dessen Rueckmeldung erzeugt keine
Ereigniszeile.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Migration 0056: bezeichnung, gueltig_bis, verwendet_anzahl,
zuletzt_verwendet (alle optional, bestehende Codes unbegrenzt gueltig).
Abgelaufene Codes werden bei der Aktivierung abgelehnt, erfolgreiche
Aktivierungen gezaehlt. Neue Endpunkte: Status setzen, Loeschen; Anlegen
nimmt optional bezeichnung/gueltig_tage. GUI-Runde 10/2026 Punkt 2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Testprofile von Default Lab und WLAN-Test zeigen auf die Vorlagen
Schulcomputer (Mint/Debian/Ubuntu) derselben Distro, die Basis-Workspaces
entfallen (Migration 0054). fetch_workspaces() liefert die Namen der
freigegebenen Kundengruppen/Organisationen fuer Anzeigen wie
"Vorlage fuer Schulen".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Liebherrs gepflegter Schulcomputer wird Vorlage je Distro (Kundengruppe
Schule), Liebherr- und Gaissach-Profile zeigen auf die Mint-Variante.
Alter globaler Schulcomputer wird Schulcomputer Basis je Distro fuer die
Bestandsprofile. Gast/fjmfm geloescht, Entwickler bleibt als Entwickler
(Mint) bis nach dem 01.11.2026 (gueltiger Aktivierungszugang).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rein additiv mit Rueckfuellung: jeder Workspace bekommt Version 1 mit
seinem bisherigen Inhalt, alle Organisationen die Kundengruppe Schule.
Neu: Sichtbarkeit/Freigaben fuer Vorlagen, Workspace an der OE mit
gepinnter Version und Auto-Haken, Gruppen-Webapps, Org-Berechtigung
darf_eigene_workspaces. Workspace-Creator neu, Schritt C.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CreateBereitstellungsvorlageRequest bekommt scheme + extra_partitions
(Mountpoint/Prozent/Dateisystem je Zusatzpartition), mit serverseitiger
Validierung (Prozentsumme < 100, keine doppelten Mountpoints, nur
ext4/btrfs). Bisher war "custom" laut Code-Kommentar nur per direkter
DB-Pflege erreichbar - jetzt vollstaendig ueber das bestehende Admin-
Formular (Organisationen -> Bereitstellungsvorlagen).
fetch_templates() liefert partitioning jetzt mit aus, damit die Admin-
Tabelle das gewaehlte Schema anzeigen kann.
Migration 0046 dokumentiert die neue JSONB-Form im Spalten-Default und
zieht bestehende Zeilen nach (Muster wie Migration 0026).
Teil der E2E-Testrunde, siehe platform-docs/roadmap/
e2e-testrunde-lokale-adressierung.md Phase 3. Gegenstueck im Install-
Backend (image_deploy_partition_custom() etc.) ist in tuxflotte-installer
bereits umgesetzt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DWKevK2QUK5tsGmqfSD6Yy
Migration 0045: 47 von 56 Merkmalen hatten keine Beschreibung (Datenbank-
Check 11.09.2026) - Kurzbeschreibungen ergänzt, gleicher Ton wie die 9
bestehenden. Neue Spalten homepage_url/icon_source_hint (nur real gegen
die jeweilige URL bzw. https://cdn.simpleicons.org/<slug> geprüft
gesetzt, sonst NULL statt geraten) sowie icon_filename/icon_content_type
(Cache, analog workspace_webapps).
Neuer Icon-Fetch: fetch_merkmal_icon() probiert zuerst den Simple-Icons-
Slug, sonst fetch_favicon() der Homepage (bestehende Funktion aus dem
Webapp-Mechanismus direkt wiederverwendet) - Kombi aus beidem war die
Nutzer-Entscheidung in der Plan-Klärungsrunde. aktualisiere_merkmal_icon()
ist ein eigener, wiederholbar aufrufbarer Schritt (POST /api/v1/merkmale/
{id}/icon/aktualisieren) statt Teil des Anlegens, weil Merkmale per
Migration entstehen, nicht per API-Call mit sofortigem Netzwerk-Kontext.
Auslieferung über GET /merkmal-icons/{filename}, gleiches Muster wie
/webapp-icons.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLk93dhDMrkPXefVdknMV9
Webapps bekommen zwei neue, optionale Eigenschaften (Migration 0043):
kategorie_id (FK auf kategorien, nullable) und kiosk_modus (Boolean).
Kein eigener "Webapps"-Menüpunkt (per Nutzer-Feedback in der Plan-Runde
verworfen) - stattdessen ordnet sich eine Webapp optional einer der
bestehenden App-Kategorien zu, KATEGORIE_ZU_XDG_CATEGORIES übersetzt das
in eine echte Freedesktop-Categories=-Zeile fürs .desktop-Menü (Default
unverändert Network;WebBrowser; ohne gewählte Kategorie).
Kiosk-Modus: bei aktiviertem kiosk_modus löst der Server (nicht das
Gerät) anhand der Workspace-Merkmal-Zuordnung auf, welcher Browser das
Kiosk-Fenster öffnet (Chrome bevorzugt, Chromium Fallback, sonst normaler
Tab) - _resolve_kiosk_browser() in fetch_workspace_webapps().
Migration 0044: Chromium + Microsoft Edge als neue Browser-Merkmale
(Google Chrome existiert bereits aus Migration 0031). Chromium bewusst
NUR für debian-image/mint-image blueprint-verknüpft, nicht ubuntu-image -
recherchiert: Ubuntus "chromium"-Paket ist seit 19.10 nur ein
transitionelles Paket, das im Hintergrund Snap nachzieht (passt nicht zu
unserem Modell), während Debian und Mint ein echtes .deb bauen. Microsoft
Edge über das offizielle, distributionsunabhängige Microsoft-Repo auf
allen drei Backends.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLk93dhDMrkPXefVdknMV9
- Migration 0041: "Buero & Produktivitaet" -> "Büro & Produktivität"
(ASCII-Ersatzschreibweise, key unveraendert - Fremdschluessel laufen
ueber kategorie_id, nicht ueber key).
- Migration 0042: fedora-Backend nach Nutzer-Bestaetigung komplett
entfernt (siehe Rueckfrage bei Migration 0040) - dazu erst die eine
darauf verweisende Bereitstellungsvorlage ("Schulcomputer (Fedora)")
und ihre 4 historischen Zuweisungen an bereits archivierte Testgeraete
geloescht (sonst ON DELETE RESTRICT), dann das Backend selbst
(Blueprints kaskadieren automatisch mit).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLk93dhDMrkPXefVdknMV9
- debug_mode_until wurde beim Ablaufen nie geloescht - Auftragskatalog-
Seite und Geraeteliste zeigten den Debug-Modus dadurch dauerhaft als
aktiv an, auch Tage nach Ablauf (live an zwei echten Geraeten gefunden,
abgelaufen am 02./09.09., trotzdem noch "aktiv" angezeigt).
_health_felder_aus_row() liefert das Feld jetzt nur noch, wenn es
tatsaechlich noch in der Zukunft liegt.
- fetch_unassigned_devices() (Flows "Unbestaetigte Geraete") hatte den
archived_at-Filter nie bekommen, den fetch_devices_for_organization()/
fetch_all_devices() schon hatten - bereits geloeschte Geraete ohne
Zuweisung erschienen dadurch dauerhaft als offene Aufgabe.
- Migration 0040: Backend-Namen gekuerzt (Debian/Mint/Ubuntu statt
"... (Golden Image) ..."), altes "mint"-Backend (vor dem Golden-Image-
Pivot, keine Bereitstellungsvorlage nutzt es mehr) geloescht. "fedora"
bewusst NICHT angefasst - echte Bereitstellungsvorlage+Zuweisungen
haengen dran, siehe Rueckfrage an den Nutzer.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLk93dhDMrkPXefVdknMV9
- Migration 0039: organizations.hostname_praefix/-stellen/-nummer_modus/
-naechste_sequenz. Leerer Präfix = keine Konvention (unverändertes
Verhalten, Client bestimmt den Hostnamen selbst).
- generate_hostname_for_organization(): erzeugt "<praefix>-<nummer>",
sequenziell (Zeilen-Lock via FOR UPDATE) oder zufällig (freie Nummer
per secrets.randbelow(), Kollisionsprüfung gegen vorhandene Hostnamen,
Fallback auf nächste freie sequenzielle Nummer nach 20 Versuchen).
- resolve_hostname_for_activation(): greift nur bei einem GENUIN NEUEN
Gerät (device_fingerprint noch unbekannt) - eine Re-Aktivierung eines
bekannten Geräts behält immer den vom Client gemeldeten Hostnamen,
überschreibt also keine manuelle Umbenennung.
- agent_checkin(): liefert jetzt auch "hostname" (devices.hostname) an
den Agenten.
- Neue Endpunkte GET/PUT /api/v1/organizations/{id}/hostname-konvention.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLk93dhDMrkPXefVdknMV9
- Migration 0038: gruppen.workspace_id (nullable FK), device_merkmale
Tabelle entfernt (keine Datenzeilen auf anode, geprüft vor Drop).
- set_gruppe_workspace()/clear_gruppe_workspace(): weist einer
Gerätegruppe einen alternativen Workspace zu, ersetzt die komplette
Baseline für Mitgliedsgeräte statt nur einzelner Merkmale. Prüft
Organisationszugehörigkeit des Workspace (global oder eigene Org) und
die Exklusivitätsregel (ein Gerät nur in einer workspace-tragenden
Gruppe gleichzeitig) - sowohl beim Zuweisen als auch beim Hinzufügen
eines Geräts zu einer bereits workspace-tragenden Gruppe.
- resolve_effective_workspace_id(): neue Auflösungsstufe zwischen
Bereitstellungsvorlage und OE-/Gruppen-Merkmal-Overrides.
- fetch_auftragskatalog_state()/_listing(): device_merkmale-Override-Ebene
entfernt (gewann bisher immer), select_auftrag/deselect_auftrag-
Endpunkte + set_auftrag_selection() entfernt. get_device_auftragskatalog
bleibt als reine Ist-Zustand-Anzeige.
- Neuer Endpunkt GET /api/v1/organizations/{id}/workspaces (global +
eigene, org-gefiltert - fetch_workspaces() bleibt admin-only, würde
sonst fremde private Workspaces preisgeben).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLk93dhDMrkPXefVdknMV9
Ergaenzung zum bisherigen rein kundeneigenen workspace_webapps: Admin
kann jetzt zusaetzlich global wiederverwendbare Vorlagen anlegen
('bereitstellen und zur Auswahl stellen'), Kunden aktivieren sie pro
Workspace zusaetzlich zu weiterhin frei erstellbaren eigenen
Eintraegen ('Kunden koennen selbst welche erstellen').
Neue Tabelle webapp_templates (Migration 0033, diesmal korrekt ueber
TUXFLOTTE_DATABASE_URL statt sudo-postgres angewendet - siehe Lehre aus
dem vorherigen Owner-Bug). workspace_webapps bekommt ein nullable
template_id (ON DELETE SET NULL) zur Aktivierungs-Nachverfolgung.
activate_webapp_template() kopiert Name/URL/Icon-Datei PHYSISCH unter
einem neuen, vom eigenen Eintrag abgeleiteten Dateinamen - keine
laufende Referenz auf die Vorlagen-Icon-Datei, sonst wuerde ein
spaeteres Loeschen/Aktualisieren der Vorlage die schon aktivierte Kopie
mit betreffen.
Neue Endpunkte: /api/v1/webapp-templates (CRUD),
/api/v1/workspaces/{id}/webapp-templates/available (noch nicht
aktivierte Vorlagen fuer einen Workspace), .../activate.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLk93dhDMrkPXefVdknMV9
Nachtrag: Migration 0030 (App-Store-Batch-1-Merkmale) war im letzten
Commit versehentlich nicht mit dabei - jetzt nachgeholt (git status hat
es aufgedeckt).
Neue Tabelle workspace_webapps (Migration 0032): kundeneigene
{name, url}-Eintraege pro Workspace, kein fester Katalog wie bei
Merkmalen - jede Organisation/jeder Workspace hat ihre/seine eigene
Liste (Nutzer-Anforderung 09.09.2026: 'der Kunde hat diverse URLs').
app.py-Aenderungen:
- fetch_favicon(): bestes-Effort-Ermittlung des Website-Favicons
(erst <link rel=icon> per Regex aus dem HTML, sonst /favicon.ico an
der Domain-Wurzel) - bewusst ohne neue pip-Abhaengigkeit (nur
urllib, passt zum bisher sehr schlanken requirements.txt).
- CRUD-Endpunkte /api/v1/workspaces/{id}/webapps[/{webapp_id}]
(GET/POST/PUT/DELETE), Icon-Serving unter /webapp-icons/{filename}
(unauthentifiziert wie /golden-images/, gleicher
Path-Traversal-Schutz).
- Checkin-Response um 'webapps' erweitert (fetch_workspace_webapps(),
gleiches assignments->bereitstellungsvorlagen-Join-Muster wie
fetch_assigned_blueprints()).
- WICHTIG: Server komponiert nie eine eigene oeffentliche URL (ANODE_URL
ist nur client-seitig bekannt, siehe agent.py/backend.sh) - Checkin
liefert nur den relativen icon_path, der Agent haengt ANODE_URL davor.
Gehört zusammen mit admin/ansible-content (neue Rolle
webapp-shortcuts, echt end-to-end getestet) und admin/kundenplattform
(Admin-UI unter /admin/technik/workspaces/{id}, Icon-Proxy analog zum
bestehenden ISO-Download-Proxy-Muster).
Live auf anode angewendet: Migration 0032 (workspace_webapps-Tabelle).
app.py-Deployment (git pull + Neustart) folgt separat.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLk93dhDMrkPXefVdknMV9