Commit Graph

216 Commits

Author SHA1 Message Date
7ffa8f039b fix: PostgreSQL date subtraction in historical value query
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
**Error:**
function pg_catalog.extract(unknown, integer) does not exist
HINT: No function matches the given name and argument types.

**Problem:**
In PostgreSQL, date - date returns INTEGER (days), not INTERVAL.
EXTRACT(EPOCH FROM integer) fails because EPOCH expects timestamp/interval.

**Solution:**
Changed from:
  ORDER BY ABS(EXTRACT(EPOCH FROM (date - '2026-01-01')))

To:
  ORDER BY ABS(date - '2026-01-01'::date)

This directly uses the day difference (integer) for sorting,
which is exactly what we need to find the closest date.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 13:22:05 +01:00
efde158dd4 feat: Auto-populate goal start_value from historical data
All checks were successful
Deploy Development / deploy (push) Successful in 45s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
**Problem:** Goals created today had start_value = current_value,
showing 0% progress even after months of tracking.

**Solution:**
1. Added start_date and start_value to GoalCreate/GoalUpdate models
2. New function _get_historical_value_for_goal_type():
   - Queries source table for value on specific date
   - ±7 day window for closest match
   - Works with all goal types via goal_type_definitions
3. create_goal() logic:
   - If start_date < today → auto-populate from historical data
   - If start_date = today → use current value
   - User can override start_value manually
4. update_goal() logic:
   - Changing start_date recalculates start_value
   - Can manually override start_value

**Example:**
- Goal created today with start_date = 3 months ago
- System finds weight on that date (88 kg)
- Current weight: 85.2 kg, Target: 82 kg
- Progress: (85.2 - 88) / (82 - 88) = 47% ✓

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 13:14:33 +01:00
a6701bf7b2 fix: Include start_value in get_active_goals query
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
Goal progress placeholders were filtering out all goals because
start_value was missing from the SELECT statement.

Added start_value to both:
- get_active_goals() - for placeholder formatters
- get_goal_by_id() - for consistency

This will fix:
- active_goals_md progress column (was all "-")
- top_3_goals_behind_schedule (was "keine Ziele")
- top_3_goals_on_track (was "keine Ziele")

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 13:02:43 +01:00
befc310958 fix: focus_areas column name + goal progress calculation
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Fixed 2 critical placeholder issues:

1. focus_areas_weighted_json was empty:
   - Query used 'area_key' but column is 'key' in focus_area_definitions
   - Changed to SELECT key, not area_key

2. Goal progress placeholders showed "nicht verfügbar":
   - progress_pct in goals table is NULL (not auto-calculated)
   - Added manual calculation in all 3 formatter functions:
     * _format_goals_as_markdown() - shows % in table
     * _format_goals_behind() - finds lowest progress
     * _format_goals_on_track() - finds >= 50% progress

All placeholders should now return proper values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 12:43:54 +01:00
112226938d fix: Convert goal values to float before progress calculation
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
TypeError: unsupported operand type(s) for -: 'decimal.Decimal' and 'float'

PostgreSQL NUMERIC columns return Decimal objects. Must convert
current_value, target_value, start_value to float before passing
to calculate_goal_progress_pct().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 12:39:26 +01:00
8da577fe58 fix: Phase 0b - body_progress_score + placeholder formatting
All checks were successful
Deploy Development / deploy (push) Successful in 44s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
Fixed remaining placeholder calculation issues:

1. body_progress_score returning 0:
   - When start_value is NULL, query oldest weight from last 90 days
   - Prevents progress = 0% when start equals current

2. focus_areas_weighted_json empty:
   - Changed from goal_utils.get_focus_weights_v2() to scores.get_user_focus_weights()
   - Now uses same function as focus_area_weights_json

3. Implemented 5 TODO markdown formatting functions:
   - _format_goals_as_markdown() - table with progress bars
   - _format_focus_areas_as_markdown() - weighted list
   - _format_top_focus_areas() - top N by weight
   - _format_goals_behind() - lowest progress goals
   - _format_goals_on_track() - goals >= 50% progress

All placeholders should now return proper values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 12:34:24 +01:00
b09a7b200a fix: Phase 0b - implement active_goals and focus_areas JSON placeholders
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Root cause: Two TODO stubs always returned '[]'

