BEGIN; -- Workspace-Creator neu, Schritt C (07.10.2026, siehe -- platform-docs/roadmap/workspace-creator-neu.md): Datenmodell für -- Distro am Workspace, Versionen, Workspace an der OE, Kundengruppen und -- Gruppen-Webapps. Rein additiv mit Rückfüllung - der bisherige Inhalt -- jedes Workspace wird zu Version 1, am Soll-Zustand eines Geräts ändert -- sich nichts. Die alten Strukturen (workspace_merkmale, -- gruppen.workspace_id) entfernt erst 0051, nachdem der neue Code läuft. -- Kundengruppen: steuern, welche Vorlagen eine Organisation sieht (eine -- Schule braucht keine KMU-Vorlagen und umgekehrt). CREATE TABLE kundengruppen ( id UUID PRIMARY KEY, key TEXT NOT NULL UNIQUE, name TEXT NOT NULL, sort_order INTEGER NOT NULL DEFAULT 0 ); INSERT INTO kundengruppen (id, key, name, sort_order) VALUES (gen_random_uuid(), 'schule', 'Schule', 10), (gen_random_uuid(), 'unternehmen', 'Unternehmen', 20); ALTER TABLE organizations ADD COLUMN kundengruppe_id UUID REFERENCES kundengruppen(id) ON DELETE SET NULL; -- Alle bisherigen Organisationen sind Schulen bzw. Schul-Testumgebungen. UPDATE organizations SET kundengruppe_id = (SELECT id FROM kundengruppen WHERE key = 'schule'); -- "Eigene Workspaces" als buchbare Leistung je Organisation (Kunden-Admin -- bekommt dann einen eingeschränkten Assistenten, Schritt G). ALTER TABLE organizations ADD COLUMN darf_eigene_workspaces BOOLEAN NOT NULL DEFAULT FALSE; -- Workspace: Distro (fest, NULL nur für Bestand, der noch mehrere Distros -- bedient - wird in der Bestandsmigration aufgeteilt), Vorlagen-Kennzeichen -- und Sichtbarkeit. organization_id bleibt der Eigentümer (NULL = Tuxflotte). ALTER TABLE workspaces ADD COLUMN backend_id UUID REFERENCES backends(id) ON DELETE RESTRICT; ALTER TABLE workspaces ADD COLUMN ist_vorlage BOOLEAN NOT NULL DEFAULT FALSE; ALTER TABLE workspaces ADD COLUMN sichtbarkeit TEXT NOT NULL DEFAULT 'organisation' CHECK (sichtbarkeit IN ('global', 'kundengruppe', 'organisation')); UPDATE workspaces SET sichtbarkeit = 'global', ist_vorlage = TRUE WHERE organization_id IS NULL; -- Bei sichtbarkeit = 'kundengruppe' bzw. 'organisation': für wen genau. -- Ein Workspace, der einer Organisation gehört, ist für sie immer sichtbar. CREATE TABLE workspace_freigabe_kundengruppen ( workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE, kundengruppe_id UUID NOT NULL REFERENCES kundengruppen(id) ON DELETE CASCADE, PRIMARY KEY (workspace_id, kundengruppe_id) ); CREATE TABLE workspace_freigabe_organisationen ( workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE, organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, PRIMARY KEY (workspace_id, organization_id) ); -- Versionen: Inhalt (Merkmale, Webapps) hängt an einer Version. Höchstens -- ein Entwurf je Workspace; Veröffentlichen friert den Inhalt ein. CREATE TABLE workspace_versionen ( id UUID PRIMARY KEY, workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE, nummer INTEGER NOT NULL, status TEXT NOT NULL CHECK (status IN ('entwurf', 'veroeffentlicht')), notiz TEXT, erstellt_am TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, veroeffentlicht_am TIMESTAMPTZ, UNIQUE (workspace_id, nummer) ); CREATE UNIQUE INDEX workspace_versionen_ein_entwurf ON workspace_versionen (workspace_id) WHERE status = 'entwurf'; CREATE TABLE workspace_version_merkmale ( workspace_version_id UUID NOT NULL REFERENCES workspace_versionen(id) ON DELETE CASCADE, merkmal_id UUID NOT NULL REFERENCES merkmale(id) ON DELETE CASCADE, PRIMARY KEY (workspace_version_id, merkmal_id) ); -- Bestand wird Version 1 (veröffentlicht), Inhalt 1:1 übernommen. INSERT INTO workspace_versionen (id, workspace_id, nummer, status, notiz, erstellt_am, veroeffentlicht_am) SELECT gen_random_uuid(), w.id, 1, 'veroeffentlicht', 'Übernommen aus dem Bestand (Migration 0050)', w.created_at, CURRENT_TIMESTAMP FROM workspaces w; INSERT INTO workspace_version_merkmale (workspace_version_id, merkmal_id) SELECT v.id, wm.merkmal_id FROM workspace_merkmale wm JOIN workspace_versionen v ON v.workspace_id = wm.workspace_id AND v.nummer = 1; -- Webapps gehören künftig zu einer Version (workspace_id bleibt als -- Abkürzung erhalten). Eine Webapp-Zeile gibt es je Version; beim Anlegen -- einer neuen Version werden die Zeilen kopiert (Icon-Datei wird geteilt). ALTER TABLE workspace_webapps ADD COLUMN workspace_version_id UUID REFERENCES workspace_versionen(id) ON DELETE CASCADE; UPDATE workspace_webapps ww SET workspace_version_id = v.id FROM workspace_versionen v WHERE v.workspace_id = ww.workspace_id AND v.nummer = 1; ALTER TABLE workspace_webapps ALTER COLUMN workspace_version_id SET NOT NULL; -- Workspace an der OE (vererbt den Baum hinunter): gepinnte Version und -- Haken "künftige Versionen automatisch übernehmen". ALTER TABLE organisationseinheiten ADD COLUMN workspace_id UUID REFERENCES workspaces(id) ON DELETE RESTRICT; ALTER TABLE organisationseinheiten ADD COLUMN workspace_version_id UUID REFERENCES workspace_versionen(id) ON DELETE RESTRICT; ALTER TABLE organisationseinheiten ADD COLUMN automatisch_aktualisieren BOOLEAN NOT NULL DEFAULT TRUE; ALTER TABLE organisationseinheiten ADD CONSTRAINT oe_workspace_version_nur_mit_workspace CHECK (workspace_version_id IS NULL OR workspace_id IS NOT NULL); -- Gruppen ergänzen künftig auch Webapps (Merkmale schon über gruppen_merkmale). CREATE TABLE gruppen_webapps ( id UUID PRIMARY KEY, gruppe_id UUID NOT NULL REFERENCES gruppen(id) ON DELETE CASCADE, name TEXT NOT NULL, url TEXT NOT NULL, icon_filename TEXT, icon_content_type TEXT, kategorie_id UUID REFERENCES kategorien(id) ON DELETE SET NULL, kiosk_modus BOOLEAN NOT NULL DEFAULT FALSE, template_id UUID REFERENCES webapp_templates(id) ON DELETE SET NULL, sort_order INTEGER NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); COMMIT;