BREAKING: Analysis page switched from old /insights/run to new /prompts/execute
Changes:
- Backend: Added save=true parameter to /prompts/execute
- When enabled, saves final output to ai_insights table
- Extracts content from pipeline output (last stage)
- Frontend api.js: Added save parameter to executeUnifiedPrompt()
- Frontend Analysis.jsx: Switched from api.runInsight() to api.executeUnifiedPrompt()
- Transforms new result format to match InsightCard expectations
- Pipeline outputs properly extracted and displayed
Fixes: PIPELINE_MASTER responses (old template being sent to AI)
The old /insights/run endpoint used raw template field, which for the
legacy "pipeline" prompt was literally "PIPELINE_MASTER". The new
executor properly handles stages and data processing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Removed conditional hiding of test button (prompt?.slug)
- Button now always visible with helpful tooltip
- handleTest already has save-check logic
Improves discoverability of test functionality.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Frontend: debug viewer now shows even when test fails
- Frontend: export button to download complete prompt config as JSON
- Backend: attach debug info to JSON validation errors
- Backend: include raw output and length in error details
Users can now debug failed prompts and export configs for analysis.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Backend: debug mode in prompt_executor with placeholder tracking
- Backend: show resolved/unresolved placeholders, final prompts, AI responses
- Frontend: test button in UnifiedPromptModal for saved prompts
- Frontend: debug output viewer with JSON preview
- Frontend: wider placeholder example fields in PlaceholderPicker
Resolves pipeline execution debugging issues.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- PlaceholderPicker: Example values in separate full-width row
- Analysis.jsx: Show only pipeline-type prompts
- Analysis.jsx: Remove base prompts and Prompts tab
- Cleanup: Remove PromptEditor component and unused imports
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Major improvements:
1. PlaceholderPicker component (new)
- Loads placeholders dynamically from backend catalog
- Grouped by categories: Profil, Körper, Ernährung, Training, etc.
- Search/filter functionality
- Shows live example values from user data
- Popup modal with expand/collapse categories
2. Replaced hardcoded placeholder chips
- 'Platzhalter einfügen' button opens picker
- Works in both base templates and pipeline inline templates
- Auto-closes after selection
3. Uses existing backend system
- GET /api/prompts/placeholders
- placeholder_resolver.py with PLACEHOLDER_MAP
- Dynamic, module-based placeholder system
- No manual updates needed when modules add new placeholders
Benefits:
- Scalable: New modules can add placeholders without frontend changes
- User-friendly: Search and categorization
- Context-aware: Shows real example values
- Future-proof: Backend-driven catalog
New features:
1. Placeholder chips now visible in pipeline inline templates
- Click to insert: weight_data, nutrition_data, activity_data, etc.
- Same UX as base prompts
2. Convert to Base Prompt button
- New icon (ArrowDownToLine) in actions column
- Only visible for 1-stage pipeline prompts
- Converts pipeline → base by extracting inline template
- Validates: must be 1-stage, 1-prompt, inline source
This allows migrated prompts to be properly categorized as base prompts
for reuse in other pipelines.
Fixes:
1. Template field in stages now full width (was too narrow)
2. Table horizontal scrollbar for mobile (overflow-x: auto)
3. Table min-width 900px to prevent icon clipping
4. Added clickable placeholder chips below base template
- Click to insert placeholders into template
- Shows: weight_data, nutrition_data, activity_data, sleep_data, etc.
UI now mobile-ready and more user-friendly.
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>
- PromptEditModal: all inputs/textareas now full-width
- Labels positioned above fields (not inline)
- Text left-aligned (was right-aligned)
- Added resize:vertical for textareas
- Side-by-side comparison with word-wrap
- Follows app-wide form design pattern
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Frontend components:
- PromptEditModal.jsx: Full editor with preview, generator, optimizer
- PromptGenerator.jsx: KI-assisted prompt creation from goal description
- Extended api.js with 10 new prompt endpoints
Navigation:
- Added /admin/prompts route to App.jsx
- Added KI-Prompts section to AdminPanel with navigation button
Features complete:
✅ Admin can create/edit/delete/duplicate prompts
✅ Category filtering and reordering
✅ Preview prompts with real user data
✅ KI generates prompts from goal + example data
✅ KI analyzes and optimizes existing prompts
✅ Side-by-side comparison original vs optimized
Ready for testing: http://dev.mitai.jinkendo.de/admin/prompts
Issue #28 Phase 2 complete - 13-18h estimated, ~14h actual
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>
Removed local quality filter UI from History page since backend now
handles filtering globally. Activities are already filtered when loaded.
Changes:
- Removed qualityLevel local state
- Simplified filtA to only filter by period
- Replaced filter buttons with info banner showing active global filter
- Added 'Hier ändern →' link to Settings
User can now only change quality filter in Settings (global), not per
page. History shows which filter is active with link to change it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The component was loading data from backend (which uses global filter)
but useEffect dependency didn't include quality_filter_level, so it
didn't reload when user changed the filter in Settings.
Added useProfile() context and activeProfile.quality_filter_level
to dependency array.
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>
Statt einfachem On/Off Toggle jetzt 4 Qualitätsstufen:
- 📊 Alle (kein Filter)
- ✓ Hochwertig (excellent + good + acceptable)
- ✓✓ Sehr gut (excellent + good)
- ⭐ Exzellent (nur excellent)
UI:
- Button-Group (Segmented Control) mit 4 Stufen
- Beschreibung welche Labels inkludiert werden
- Anzeige: X von Y Aktivitäten (wenn gefiltert)
User-Feedback: Stufenweiser Filter ist flexibler als binärer Toggle
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Problem: Errors during import were logged but not visible to user.
Changes:
- Backend: Collect error messages and return in response (first 10 errors)
- Frontend: Display error details in import result box
- UI: Red background when errors > 0, shows detailed error messages
Now users can see exactly which rows failed and why.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>
**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>
- 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>
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>
- 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>
- ✓ 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>
- 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>
- Add RestDaysWidget component showing today's rest days with icons & colors
- Integrate widget into Dashboard (above training distribution)
- Highlight current day in RestDaysPage (accent border + HEUTE badge)
- Fix: Improve error handling in api.js (parse JSON detail field)
Part of v9d Phase 2 (Vitals & Recovery)
Changes:
1. Added sleep entry to CaptureHub (between Activity and Guide)
- Icon: 🌙
- Label: "Schlaf"
- Sub: "Schlafdaten erfassen oder Apple Health importieren"
- Color: #7B68EE (purple)
- Route: /sleep
2. Removed sleep from main bottom navigation
- Nav link removed (was 6 items → now 5 items)
- Moon icon import removed (no longer used)
- Route /sleep remains active (Widget + CaptureHub links work)
3. Widget link unchanged
- SleepWidget.jsx still links to /sleep ✓
- Dashboard → Widget → /sleep works
Result:
- Consistent UX: All data entry under "Erfassen"
- Clean navigation: 5 main nav items (was 6)
- Sleep accessible via: Dashboard Widget or Erfassen → Schlaf
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>
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>
- 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>
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>
- 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>
- 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>
- 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>
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>
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>
- 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 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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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: Imported nutrition data not visible in UI
Root Cause: NutritionPage only had analysis tabs, no raw data view
Solution: Added "Daten" tab with entries list showing date, kcal, macros
Tested: Entries now visible after CSV import
Closes: BUG-002
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Alle verbleibenden Screens mit proaktiver Limit-Anzeige:
- ActivityPage: Manuelle Einträge mit Badge + deaktiviertem Button
- Analysis: AI-Analysen (Pipeline + Einzelanalysen) mit Hover-Tooltip
- NutritionPage: Hat bereits Error-Handling (bulk import)
Konsistentes Pattern:
- Usage-Badge im Titel
- Button deaktiviert + Hover-Tooltip bei Limit
- "🔒 Limit erreicht" Button-Text
- Error-Handling für API-Fehler
- Usage reload nach erfolgreichem Speichern
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Dashboard QuickWeight: Feature limit enforcement hinzugefügt
- Hover-Tooltip Fix: Button in div wrapper (disabled buttons zeigen keine nativen tooltips)
- Error handling für Dashboard weight input
- Konsistentes UX über alle Eingabe-Screens
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implementiert User-freundliches Limit-Feedback für Daten-Einträge:
- Button wird deaktiviert wenn Limit erreicht
- Hover-Tooltip erklärt warum ("Limit erreicht X/Y")
- Button-Text zeigt "🔒 Limit erreicht"
- Error-Handling für alle API-Fehler
- Usage-Badge wird nach Speichern aktualisiert
Betrifft: Weight, Circumference, Caliper Screens
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move all positioning logic from inline styles to CSS
- New classes: .badge-container-right, .badge-button-layout
- All badge styling now in UsageBadge.css (single source)
- Easier to maintain and adjust globally
- Mobile responsive adjustments in one place
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Smaller font (0.65rem), more spacing (10px margin)
- Reduced opacity (0.6), hover effect (0.9)
- OK status now gray instead of green (less prominent)
- Position: right-aligned in headings (flex space-between)
- Buttons: badge on right side of main text, description below
- Much more discreet overall appearance
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Weight page: badge on "Eintrag hinzufügen" heading
- Settings: badges on export buttons (ZIP/JSON)
- Analysis: badges on pipeline and individual analysis titles
- Shows real-time usage status (e.g., "7/5" with red color)
Phase 3: Frontend Display 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>
Major UX improvements:
- Display effective value in input (override if set, otherwise tier limit)
- Format NULL as "unlimited" (easy to type, no special char needed)
- Auto-remove override when value equals tier default
- "Zurück" button resets to tier default value
- Wider input field (120px) for "unlimited" text
This solves:
- User can now see and edit current effective values
- "unlimited" can be typed and saved
- Redundant overrides (value = tier default) are prevented
- No more confusion with empty fields vs actual values
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use `null` (unlimited) instead of `feature.default_limit` when no
tier_limits entry exists. This fixes Selfhosted tier showing 0
instead of ∞ for features like AI analysis.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- formatValue: NULL → '' (empty field with placeholder ∞)
- handleChange: Accept ONLY '∞' or 'unlimited' (no other formats)
- Input styling: Green only for '∞', empty fields normal color
- Simplified legend: Only ∞ or unlimited accepted
- Boolean features: Toggle buttons with 1/0 values
- Add package-lock.json to .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
User can now input unlimited with:
- "unbegrenzt" (German)
- "unlimited" (English)
- "inf"
- "999999"
- "∞" (infinity symbol)
All map to NULL (unlimited) in database.
Updated legend to show:
- "unbegrenzt, inf, 999999" = Unbegrenzt
- Clear documentation for users
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical bug fix:
- Added missing "import { Link } from 'react-router-dom'"
- Caused Settings page to crash on render
- Route /settings now works again
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
User can now view:
- Current tier (Free, Basic, Premium, Selfhosted) with icon
- Trial status and end date
- Access expiration date
- Feature limits with usage bars
- Progress indicators (green/orange/red based on usage)
- Reset period info (daily/monthly/never)
Coupon redemption:
- Input field for coupon code
- Auto-uppercase, monospace display
- Enter key support
- Success/error feedback
- Auto-refresh after redemption
Features:
- Clean card-based layout
- Visual tier badges with colors
- Progress bars for count limits
- Trial and access warnings
- Integrated in Settings page
Link added to SettingsPage:
- "👑 Abo-Status, Limits & Coupon einlösen"
- Easy access for all users
Phase 3 complete - all user-facing subscription features done!
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AdminPanel.jsx:
- Removed ai_enabled, ai_limit_day, export_enabled UI
- Kept only role selection (Admin/User)
- Added link to Feature-Overrides page
- Simplified perms state to only role
- Changed display to show tier and email
AdminUserRestrictionsPage.jsx:
- Removed legacy system warning
- Clean interface, no confusion
Result:
- ONE consistent permission system (feature-overrides)
- Clear separation: role in AdminPanel, limits in Feature-Overrides
- No data migration needed (no old users exist)
- System ready for production
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>