Commit Graph

308 Commits

Author SHA1 Message Date
b22481d4ce fix: empty string validation + auto-calculate sleep duration
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
Fixes:
1. Empty string → null conversion for optional integer fields
   - Backend validation error: "Input should be a valid integer"
   - Solution: cleanSleepData() converts '' → null before save
   - Applied to: deep/rem/light/awake minutes, quality, wake_count

2. Auto-calculate duration from bedtime + wake_time
   - useEffect watches bedtime + wake_time changes
   - Calculates minutes including midnight crossover
   - Shows clickable suggestion: "💡 Vorschlag: 7h 30min (übernehmen?)"
   - Applied to NewEntryForm + SleepEntry edit mode

3. Improved plausibility check
   - Now triggers correctly in both create and edit mode
   - Live validation as user types

Test results:
 Simple entry (date + duration) saves without error
 Detail fields (phases) trigger plausibility check
 Bedtime + wake time auto-suggest duration
 Suggestion clickable → updates duration field

Note for future release:
- Unify "Erfassen" dialog design across modules
  (Activity/Nutrition/Weight have different styles/tabs)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 13:53:13 +01:00
1644b34d5c fix: manual sleep entry creation + import overwrite protection
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
Critical fixes:
1. Added "+ Schlaf erfassen" button back (was missing!)
   - Opens NewEntryForm component inline
   - Default: 450 min (7h 30min), quality 3
   - Collapsible detail view
   - Live plausibility check

