Admin endpoints for profile configuration:
- Extended TrainingTypeCreate/Update models with profile field
- Added profile column to all SELECT queries
- Profile templates for Running, Meditation, Strength Training
- Template endpoints: list, get, apply
- Profile stats endpoint (configured/unconfigured count)
New file: profile_templates.py
- TEMPLATE_RUNNING: Endurance-focused with HR zones
- TEMPLATE_MEDITATION: Mental-focused (low HR ≤ instead of ≥)
- TEMPLATE_STRENGTH: Strength-focused
API Endpoints:
- GET /api/admin/training-types/profiles/templates
- GET /api/admin/training-types/profiles/templates/{key}
- POST /api/admin/training-types/{id}/profile/apply-template
- GET /api/admin/training-types/profiles/stats
Next: Frontend Admin-UI (ProfileEditor component)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
451 lines
15 KiB
Python
451 lines
15 KiB
Python
"""
|
|
Training Type Profile Templates
|
|
Pre-configured profiles for common training types.
|
|
|
|
Issue: #15
|
|
Date: 2026-03-23
|
|
"""
|
|
|
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
# TEMPLATE: LAUFEN (Running) - Ausdauer-fokussiert
|
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
|
|
TEMPLATE_RUNNING = {
|
|
"version": "1.0",
|
|
"name": "Laufen (Standard)",
|
|
"description": "Ausdauerlauf mit Herzfrequenz-Zonen",
|
|
|
|
"rule_sets": {
|
|
"minimum_requirements": {
|
|
"enabled": True,
|
|
"pass_strategy": "weighted_score",
|
|
"pass_threshold": 0.6,
|
|
"rules": [
|
|
{
|
|
"parameter": "duration_min",
|
|
"operator": "gte",
|
|
"value": 15,
|
|
"weight": 5,
|
|
"optional": False,
|
|
"reason": "Mindestens 15 Minuten für Trainingseffekt"
|
|
},
|
|
{
|
|
"parameter": "avg_hr",
|
|
"operator": "gte",
|
|
"value": 100,
|
|
"weight": 3,
|
|
"optional": False,
|
|
"reason": "Puls muss für Ausdauerreiz erhöht sein"
|
|
},
|
|
{
|
|
"parameter": "distance_km",
|
|
"operator": "gte",
|
|
"value": 1.0,
|
|
"weight": 2,
|
|
"optional": False,
|
|
"reason": "Mindestens 1 km Distanz"
|
|
}
|
|
]
|
|
},
|
|
|
|
"intensity_zones": {
|
|
"enabled": True,
|
|
"zones": [
|
|
{
|
|
"id": "regeneration",
|
|
"name": "Regeneration",
|
|
"color": "#4CAF50",
|
|
"effect": "Aktive Erholung",
|
|
"target_duration_min": 30,
|
|
"rules": [
|
|
{
|
|
"parameter": "avg_hr_percent",
|
|
"operator": "between",
|
|
"value": [50, 60]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "grundlagenausdauer",
|
|
"name": "Grundlagenausdauer",
|
|
"color": "#2196F3",
|
|
"effect": "Fettverbrennung, aerobe Basis",
|
|
"target_duration_min": 45,
|
|
"rules": [
|
|
{
|
|
"parameter": "avg_hr_percent",
|
|
"operator": "between",
|
|
"value": [60, 70]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "entwicklungsbereich",
|
|
"name": "Entwicklungsbereich",
|
|
"color": "#FF9800",
|
|
"effect": "VO2max-Training, Laktattoleranz",
|
|
"target_duration_min": 30,
|
|
"rules": [
|
|
{
|
|
"parameter": "avg_hr_percent",
|
|
"operator": "between",
|
|
"value": [70, 80]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "schwellentraining",
|
|
"name": "Schwellentraining",
|
|
"color": "#F44336",
|
|
"effect": "Anaerobe Schwelle, Wettkampftempo",
|
|
"target_duration_min": 20,
|
|
"rules": [
|
|
{
|
|
"parameter": "avg_hr_percent",
|
|
"operator": "between",
|
|
"value": [80, 90]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
|
|
"training_effects": {
|
|
"enabled": True,
|
|
"default_effects": {
|
|
"primary_abilities": [
|
|
{
|
|
"category": "konditionell",
|
|
"ability": "ausdauer",
|
|
"intensity": 5
|
|
}
|
|
],
|
|
"secondary_abilities": [
|
|
{
|
|
"category": "konditionell",
|
|
"ability": "schnelligkeit",
|
|
"intensity": 2
|
|
},
|
|
{
|
|
"category": "koordinativ",
|
|
"ability": "rhythmus",
|
|
"intensity": 3
|
|
},
|
|
{
|
|
"category": "psychisch",
|
|
"ability": "willenskraft",
|
|
"intensity": 4
|
|
}
|
|
]
|
|
},
|
|
"metabolic_focus": ["aerobic", "fat_oxidation"],
|
|
"muscle_groups": ["legs", "core", "cardiovascular"]
|
|
},
|
|
|
|
"periodization": {
|
|
"enabled": True,
|
|
"frequency": {
|
|
"per_week_optimal": 3,
|
|
"per_week_max": 5
|
|
},
|
|
"recovery": {
|
|
"min_hours_between": 24
|
|
}
|
|
},
|
|
|
|
"performance_indicators": {
|
|
"enabled": False
|
|
},
|
|
|
|
"safety": {
|
|
"enabled": True,
|
|
"warnings": [
|
|
{
|
|
"parameter": "avg_hr_percent",
|
|
"operator": "gt",
|
|
"value": 95,
|
|
"severity": "high",
|
|
"message": "Herzfrequenz zu hoch - Überbelastungsrisiko"
|
|
},
|
|
{
|
|
"parameter": "duration_min",
|
|
"operator": "gt",
|
|
"value": 180,
|
|
"severity": "medium",
|
|
"message": "Sehr lange Einheit - achte auf Regeneration"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
# TEMPLATE: MEDITATION - Mental-fokussiert (≤ statt ≥ bei HR!)
|
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
|
|
TEMPLATE_MEDITATION = {
|
|
"version": "1.0",
|
|
"name": "Meditation (Standard)",
|
|
"description": "Mentales Training mit niedrigem Puls",
|
|
|
|
"rule_sets": {
|
|
"minimum_requirements": {
|
|
"enabled": True,
|
|
"pass_strategy": "weighted_score",
|
|
"pass_threshold": 0.6,
|
|
"rules": [
|
|
{
|
|
"parameter": "duration_min",
|
|
"operator": "gte",
|
|
"value": 5,
|
|
"weight": 5,
|
|
"optional": False,
|
|
"reason": "Mindestens 5 Minuten für Entspannungseffekt"
|
|
},
|
|
{
|
|
"parameter": "avg_hr",
|
|
"operator": "lte",
|
|
"value": 80,
|
|
"weight": 4,
|
|
"optional": False,
|
|
"reason": "Niedriger Puls zeigt Entspannung an"
|
|
}
|
|
]
|
|
},
|
|
|
|
"intensity_zones": {
|
|
"enabled": True,
|
|
"zones": [
|
|
{
|
|
"id": "deep_relaxation",
|
|
"name": "Tiefenentspannung",
|
|
"color": "#4CAF50",
|
|
"effect": "Parasympathikus-Aktivierung",
|
|
"target_duration_min": 10,
|
|
"rules": [
|
|
{
|
|
"parameter": "avg_hr_percent",
|
|
"operator": "between",
|
|
"value": [35, 45]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "light_meditation",
|
|
"name": "Leichte Meditation",
|
|
"color": "#2196F3",
|
|
"effect": "Achtsamkeit, Fokus",
|
|
"target_duration_min": 15,
|
|
"rules": [
|
|
{
|
|
"parameter": "avg_hr_percent",
|
|
"operator": "between",
|
|
"value": [45, 55]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
|
|
"training_effects": {
|
|
"enabled": True,
|
|
"default_effects": {
|
|
"primary_abilities": [
|
|
{
|
|
"category": "kognitiv",
|
|
"ability": "konzentration",
|
|
"intensity": 5
|
|
},
|
|
{
|
|
"category": "psychisch",
|
|
"ability": "stressresistenz",
|
|
"intensity": 5
|
|
}
|
|
],
|
|
"secondary_abilities": [
|
|
{
|
|
"category": "kognitiv",
|
|
"ability": "wahrnehmung",
|
|
"intensity": 4
|
|
},
|
|
{
|
|
"category": "psychisch",
|
|
"ability": "selbstvertrauen",
|
|
"intensity": 3
|
|
}
|
|
]
|
|
},
|
|
"metabolic_focus": ["parasympathetic_activation"],
|
|
"muscle_groups": []
|
|
},
|
|
|
|
"periodization": {
|
|
"enabled": True,
|
|
"frequency": {
|
|
"per_week_optimal": 5,
|
|
"per_week_max": 7
|
|
},
|
|
"recovery": {
|
|
"min_hours_between": 0
|
|
}
|
|
},
|
|
|
|
"performance_indicators": {
|
|
"enabled": False
|
|
},
|
|
|
|
"safety": {
|
|
"enabled": True,
|
|
"warnings": [
|
|
{
|
|
"parameter": "avg_hr",
|
|
"operator": "gt",
|
|
"value": 100,
|
|
"severity": "medium",
|
|
"message": "Herzfrequenz zu hoch für Meditation - bist du wirklich entspannt?"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
# TEMPLATE: KRAFTTRAINING - Kraft-fokussiert
|
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
|
|
TEMPLATE_STRENGTH = {
|
|
"version": "1.0",
|
|
"name": "Krafttraining (Standard)",
|
|
"description": "Krafttraining mit moderater Herzfrequenz",
|
|
|
|
"rule_sets": {
|
|
"minimum_requirements": {
|
|
"enabled": True,
|
|
"pass_strategy": "weighted_score",
|
|
"pass_threshold": 0.5,
|
|
"rules": [
|
|
{
|
|
"parameter": "duration_min",
|
|
"operator": "gte",
|
|
"value": 20,
|
|
"weight": 5,
|
|
"optional": False,
|
|
"reason": "Mindestens 20 Minuten für Muskelreiz"
|
|
},
|
|
{
|
|
"parameter": "kcal_active",
|
|
"operator": "gte",
|
|
"value": 100,
|
|
"weight": 2,
|
|
"optional": True,
|
|
"reason": "Mindest-Kalorienverbrauch"
|
|
}
|
|
]
|
|
},
|
|
|
|
"intensity_zones": {
|
|
"enabled": False
|
|
},
|
|
|
|
"training_effects": {
|
|
"enabled": True,
|
|
"default_effects": {
|
|
"primary_abilities": [
|
|
{
|
|
"category": "konditionell",
|
|
"ability": "kraft",
|
|
"intensity": 5
|
|
}
|
|
],
|
|
"secondary_abilities": [
|
|
{
|
|
"category": "koordinativ",
|
|
"ability": "differenzierung",
|
|
"intensity": 3
|
|
},
|
|
{
|
|
"category": "psychisch",
|
|
"ability": "willenskraft",
|
|
"intensity": 4
|
|
}
|
|
]
|
|
},
|
|
"metabolic_focus": ["anaerobic", "muscle_growth"],
|
|
"muscle_groups": ["full_body"]
|
|
},
|
|
|
|
"periodization": {
|
|
"enabled": True,
|
|
"frequency": {
|
|
"per_week_optimal": 3,
|
|
"per_week_max": 5
|
|
},
|
|
"recovery": {
|
|
"min_hours_between": 48
|
|
}
|
|
},
|
|
|
|
"performance_indicators": {
|
|
"enabled": False
|
|
},
|
|
|
|
"safety": {
|
|
"enabled": True,
|
|
"warnings": []
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
# TEMPLATE REGISTRY
|
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
|
|
TEMPLATES = {
|
|
"running": {
|
|
"name_de": "Laufen",
|
|
"name_en": "Running",
|
|
"icon": "🏃",
|
|
"categories": ["cardio", "running"],
|
|
"template": TEMPLATE_RUNNING
|
|
},
|
|
"meditation": {
|
|
"name_de": "Meditation",
|
|
"name_en": "Meditation",
|
|
"icon": "🧘",
|
|
"categories": ["geist", "meditation"],
|
|
"template": TEMPLATE_MEDITATION
|
|
},
|
|
"strength": {
|
|
"name_de": "Krafttraining",
|
|
"name_en": "Strength Training",
|
|
"icon": "💪",
|
|
"categories": ["kraft", "krafttraining"],
|
|
"template": TEMPLATE_STRENGTH
|
|
}
|
|
}
|
|
|
|
|
|
def get_template(template_key: str) -> dict:
|
|
"""Get profile template by key."""
|
|
template_info = TEMPLATES.get(template_key)
|
|
if not template_info:
|
|
return None
|
|
return template_info["template"]
|
|
|
|
|
|
def list_templates() -> list:
|
|
"""List all available templates."""
|
|
return [
|
|
{
|
|
"key": key,
|
|
"name_de": info["name_de"],
|
|
"name_en": info["name_en"],
|
|
"icon": info["icon"],
|
|
"categories": info["categories"]
|
|
}
|
|
for key, info in TEMPLATES.items()
|
|
]
|