Implemented:
- active_goals_json: Calls get_active_goals() from goal_utils
- focus_areas_weighted_json: Builds weighted list with names/categories

Result:
- active_goals_json now shows actual goals
- body_progress_score should calculate correctly
- top_3_goals placeholders will work

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 12:19:37 +01:00
05d15264c8 fix: Phase 0b - complete Decimal/float conversion in nutrition_metrics
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
Previous commit only converted weight values, but missed:
- avg_intake (calories from DB)
- avg_protein (protein_g from DB)
- protein_per_kg calculations in loops

All DB numeric values now converted to float BEFORE arithmetic.

Fixed locations:
- Line 44: avg_intake conversion
- Line 126: avg_protein conversion
- Line 175: protein_per_kg in loop
- Line 213: protein_values list comprehension

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 11:32:07 +01:00
78437b649f fix: Phase 0b - PostgreSQL Decimal type handling
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float'
TypeError: unsupported operand type(s) for -: 'float' and 'decimal.Decimal'

PostgreSQL NUMERIC/DECIMAL columns return decimal.Decimal objects,
not float. These cannot be mixed in arithmetic operations.

Fixed 3 locations:
- Line 62: float(weight_row['weight']) * 32.5
- Line 153: float(weight_row['weight']) for protein_per_kg
- Line 202: float(weight_row['avg_weight']) for adequacy calc

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 11:23:40 +01:00
6f20915d73 fix: Phase 0b - body_progress_score uses correct column name
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Bug: Filtered goals by g.get('type_key') but goals table has 'goal_type' column.
Result: weight_goals was always empty → _score_weight_trend returned None.

Fix: Changed 'type_key' → 'goal_type' (matches goals table schema).

Verified: Migration 022 defines goal_type column, not type_key.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 11:16:29 +01:00
202c36fad7 fix: Phase 0b - replace non-existent get_goals_by_type import
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
ImportError: cannot import name 'get_goals_by_type' from 'goal_utils'

Changes:
- body_metrics.py: Use get_active_goals() + filter by type_key
- nutrition_metrics.py: Remove unused import (dead code)

Result: Score functions no longer crash on import error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 11:04:28 +01:00
cc76ae677b fix: Phase 0b - score functions use English focus area keys
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
Root cause: All 3 score functions returned None because they queried
German focus area keys that don't exist in database (migration 031
uses English keys).

Changes:
- body_progress_score: körpergewicht/körperfett/muskelmasse
  → weight_loss/muscle_gain/body_recomposition
- nutrition_score: ernährung_basis/proteinzufuhr/kalorienbilanz
  → protein_intake/calorie_balance/macro_consistency/meal_timing/hydration
- activity_score: kraftaufbau/cardio/bewegungsumfang/trainingsqualität
  → strength/aerobic_endurance/flexibility/rhythm/coordination (grouped)

Result: Scores now calculate correctly with existing focus area weights.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 10:59:37 +01:00
14c4ea13d9 feat: Phase 0b - add avg_per_week_30d aggregation method
All checks were successful
Deploy Development / deploy (push) Successful in 44s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
- Calculates average count per week over 30 days
- Use case: Training frequency per week (smoothed)
- Formula: (count in 30 days) / 4.285 weeks
- Documentation: .claude/docs/technical/AGGREGATION_METHODS.md
2026-03-28 10:45:36 +01:00
9fa6c5dea7 feat: Phase 0b - add nutrition focus areas to score mapping
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
2026-03-28 10:20:46 +01:00
949301a91d feat: Phase 0b - add nutrition focus area category (migration 033) 2026-03-28 10:20:08 +01:00
43e6c3e7f4 fix: Phase 0b - map German to English category names
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
2026-03-28 10:13:10 +01:00
e3e635d9f5 fix: Phase 0b - remove orphaned German mapping entries
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
2026-03-28 10:10:18 +01:00
289b132b8f fix: Phase 0b - map_focus_to_score_components English keys
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
2026-03-28 09:53:59 +01:00
919eae6053 fix: Phase 0b - sleep dict access in health_stability_score regularity
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
2026-03-28 09:42:54 +01:00
91bafc6af1 fix: Phase 0b - activity duration column in health_stability_score
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 13s
2026-03-28 09:40:07 +01:00
10ea560fcf fix: Phase 0b - fix last sleep column names in health_stability_score
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
Fixed remaining sleep_log column name errors in calculate_health_stability_score:
- SELECT: total_sleep_min, deep_min, rem_min → duration_minutes, deep_minutes, rem_minutes
- _score_sleep_quality: Updated dict access to use new column names

