-- Migration 024: Reifegradmodelle / Fähigkeitsmatrix (kontextbezogen) -- Datum: 2026-04-27 -- ============================================================================ -- MATURITY MODELS -- ============================================================================ CREATE TABLE IF NOT EXISTS maturity_models ( id SERIAL PRIMARY KEY, name VARCHAR(200) NOT NULL, description TEXT, focus_area_id INT REFERENCES focus_areas(id) ON DELETE RESTRICT, style_direction_id INT REFERENCES style_directions(id) ON DELETE RESTRICT, target_group_id INT REFERENCES target_groups(id) ON DELETE RESTRICT, level_count INT NOT NULL DEFAULT 5 CHECK (level_count BETWEEN 3 AND 10), status VARCHAR(20) DEFAULT 'draft' CHECK (status IN ('draft', 'active', 'archived')), version VARCHAR(20) DEFAULT '1.0', created_by INT REFERENCES profiles(id) ON DELETE SET NULL, club_id INT REFERENCES clubs(id) ON DELETE SET NULL, import_source VARCHAR(50), import_id VARCHAR(200), created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), CONSTRAINT maturity_models_context_name_unique UNIQUE (name, focus_area_id, style_direction_id, target_group_id) ); -- ============================================================================ -- MODEL LEVELS (Stufen-Labels pro Modell) -- ============================================================================ CREATE TABLE IF NOT EXISTS model_levels ( id SERIAL PRIMARY KEY, maturity_model_id INT NOT NULL REFERENCES maturity_models(id) ON DELETE CASCADE, level_number INT NOT NULL CHECK (level_number >= 1), name VARCHAR(100) NOT NULL, description TEXT, sort_order INT NOT NULL, created_at TIMESTAMP DEFAULT NOW(), UNIQUE(maturity_model_id, level_number) ); -- ============================================================================ -- MODEL SKILLS: Welche Fähigkeiten sind im Modell geführt (Matrix-Zeilen) -- ============================================================================ CREATE TABLE IF NOT EXISTS model_skills ( id SERIAL PRIMARY KEY, maturity_model_id INT NOT NULL REFERENCES maturity_models(id) ON DELETE CASCADE, skill_id INT NOT NULL REFERENCES skills(id) ON DELETE CASCADE, sort_order INT NOT NULL DEFAULT 0, relevance VARCHAR(50), created_at TIMESTAMP DEFAULT NOW(), UNIQUE(maturity_model_id, skill_id) ); CREATE INDEX IF NOT EXISTS idx_model_skills_model ON model_skills(maturity_model_id); CREATE INDEX IF NOT EXISTS idx_model_skills_skill ON model_skills(skill_id); -- ============================================================================ -- MODEL SKILL LEVELS (Zelltexte der Matrix) -- ============================================================================ CREATE TABLE IF NOT EXISTS model_skill_levels ( id SERIAL PRIMARY KEY, maturity_model_id INT NOT NULL REFERENCES maturity_models(id) ON DELETE CASCADE, skill_id INT NOT NULL REFERENCES skills(id) ON DELETE CASCADE, level_number INT NOT NULL CHECK (level_number >= 1), description TEXT NOT NULL, observable_criteria TEXT, example_exercise_hints JSONB, ai_generated BOOLEAN DEFAULT false, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), UNIQUE(maturity_model_id, skill_id, level_number) ); -- ============================================================================ -- SKILLS: optionale Matrix-Felder (Spec) -- ============================================================================ ALTER TABLE skills ADD COLUMN IF NOT EXISTS primary_focus_area_id INT REFERENCES focus_areas(id) ON DELETE SET NULL; ALTER TABLE skills ADD COLUMN IF NOT EXISTS is_cross_domain BOOLEAN DEFAULT false; -- ============================================================================ -- INDEXES -- ============================================================================ CREATE INDEX IF NOT EXISTS idx_maturity_models_focus ON maturity_models(focus_area_id); CREATE INDEX IF NOT EXISTS idx_maturity_models_style ON maturity_models(style_direction_id); CREATE INDEX IF NOT EXISTS idx_maturity_models_target ON maturity_models(target_group_id); CREATE INDEX IF NOT EXISTS idx_maturity_models_status ON maturity_models(status); CREATE INDEX IF NOT EXISTS idx_model_levels_model ON model_levels(maturity_model_id); CREATE INDEX IF NOT EXISTS idx_model_skill_levels_model ON model_skill_levels(maturity_model_id); CREATE INDEX IF NOT EXISTS idx_model_skill_levels_skill ON model_skill_levels(skill_id); CREATE INDEX IF NOT EXISTS idx_skills_primary_focus ON skills(primary_focus_area_id); -- ============================================================================ -- TRIGGERS updated_at -- ============================================================================ DROP TRIGGER IF EXISTS maturity_models_update ON maturity_models; CREATE TRIGGER maturity_models_update BEFORE UPDATE ON maturity_models FOR EACH ROW EXECUTE FUNCTION update_timestamp(); DROP TRIGGER IF EXISTS model_skill_levels_update ON model_skill_levels; CREATE TRIGGER model_skill_levels_update BEFORE UPDATE ON model_skill_levels FOR EACH ROW EXECUTE FUNCTION update_timestamp();