- Introduced a single TDEE calculation based on current weight, replacing the fixed 2500 kcal value.
- Updated `get_energy_balance_data` to use daily totals for intake calculations and improved energy balance logic.
- Enhanced `get_nutrition_average_data` to calculate averages over calendar days instead of raw log entries.
- Adjusted placeholder resolution to ensure consistent metadata usage across requests.
- Fixed issues in the charts router to reflect the new energy balance logic and TDEE calculations.
These changes improve the accuracy of nutritional assessments and streamline data handling in the application.
Backend workflow_executor.py:
- load_prompt_template() now uses modern resolve_placeholders() from prompt_executor
- Calls get_placeholder_example_values() to populate ALL registered placeholders
- Passes catalog for |d modifier support
- Fixes issue where basis prompts had empty/null placeholder values in workflows
Backend placeholder_resolver.py:
- get_placeholder_catalog() now includes ALL placeholders from PLACEHOLDER_MAP
- Uncategorized placeholders added to "Sonstiges" category
- Fixes discrepancy: 111 total placeholders but only ~30 shown in picker
Root Cause:
- Workflow used old resolve_placeholders() (only PLACEHOLDER_MAP, no variables)
- Isolated execution used modern resolve_placeholders() (full variables dict)
- Catalog excluded non-registry placeholders from PLACEHOLDER_MAP
Impact:
- All placeholders now resolve correctly in workflow execution
- PlaceholderPicker shows all 111+ placeholders (not just registry ones)
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Bug Fixes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Migrated all 16 calculation functions from calculations/nutrition_metrics.py to data_layer/nutrition_metrics.py
- Functions: Energy balance (7d calculation, deficit/surplus classification)
- Functions: Protein adequacy (g/kg, days in target, 28d score)
- Functions: Macro consistency (score, intake volatility)
- Functions: Nutrition scoring (main score with focus weights, calorie/macro adherence helpers)
- Functions: Energy availability warning (with severity levels and recommendations)
- Functions: Data quality assessment
- Functions: Fiber/sugar averages (TODO stubs)
- Updated data_layer/__init__.py with 12 new exports
- Refactored placeholder_resolver.py to import nutrition_metrics from data_layer
Module 2/6 complete. Single Source of Truth for nutrition metrics established.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Migrated all 20 calculation functions from calculations/body_metrics.py to data_layer/body_metrics.py
- Functions: weight trends (7d median, 28d/90d slopes, goal projection, progress)
- Functions: body composition (FM/LBM changes)
- Functions: circumferences (waist/hip/chest/arm/thigh deltas, WHR)
- Functions: recomposition quadrant
- Functions: scoring (body progress, data quality)
- Updated data_layer/__init__.py with 20 new exports
- Refactored placeholder_resolver.py to import body_metrics from data_layer
Module 1/6 complete. Single Source of Truth for body metrics established.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Data Layer:
- get_resting_heart_rate_data() - avg RHR with min/max trend
- get_heart_rate_variability_data() - avg HRV with min/max trend
- get_vo2_max_data() - latest VO2 Max with date
Placeholder Layer:
- get_vitals_avg_hr() - refactored to use data layer
- get_vitals_avg_hrv() - refactored to use data layer
- get_vitals_vo2_max() - refactored to use data layer
All 3 health data functions + 3 placeholder refactors complete.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Data Layer:
- get_sleep_duration_data() - avg duration with hours/minutes breakdown
- get_sleep_quality_data() - Deep+REM percentage with phase breakdown
- get_rest_days_data() - total count + breakdown by rest type
Placeholder Layer:
- get_sleep_avg_duration() - refactored to use data layer
- get_sleep_avg_quality() - refactored to use data layer
- get_rest_days_count() - refactored to use data layer
All 3 recovery data functions + 3 placeholder refactors complete.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Data Layer:
- get_activity_summary_data() - count, duration, calories, frequency
- get_activity_detail_data() - detailed activity log with all fields
- get_training_type_distribution_data() - category distribution with percentages
Placeholder Layer:
- get_activity_summary() - refactored to use data layer
- get_activity_detail() - refactored to use data layer
- get_trainingstyp_verteilung() - refactored to use data layer
All 3 activity data functions + 3 placeholder refactors complete.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Data Layer:
- get_nutrition_average_data() - all macros in one call
- get_nutrition_days_data() - coverage tracking
- get_protein_targets_data() - 1.6g/kg and 2.2g/kg targets
- get_energy_balance_data() - deficit/surplus/maintenance
- get_protein_adequacy_data() - 0-100 score
- get_macro_consistency_data() - 0-100 score
Placeholder Layer:
- get_nutrition_avg() - refactored to use data layer
- get_nutrition_days() - refactored to use data layer
- get_protein_ziel_low() - refactored to use data layer
- get_protein_ziel_high() - refactored to use data layer
All 6 nutrition data functions + 4 placeholder refactors complete.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Log when using created_at as fallback for start_date
- Log when skipping due to missing created_at
- Log when skipping due to invalid date range (total_days <= 0)
This will reveal exactly why Körperfett and Zielgewicht are not added.
- Log each goal processing (name, values, dates)
- Log skip reasons (missing values, no target_date)
- Log exceptions during calculation
- Log successful additions with calculated values
This will reveal why Weight goal (+7% ahead) is not showing up.
OLD: Showed 3 goals with lowest progress %
NEW: Calculates expected progress based on elapsed time vs. total time
Shows goals with largest negative deviation (behind schedule)
Example Weight Goal:
- Total time: 98 days (22.02 - 31.05)
- Elapsed: 34 days (35%)
- Actual progress: 41%
- Deviation: +7% (AHEAD, not behind)
Also updated on_track to show goals with positive deviation (ahead of schedule).
Note: Linear progress is a simplification. Real-world progress curves vary
by goal type (weight loss, muscle gain, VO2max, etc). Future: AI-based
projection models for more realistic expectations.
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>
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>
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>
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>
- 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>
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
- Each circumference point shows most recent value (even from different dates)
- Age annotations: heute, gestern, vor X Tagen/Wochen/Monaten
- Gives AI better context about measurement freshness
- Example: 'Brust 105cm (heute), Nacken 38cm (vor 2 Wochen)'
- Previously only checked c_chest, c_waist, c_hip
- Now includes c_neck, c_belly, c_thigh, c_calf, c_arm
- Fixes 'keine Daten' when entries exist with only non-primary measurements
Problem: dob Spalte ist DATE (PostgreSQL) → Python bekommt datetime.date,
nicht String → strptime() schlägt fehl → age = "unbekannt"
Fix: Prüfe isinstance(dob, str) und handle beide Typen:
- String → strptime()
- date object → direkt verwenden
Jetzt funktioniert {{age}} Platzhalter korrekt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- caliper_summary: use body_fat_pct (not bf_jpl)
- circ_summary: use c_chest, c_waist, c_hip (not brust, taille, huefte)
- get_latest_bf: use body_fat_pct for consistency
Fixes SQL errors when running base prompts that feed pipeline prompts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New placeholder: {{activity_detail}} returns formatted activity log
- Shows last 20 activities with date, type, duration, kcal, HR
- Makes activity analysis prompts work properly
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend complete:
- Migration 017: Add category column to ai_prompts
- placeholder_resolver.py: 20+ placeholders with resolver functions
- Extended routers/prompts.py with CRUD endpoints:
* POST /api/prompts (create)
* PUT /api/prompts/:id (update)
* DELETE /api/prompts/:id (delete)
* POST /api/prompts/:id/duplicate
* PUT /api/prompts/reorder
* POST /api/prompts/preview
* GET /api/prompts/placeholders
* POST /api/prompts/generate (KI-assisted generation)
* POST /api/prompts/:id/optimize (KI analysis)
- Extended models.py with PromptCreate, PromptUpdate, PromptGenerateRequest
Frontend:
- AdminPromptsPage.jsx: Full CRUD UI with category filter, reordering
Meta-Features:
- KI generates prompts from goal description + example data
- KI analyzes and optimizes existing prompts
Next: PromptEditModal, PromptGenerator, api.js integration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>