This was blocking goal_progress_score from calculating.

Changes:
- scores.py: Fixed sleep_log SELECT query and _score_sleep_quality dict access

This should be the LAST column name bug! All Phase 0b calculations should now work.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 09:35:36 +01:00
b230a03fdd fix: Phase 0b - fix blood_pressure and top_goal_name bugs
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 14s
Final bug fixes:
1. blood_pressure_log query - changed 'date' column to 'measured_at' (correct column for TIMESTAMP)
2. top_goal_name KeyError - added 'name' to SELECT in get_active_goals()
3. top_goal_name fallback - use goal_type if name is NULL

Changes:
- scores.py: Fixed blood_pressure_log query to use measured_at instead of date
- goal_utils.py: Added 'name' column to get_active_goals() SELECT
- placeholder_resolver.py: Added fallback to goal_type if name is None

These were the last 2 errors showing in logs. All major calculation bugs should now be fixed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 09:32:04 +01:00
02394ea19c fix: Phase 0b - fix remaining calculation bugs from log analysis
All checks were successful
Deploy Development / deploy (push) Successful in 43s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
Bugs fixed based on actual error logs:
1. TypeError: progress_pct None handling - changed .get('progress_pct', 0) to (goal.get('progress_pct') or 0)
2. UUID Error: focus_area_id query - changed WHERE focus_area_id = %s to WHERE key = %s
3. NameError: calculate_recovery_score_v2 - added missing import in calculate_category_progress
4. UndefinedColumn: c_thigh_r - removed left/right separation, only c_thigh exists
5. UndefinedColumn: resting_heart_rate - fixed remaining AVG(resting_heart_rate) to AVG(resting_hr)
6. KeyError: total_sleep_min - changed dict access to duration_minutes

Changes:
- scores.py: Fixed progress_pct None handling, focus_area key query, added recovery import
- body_metrics.py: Fixed thigh_28d_delta to use single c_thigh column
- recovery_metrics.py: Fixed resting_hr SELECT queries, fixed sleep_debt dict access

All errors from logs should now be resolved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 08:50:55 +01:00
dd3a4111fc fix: Phase 0b - fix remaining calculation errors
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Fixes applied:
1. WHERE clause column names (total_sleep_min → duration_minutes, resting_heart_rate → resting_hr)
2. COUNT() column names (avg_heart_rate → hr_avg, quality_label → rpe)
3. Type errors (Decimal * float) - convert to float before multiplication
4. rest_days table (type column removed in migration 010, now uses rest_config JSONB)
5. c_thigh_l → c_thigh (no separate left/right columns)
6. focus_area_definitions queries (focus_area_id → key, label_de → name_de)

Missing functions implemented:
- goal_utils.get_active_goals() - queries goals table for active goals
- goal_utils.get_goal_by_id() - gets single goal
- calculations.scores.calculate_category_progress() - maps categories to score functions

Changes:
- activity_metrics.py: Fixed Decimal/float type errors, rest_config JSONB, data quality query
- recovery_metrics.py: Fixed all WHERE clause column names
- body_metrics.py: Fixed c_thigh column reference
- scores.py: Fixed focus_area queries, added calculate_category_progress()
- goal_utils.py: Added get_active_goals(), get_goal_by_id()

All calculation functions should now work with correct schema.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 08:39:31 +01:00
4817fd2b29 fix: Phase 0b - correct all SQL column names in calculation engine
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
Schema corrections applied:
- weight_log: weight_kg → weight
- nutrition_log: calories → kcal
- activity_log: duration → duration_min, avg_heart_rate → hr_avg, max_heart_rate → hr_max
- rest_days: rest_type → type (aliased for backward compat)
- vitals_baseline: resting_heart_rate → resting_hr
- sleep_log: total_sleep_min → duration_minutes, deep_min → deep_minutes, rem_min → rem_minutes, waketime → wake_time
- focus_area_definitions: fa.focus_area_id → fa.key (proper join column)

