-- Migration 057: Kanon EAV-primär für erweiterte Trainingsmetriken -- Date: 2026-04-15 -- activity_log-Spalten bleiben erhalten (Lesefallback / API); training_parameters.source_field -- wird für diese Keys entfernt. Idempotenter EAV-Backfill aus Spalten (wie 055), dann source_field NULL. -- Siehe: backend/data_layer/activity_data_canon.py -- min_hr (Spalte hr_min) INSERT INTO activity_session_metrics ( activity_log_id, training_parameter_id, value_num, value_int, value_text, value_bool, updated_at ) SELECT a.id, tp.id, NULL, a.hr_min, NULL, NULL, NOW() FROM activity_log a JOIN training_parameters tp ON tp.key = 'min_hr' AND tp.is_active = true WHERE a.hr_min IS NOT NULL ON CONFLICT (activity_log_id, training_parameter_id) DO NOTHING; INSERT INTO activity_session_metrics ( activity_log_id, training_parameter_id, value_num, value_int, value_text, value_bool, updated_at ) SELECT a.id, tp.id, a.pace_min_per_km::double precision, NULL, NULL, NULL, NOW() FROM activity_log a JOIN training_parameters tp ON tp.key = 'pace_min_per_km' AND tp.is_active = true WHERE a.pace_min_per_km IS NOT NULL ON CONFLICT (activity_log_id, training_parameter_id) DO NOTHING; INSERT INTO activity_session_metrics ( activity_log_id, training_parameter_id, value_num, value_int, value_text, value_bool, updated_at ) SELECT a.id, tp.id, NULL, a.cadence, NULL, NULL, NOW() FROM activity_log a JOIN training_parameters tp ON tp.key = 'cadence' AND tp.is_active = true WHERE a.cadence IS NOT NULL ON CONFLICT (activity_log_id, training_parameter_id) DO NOTHING; INSERT INTO activity_session_metrics ( activity_log_id, training_parameter_id, value_num, value_int, value_text, value_bool, updated_at ) SELECT a.id, tp.id, NULL, a.avg_power, NULL, NULL, NOW() FROM activity_log a JOIN training_parameters tp ON tp.key = 'avg_power' AND tp.is_active = true WHERE a.avg_power IS NOT NULL ON CONFLICT (activity_log_id, training_parameter_id) DO NOTHING; INSERT INTO activity_session_metrics ( activity_log_id, training_parameter_id, value_num, value_int, value_text, value_bool, updated_at ) SELECT a.id, tp.id, NULL, a.elevation_gain, NULL, NULL, NOW() FROM activity_log a JOIN training_parameters tp ON tp.key = 'elevation_gain' AND tp.is_active = true WHERE a.elevation_gain IS NOT NULL ON CONFLICT (activity_log_id, training_parameter_id) DO NOTHING; INSERT INTO activity_session_metrics ( activity_log_id, training_parameter_id, value_num, value_int, value_text, value_bool, updated_at ) SELECT a.id, tp.id, a.temperature_celsius::double precision, NULL, NULL, NULL, NOW() FROM activity_log a JOIN training_parameters tp ON tp.key = 'temperature_celsius' AND tp.is_active = true WHERE a.temperature_celsius IS NOT NULL ON CONFLICT (activity_log_id, training_parameter_id) DO NOTHING; INSERT INTO activity_session_metrics ( activity_log_id, training_parameter_id, value_num, value_int, value_text, value_bool, updated_at ) SELECT a.id, tp.id, NULL, a.humidity_percent, NULL, NULL, NOW() FROM activity_log a JOIN training_parameters tp ON tp.key = 'humidity_percent' AND tp.is_active = true WHERE a.humidity_percent IS NOT NULL ON CONFLICT (activity_log_id, training_parameter_id) DO NOTHING; INSERT INTO activity_session_metrics ( activity_log_id, training_parameter_id, value_num, value_int, value_text, value_bool, updated_at ) SELECT a.id, tp.id, a.avg_hr_percent::double precision, NULL, NULL, NULL, NOW() FROM activity_log a JOIN training_parameters tp ON tp.key = 'avg_hr_percent' AND tp.is_active = true WHERE a.avg_hr_percent IS NOT NULL ON CONFLICT (activity_log_id, training_parameter_id) DO NOTHING; INSERT INTO activity_session_metrics ( activity_log_id, training_parameter_id, value_num, value_int, value_text, value_bool, updated_at ) SELECT a.id, tp.id, a.kcal_per_km::double precision, NULL, NULL, NULL, NOW() FROM activity_log a JOIN training_parameters tp ON tp.key = 'kcal_per_km' AND tp.is_active = true WHERE a.kcal_per_km IS NOT NULL ON CONFLICT (activity_log_id, training_parameter_id) DO NOTHING; UPDATE training_parameters SET source_field = NULL WHERE key IN ( 'min_hr', 'pace_min_per_km', 'cadence', 'avg_power', 'elevation_gain', 'temperature_celsius', 'humidity_percent', 'avg_hr_percent', 'kcal_per_km' ); DO $$ BEGIN RAISE NOTICE 'Migration 057: EAV-primary canon — backfill + source_field cleared for extended metrics'; END $$;