- Full-width fields with section headers (mobile-friendly)
- Inline editing for all measurements (edit mode per row)
- Smart upsert: date change loads existing entry → update instead of duplicate
- Units integrated into labels (no overflow)
- Baseline: auto-detects existing entry and switches to update mode
- Blood Pressure: inline editing with all fields (date, time, BP, context, flags)
- Edit/Save/Cancel buttons with lucide-react icons
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Einfache 3-Tab-Struktur als Platzhalter:
- Morgenmessung (Baseline)
- Blutdruck (BP)
- Import
Verhindert Crash durch alte API-Calls.
Vollständige UI folgt nach Backend-Test.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ModuleNotFoundError: No module named 'dateutil' beim Server-Start.
Ursache: vitals.py importiert dateutil.parser für Omron-Datumsformatierung,
aber python-dateutil fehlte in requirements.txt.
Fix: python-dateutil==2.9.0 zu requirements.txt hinzugefügt.
Nach dem Update: Docker Container neu bauen auf dem Pi:
cd /home/lars/docker/bodytrack-dev
docker compose -f docker-compose.dev-env.yml build --no-cache backend
docker compose -f docker-compose.dev-env.yml up -d
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
**Backend (insights.py):**
- Extended _get_profile_data() to fetch sleep, rest_days, vitals
- Added template variables for Sleep Module:
{{sleep_summary}}, {{sleep_detail}}, {{sleep_avg_duration}}, {{sleep_avg_quality}}
- Added template variables for Rest Days:
{{rest_days_summary}}, {{rest_days_count}}, {{rest_days_types}}
- Added template variables for Vitals:
{{vitals_summary}}, {{vitals_detail}}, {{vitals_avg_hr}}, {{vitals_avg_hrv}},
{{vitals_avg_bp}}, {{vitals_vo2_max}}
**Frontend (Analysis.jsx):**
- Added 12 new template variables to VARS list in PromptEditor
- Enables AI prompt creation for Sleep, Rest Days, and Vitals analysis
All modules now have AI evaluation support for future prompt creation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Mark Sleep Module as complete (Phase 2b)
- Mark Rest Days as complete (Phase 2a)
- Mark Extended Vitals as complete (Phase 2d)
- Add migration details (010-014)
- HF-Zonen + Recovery Score marked as next (Phase 2e)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Import endpoints for Omron blood pressure CSV (German date format)
- Import endpoints for Apple Health vitals CSV
- Import UI tab in VitalsPage with drag & drop for both sources
- German month mapping for Omron date parsing ("13 März 2026")
- Upsert logic preserves manual entries (source != 'manual')
- Import result feedback (inserted/updated/skipped/errors)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Avg blood pressure (systolic/diastolic) 7d and 30d
- Latest VO2 Max value
- Avg SpO2 7d and 30d
- Backend now provides all metrics expected by frontend
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Form sections:
- Morgenmessung: Ruhepuls, HRV
- Blutdruck (Omron): Systolisch, Diastolisch, Puls
- Fitness & Sauerstoff (Apple Watch): VO2 Max, SpO2, Atemfrequenz
- Warnungen: Unregelmäßiger Herzschlag, Mögliches AFib (checkboxes)
Display:
- All vitals shown in entry list with icons
- Blood pressure highlighted in red (🩸)
- VO2 Max in green (🏃)
- Warnings in orange (⚠️)
Stats overview:
- Dynamic grid showing available metrics
- Avg blood pressure 7d
- Latest VO2 Max
- Avg SpO2 7d
Save/Update:
- Only non-empty fields included in payload
- At least one vital must be provided
Ready for manual testing + import implementation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migration 014:
- blood_pressure_systolic/diastolic (mmHg)
- pulse (bpm) - during BP measurement
- vo2_max (ml/kg/min) - from Apple Watch
- spo2 (%) - blood oxygen saturation
- respiratory_rate (breaths/min)
- irregular_heartbeat, possible_afib (boolean flags from Omron)
- Added 'omron' to source enum
Backend:
- Updated Pydantic models (VitalsEntry, VitalsUpdate)
- Updated all SELECT queries to include new fields
- Updated INSERT/UPDATE with COALESCE for partial updates
- Validation: at least one vital must be provided
Preparation for Omron + Apple Health imports
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Only include fields in payload if they have values
- Prevents sending empty strings to backend (Pydantic validation error)
- Applies to both create and update operations
Error was: 'Input should be a valid integer, unable to parse string as an integer'
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend:
- New router: vitals.py with CRUD endpoints
- GET /api/vitals (list)
- GET /api/vitals/by-date/{date}
- POST /api/vitals (upsert)
- PUT /api/vitals/{id}
- DELETE /api/vitals/{id}
- GET /api/vitals/stats (7d/30d averages, trends)
- Registered in main.py
Frontend:
- VitalsPage.jsx with manual entry form
- List with inline editing
- Stats overview (averages, trend indicators)
- Added to CaptureHub (❤️ icon)
- Route /vitals in App.jsx
API:
- Added vitals methods to api.js
v9d Phase 2d - Vitals tracking complete
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Changed from 'folgt in nächster Iteration' to 'Analyse & Entwicklung, folgen später'
- Listed all 5 dimensions with clear purpose
- Clarifies that Minimum Requirements is sufficient for validation
- Other dimensions planned for v9e/v9f (ability development, AI prompts)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changes:
- Responsive layout: fields stack vertically, no more cramped grid
- Clear labels: 'WAS?', 'BEDINGUNG', 'WICHTIGKEIT'
- Weight field only shown when using 'weighted_score' strategy
- Weight explanation: '1 = unwichtig, 10 = sehr wichtig'
- Success message replaces alert() dialog (auto-dismiss after 2s)
- Delete button moved to rule header
- Better visual hierarchy with sections
User feedback:
- Felder lassen sich auf Handy nicht gut bearbeiten
- Überschriften nicht eindeutig
- Gewicht-Feld Verwirrung
- Keine OK-Dialoge
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Added label row: PARAMETER | OPERATOR | SCHWELLENWERT | GEWICHT
- Prevents confusion between threshold value and weight fields
- Better placeholder for value field (z.B. 90)
- Between operator: stacked vertical inputs with Min/Max labels
- User feedback: confusion between value and weight fields
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- PostgreSQL returns numeric values as Decimal objects
- psycopg2.Json() cannot serialize Decimal to JSON
- Added convert_decimals() helper function
- Converts activity_data, context, and evaluation_result before saving
Fixes: Batch evaluation errors (31 errors 'Decimal is not JSON serializable')
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ✓ Green: Successfully evaluated (excellent/good/acceptable/poor)
- ⚠ Orange: Training type assigned but not evaluated (no profile)
- ✕ Gray: No training type assigned
- Tooltip shows evaluation details on hover
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Shows first 10 errors with activity_id and error message
- Helps admin debug evaluation failures
- Errors shown in error box with details
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Shows first 10 errors with activity_id, training_type_id, and error message
- Helps debug evaluation failures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ProfileBuilder now renders inline below training type row
- Type editor form also inline (not at top of page)
- Both forms appear at item position with marginTop: 8
- User feedback: 'Die Position bleibt die ganze Zeit gleich!'
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MAJOR UX IMPROVEMENT - No more JSON editing required!
New Component: ProfileBuilder.jsx
- Visual form for configuring training type profiles
- Parameter dropdown (dynamically loaded from API)
- Operator dropdown (>=, <=, >, <, =, ≠, between)
- Value input (type-aware, between shows min/max)
- Weight slider (1-10)
- Add/remove rules visually
- Pass strategy selection
- Optional checkbox per rule
- Expandable sections
Integration: AdminTrainingTypesPage.jsx
- Added ProfileBuilder component
- ⚙️ Settings icon per training type
- Opens visual form when clicked
- ✓ Profil badge shows configured types
- Loads 16 parameters from API
- Save directly to training type
User Experience:
1. Go to /admin/training-types
2. Click ⚙️ icon on any type
3. Visual form opens
4. Add rules via dropdowns
5. Save → Profile configured!
NO JSON EDITING NEEDED! 🎉
Next: Add visual builders for other dimensions (Zones, Effects, etc.)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixed "U.get is not a function" error:
- Added missing API methods to api.js:
- getProfileStats()
- getProfileTemplates()
- applyProfileTemplate()
- getTrainingParameters()
- batchEvaluateActivities()
- Updated AdminTrainingProfiles.jsx to use correct methods
- Replaced api.get/post/put with specific named methods
Error resolved. Page should now load correctly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New admin page for profile configuration:
- AdminTrainingProfiles.jsx: Profile management interface
- Statistics dashboard (configured/unconfigured count)
- Training types list with profile status badges
- JSON-based profile editor (modal)
- One-click template application (Running, Meditation, Strength)
- Batch re-evaluation button for existing activities
- Link in AdminPanel under "Trainingstypen (v9d)"
Features:
- Apply templates with one click
- Edit profiles as JSON in modal
- Real-time validation
- Success/error messages
- Responsive layout
Route: /admin/training-profiles
Next: Test and iterate, then Phase 3 (User-UI for viewing results)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
SQL Error: VALUES lists must all be the same length (line 130)
Cause: kcal_per_km row was missing validation_rules JSONB value
Fixed: Added validation_rules '{"min": 0, "max": 1000}'::jsonb
All 16 parameter rows now have correct 10 columns:
key, name_de, name_en, category, data_type, unit, source_field,
validation_rules, description_de, description_en
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Problem: Backend crashed on startup due to evaluation import failure
Solution: Wrap evaluation_helper import in try/except
Changes:
- Import evaluation_helper with error handling
- Add EVALUATION_AVAILABLE flag
- All evaluation calls now check flag before executing
- System remains functional even if evaluation system unavailable
This prevents backend crashes if:
- Migrations haven't run yet
- Dependencies are missing
- Import errors occur
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Automatic evaluation on activity INSERT/UPDATE:
- create_activity(): Evaluate after manual creation
- update_activity(): Re-evaluate after manual update
- import_activity_csv(): Evaluate after CSV import (INSERT + UPDATE)
- bulk_categorize_activities(): Evaluate after bulk training type assignment
All evaluation calls wrapped in try/except to prevent activity operations
from failing if evaluation encounters an error. Only activities with
training_type_id assigned are evaluated.
Phase 1.2 complete ✅
## Next Steps (Phase 2):
Admin-UI for training type profile configuration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>