Affected files:
- body_metrics.py: weight column (all queries)
- nutrition_metrics.py: kcal column + weight
- activity_metrics.py: duration_min, hr_avg, hr_max, quality via RPE mapping
- recovery_metrics.py: sleep + vitals columns
- correlation_metrics.py: kcal, weight
- scores.py: focus_area key selection

All 100+ Phase 0b placeholders should now calculate correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 08:28:20 +01:00
53969f8768 fix: SyntaxError in placeholder_resolver.py line 1037
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 14s
- Fixed unterminated string literal in get_placeholder_catalog()
- Line 1037 had extra quote: ('quality_sessions_pct', 'Qualitätssessions (%)'),'
- Should be: ('quality_sessions_pct', 'Qualitätssessions (%)'),

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 08:18:31 +01:00
6f94154b9e fix: Add error logging to Phase 0b placeholder calculation wrappers
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Problem: All _safe_* functions were silently catching exceptions and returning 'nicht verfügbar',
making it impossible to debug why calculations fail.

Solution: Add detailed error logging with traceback to all 4 wrapper functions:
- _safe_int(): Logs function name, exception type, message, full stack trace
- _safe_float(): Same logging
- _safe_str(): Same logging
- _safe_json(): Same logging

Now when placeholders return 'nicht verfügbar', the backend logs will show:
- Which placeholder function failed
- What exception occurred
- Full stack trace for debugging

Example log output:
[ERROR] _safe_int(goal_progress_score, uuid): ModuleNotFoundError: No module named 'calculations'
Traceback (most recent call last):
  ...

This will help identify if issue is:
- Missing calculations module import
- Missing data in database
- Wrong column names
- Calculation logic errors
2026-03-28 07:39:53 +01:00
7d4f6fe726 fix: Update placeholder catalog with Phase 0b placeholders
All checks were successful
Deploy Development / deploy (push) Successful in 1m2s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
Added ~40 Phase 0b placeholders to get_placeholder_catalog():
- Scores (6 new): goal_progress_score, body/nutrition/activity/recovery/data_quality
- Focus Areas (8 new): top focus area, category progress/weights
- Body Metrics (7 new): weight trends, FM/LBM changes, waist, recomposition
- Nutrition (4 new): energy balance, protein g/kg, adequacy, consistency
- Activity (6 new): minutes/week, quality, ability balance, compliance
- Recovery (4 new): sleep duration/debt/regularity/quality
- Vitals (3 new): HRV/RHR vs baseline, VO2max trend

Fixes: Placeholders now visible in Admin UI placeholder list
2026-03-28 07:35:48 +01:00
bf0b32b536 feat: Phase 0b - Integrate 100+ Goal-Aware Placeholders
Extended placeholder_resolver.py with:
- 100+ new placeholders across 5 levels (meta-scores, categories, individual metrics, correlations, JSON)
- Safe wrapper functions (_safe_int, _safe_float, _safe_str, _safe_json)
- Integration with calculation engine (body, nutrition, activity, recovery, correlations, scores)
- Dynamic Focus Areas v2.0 support (category progress/weights)
- Top-weighted goals/focus areas (instead of deprecated primary goal)

Placeholder categories:
- Meta Scores: goal_progress_score, body/nutrition/activity/recovery_score (6)
- Top-Weighted: top_goal_*, top_focus_area_* (5)
- Category Scores: focus_cat_*_progress/weight for 7 categories (14)
- Body Metrics: weight trends, FM/LBM changes, circumferences, recomposition (12)
- Nutrition Metrics: energy balance, protein adequacy, macro consistency (7)
- Activity Metrics: training volume, ability balance, load monitoring (13)
- Recovery Metrics: HRV/RHR vs baseline, sleep quality/debt/regularity (7)
- Correlation Metrics: lagged correlations, plateau detection, driver panel (7)
- JSON/Markdown: active_goals, focus_areas, top drivers (8)

