-- Benutzergruppen (Teams): Rollen koennen einer ganzen Gruppe auf einer -- Hostgruppe gewaehrt werden ("Verbindungen mit einer Gruppe teilen"), -- statt jedes Mitglied einzeln ueber user_hostgroup_roles pflegen zu -- muessen. Volle Rollen-Vererbung: jedes aktuelle und zukuenftige -- Mitglied der Gruppe erhaelt automatisch alle der Gruppe gewaehrten -- Rollen (Durchsetzung in app/rbac.py: user_has_role() vereinigt direkte -- User-Grants mit Grants ueber Gruppenmitgliedschaft). CREATE TABLE IF NOT EXISTS user_groups ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, description TEXT, created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')) ); CREATE TABLE IF NOT EXISTS user_group_members ( user_group_id INTEGER NOT NULL REFERENCES user_groups(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, added_by INTEGER REFERENCES users(id), added_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')), PRIMARY KEY (user_group_id, user_id) ); CREATE INDEX IF NOT EXISTS idx_ugm_user ON user_group_members(user_id); CREATE TABLE IF NOT EXISTS group_hostgroup_roles ( user_group_id INTEGER NOT NULL REFERENCES user_groups(id) ON DELETE CASCADE, host_group_id INTEGER NOT NULL REFERENCES host_groups(id) ON DELETE CASCADE, role_id INTEGER NOT NULL REFERENCES roles(id), granted_by INTEGER REFERENCES users(id), granted_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')), expires_at TEXT, PRIMARY KEY (user_group_id, host_group_id, role_id) ); CREATE INDEX IF NOT EXISTS idx_ghr_group ON group_hostgroup_roles(user_group_id); CREATE INDEX IF NOT EXISTS idx_ghr_hostgroup ON group_hostgroup_roles(host_group_id);