mitai-jinkendo/backend/migrations/014_training_profiles.sql
Lars 1b9cd6d5e6
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
feat: Training Type Profiles - Phase 1.1 Foundation (#15)
## Implemented

### DB-Schema (Migrations)
- Migration 013: training_parameters table (16 standard parameters)
- Migration 014: training_types.profile + activity_log.evaluation columns
- Performance metric calculations (avg_hr_percent, kcal_per_km)

### Backend - Rule Engine
- RuleEvaluator: Generic rule evaluation with 9 operators
  - gte, lte, gt, lt, eq, neq, between, in, not_in
  - Weighted scoring system
  - Pass strategies: all_must_pass, weighted_score, at_least_n

- IntensityZoneEvaluator: HR zone analysis
- TrainingEffectsEvaluator: Abilities development

### Backend - Master Evaluator
- TrainingProfileEvaluator: 7-dimensional evaluation
  1. Minimum Requirements (Quality Gates)
  2. Intensity Zones (HR zones)
  3. Training Effects (Abilities)
  4. Periodization (Frequency & Recovery)
  5. Performance Indicators (KPIs)
  6. Safety (Warnings)
  7. AI Context (simplified for MVP)

- evaluation_helper.py: Utilities for loading + saving
- routers/evaluation.py: API endpoints
  - POST /api/evaluation/activity/{id}
  - POST /api/evaluation/batch
  - GET /api/evaluation/parameters

### Integration
- main.py: Router registration

## TODO (Phase 1.2)
- Auto-evaluation on activity INSERT/UPDATE
- Admin-UI for profile editing
- User-UI for results display

## Testing
-  Syntax checks passed
- 🔲 Runtime testing pending (after auto-evaluation)

Part of Issue #15 - Training Type Profiles System
2026-03-23 10:49:26 +01:00

115 lines
6.3 KiB
PL/PgSQL

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