-- Migration 014: Training Type Profiles & Activity Evaluation -- Training Type Profiles System - Schema Extensions -- Date: 2026-03-23 -- Issue: #15 -- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -- EXTEND TRAINING TYPES -- Add profile column for comprehensive training type configuration -- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ALTER TABLE training_types ADD COLUMN IF NOT EXISTS profile JSONB DEFAULT NULL; CREATE INDEX idx_training_types_profile_enabled ON training_types ((profile->'rule_sets'->'minimum_requirements'->>'enabled')) WHERE profile IS NOT NULL; COMMENT ON COLUMN training_types.profile IS 'Comprehensive training type profile with 7 dimensions (rule_sets, intensity_zones, training_effects, periodization, performance_indicators, safety, ai_context)'; -- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -- EXTEND ACTIVITY LOG -- Add evaluation results and quality labels -- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ALTER TABLE activity_log ADD COLUMN IF NOT EXISTS evaluation JSONB DEFAULT NULL; ALTER TABLE activity_log ADD COLUMN IF NOT EXISTS quality_label VARCHAR(20); ALTER TABLE activity_log ADD COLUMN IF NOT EXISTS overall_score FLOAT; CREATE INDEX idx_activity_quality_label ON activity_log(quality_label) WHERE quality_label IS NOT NULL; CREATE INDEX idx_activity_overall_score ON activity_log(overall_score DESC) WHERE overall_score IS NOT NULL; CREATE INDEX idx_activity_evaluation_passed ON activity_log ((evaluation->'rule_set_results'->'minimum_requirements'->>'passed')) WHERE evaluation IS NOT NULL; COMMENT ON COLUMN activity_log.evaluation IS 'Complete evaluation result (7 dimensions, scores, recommendations, warnings)'; COMMENT ON COLUMN activity_log.quality_label IS 'Quality label: excellent, good, acceptable, poor (for quick filtering)'; COMMENT ON COLUMN activity_log.overall_score IS 'Overall quality score 0.0-1.0 (for sorting)'; -- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -- ADD MISSING COLUMNS (if not already added by previous migrations) -- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -- Add HR columns if not exist (might be in Migration 008) DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='activity_log' AND column_name='hr_min') THEN ALTER TABLE activity_log ADD COLUMN hr_min INTEGER CHECK (hr_min > 0 AND hr_min < 200); END IF; END $$; -- Add performance columns for calculated values ALTER TABLE activity_log ADD COLUMN IF NOT EXISTS avg_hr_percent FLOAT; ALTER TABLE activity_log ADD COLUMN IF NOT EXISTS kcal_per_km FLOAT; ALTER TABLE activity_log ADD COLUMN IF NOT EXISTS pace_min_per_km FLOAT; ALTER TABLE activity_log ADD COLUMN IF NOT EXISTS cadence INTEGER; ALTER TABLE activity_log ADD COLUMN IF NOT EXISTS avg_power INTEGER; ALTER TABLE activity_log ADD COLUMN IF NOT EXISTS elevation_gain INTEGER; ALTER TABLE activity_log ADD COLUMN IF NOT EXISTS temperature_celsius FLOAT; ALTER TABLE activity_log ADD COLUMN IF NOT EXISTS humidity_percent INTEGER; COMMENT ON COLUMN activity_log.avg_hr_percent IS 'Average HR as percentage of user max HR (calculated)'; COMMENT ON COLUMN activity_log.kcal_per_km IS 'Calories burned per kilometer (calculated)'; -- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -- HELPER FUNCTION: Calculate avg_hr_percent -- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CREATE OR REPLACE FUNCTION calculate_avg_hr_percent() RETURNS TRIGGER AS $$ DECLARE user_max_hr INTEGER; BEGIN -- Get user's max HR from profile SELECT hf_max INTO user_max_hr FROM profiles WHERE id = NEW.profile_id; -- Calculate percentage if both values exist IF NEW.hr_avg IS NOT NULL AND user_max_hr IS NOT NULL AND user_max_hr > 0 THEN NEW.avg_hr_percent := (NEW.hr_avg::float / user_max_hr::float) * 100; END IF; -- Calculate kcal per km IF NEW.kcal_active IS NOT NULL AND NEW.distance_km IS NOT NULL AND NEW.distance_km > 0 THEN NEW.kcal_per_km := NEW.kcal_active::float / NEW.distance_km; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; -- Trigger for automatic calculation DROP TRIGGER IF EXISTS trg_calculate_performance_metrics ON activity_log; CREATE TRIGGER trg_calculate_performance_metrics BEFORE INSERT OR UPDATE ON activity_log FOR EACH ROW EXECUTE FUNCTION calculate_avg_hr_percent(); -- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -- SUMMARY -- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DO $$ BEGIN RAISE NOTICE '✓ Migration 014 completed'; RAISE NOTICE ' - Extended training_types with profile column'; RAISE NOTICE ' - Extended activity_log with evaluation columns'; RAISE NOTICE ' - Added performance metric calculations'; RAISE NOTICE ' - Created indexes for fast queries'; END $$;