Migration 028 failed because goals table doesn't have is_active column yet.
Removed WHERE clause from index definition.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixed health mode calculation to include all 6 dimensions.
Simplified CASE statements (single CASE instead of multiple additions).
Before: health mode only set flexibility (15%) + health (55%) = 70% ❌
After: health mode sets all dimensions = 100% ✅
- weight_loss: 5%
- muscle_gain: 0%
- strength: 10%
- endurance: 20%
- flexibility: 15%
- health: 50%
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixed health mode calculation in focus_areas migration.
Changed health_pct from 50 to 55 to ensure sum equals 100%.
Before: 0+0+10+20+15+50 = 95% (constraint violation)
After: 0+0+10+20+15+55 = 100% (valid)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BREAKING: Replaces single 'primary goal' with weighted multi-goal system
Migration 027:
- New table: focus_areas (6 dimensions with percentages)
- Constraint: Sum must equal 100%
- Auto-migration: goal_mode → focus_areas for existing users
- Unique constraint: One active focus_areas per profile
Backend:
- get_focus_weights() V2: Reads from focus_areas table
- Fallback: Uses goal_mode if focus_areas not set
- New endpoints: GET/PUT /api/goals/focus-areas
- Validation: Sum=100, range 0-100
API:
- getFocusAreas() - Get current weights
- updateFocusAreas(data) - Update weights (upsert)
Focus dimensions:
1. weight_loss_pct (Fettabbau)
2. muscle_gain_pct (Muskelaufbau)
3. strength_pct (Kraftsteigerung)
4. endurance_pct (Ausdauer)
5. flexibility_pct (Beweglichkeit)
6. health_pct (Allgemeine Gesundheit)
Benefits:
- Multiple goals with custom priorities
- More flexible than single primary goal
- KI can use weighted scores
- Ready for Phase 0b placeholder integration
UI: Coming in next commit (slider interface)
NEW FEATURE: Filter conditions for goal types
Enables counting/aggregating specific subsets of data.
Example use case: Count only strength training sessions per week
- Create goal type with filter: {"training_type": "strength"}
- count_7d now counts only strength training, not all activities
Implementation:
- Migration 026: filter_conditions JSONB column
- Backend: Dynamic WHERE clause building from JSON filters
- Supports single value: {"training_type": "strength"}
- Supports multiple values: {"training_type": ["strength", "hiit"]}
- Works with all 8 aggregation methods (count, avg, sum, min, max)
- Frontend: JSON textarea with example + validation
- Pydantic models: filter_conditions field added
Technical details:
- SQL injection safe (parameterized queries)
- Graceful degradation (invalid JSON ignored with warning)
- Backward compatible (NULL filters = no filtering)
Answers user question: 'Kann ich Trainingstypen wie Krafttraining separat zählen?'
Answer: YES! 🎯
Fixes cases where Migration 024 partially ran:
- Removes created_by/updated_by columns if they exist
- Re-inserts seed data with ON CONFLICT DO NOTHING
- Fully automated, no manual intervention needed
- Production-safe (idempotent)
This ensures clean deployment to production without manual DB changes.
Goal type definitions are global system entities, not user-specific.
System types seeded in migration cannot have created_by FK.
Changes:
- Remove created_by/updated_by columns from goal_type_definitions
- Update CREATE/UPDATE endpoints to not use these fields
- Migration now runs cleanly on container start
- No manual intervention needed for production deployment
The migration system tracks migrations via filename automatically.
Removed manual DO block that used wrong column name (version vs filename).
Also removed unused json import from goals.py.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Issue: template has NOT NULL constraint but pipeline-type prompts
don't use template (they use stages JSONB instead).
Solution: ALTER COLUMN template DROP NOT NULL before inserting
pipeline configs into ai_prompts.
Fixed Step 3 pipeline_configs migration:
- Simplified JSONB aggregation logic
- Properly scope pc alias in subqueries
- Use UNNEST with FROM clause for array expansion
Previous version had correlation issues with nested subqueries.
Migration 018:
- Add display_name column to ai_prompts
- Migrate existing prompts from hardcoded SLUG_LABELS
- Fallback: name if display_name is NULL
Backend:
- PromptCreate/Update models with display_name field
- create/update/duplicate endpoints handle display_name
- Fallback: use name if display_name not provided
Frontend:
- PromptEditModal: display_name input field
- Placeholder picker: button + dropdown with all placeholders
- Shows example values, inserts {{placeholder}} on click
- Analysis.jsx: use display_name instead of SLUG_LABELS
User-facing changes:
- Prompts now show custom display names (e.g. '🍽️ Ernährung')
- Admin can edit display names instead of hardcoded labels
- Template editor has 'Platzhalter einfügen' button
- No more hardcoded SLUG_LABELS in frontend
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>
Implemented global quality_filter_level in user profiles for consistent
data filtering across all views (Dashboard, History, Charts, KI-Pipeline).
Backend changes:
- Migration 016: Add quality_filter_level column to profiles table
- quality_filter.py: Centralized helper functions for SQL filtering
- insights.py: Apply global filter in _get_profile_data()
- activity.py: Apply global filter in list_activity()
Frontend changes:
- SettingsPage.jsx: Add Datenqualität section with 4-level selector
- History.jsx: Use global quality filter from profile context
Filter levels: all, quality (good+excellent+acceptable), very_good
(good+excellent), excellent (only excellent)
Closes#31
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>
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: User can create multiple rest days of same type per date
(e.g., 2x Mental Rest on 2026-03-23) - makes no sense.
Solution: UNIQUE constraint on (profile_id, date, focus)
## Migration 012:
- Add focus column (extracted from rest_config JSONB)
- Populate from existing data
- Add NOT NULL constraint
- Add CHECK constraint (valid focus values)
- Add UNIQUE constraint (profile_id, date, focus)
- Add index for performance
## Backend:
- Insert focus column alongside rest_config
- Handle UniqueViolation gracefully
- User-friendly error: "Du hast bereits einen Ruhetag 'Muskelregeneration' für 23.03."
## Benefits:
- DB-level enforcement (clean)
- Fast queries (no JSONB scan)
- Clear error messages
- Prevents: 2x muscle_recovery same day
- Allows: muscle_recovery + mental_rest same day ✓
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Creates rest_days table for rest day tracking
- Creates vitals_log table for resting HR + HRV
- Creates weekly_goals table for training planning
- Extends profiles with hf_max and sleep_goal_minutes columns
- Extends activity_log with avg_hr and max_hr columns
- Fixes sleep_goal_minutes missing column error in stats endpoint
- Includes stats error handling in SleepWidget
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Profile IDs are UUID type in the profiles table, not VARCHAR.
This was causing foreign key constraint error on migration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add sleep_log table with JSONB sleep_segments (Migration 009)
- Add sleep router with CRUD + stats endpoints (7d avg, 14d debt, trend, phases)
- Add SleepPage with quick/detail entry forms and inline edit
- Add SleepWidget to Dashboard showing last night + 7d average
- Add sleep navigation entry with Moon icon
- Register sleep router in main.py
- Add 9 new API methods in api.js
Phase 2b complete - ready for testing on dev
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend (v9d Phase 1b):
- Migration 006: Add abilities JSONB column + descriptions
- admin_training_types.py: Full CRUD endpoints for training types
- List, Get, Create, Update, Delete
- Abilities taxonomy endpoint (5 dimensions: koordinativ, konditionell, kognitiv, psychisch, taktisch)
- Validation: Cannot delete types in use
- Register admin_training_types router in main.py
Frontend:
- AdminTrainingTypesPage: Full CRUD UI
- Create/edit form with all fields (category, subcategory, names, icon, descriptions, sort_order)
- List grouped by category with color coding
- Delete with usage check
- Note about abilities mapping coming in v9f
- Add TrainingTypeDistribution to ActivityPage stats tab
- Add admin link in AdminPanel (v9d section)
- Update api.js with admin training types methods
Notes:
- Abilities mapping UI deferred to v9f (flexible prompt system)
- Placeholders (abilities column) in place for future AI analysis
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Migration 005: Add cardio subcategories (Gehen, Tanzen)
- Migration 005: Add new category "Geist & Meditation" with 4 subcategories
(Meditation, Atemarbeit, Achtsamkeit, Visualisierung)
- Update categories endpoint with mind category metadata
- Update Apple Health mapping: dance → dance, add meditation/mindfulness
- 6 new training types total
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 1: Training Types Basis
=============================
Backend:
- Migration 004: training_types table + seed data (24 types)
- New router: /api/training-types (grouped, flat, categories)
- Extend activity_log: training_type_id, training_category, training_subcategory
- Extend ActivityEntry model: support training type fields
Frontend:
- TrainingTypeSelect component (two-level dropdown)
- TrainingTypeDistribution component (pie chart)
- API functions: listTrainingTypes, listTrainingTypesFlat, getTrainingCategories
Quick Win: Logout Button
========================
- Add LogOut icon button in app header
- Confirm dialog before logout
- Redirect to / after logout
- Hover effect: red color on hover
Not yet integrated:
- TrainingTypeSelect not yet in ActivityPage form
- TrainingTypeDistribution not yet in Dashboard
(will be added in next commit)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend:
- New endpoint: POST /api/auth/register
- New endpoint: GET /api/auth/verify/{token}
- Migration: Add email_verified, verification_token, verification_expires
- Helper: send_email() for reusable SMTP
- Validation: email format, password length (min 8), name
- Auto-login after verification (returns session token)
- Rate limit: 3 registrations per hour per IP
Features:
- Verification token valid for 24h
- Existing users marked as verified (grandfather clause)
- SMTP configured via .env (SMTP_HOST, SMTP_USER, SMTP_PASS)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical fixes for feature enforcement:
- Add GET /api/features/{feature_id}/check-access endpoint (was missing!)
- Add migration for missing features: data_export, csv_import
- These features were used in frontend but didn't exist in DB
This fixes:
- "No analysis available" when setting KI limit
- Export features not working
- Frontend calling non-existent API endpoint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changed all profile_id columns from TEXT to UUID to match profiles.id type.
Changed all auto-generated IDs from gen_random_uuid() to uuid_generate_v4()
to match existing schema.sql convention.
Fixed tables:
- tier_limits: id TEXT → UUID
- user_feature_restrictions: id, profile_id, created_by TEXT → UUID
- user_feature_usage: id, profile_id TEXT → UUID
- coupons: id, created_by TEXT → UUID
- coupon_redemptions: id, coupon_id, profile_id, access_grant_id TEXT → UUID
- access_grants: id, profile_id, coupon_id, paused_by TEXT → UUID
- user_activity_log: id, profile_id TEXT → UUID
- user_stats: profile_id TEXT → UUID
- profiles.invited_by: TEXT → UUID
This fixes: foreign key constraint "user_feature_restrictions_profile_id_fkey"
cannot be implemented - Key columns "profile_id" and "id" are of
incompatible types: text and uuid
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>