TODO: Implement goal_utils extensions for JSON formatters
TODO: Add unit tests for all placeholder functions
2026-03-28 07:22:37 +01:00
09e6a5fbfb feat: Phase 0b - Calculation Engine for 120+ Goal-Aware Placeholders
- body_metrics.py: K1-K5 calculations (weight trend, FM/LBM, circumferences, recomposition, body score)
- nutrition_metrics.py: E1-E5 calculations (energy balance, protein adequacy, macro consistency, nutrition score)
- activity_metrics.py: A1-A8 calculations (training volume, intensity, quality, ability balance, load monitoring)
- recovery_metrics.py: Improved Recovery Score v2 (HRV, RHR, sleep, regularity, load balance)
- correlation_metrics.py: C1-C7 calculations (lagged correlations, plateau detection, driver panel)
- scores.py: Meta-scores with Dynamic Focus Areas v2.0 integration

All calculations include:
- Data quality assessment
- Confidence levels
- Dynamic weighting by user's focus area priorities
- Support for custom goals via goal_utils integration

Next: Placeholder integration in placeholder_resolver.py
2026-03-28 07:20:40 +01:00
56933431f6 chore: remove deprecated vitals.py (-684 lines)
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 13s
This file was replaced by the refactored vitals system:
- vitals_baseline.py (morning measurements)
- blood_pressure.py (BP tracking with context)

Migration 015 completed the split in v9d Phase 2d.
File was no longer imported in main.py.

Cleanup result: -684 lines of dead code
2026-03-28 06:41:51 +01:00
12d516c881 refactor: split goals.py into 5 modular routers
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
Code Splitting Results:
- goals.py: 1339 → 655 lines (-684 lines, -51%)
- Created 4 new routers:
  * goal_types.py (426 lines) - Goal Type Definitions CRUD
  * goal_progress.py (155 lines) - Progress tracking
  * training_phases.py (107 lines) - Training phases
  * fitness_tests.py (94 lines) - Fitness tests

Benefits:
 Improved maintainability (smaller, focused files)
 Better context window efficiency for AI tools
 Clearer separation of concerns
 Easier testing and debugging

All routers registered in main.py.
Backward compatible - no API changes.
2026-03-28 06:31:31 +01:00
448f6ad4f4 fix: use psycopg2 placeholders (%s) not PostgreSQL ($N)
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
Bug 1 Final Fix:
- Changed all placeholders from $1, $2, $3 to %s
- psycopg2 expects Python-style %s, converts to $N internally
- Using $N directly causes 'there is no parameter $1' error
- Removed param_idx counter (not needed with %s)

Root cause: Mixing PostgreSQL native syntax with psycopg2 driver
This is THE fix that will finally work!
2026-03-27 22:14:28 +01:00
e4a2b63a48 fix: vitals baseline parameter sync + goal utils transaction rollback
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Bug 1 Fix (Ruhepuls):
- Completely rewrote vitals_baseline POST endpoint
- Clear separation: param_values array contains ALL values (pid, date, ...)
- Synchronized insert_cols, insert_placeholders, and param_values
- Added debug logging
- Simplified UPDATE logic (EXCLUDED.col instead of COALESCE)

Bug 2 Fix (Custom Goal Type Transaction Error):
- Added transaction rollback in goal_utils._fetch_by_aggregation_method()
- When SQL query fails (e.g., invalid column name), rollback transaction
- Prevents 'InFailedSqlTransaction' errors on subsequent queries
- Enhanced error logging (shows filter conditions, SQL, params)
- Returns None gracefully so goal creation can continue

User Action Required for Bug 2:
- Edit goal type 'Trainingshäufigkeit Krafttraining'
- Change filter from {"training_type": "strength"}
  to {"training_category": "strength"}
- activity_log has training_category, NOT training_type column
2026-03-27 22:09:52 +01:00
ce4cd7daf1 fix: include filter_conditions in goal type list query
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
Bug 3 Fix: filter_conditions was missing from SELECT statement in
list_goal_type_definitions(), preventing edit form from loading
existing filter JSON.

- Added filter_conditions to line 1087
- Now edit form correctly populates filter textarea
2026-03-27 21:57:25 +01:00
37ea1f8537 fix: vitals_baseline dynamic query parameter mismatch
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
**Bug:** POST /api/vitals/baseline threw UndefinedParameter
**Cause:** Dynamic SQL generation had desynchronized column names and placeholders
**Fix:** Rewrote to use synchronized insert_cols, insert_placeholders, update_fields arrays

