shinkan-jinkendo/backend/migrations/025_maturity_model_context_mn.sql
Lars f1ee1eec7e
Some checks failed
Deploy Development / deploy (push) Successful in 35s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 5s
Test Suite / playwright-tests (push) Failing after 1m55s
feat: update maturity models and version to 0.7.2
- 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.
2026-04-27 11:42:03 +02:00

161 lines
6.7 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 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 $$;