- Incremented application version to 0.7.2 and updated database schema version to 20260427025. - Enhanced maturity models functionality to support M:N relationships for focus areas, style directions, and target groups. - Updated frontend to allow multi-selection for focus areas, style directions, and target groups. - Documented changes in the changelog for version 0.7.2, including new migration details and UI improvements.
161 lines
6.7 KiB
SQL
161 lines
6.7 KiB
SQL
-- Migration 025: Reifegradmodell-Kontext als M:N (Fokusbereich, Stilrichtung, Zielgruppe)
|
||
-- + Bootstrap: ein Modell aus allen importierten Skills (Wiki / Migration 023)
|
||
-- Datum: 2026-04-27
|
||
|
||
-- ============================================================================
|
||
-- JUNCTION TABLES
|
||
-- ============================================================================
|
||
|
||
CREATE TABLE IF NOT EXISTS maturity_model_focus_areas (
|
||
id SERIAL PRIMARY KEY,
|
||
maturity_model_id INT NOT NULL REFERENCES maturity_models(id) ON DELETE CASCADE,
|
||
focus_area_id INT NOT NULL REFERENCES focus_areas(id) ON DELETE CASCADE,
|
||
is_primary BOOLEAN DEFAULT false,
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
UNIQUE (maturity_model_id, focus_area_id)
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_mmfa_model ON maturity_model_focus_areas(maturity_model_id);
|
||
CREATE INDEX IF NOT EXISTS idx_mmfa_focus ON maturity_model_focus_areas(focus_area_id);
|
||
|
||
CREATE TABLE IF NOT EXISTS maturity_model_style_directions (
|
||
id SERIAL PRIMARY KEY,
|
||
maturity_model_id INT NOT NULL REFERENCES maturity_models(id) ON DELETE CASCADE,
|
||
style_direction_id INT NOT NULL REFERENCES style_directions(id) ON DELETE CASCADE,
|
||
is_primary BOOLEAN DEFAULT false,
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
UNIQUE (maturity_model_id, style_direction_id)
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_mmsd_model ON maturity_model_style_directions(maturity_model_id);
|
||
CREATE INDEX IF NOT EXISTS idx_mmsd_style ON maturity_model_style_directions(style_direction_id);
|
||
|
||
CREATE TABLE IF NOT EXISTS maturity_model_target_groups (
|
||
id SERIAL PRIMARY KEY,
|
||
maturity_model_id INT NOT NULL REFERENCES maturity_models(id) ON DELETE CASCADE,
|
||
target_group_id INT NOT NULL REFERENCES target_groups(id) ON DELETE CASCADE,
|
||
is_primary BOOLEAN DEFAULT false,
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
UNIQUE (maturity_model_id, target_group_id)
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_mmtg_model ON maturity_model_target_groups(maturity_model_id);
|
||
CREATE INDEX IF NOT EXISTS idx_mmtg_tg ON maturity_model_target_groups(target_group_id);
|
||
|
||
-- ============================================================================
|
||
-- Daten aus 1:1-FKs übernehmen (falls Spalten noch existieren), dann FK-Spalten entfernen
|
||
-- ============================================================================
|
||
|
||
DO $$
|
||
BEGIN
|
||
IF EXISTS (
|
||
SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = 'public' AND table_name = 'maturity_models' AND column_name = 'focus_area_id'
|
||
) THEN
|
||
INSERT INTO maturity_model_focus_areas (maturity_model_id, focus_area_id, is_primary)
|
||
SELECT id, focus_area_id, true
|
||
FROM maturity_models
|
||
WHERE focus_area_id IS NOT NULL
|
||
ON CONFLICT (maturity_model_id, focus_area_id) DO NOTHING;
|
||
END IF;
|
||
|
||
IF EXISTS (
|
||
SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = 'public' AND table_name = 'maturity_models' AND column_name = 'style_direction_id'
|
||
) THEN
|
||
INSERT INTO maturity_model_style_directions (maturity_model_id, style_direction_id, is_primary)
|
||
SELECT id, style_direction_id, true
|
||
FROM maturity_models
|
||
WHERE style_direction_id IS NOT NULL
|
||
ON CONFLICT (maturity_model_id, style_direction_id) DO NOTHING;
|
||
END IF;
|
||
|
||
IF EXISTS (
|
||
SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = 'public' AND table_name = 'maturity_models' AND column_name = 'target_group_id'
|
||
) THEN
|
||
INSERT INTO maturity_model_target_groups (maturity_model_id, target_group_id, is_primary)
|
||
SELECT id, target_group_id, true
|
||
FROM maturity_models
|
||
WHERE target_group_id IS NOT NULL
|
||
ON CONFLICT (maturity_model_id, target_group_id) DO NOTHING;
|
||
END IF;
|
||
END $$;
|
||
|
||
ALTER TABLE maturity_models DROP CONSTRAINT IF EXISTS maturity_models_context_name_unique;
|
||
|
||
ALTER TABLE maturity_models DROP COLUMN IF EXISTS focus_area_id;
|
||
ALTER TABLE maturity_models DROP COLUMN IF EXISTS style_direction_id;
|
||
ALTER TABLE maturity_models DROP COLUMN IF EXISTS target_group_id;
|
||
|
||
CREATE UNIQUE INDEX IF NOT EXISTS idx_maturity_models_wiki_import
|
||
ON maturity_models(import_source, import_id)
|
||
WHERE import_id IS NOT NULL;
|
||
|
||
-- ============================================================================
|
||
-- Bootstrap: Standard-Modell für alle Skills aus der Wiki-Matrix (Migration 023)
|
||
-- ============================================================================
|
||
|
||
DO $$
|
||
DECLARE
|
||
mid INT;
|
||
n_skills INT;
|
||
BEGIN
|
||
SELECT COUNT(*) INTO n_skills FROM skills;
|
||
IF n_skills = 0 THEN
|
||
RAISE NOTICE 'Bootstrap: keine Skills – übersprungen';
|
||
RETURN;
|
||
END IF;
|
||
|
||
SELECT id INTO mid FROM maturity_models WHERE import_id = 'faehigkeitsmatrix_karatetrainer' LIMIT 1;
|
||
IF mid IS NOT NULL THEN
|
||
RAISE NOTICE 'Bootstrap: Modell bereits vorhanden (id=%)', mid;
|
||
RETURN;
|
||
END IF;
|
||
|
||
INSERT INTO maturity_models (name, description, level_count, status, import_source, import_id, version)
|
||
VALUES (
|
||
'Fähigkeitsmatrix (Wiki Import)',
|
||
'Alle Fähigkeiten aus der Wiki-Matrix (Karatetrainer). Haupt- und Untergruppen kommen aus skill_main_categories / skill_categories.',
|
||
5,
|
||
'active',
|
||
'wiki_matrix',
|
||
'faehigkeitsmatrix_karatetrainer',
|
||
'1.0'
|
||
)
|
||
RETURNING id INTO mid;
|
||
|
||
INSERT INTO maturity_model_focus_areas (maturity_model_id, focus_area_id, is_primary)
|
||
SELECT mid, fa.id, (fa.name = 'Karate')
|
||
FROM focus_areas fa
|
||
WHERE fa.name IN ('Karate', 'Selbstverteidigung', 'Gewaltschutz')
|
||
ON CONFLICT (maturity_model_id, focus_area_id) DO NOTHING;
|
||
|
||
INSERT INTO model_levels (maturity_model_id, level_number, name, description, sort_order)
|
||
VALUES
|
||
(mid, 1, 'Einsteiger', NULL, 1),
|
||
(mid, 2, 'Grundlagen', NULL, 2),
|
||
(mid, 3, 'Aufbau', NULL, 3),
|
||
(mid, 4, 'Fortgeschritten', NULL, 4),
|
||
(mid, 5, 'Experte', NULL, 5);
|
||
|
||
INSERT INTO model_skills (maturity_model_id, skill_id, sort_order, relevance)
|
||
SELECT
|
||
mid,
|
||
s.id,
|
||
ROW_NUMBER() OVER (
|
||
ORDER BY mc.sort_order NULLS LAST, sc.sort_order NULLS LAST, s.name
|
||
),
|
||
NULL
|
||
FROM skills s
|
||
LEFT JOIN skill_categories sc ON s.category_id = sc.id
|
||
LEFT JOIN skill_main_categories mc ON s.main_category_id = mc.id;
|
||
|
||
INSERT INTO model_skill_levels (maturity_model_id, skill_id, level_number, description, observable_criteria)
|
||
SELECT mid, sld.skill_id, sld.level, sld.description, NULL
|
||
FROM skill_level_definitions sld
|
||
ON CONFLICT (maturity_model_id, skill_id, level_number) DO NOTHING;
|
||
|
||
RAISE NOTICE 'Bootstrap: Reifegradmodell id=% angelegt (% Skills)', mid, n_skills;
|
||
END $$;
|