- Track param_idx correctly (start at 3 after pid and date)
- Build INSERT columns and placeholders in parallel
- Cleaner, more maintainable code
- Fixes Ruhepuls entry error
2026-03-27 21:23:56 +01:00
378bf434fc fix: 3 critical bugs in Goals and Vitals
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 21s
**Bug 1: Focus contributions not saved**
- GoalsPage: Added focus_contributions to data object (line 232)
- Was missing from API payload, causing loss of focus area assignments

**Bug 2: Filter focus areas in goal form**
- Only show focus areas user has weighted (weight > 0)
- Cleaner UX, avoids confusion with non-prioritized areas
- Filters focusAreasGrouped by userFocusWeights

**Bug 3: Vitals RHR entry - Internal Server Error**
- Fixed: Endpoint tried to INSERT into vitals_log (renamed in Migration 015)
- Now uses vitals_baseline table (correct post-migration table)
- Removed BP fields from baseline endpoint (use /blood-pressure instead)
- Backward compatible return format

All fixes tested and ready for production.
2026-03-27 21:04:28 +01:00
3116fbbc91 feat: Dynamic Focus Areas system v2.0 - fully implemented
All checks were successful
Deploy Development / deploy (push) Successful in 44s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
**Migration 032:**
- user_focus_area_weights table (profile_id, focus_area_id, weight)
- Migrates legacy 6 preferences to dynamic weights

**Backend (focus_areas.py):**
- GET /user-preferences: Returns dynamic focus weights with percentages
- PUT /user-preferences: Saves user weights (dict: focus_area_id → weight)
- Auto-calculates percentages from relative weights
- Graceful fallback if Migration 032 not applied

**Frontend (GoalsPage.jsx):**
- REMOVED: Goal Mode cards (obsolete)
- REMOVED: 6 hardcoded legacy focus sliders
- NEW: Dynamic focus area cards (weight > 0 only)
- NEW: Edit mode with sliders for all 26 areas (grouped by category)
- Clean responsive design

**How it works:**
1. Admin defines focus areas in /admin/focus-areas (26 default)
2. User sets weights for areas they care about (0-100 relative)
3. System calculates percentages automatically
4. Cards show only weighted areas
5. Goals assign to 1-n focus areas (existing functionality)
2026-03-27 20:51:19 +01:00
029530e078 fix: backward compatibility for focus_areas migration
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
- get_focus_areas now tries user_focus_preferences first (Migration 031)
- Falls back to old focus_areas table if Migration 031 not applied
- get_goals_grouped wraps focus_contributions loading in try/catch
- Graceful degradation until migrations run
2026-03-27 20:34:06 +01:00
ba5d460e92 fix: Graceful fallback if Migration 031 not yet applied
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
- Wrap focus_contributions loading in try/catch
- If tables don't exist (migration not run), continue without them
- Backward compatible with pre-migration state
- Logs warning but doesn't crash
2026-03-27 20:24:16 +01:00
34ea51b8bd fix: Add /api prefix to focus_areas router
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
- Changed prefix from '/focus-areas' to '/api/focus-areas'
- Consistent with all other routers (goals, prompts, etc.)
- Fixes 404 Not Found on /admin/focus-areas page
2026-03-27 20:00:41 +01:00
f312dd0dbb feat: Backend Phase 2 - Focus Areas API + Goals integration
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
**New Router: focus_areas.py**
- GET /focus-areas/definitions (list all, grouped by category)
- POST/PUT/DELETE /focus-areas/definitions (Admin CRUD)
- GET /focus-areas/user-preferences (legacy + future dynamic)
- PUT /focus-areas/user-preferences (auto-normalize to 100%)
- GET /focus-areas/stats (progress per focus area)

**Goals Router Extended:**
- FocusContribution model (focus_area_id + contribution_weight)
- GoalCreate/Update: focus_contributions field
- create_goal: Insert contributions after goal creation
- update_goal: Delete old + insert new contributions
- get_goals_grouped: Load focus_contributions per goal