2. Fixed import overwriting manual entries
   - Problem: ON CONFLICT WHERE clause didn't prevent updates
   - Solution: Explicit if/else logic
     - If manual entry exists → skip (don't touch)
     - If non-manual entry exists → UPDATE
     - If no entry exists → INSERT
   - Properly counts imported vs skipped

Test results:
 CSV import with drag & drop
 Inline editing
 Segment timeline view with colors
 Source badges (Manual/Apple Health)
 Plausibility check (backend + frontend)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 13:43:02 +01:00
b52c877367 feat: complete sleep module overhaul - app standard compliance
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
Backend improvements:
- Plausibility check: phases must sum to duration (±5 min tolerance)
- Auto-calculate wake_count from awake segments in import
- Applied to both create_sleep and update_sleep endpoints

Frontend complete rewrite:
-  Drag & Drop CSV import (like NutritionPage)
-  Inline editing (no scroll to top, edit directly in list)
-  Toast notifications (no more alerts, auto-dismiss 4s)
-  Source badges (Manual/Apple Health/Garmin with colors)
-  Expandable segment timeline view (JSONB sleep_segments)
-  Live plausibility check (shows error if phases ≠ duration)
-  Color-coded sleep phases (deep/rem/light/awake)
-  Show wake_count in list view

Design improvements:
- Stats card on top (7-day avg)
- Import drag zone with visual feedback
- Clean inline edit mode with validation
- Timeline view with phase colors
- Responsive button layout

Confirmed: Kernschlaf (Apple Health) = Leichtschlaf (light_minutes) ✓

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 13:09:34 +01:00
da376a8b18 feat: store full datetime in sleep_segments JSONB
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
Enhanced sleep_segments data structure:
- start: ISO datetime (2026-03-21T22:30:00) instead of HH:MM
- end: ISO datetime (2026-03-21T23:15:00) - NEW
- phase: sleep phase type
- duration_min: duration in minutes

Benefits:
- Exact timestamp for each segment (no date ambiguity)
- Can reconstruct complete sleep timeline
- Enables precise cycle analysis
- Handles midnight crossings correctly

Example:
[
  {"phase": "light", "start": "2026-03-21T22:30:00", "end": "2026-03-21T23:15:00", "duration_min": 45},
  {"phase": "deep", "start": "2026-03-21T23:15:00", "end": "2026-03-22T00:30:00", "duration_min": 75}
]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 12:57:20 +01:00
9a9c597187 fix: sleep import groups segments by gap instead of date boundary
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 13s
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>
2026-03-22 12:09:25 +01:00
b1a92c01fc feat: Apple Health CSV import for sleep data (v9d Phase 2c)
All checks were successful
Deploy Development / deploy (push) Successful in 45s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 12s
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>
2026-03-22 11:49:09 +01:00
b65efd3b71 feat: add missing migration 008 (vitals, rest days, sleep_goal_minutes)
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
- 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>
2026-03-22 10:59:55 +01:00
9e4d6fa715 fix: make sleep stats optional to prevent page crash
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
If stats endpoint fails, page will still load with empty stats.
This prevents 500 errors from blocking the entire sleep page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 08:33:28 +01:00
836bc4294b fix: convert empty strings to None for TIME fields in sleep router
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
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>
2026-03-22 08:28:44 +01:00
39d676e5c8 fix: migration 009 - change profile_id from VARCHAR(36) to UUID
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
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>
2026-03-22 08:22:58 +01:00
ef81c46bc0 feat: v9d Phase 2b - Sleep Module Core (Schlaf-Modul)
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
- 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>
2026-03-22 08:17:11 +01:00
40a4739349 docs: mark v9d Phase 1b as deployed to production
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
- Successful production deployment confirmed (21.03.2026)
- Document complete learnable mapping system
- List all 4 migrations (004-007)
- Update roadmap: Phase 2 next

v9d Phase 1b complete:
- 29 training types
- DB-based learnable mapping system
- Apple Health import with German support
- Inline editing UX
- Auto-learning from bulk categorization

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 21:25:18 +01:00
3be82dc8c2 feat: inline editing for activity mappings (improved UX)
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
- Edit form now appears at the position of the item being edited
- No scrolling needed - stays at same location
- Matches ActivityPage inline editing behavior
- Visual indicator: Accent border when editing
- Create form still appears at top (separate from list)

Benefits:
- Better UX - no need to scroll to top
- Easier to find edited item after saving
- Consistent with rest of app

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 19:46:11 +01:00
829edecbdc feat: learnable activity type mapping system (DB-based, auto-learning)
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 12s
Replaces hardcoded mappings with database-driven, self-learning system.

Backend:
- Migration 007: activity_type_mappings table
  - Supports global and user-specific mappings
  - Seeded with 40+ default mappings (German + English)
  - Unique constraint: (activity_type, profile_id)
- Refactored: get_training_type_for_activity() queries DB
  - Priority: user-specific → global → NULL
- Bulk categorization now saves mapping automatically
  - Source: 'bulk' for learned mappings
- admin_activity_mappings.py: Full CRUD endpoints
  - List, Get, Create, Update, Delete
  - Coverage stats endpoint
- CSV import uses DB mappings (no hardcoded logic)

Frontend:
- AdminActivityMappingsPage: Full mapping management UI
  - Coverage stats (% mapped, unmapped count)
  - Filter: All / Global
  - Create/Edit/Delete mappings
  - Tip: System learns from bulk categorization
- Added route + admin link
- API methods: adminList/Get/Create/Update/DeleteActivityMapping

Benefits:
- No code changes needed for new activity types
- System learns from user bulk categorizations
- User-specific mappings override global defaults
- Admin can manage all mappings via UI
- Migration pre-populates 40+ common German/English types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 19:31:58 +01:00
a4bd738e6f fix: Apple Health import - German names + duplicate detection
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 13s
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>
2026-03-21 19:16:09 +01:00
4d9ef5b33b docs: mark v9d Phase 1b as complete, ready for production
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 13s
- Update status: Phase 1b complete on develop
- Document all 29 training types
- List all completed features
- Ready for testing and prod deployment
- Next: v9d Phase 2 (Ruhetage, Ruhepuls, HF-Zonen, Schlaf)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 19:02:56 +01:00
d4826c8df4 feat: add training type badges to activity list (v9d Phase 1b complete)
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
- Load training categories in ActivityPage
- Display colored badge next to activity name in list view
- Badge shows category icon + name with category color
- Only shown if training_category is set
- Completes v9d Phase 1b

Ready for testing and production deployment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 19:02:25 +01:00
967d92025c fix: move TrainingTypeDistribution to History + improve admin form UX
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
UX improvements based on user feedback:

1. Move TrainingTypeDistribution from ActivityPage to History page
   - ActivityPage is for data entry, not visualization
   - History (Verlauf) shows personal development/progress
   - Chart now respects period selector (7/30/90/365 days)

2. Improve AdminTrainingTypesPage form styling
   - All input fields now full width (100%)
   - Labels changed from inline to headings above fields
   - Textareas increased from 2 to 4 rows
   - Added resize: vertical for textareas
   - Increased gap between fields from 12px to 16px
   - Follows style guide conventions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 16:56:35 +01:00
eecc00e824 feat: admin CRUD for training types + distribution chart in ActivityPage
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
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>
2026-03-21 15:32:32 +01:00
d164ab932d feat: add extended training types (cardio walk/dance, mind & meditation)
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
- 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>
2026-03-21 15:16:07 +01:00
96b0acacd2 feat: automatic training type mapping for Apple Health import and bulk categorization
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 13s
- 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>
2026-03-21 15:08:18 +01:00
08cead49fe feat(v9d): integrate training type UI components
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
Phase 1b - UI Integration:
===========================

ActivityPage:
- Replace old activity type dropdown with TrainingTypeSelect
- Add training_type_id, training_category, training_subcategory to form
- Two-level selection (category → subcategory)

Dashboard:
- Add TrainingTypeDistribution card (pie chart)
- Shows last 28 days activity distribution by type
- Conditional rendering (only if activities exist)

Still TODO:
- History: Add type badge display (next commit)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 14:56:11 +01:00
df01ee3de3 docs: mark v9d Phase 1 as deployed and tested
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
- Training types system:  deployed to dev
- Logout button:  tested and working
- Migration 004:  applied successfully (23 types)
- API endpoints:  functional

Next: Phase 1b (UI integration)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:46:55 +01:00
410b2ce308 feat(v9d): add training types system + logout button
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
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>
2026-03-21 13:05:33 +01:00
0aca5fda5d docs: update CLAUDE.md for v9c completion and new bug fixes
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 12s
- Mark v9c as deployed to production (21.03.2026)
- Add BUG-005 to BUG-008 (login/verify navigation fixes)
- Document TrialBanner mailto change (on develop)
- Mark v9d as in progress

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 12:56:18 +01:00
526da02512 fix: change trial banner button to mailto contact link
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
Replace subscription selection link with email contact for now.
Future: Central subscription system on jinkendo.de for all apps.

Button text:
- "Abo wählen" → "Abo anfragen"
- "Jetzt upgraden" → "Kontakt aufnehmen"

Opens mailto:mitai@jinkendo.de with pre-filled subject and body.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 12:52:13 +01:00
3dc3774d76 fix: parse JSON error messages and redirect to dashboard
All checks were successful
Deploy Development / deploy (push) Successful in 53s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
1. Parse JSON error responses to extract 'detail' field
   Fixes: {"detail":"..."} shown as raw JSON instead of clean text
2. Redirect 'already_verified' to '/' instead of '/login'
   Fixes: Users land on empty page when already logged in
3. Change button text: "Jetzt anmelden" → "Weiter zum Dashboard"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 12:35:04 +01:00
1cd93d521e fix: email verification redirect and already-used token message
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
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>
2026-03-21 12:28:51 +01:00
1521c2f221 fix: redirect to dashboard after successful login
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
LoginScreen was not navigating after login, leaving users on empty page.
Now explicitly redirects to '/' (dashboard) after successful login.

This fixes the "empty page after first login" issue.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 12:09:37 +01:00
2e68b29d9c fix: improve Dashboard error handling and add debug logging
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
- Add .catch() handler to load() Promise to prevent infinite loading state
- Add console.log statements for component lifecycle debugging
- Make EmailVerificationBanner/TrialBanner conditional on activeProfile
- Ensure greeting header always renders with fallback

This should fix the empty dashboard issue for new users.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 11:56:09 +01:00
e62b05c224 fix: prevent React StrictMode double execution in Verify
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
Added hasVerified flag to prevent useEffect from running twice
in React 18 StrictMode (development mode).

This was causing:
1. First call: 200 OK - verification successful
2. Second call: 400 Bad Request - already verified
3. Error shown to user despite successful verification

The fix ensures verify() only runs once per component mount.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 11:38:03 +01:00
ca9112ebc0 fix: email verification auto-login and user experience
All checks were successful
Deploy Development / deploy (push) Successful in 37s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
AuthContext:
- Added setAuthFromToken() for direct token/profile set
- Used for email verification auto-login (no /login request)
- Properly initializes session with token and profile

Verify.jsx:
- Fixed auto-login: now uses setAuthFromToken() instead of login()
- Added "already_verified" status for better UX
- Auto-redirect to /login after 3s if already verified
- Shows friendly message instead of error

This fixes:
- 422 Unprocessable Entity error during auto-login
- Empty dashboard page after verification (now redirects correctly)
- "Ungültiger Link" error on second click (now shows "bereits bestätigt")

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 10:32:24 +01:00
f843d71d6b feat: resend verification email functionality
All checks were successful
Deploy Development / deploy (push) Successful in 36s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Backend:
- Added POST /api/auth/resend-verification endpoint
- Rate limited to 3/hour to prevent abuse
- Generates new verification token (24h validity)
- Sends new verification email

Frontend:
- Verify.jsx: Added "expired" status with resend flow
- Email input + "Neue Bestätigungs-E-Mail senden" button
- EmailVerificationBanner: Added "Neue E-Mail senden" button
- Shows success/error feedback inline
- api.js: Added resendVerification() helper

User flows:
1. Expired token → Verify page shows resend form
2. Email lost → Dashboard banner has resend button
3. Both flows use same backend endpoint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 10:23:38 +01:00
9fb6e27256 fix: email verification flow and trial system
All checks were successful
Deploy Development / deploy (push) Successful in 35s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
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>
2026-03-21 10:20:06 +01:00
49467ca6e9 docs: document automatic migrations system
All checks were successful
Deploy Development / deploy (push) Successful in 36s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Updated CLAUDE.md to reflect new database migrations system:
- Added backend/migrations/ to directory structure
- Added schema_migrations table to database schema
- Updated deployment section with migration workflow
- Added reference to .claude/docs/technical/MIGRATIONS.md

The migrations system automatically applies SQL files (XXX_*.sql pattern)
on container startup, with tracking in schema_migrations table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 10:12:28 +01:00
913b485500 fix: only process numbered migrations (XXX_*.sql pattern)
All checks were successful
Deploy Development / deploy (push) Successful in 34s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Modified run_migrations() to only process files matching pattern: \d{3}_*.sql
This prevents utility scripts (check_features.sql) and manually applied
migrations (v9c_*.sql) from being executed.

Only properly numbered migrations like 003_add_email_verification.sql
will be processed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 10:08:56 +01:00
22651647cb fix: add automatic migration system to db_init.py
All checks were successful
Deploy Development / deploy (push) Successful in 35s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Added migration tracking and execution to db_init.py:
- Created schema_migrations table to track applied migrations
- Added run_migrations() to automatically apply pending SQL files
- Migrations from backend/migrations/*.sql are now applied on startup

This fixes the missing email verification columns (migration 003).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 10:07:37 +01:00
9fa60434c1 fix: correct AuthContext import in Verify.jsx
All checks were successful
Deploy Development / deploy (push) Successful in 34s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 12s
Fixed build error where AuthContext was imported directly instead of using the useAuth hook.
Changed from import { AuthContext } + useContext(AuthContext) to import { useAuth } + useAuth().

This was blocking the Docker build and production deployment of v9c.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 09:59:59 +01:00
514b68e34f docs: v9c finalization complete
Some checks failed
Deploy Development / deploy (push) Failing after 24s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 12s
Updates:
- Bug-Fixes: Added BUG-003 (chart extrapolation) and BUG-004 (history refresh)
- v9c Finalization: Self-registration + Trial UI marked as complete
- Moved open items to v9d

v9c is now feature-complete and ready for production deployment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 09:57:26 +01:00
961897ce2f feat: add trial system UI with countdown banner
Some checks failed
Deploy Development / deploy (push) Failing after 24s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Component:
- TrialBanner.jsx: Displays remaining trial days with urgency levels

Features:
- Calculates days left from profile.trial_ends_at
- Three urgency levels:
  * Normal (>7 days): Accent blue, "Abo wählen"
  * Warning (≤7 days): Orange, "Abo wählen"
  * Urgent (≤3 days): Red + ⚠️, "Jetzt upgraden"
- Auto-hides when no trial or trial ended
- Responsive flex layout
- Call-to-action button links to /settings?tab=subscription

Integration:
- Added to Dashboard after header greeting
- Uses activeProfile from ProfileContext
- Clean, non-intrusive design

UX:
- Clear messaging: "Trial endet in X Tagen"
- Special case: "morgen" for 1 day left
- Color-coded severity (blue → orange → red)
- Prominent CTA button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 09:56:35 +01:00
86f7a513fe feat: add self-registration frontend
Some checks failed
Deploy Development / deploy (push) Failing after 25s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Components:
- Register.jsx: Registration form with validation
- Verify.jsx: Email verification page with auto-login
- API calls: register(), verifyEmail()

Features:
- Form validation (name min 2, email format, password min 8, password confirm)
- Success screen after registration (check email)
- Auto-login after verification → redirect to dashboard
- Error handling for invalid/expired tokens
- Link to registration from login page

Routes:
- /register → public (no login required)
- /verify?token=xxx → public
- Pattern matches existing /reset-password handling

UX:
- Clean success/error states
- Loading spinners
- Auto-redirect after verify (2s)
- "Jetzt registrieren" link on login

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 09:55:23 +01:00
c1562a27f4 feat: add self-registration with email verification
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>
2026-03-21 09:53:11 +01:00
888b5c3e40 fix: [BUG-003] correlations chart shows all weight data with extrapolation
All checks were successful
Deploy Development / deploy (push) Successful in 35s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Changes:
- Show all data points (kcal OR weight, not only both)
- Extrapolate missing kcal values at end (use last known value)
- Dashed lines (strokeDasharray) for extrapolated values
- Solid lines for real measurements
- Weight always interpolates gaps (connectNulls=true)

Visual distinction:
- Solid = Real measurements + gap interpolation
- Dashed = Extrapolation at chart end

Closes: BUG-003

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 09:51:20 +01:00
d1675dcc80 fix: [BUG-004] import history refreshes after CSV import
Solution: Force remount ImportHistory via key prop
- Added importHistoryKey state (timestamp)
- Update key after import → triggers useEffect reload
- ImportHistory now updates immediately after import

Closes: BUG-004

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 09:50:35 +01:00
770a49b5f3 fix: update version string to v9c
All checks were successful
Deploy Development / deploy (push) Successful in 35s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 08:59:24 +01:00
0ab13c282e docs: update CLAUDE.md for v9c completion
All checks were successful
Deploy Development / deploy (push) Successful in 35s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 12s
Changes:
- Version: v9c-dev → v9c (komplett)
- Added nutrition module enhancements (manual entry, edit/delete, filters, import history)
- Documented bug fixes (BUG-001, BUG-002)
- Moved open items to v9d
- Two-level tab layout documented

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 08:47:04 +01:00
1f1100c289 refactor: restructure nutrition page with two-level tabs
All checks were successful
Deploy Development / deploy (push) Successful in 35s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Layout changes:
- Input tabs at top: ✏️ Einzelerfassung (default) | 📥 Import
- Single entry form shown by default (was hidden in data tab)
- Import panel + history only visible in Import tab
- Analysis section below (unchanged): OverviewCards + Analysis tabs

Benefits:
- Cleaner separation of input methods vs analysis
- Manual entry more discoverable (was buried in data tab)
- Import history only shown when relevant
- Reduces clutter on initial view

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 08:43:55 +01:00
02ca9772d6 feat: add manual nutrition entry form with auto-detect
All checks were successful
Deploy Development / deploy (push) Successful in 34s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
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>
2026-03-21 08:37:01 +01:00
873f08042e feat: add date filter to nutrition data tab
All checks were successful
Deploy Development / deploy (push) Successful in 33s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 13s
Added dropdown filter with options:
- Letzte 7 Tage
- Letzte 30 Tage (default)
- Letzte 90 Tage
- Letztes Jahr
- Alle anzeigen

Shows filtered count vs total count in title.
Handles large datasets (7+ years) efficiently.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 08:33:03 +01:00
0f072f4735 feat: add nutrition entry editing and import history
All checks were successful
Deploy Development / deploy (push) Successful in 33s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 12s
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>
2026-03-21 08:26:47 +01:00