Problem:
- Photo upload with empty date parameter (date='')
- PostgreSQL rejects empty string for DATE field
- Error: "invalid input syntax for type date: ''"
- Occurred when saving circumference entry with only photo
Fix:
- Convert empty string to NULL before INSERT
- Check: date if date and date.strip() else None
- NULL is valid for optional date field
Test case:
- Circumference entry with only photo → should work now
- Photo without date → stored with date=NULL ✓
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Conceptual change: duration_minutes = actual sleep time (not time in bed)
Backend:
- Plausibility check: deep + rem + light = duration (awake separate)
- Import: duration = deep + rem + light (without awake)
- Updated error message: clarifies awake not counted
Frontend:
- Label: "Schlafdauer (reine Schlafzeit, Minuten)"
- Auto-calculate: bedtime-waketime minus awake_minutes
- Plausibility check: only validates sleep phases (not awake)
- Both NewEntry and Edit mode updated
Rationale:
- Standard in sleep tracking (Apple Health shows "Sleep", not "Time in Bed")
- Clearer semantics: duration = how long you slept
- awake_minutes tracked separately for analysis
- More intuitive for users
Example:
- Time in bed: 22:00 - 06:00 = 480 min (8h)
- Awake phases: 30 min
- Sleep duration: 450 min (7h 30min) ✓
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Problem: Segments crossing midnight were split into different nights
- 22:30-23:15 (21.03) → assigned to 21.03
- 00:30-02:45 (22.03) → assigned to 22.03
But both belong to the same night (21/22.03)!
Solution: Gap-based grouping
- Sort segments chronologically
- Group segments with gap < 2 hours
- Night date = wake_time.date() (last segment's end date)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend:
- New endpoint POST /api/sleep/import/apple-health
- Parses Apple Health sleep CSV format
- Maps German phase names (Kern→light, REM→rem, Tief→deep, Wach→awake)
- Aggregates segments by night (wake date)
- Stores raw segments in JSONB (sleep_segments)
- Does NOT overwrite manual entries (source='manual')
Frontend:
- Import button in SleepPage with file picker
- Progress indicator during import
- Success/error messages
- Auto-refresh after import
Documentation:
- Added architecture rules reference to CLAUDE.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PostgreSQL TIME type doesn't accept empty strings.
Converting empty bedtime/wake_time to None before INSERT/UPDATE.
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>
Issue 1: Automatic training type mapping didn't work
- Root cause: Only English workout names were mapped
- Solution: Added 20+ German workout type mappings:
- "Traditionelles Krafttraining" → hypertrophy
- "Outdoor Spaziergang" → walk
- "Innenräume Spaziergang" → walk
- "Matrial Arts" → technique (handles typo)
- "Cardio Dance" → dance
- "Geist & Körper" → yoga
- Plus: Laufen, Gehen, Radfahren, Schwimmen, etc.
Issue 2: Reimporting CSV created duplicates without training types
- Root cause: Import always did INSERT with new UUID, no duplicate check
- Solution: Check if entry exists (profile_id + date + start_time)
- If exists: UPDATE with new data + training type mapping
- If new: INSERT as before
- Handles multiple workouts per day (different start times)
- "Skipped" count now includes updated entries
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>
- Add get_training_type_for_apple_health() mapping function (23 workout types)
- CSV import now automatically assigns training_type_id/category/subcategory
- New endpoint: GET /activity/uncategorized (grouped by activity_type)
- New endpoint: POST /activity/bulk-categorize (bulk update training types)
- New component: BulkCategorize with two-level dropdown selection
- ActivityPage: new "Kategorisieren" tab for existing activities
- Update CLAUDE.md: v9d Phase 1b progress
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>
1. Use window.location.href instead of navigate() for reliable redirect
2. Improve backend error message for already-used verification tokens
3. Show user-friendly message when token was already verified
4. Reduce redirect delay from 2s to 1.5s for better UX
Fixes:
- Empty page after email verification
- Generic error when clicking verification link twice
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend fixes:
- Fixed timezone-aware datetime comparison in verify_email endpoint
- Added trial_ends_at (14 days) for new registrations
- All datetime.now() calls now use timezone.utc
Frontend additions:
- Added EmailVerificationBanner component for unverified users
- Banner shows warning before trial banner in Dashboard
- Clear messaging about verification requirement
This fixes the 500 error on email verification and ensures new users
see both verification and trial status correctly.
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>
Features:
- Manual entry form above data list
- Date picker with auto-load existing entries
- Upsert logic: creates new or updates existing entry
- Smart button text: "Hinzufügen" vs "Aktualisieren"
- Prevents duplicate entries per day
- Feature enforcement for nutrition_entries
Backend:
- POST /nutrition - Create or update entry (upsert)
- GET /nutrition/by-date/{date} - Load entry by date
- Auto-detects existing entry and switches to UPDATE mode
- Increments usage counter only on INSERT
Frontend:
- EntryForm component with date picker + macros inputs
- Auto-loads data when date changes
- Shows info message when entry exists
- Success/error feedback
- Disabled state while loading/saving
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Features:
- Import history panel showing all CSV imports with date, count, and range
- Edit/delete functionality for nutrition entries (inline editing)
- New backend endpoints: GET /import-history, PUT /{id}, DELETE /{id}
UI Changes:
- Import history displayed under import panel
- "Daten" tab now has edit/delete buttons per entry
- Inline form for editing macros (kcal, protein, fat, carbs)
- Confirmation dialog for deletion
Backend:
- nutrition.py: Added import_history, update_nutrition, delete_nutrition endpoints
- Groups imports by created date to show history
Frontend:
- NutritionPage: New DataTab and ImportHistory components
- api.js: Added nutritionImportHistory, updateNutrition, deleteNutrition
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Problem:
- /api/nutrition/weekly crashed with 500 Internal Server Error
- TypeError: strptime() argument 1 must be str, not datetime.date
Root Cause:
- d['date'] from PostgreSQL is already datetime.date object
- datetime.strptime() expects string input
- Line 156: wk=datetime.strptime(d['date'],'%Y-%m-%d').strftime('%Y-W%V')
Solution:
- Added type check before strptime()
- If date already has strftime method → use directly
- Else → parse as string first
- Works with both datetime.date objects and strings
Tested:
- /nutrition page loads without error
- Weekly aggregation works correctly
- Chart displays nutrition data
Closes: BUG-001
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add user-facing usage overview endpoint
- Returns all features with usage, limits, reset info
- Fully dynamic - automatically includes new features
- Phase 3: Frontend Display preparation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create feature_logger.py with JSON logging infrastructure
- Add log_feature_usage() calls to all 9 routers after check_feature_access()
- Logs written to /app/logs/feature-usage.log
- Tracks all usage (not just violations) for future analysis
- Phase 2: Non-blocking monitoring complete
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixes two critical bugs in AI analysis storage:
1. History now works - analyses are saved, not overwritten
- Removed DELETE statements before INSERT in insights.py
- All analyses are now preserved per scope
- Displayed in descending order by creation date
2. Pipeline saves under correct scope 'pipeline' instead of 'gesamt'
- Changed scope from 'gesamt' to 'pipeline' in pipeline endpoint
- Pipeline results now appear under correct category in history
3. Fixed pipeline appearing twice in UI
- Filter now excludes both 'pipeline_*' and 'pipeline' from individual list
- Pipeline only appears in dedicated section at top
Changes:
- backend/routers/insights.py: Removed DELETE, changed scope to 'pipeline'
- frontend/src/pages/Analysis.jsx: Fixed filter to exclude 'pipeline'
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reverts all feature enforcement changes (commits 3745ebd, cbad50a, cd4d912, 8415509)
to restore original working functionality.
Issues caused by feature enforcement implementation:
- Export buttons disappeared and never reappeared
- KI analysis counter not incrementing
- New analyses not saving
- Pipeline appearing twice
- Many core features broken
Restored files to working state before enforcement implementation (commit 0210844):
- Backend: auth.py, insights.py, exportdata.py, importdata.py, nutrition.py, activity.py
- Frontend: Analysis.jsx, SettingsPage.jsx, api.js
- Removed: FeatureGate.jsx, useFeatureAccess.js
The original simple AI limit system (ai_enabled, ai_limit_day) is now active again.
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>
- Remove active=true filter - admins need to configure all tiers
- Add reset_period to features query for frontend display
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New router: routers/coupons.py
Admin endpoints:
- GET /api/coupons - List all coupons with stats
- POST /api/coupons - Create new coupon
- PUT /api/coupons/{id} - Update coupon
- DELETE /api/coupons/{id} - Soft-delete (set active=false)
- GET /api/coupons/{id}/redemptions - Redemption history
User endpoints:
- POST /api/coupons/redeem - Redeem coupon code
Features:
- Three coupon types: single_use, period, wellpass
- Wellpass logic: Pauses existing personal grants, resumes after expiry
- Max redemptions limit (NULL = unlimited)
- Validity period checks
- Activity logging
- Duplicate redemption prevention
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New router: routers/subscription.py
Endpoints:
- GET /api/subscription/me - Own subscription info (tier, trial, grants)
- GET /api/subscription/usage - Feature usage with limits
- GET /api/subscription/limits - All feature limits for current tier
Features:
- Shows effective tier (considers access_grants)
- Lists active access grants (from coupons, trials)
- Per-feature usage tracking
- Email verification status
Uses new middleware: get_effective_tier(), check_feature_access()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>