**Main.py:**
- Registered focus_areas router

**Features:**
- Many-to-Many mapping (goals ↔ focus areas)
- Contribution weights (0-100%)
- Auto-mapped by Migration 031
- User can edit via UI (next: frontend)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 19:48:05 +01:00
2f64656d4d feat: Migration 031 - Focus Area System v2.0 (dynamic, extensible)
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
2026-03-27 19:44:18 +01:00
0a1da37197 fix: Remove g.direction from SELECT - column does not exist
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
2026-03-27 17:08:30 +01:00
fac8820208 fix: SQL error - direction is in goals table, not goal_type_definitions
Some checks failed
Build Test / lint-backend (push) Waiting to run
Build Test / build-frontend (push) Waiting to run
Deploy Development / deploy (push) Has been cancelled
2026-03-27 17:05:14 +01:00
217990d417 fix: Prevent manual progress entries for automatic goals
All checks were successful
Deploy Development / deploy (push) Successful in 43s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
**Backend Safeguards:**
- get_goals_grouped: Added source_table, source_column, direction to SELECT
- create_goal_progress: Check source_table before allowing manual entry
- Returns HTTP 400 if user tries to log progress for automatic goals (weight, activity, etc.)

**Prevents:**
- Data confusion: Manual entries in goal_progress_log for weight/activity/etc.
- Dual tracking: Same data in multiple tables
- User error: Wrong data entry location

**Result:**
- Frontend filter (!goal.source_table) now works correctly
- CustomGoalsPage shows ONLY custom goals (flexibility, strength, etc.)
- Clear error message if manual entry attempted via API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 17:00:53 +01:00
7db98a4fa6 feat: Goal Progress Log - backend + API (v2.1)
All checks were successful
Deploy Development / deploy (push) Successful in 44s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Implemented progress tracking system for all goals.

**Backend:**
- Migration 030: goal_progress_log table with unique constraint per day
- Trigger: Auto-update goal.current_value from latest progress
- Endpoints: GET/POST/DELETE /api/goals/{id}/progress
- Pydantic Models: GoalProgressCreate, GoalProgressUpdate

**Features:**
- Manual progress tracking for custom goals (flexibility, strength, etc.)
- Full history with date, value, note
- current_value always reflects latest progress entry
- One entry per day per goal (unique constraint)
- Cascade delete when goal is deleted

**API:**
- GET /api/goals/{goal_id}/progress - List all entries
- POST /api/goals/{goal_id}/progress - Log new progress
- DELETE /api/goals/{goal_id}/progress/{progress_id} - Delete entry

**Next:** Frontend UI (progress button, modal, history list)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 13:58:14 +01:00
ce37afb2bb fix: Migration 029 - activate missing goal types (flexibility, strength)
All checks were successful
Deploy Development / deploy (push) Successful in 43s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
These goal types existed but were inactive or misconfigured.

Uses UPSERT (INSERT ... ON CONFLICT DO UPDATE):
- If exists → activate + fix labels/icons/category
- If not exists → create properly

Idempotent: Safe to run multiple times, works on dev + prod.

Both types have no automatic data source (source_table = NULL),
so current_value must be updated manually.

Fixes: flexibility and strength goals not visible in admin

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 13:53:47 +01:00
9e95fd8416 fix: get_goals_grouped - remove is_active check (column doesn't exist)
All checks were successful
Deploy Development / deploy (push) Successful in 44s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
goals table doesn't have is_active column.
Removed AND g.is_active = true from WHERE clause.

Fixes: psycopg2.errors.UndefinedColumn: column g.is_active does not exist

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 12:45:03 +01:00
ca4f722b47 fix: goal_utils - support different date column names
All checks were successful
Deploy Development / deploy (push) Successful in 45s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Fixed: column 'date' does not exist in blood_pressure_log

blood_pressure_log uses 'measured_at' instead of 'date'.
Added DATE_COLUMN_MAP for table-specific date columns:
- blood_pressure_log → measured_at
- fitness_tests → test_date
- all others → date

Replaced all hardcoded 'date' with dynamic date_col variable.

Fixes error: [ERROR] Failed to fetch value from blood_pressure_log.systolic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 12:42:56 +01:00