Problem: dob Spalte ist DATE (PostgreSQL) → Python bekommt datetime.date,
nicht String → strptime() schlägt fehl → age = "unbekannt"
Fix: Prüfe isinstance(dob, str) und handle beide Typen:
- String → strptime()
- date object → direkt verwenden
Jetzt funktioniert {{age}} Platzhalter korrekt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added "📋 Platzhalter exportieren" button in debug viewer:
- Exports all resolved placeholders with values
- Includes all available_variables
- For pipelines: exports per-stage placeholder data
- JSON format with timestamp and prompt metadata
- Filename: placeholders-{slug}-{date}.json
Use case: Development aid - see exactly what data is available
for prompt templates without null values.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
- caliper_summary: use body_fat_pct (not bf_jpl)
- circ_summary: use c_chest, c_waist, c_hip (not brust, taille, huefte)
- get_latest_bf: use body_fat_pct for consistency
Fixes SQL errors when running base prompts that feed pipeline prompts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New placeholder: {{activity_detail}} returns formatted activity log
- Shows last 20 activities with date, type, duration, kcal, HR
- Makes activity analysis prompts work properly
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Placeholder resolver returns keys with {{ }} wrappers,
but resolve_placeholders expects clean keys.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Backend: integrate get_placeholder_example_values in execute_prompt_with_data
- Backend: now provides BOTH raw data AND processed placeholders
- Backend: unwrap Markdown-wrapped JSON (```json ... ```)
- Fixes old-style prompts that expect name, weight_trend, caliper_summary
Resolves unresolved placeholders issue.
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.
Issue: template has NOT NULL constraint but pipeline-type prompts
don't use template (they use stages JSONB instead).
Solution: ALTER COLUMN template DROP NOT NULL before inserting
pipeline configs into ai_prompts.
Fixed Step 3 pipeline_configs migration:
- Simplified JSONB aggregation logic
- Properly scope pc alias in subqueries
- Use UNNEST with FROM clause for array expansion
Previous version had correlation issues with nested subqueries.
Current state:
- Pipeline configs working (migration 019)
- PipelineConfigModal complete
- AdminPromptsPage with tabs
- All Phase 1+2 features deployed and tested
Next: Consolidate into unified prompt system
- Single ai_prompts table for all types
- Dynamic stages (unlimited)
- Basis prompts + pipeline prompts
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 frontend was sending quality_filter_level to the backend, but the
Pydantic ProfileUpdate model didn't include this field, so it was
silently ignored. Profile updates never actually saved the filter.
This is why the charts didn't react to filter changes - the backend
database was never updated.
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>
Notiert an 3 Stellen:
1. insights.py: TODO-Kommentar im Code
2. ROADMAP.md: Deliverable bei M0.2 (lokal, nicht im Git)
3. Gitea Issue #28: Kommentar mit Spezifikation
Zukünftig:
- GET /api/insights/run/{slug}?quality_level=quality
- 4 Stufen: all, quality, very_good, excellent
- Frontend: Dropdown wie in History.jsx
- Pipeline-Configs können Standard-Level haben
User-Request: Quality-Level-Auswahl für KI-Analysen
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: Import failed with "invalid literal for int() with base 10: '37.95'"
because Apple Health exports HRV and other vitals with decimal values.
Root cause: Code used int() directly on string values with decimals.
Fix:
- Added safe_int(): parses decimals as float first, then rounds to int
- Added safe_float(): robust float parsing with error handling
- Applied to all vital value parsing: RHR, HRV, VO2 Max, SpO2, resp rate
Example: '37.95' → float(37.95) → int(38) ✓
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>