Unraid deployment fixes and generator improvements

- Add Next.js rewrites to proxy API calls through same origin (fixes login/media on werkout.treytartt.com)
- Fix mediaUrl() in DayCard and ExerciseRow to use relative paths in production
- Add proxyTimeout for long-running workout generation endpoints
- Add CSRF trusted origin for treytartt.com
- Split docker-compose into production (Unraid) and dev configs
- Show display_name and descriptions on workout type cards
- Generator: rules engine improvements, movement enforcement, exercise selector updates
- Add new test files for rules drift, workout research generation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-23 10:25:45 -06:00
parent 1c61b80731
commit 03681c532d
21 changed files with 2366 additions and 138 deletions

View File

@@ -73,7 +73,7 @@ class TestWorkoutTypeRulesCoverage(TestCase):
expected_types = [
'traditional_strength_training',
'hypertrophy',
'hiit',
'high_intensity_interval_training',
'functional_strength_training',
'cross_training',
'core_training',
@@ -116,14 +116,14 @@ class TestDBCalibrationCoverage(TestCase):
def test_all_8_types_in_calibration(self):
expected_names = [
'Functional Strength Training',
'Traditional Strength Training',
'HIIT',
'Cross Training',
'Core Training',
'Flexibility',
'Cardio',
'Hypertrophy',
'functional_strength_training',
'traditional_strength_training',
'high_intensity_interval_training',
'cross_training',
'core_training',
'flexibility',
'cardio',
'hypertrophy',
]
for name in expected_names:
self.assertIn(name, DB_CALIBRATION, f"Missing {name} in DB_CALIBRATION")
@@ -137,7 +137,11 @@ class TestHelperFunctions(TestCase):
_normalize_type_key('Traditional Strength Training'),
'traditional_strength_training',
)
self.assertEqual(_normalize_type_key('HIIT'), 'hiit')
self.assertEqual(_normalize_type_key('HIIT'), 'high_intensity_interval_training')
self.assertEqual(
_normalize_type_key('high intensity interval training'),
'high_intensity_interval_training',
)
self.assertEqual(_normalize_type_key('cardio'), 'cardio')
def test_classify_rep_weight(self):
@@ -500,6 +504,86 @@ class TestValidateWorkout(TestCase):
"Expected superset size warning for 8-exercise superset in strength",
)
def test_superset_focus_repetition_error(self):
"""Two curl-family exercises in one superset should produce an error."""
curl_a = _make_exercise(
name='Alternating Bicep Curls',
movement_patterns='upper pull',
is_compound=False,
exercise_tier='accessory',
)
curl_b = _make_exercise(
name='Bicep Curls',
movement_patterns='upper pull',
is_compound=False,
exercise_tier='accessory',
)
workout_spec = {
'supersets': [
_make_superset(name='Warm Up', exercises=[
_make_entry(exercise=_make_exercise(is_reps=False), duration=30),
], rounds=1),
_make_superset(
name='Working Set 1',
exercises=[
_make_entry(exercise=curl_a, reps=10, order=1),
_make_entry(exercise=curl_b, reps=10, order=2),
],
rounds=3,
),
_make_superset(name='Cool Down', exercises=[
_make_entry(exercise=_make_exercise(is_reps=False), duration=30),
], rounds=1),
],
}
violations = validate_workout(
workout_spec, 'functional_strength_training', 'general_fitness',
)
repetition_errors = [
v for v in violations
if v.rule_id == 'superset_focus_repetition' and v.severity == 'error'
]
self.assertTrue(
repetition_errors,
f"Expected superset focus repetition error, got {[v.rule_id for v in violations]}",
)
def test_adjacent_focus_repetition_info(self):
"""Adjacent working supersets with same focus profile should be advisory."""
pull_a = _make_exercise(name='Bicep Curl', movement_patterns='upper pull')
pull_b = _make_exercise(name='Hammer Curl', movement_patterns='upper pull')
workout_spec = {
'supersets': [
_make_superset(name='Warm Up', exercises=[
_make_entry(exercise=_make_exercise(is_reps=False), duration=30),
], rounds=1),
_make_superset(
name='Working Set 1',
exercises=[_make_entry(exercise=pull_a, reps=10, order=1)],
rounds=3,
),
_make_superset(
name='Working Set 2',
exercises=[_make_entry(exercise=pull_b, reps=10, order=1)],
rounds=3,
),
_make_superset(name='Cool Down', exercises=[
_make_entry(exercise=_make_exercise(is_reps=False), duration=30),
], rounds=1),
],
}
violations = validate_workout(
workout_spec, 'functional_strength_training', 'general_fitness',
)
adjacent_infos = [
v for v in violations
if v.rule_id == 'adjacent_superset_focus_repetition' and v.severity == 'info'
]
self.assertTrue(
adjacent_infos,
"Expected adjacent superset focus repetition advisory info.",
)
def test_compound_before_isolation_info(self):
"""Isolation before compound should produce info violation."""
isolation = _make_exercise(