Compare commits

..

352 Commits
V0.9i ... main

Author SHA1 Message Date
fc2905f9da Merge pull request 'feat: add DashboardConfigurePage to the frontend' (#104) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m6s
Build Test / pytest-backend (push) Successful in 9s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 19s
Reviewed-on: #104
2026-04-29 22:04:34 +02:00
387ee6840f feat: add DashboardConfigurePage to the frontend
All checks were successful
Deploy Development / deploy (push) Successful in 1m4s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 20s
- Introduced the `DashboardConfigurePage` component to enhance dashboard configuration options.
- Updated the main application file to include the new page, improving navigation and user experience.
- Ensured consistency with recent enhancements in report management and widget configurations.
2026-04-29 22:02:22 +02:00
0638a7d76b Merge pull request 'pdf generator' (#103) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m0s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 21s
Reviewed-on: #103
2026-04-29 21:55:58 +02:00
ed2b457da3 feat: enhance report management and PDF generation capabilities
All checks were successful
Deploy Development / deploy (push) Successful in 1m5s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 20s
- Introduced new API endpoints for managing report definitions, including listing, creating, and updating reports.
- Updated the frontend to include a dedicated section for configuring reports, enhancing user navigation and experience.
- Modified existing components to link to the new report settings, ensuring seamless access to report functionalities.
- Improved the report catalog API to support multiple definitions per profile and added validation for report limits.
- Updated documentation and tests to reflect the new features and ensure proper functionality.
2026-04-29 12:11:26 +02:00
3ab5dae130 feat: add viz_bundle support to report generation and enhance schema
All checks were successful
Deploy Development / deploy (push) Successful in 1m1s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 20s
- Introduced the `viz_bundle` block type to the report profile schema, allowing for the inclusion of bundled visualizations in PDF reports.
- Updated the `build_structured_report_pdf` function to handle `VizBundleBlock` and append its content to the report.
- Enhanced the report catalog API to include details for the new `viz_bundle` block type.
- Added configuration editors for various visualization bundles in the frontend settings page.
- Updated tests to validate the new `viz_bundle` functionality and ensure proper handling of report profiles.
- Bumped application version to reflect these enhancements.
2026-04-29 11:46:34 +02:00
62729d0648 feat: add report_export widget and enhance report generation capabilities
All checks were successful
Deploy Development / deploy (push) Successful in 1m4s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 19s
- Introduced the `report_export` widget to the dashboard, allowing users to generate structured PDF reports.
- Updated widget configuration to include `report_export` in the allowed widgets and added validation for its configuration.
- Enhanced the widget catalog with details for the new `report_export` entry.
- Implemented API endpoints for managing report profiles and generating PDFs.
- Added frontend components for configuring and displaying report settings.
- Updated tests to ensure proper validation and functionality of the new report generation features.
- Bumped application version to reflect the addition of the new widget and related functionalities.
2026-04-29 11:28:04 +02:00
141df021c1 refactor: rename Dashboard-Lab-Widgets to Dashboard-Widgets and update related documentation
All checks were successful
Deploy Development / deploy (push) Successful in 1m2s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Renamed references from "Dashboard-Lab-Widgets" to "Dashboard-Widgets" across documentation and codebase for consistency.
- Removed the deprecated Dashboard-Lab page and integrated its functionality into the new Dashboard-Widgets layout.
- Updated widget registration and configuration handling to reflect the new naming convention.
- Adjusted documentation in `.claude/docs/technical/DASHBOARD_WIDGETS_AGENT_GUIDE.md` and other related files to ensure clarity on the updated structure.
- Bumped application version to reflect these changes.
2026-04-23 16:18:10 +02:00
ddc87ba5ae feat: remove deprecated demo route and enhance dashboard widget registration
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Removed outdated visualization demo route and fixed demo layout in the frontend.
- Updated widget registration logic in `frontend/src/widgetSystem/registerDashboardWidgets.js` to ensure proper integration of core widgets.
- Adjusted documentation in `.claude/docs/technical/DASHBOARD_WIDGETS_AGENT_GUIDE.md` and comments in `backend/widget_catalog.py` to reflect changes.
- Added new dashboard widgets for activity and body overview, enhancing user experience and data visualization capabilities.
- Bumped application version to reflect these changes.
2026-04-23 15:24:13 +02:00
2dbfd95cca Merge pull request 'Widget Update' (#102) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m2s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
Reviewed-on: #102
2026-04-23 09:12:58 +02:00
725e7ffe4b feat: update history_overview_viz configuration and validation
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Replaced the `show_area_summaries` option with individual section visibility settings (`show_section_body`, `show_section_nutrition`, `show_section_fitness`, `show_section_recovery`) in the `history_overview_viz` widget configuration.
- Implemented migration logic to handle legacy `show_area_summaries` settings, ensuring backward compatibility.
- Updated validation logic to enforce visibility requirements for the new section keys.
- Enhanced tests to cover new configuration scenarios and validate the migration logic.
- Bumped application version to reflect these changes.
2026-04-22 12:04:37 +02:00
97dbb0f80b feat: add history_overview_viz widget and enhance configuration handling
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced the `history_overview_viz` widget to the dashboard, allowing users to visualize consolidated history data across various metrics.
- Updated widget configuration to include `history_overview_viz` in the allowed widgets and added validation for its configuration.
- Enhanced the widget catalog with details for the new `history_overview_viz` entry.
- Implemented default values and validation logic for the widget's configuration, ensuring proper handling of user inputs.
- Added tests to ensure proper validation of the `history_overview_viz` widget configuration.
- Bumped application version to reflect the addition of the new widget.
2026-04-22 11:55:11 +02:00
e20b321b64 feat: add recovery_history_viz widget and enhance configuration handling
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
- Introduced the `recovery_history_viz` widget to the dashboard, enabling users to visualize recovery history data.
- Updated widget configuration to include `recovery_history_viz` in the allowed widgets and added validation for its configuration.
- Enhanced the widget catalog with details for the new `recovery_history_viz` entry.
- Implemented default values and validation logic for the widget's configuration, ensuring proper handling of user inputs.
- Added tests to ensure proper validation of the `recovery_history_viz` widget configuration.
- Bumped application version to reflect the addition of the new widget.
2026-04-22 10:18:02 +02:00
d22e0ba0a7 feat: add fitness_history_viz widget and enhance configuration handling
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 18s
- Introduced the `fitness_history_viz` widget to the dashboard, enabling users to visualize fitness history data.
- Updated widget configuration to include `fitness_history_viz` in the allowed widgets and added validation for its configuration.
- Enhanced the widget catalog with details for the new `fitness_history_viz` entry.
- Implemented default values and validation logic for the widget's configuration, ensuring proper handling of user inputs.
- Added tests to ensure proper validation of the `fitness_history_viz` widget configuration.
- Bumped application version to reflect the addition of the new widget.
2026-04-22 10:13:21 +02:00
db5557e4aa feat: add nutrition_history_viz widget and enhance configuration handling
Some checks failed
Deploy Development / deploy (push) Successful in 50s
Build Test / pytest-backend (push) Failing after 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 18s
- Introduced the `nutrition_history_viz` widget to the dashboard, allowing users to visualize nutrition history data.
- Updated widget configuration to include `nutrition_history_viz` in the allowed widgets and added validation for its configuration.
- Enhanced the widget catalog with details for the new `nutrition_history_viz` entry.
- Implemented default values and validation logic for the widget's configuration, ensuring proper handling of user inputs.
- Added tests to ensure proper validation of the `nutrition_history_viz` widget configuration.
- Bumped application version to reflect the addition of the new widget.
2026-04-22 10:03:23 +02:00
20f195aca1 feat: enhance body_history_viz widget configuration and validation
Some checks failed
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Failing after 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Added new configuration options for the `body_history_viz` widget, including visibility settings for various charts and KPIs.
- Implemented default values for the widget's configuration to streamline user experience.
- Enhanced validation logic to ensure proper handling of configuration inputs, including error handling for unknown keys and visibility requirements.
- Updated tests to cover new configuration scenarios and validation rules for the `body_history_viz` widget.
- Bumped application version to reflect these changes.
2026-04-22 08:51:06 +02:00
01c0d1745f feat: implement merge_missing_catalog_widgets function to enhance dashboard layout
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Added the `merge_missing_catalog_widgets` function to append missing widget IDs from the catalog to the dashboard layout while preserving the existing order.
- Updated the admin and app dashboard routes to utilize the new function, ensuring that new catalog entries are visible without requiring users to reset their layouts.
- Enhanced tests to validate the functionality of the new merging logic, ensuring proper integration with existing layouts.
- Bumped application version to reflect these changes.
2026-04-22 08:38:38 +02:00
2453da0da1 feat: add body_history_viz widget and enhance configuration handling
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Introduced the `body_history_viz` widget to the dashboard, allowing users to visualize body history data.
- Updated widget configuration to include `body_history_viz` in the allowed widgets and added validation for its configuration.
- Enhanced the widget catalog with details for the new `body_history_viz` entry.
- Added tests to ensure proper validation of the `body_history_viz` widget configuration.
- Updated application version to reflect the addition of the new widget.
2026-04-22 07:00:24 +02:00
3eb7ef3ae6 feat: enhance navigation state handling for history overview
All checks were successful
Deploy Development / deploy (push) Successful in 59s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
- Updated NavLink components in App and DesktopSidebar to conditionally pass state for the '/history' route, improving user experience by maintaining the selected tab on navigation.
2026-04-21 08:19:34 +02:00
1cf3d5997d Merge pull request 'C1-C4 Diagramme' (#101) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 53s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Reviewed-on: #101
2026-04-21 08:14:07 +02:00
1c512b0d0a refactor: simplify best lag value handling in energy correlation calculations
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Updated the `_correlate_energy_weight` function to streamline the unpacking of the `best` variable, removing unnecessary tuple elements for improved clarity and efficiency in the correlation logic.
2026-04-21 08:12:21 +02:00
0365d9eb52 feat: improve history overview visualization and data handling
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
- Added `safe_float` utility to enhance float handling in correlation calculations, preventing potential errors.
- Refactored lag correlation logic in `get_history_overview_viz_bundle` to utilize absolute values safely, improving accuracy in metric comparisons.
- Enhanced nutrition body merge logic to ensure proper date handling and data integrity, optimizing the retrieval of nutrition and weight logs.
- Introduced new functions in the frontend for processing lag details, improving the visualization of correlation data in the History page.
2026-04-21 08:08:17 +02:00
3106ebedae feat: enhance lag correlation calculations and chart metadata
All checks were successful
Deploy Development / deploy (push) Successful in 1m3s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 19s
- Updated `calculate_lag_correlation` to include detailed interpretations and lag details for energy balance vs. weight change, protein vs. lean mass, and load vs. vital metrics.
- Improved handling of insufficient data scenarios in correlation charts, providing clearer messages and metadata for user insights.
- Refactored chart functions to utilize best lag values and correlation data more effectively, enhancing the visualization of relationships between metrics.
2026-04-21 08:03:43 +02:00
5cac1ededd Merge pull request 'Refaktor Level 2b' (#100) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
Reviewed-on: #100
2026-04-20 17:31:02 +02:00
3f6673b636 feat: update app version to 0.9t and enhance nutrition visualization
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
- Bumped application version to 0.9t and updated changelog with new features.
- Integrated new chart payloads for energy balance, protein adequacy, and nutrition adherence to optimize data retrieval and reduce HTTP requests.
- Updated NutritionCharts component to utilize prefetched chart payloads, improving loading efficiency and user experience.
- Refactored History page to pass chart payloads, enhancing the visualization of nutrition trends without additional requests.
2026-04-20 14:51:27 +02:00
da1e0410cc feat: update app version to 0.9s and enhance body history visualization
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Bumped application version to 0.9s and updated changelog with new features.
- Introduced `_weight_trend_kpi` function to analyze weight trends and provide verdicts based on historical data.
- Updated `get_body_history_viz_bundle` to include the new weight trend KPI, improving insights on weight changes.
- Refactored the History component to utilize the new trend KPI, enhancing user experience with clearer weight trend interpretations.
2026-04-20 14:47:22 +02:00
ba2bd3a4a2 feat: update versioning and add activity last updated endpoint
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Bumped application version to 0.9r and updated build date to 2026-04-20.
- Added a new endpoint `/activity-last-updated` to retrieve the last activity date for a user, optimizing data retrieval for activity history.
- Updated the frontend to utilize the new endpoint, enhancing the ActivitySection with the last activity date display.
- Refactored the History component to streamline data loading and improve user experience with activity insights.
2026-04-20 14:43:31 +02:00
41d809c68c Merge pull request 'Überartbeitung History - neue Gesamtübersicht' (#99) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m4s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #99
2026-04-20 14:39:54 +02:00
5d67a77a12 feat: enhance History page with new scatter chart and correlation insights
All checks were successful
Deploy Development / deploy (push) Successful in 57s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Added ScatterChart and related functions to visualize correlation data, improving user understanding of relationships between metrics.
- Introduced new utility functions for processing chart data and determining status tones, enhancing the clarity of visual representations.
- Updated the NutritionSection to include additional insights on calorie balance and protein vs. lean mass, providing a more comprehensive overview of nutrition trends.
2026-04-20 14:31:35 +02:00
7ac9752c3d feat: enhance nutrition data processing and visualization with new correlation insights
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Refactored the `calculate_lag_correlation` function to normalize lag payloads and improve correlation calculations for various nutrition metrics.
- Introduced a new function `build_nutrition_correlation_heuristic_items` to generate heuristic insights based on merged nutrition data, enhancing user understanding of dietary impacts on weight and body composition.
- Updated the `get_nutrition_history_viz_bundle` function to include daily calorie balance and protein vs. lean mass data, providing a comprehensive view of nutrition trends.
- Enhanced the frontend to visualize calorie balance and protein vs. lean mass insights, improving the user experience with clear graphical representations of dietary correlations.
2026-04-20 13:45:28 +02:00
45fb506a5e fix: update sleep debt chart payload to ensure accurate date handling and current debt representation
All checks were successful
Deploy Development / deploy (push) Successful in 1m0s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Modified the `build_sleep_debt_chart_payload` function to correctly handle date types, ensuring only valid dates are processed.
- Enhanced the logic to append today's date and current debt value to the chart data if the last recorded date is earlier than today, aligning the chart with KPI metrics.
- Updated metadata calculations to reflect the correct number of data points based on labels, improving the accuracy of the recovery chart payload.
2026-04-20 12:57:47 +02:00
d66eadf88f Merge pull request 'feat: enhance recovery metrics and dashboard with sleep debt calculations and improved visualizations' (#98) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 59s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
Reviewed-on: #98
2026-04-20 12:52:20 +02:00
6c962bf6e5 feat: enhance recovery metrics and dashboard with sleep debt calculations and improved visualizations
All checks were successful
Deploy Development / deploy (push) Successful in 1m2s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced new constants for sleep debt calculations, including target hours and rolling window days.
- Added a function to calculate sleep debt over a specified window, aligning with KPI logic.
- Updated SQL queries in recovery chart payloads to ensure accurate data retrieval for sleep metrics.
- Enhanced the RecoveryDashboardOverview component to reflect changes in sleep debt visualization and descriptions, improving user understanding of metrics.
- Refined chart labels and notes for clarity, ensuring users can easily interpret recovery and sleep data.
2026-04-20 12:47:03 +02:00
a1b458d228 Merge pull request 'Neue Aufbereitung Fitness Verlauf' (#97) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #97
2026-04-20 11:47:52 +02:00
61738cecb7 feat: enhance recovery dashboard with optional average sleep KPI and structured insights
All checks were successful
Deploy Development / deploy (push) Successful in 58s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 18s
- Added an `include_avg_sleep_kpi` parameter to the `build_recovery_dashboard_kpi_tiles` function to conditionally include average sleep data in the dashboard.
- Updated the `get_recovery_dashboard_viz_bundle` function to pass the new parameter, ensuring flexibility in data presentation.
- Refactored the insights generation in the `vitals_fitness_insights.py` file to utilize a new structured approach for better organization of heart and VO2 insights.
- Introduced new components in the frontend for displaying insights, improving the user experience and clarity of vital metrics.
2026-04-20 11:43:56 +02:00
857cc1043a refactor: streamline vital signs matrix handling and enhance recovery dashboard layout
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 21s
- Removed unnecessary snapshot key omission in the `build_vital_signs_matrix_chart_payload` function for improved data clarity.
- Introduced new components for better organization and presentation of vital signs insights, including `SectionHeading` and `VitalZoneHint`.
- Enhanced axis tick formatting in the `RecoveryDashboardOverview` component for clearer data representation.
- Updated narrative rendering logic to improve user experience and contextual understanding of vital metrics.
2026-04-20 11:09:16 +02:00
ce84f330f0 feat: add German number formatting functions and enhance narrative context in vital signs insights
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Introduced `_de_num` and `_de_num_signed` functions for formatting decimal numbers with a comma, improving text presentation in German.
- Updated `_build_consolidated_paragraphs` to utilize new formatting functions for HRV and resting heart rate comparisons, enhancing clarity in insights.
- Refined narrative descriptions for better contextual understanding of vital signs trends and their implications.
2026-04-20 10:55:49 +02:00
8cb5ad992f feat: enhance recovery dashboard with vital signs analytics and visualization improvements
All checks were successful
Deploy Development / deploy (push) Successful in 1m1s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 18s
- Updated the `build_vital_signs_matrix_chart_payload` function to accept optional keys for omitting specific snapshot data, improving flexibility in data presentation.
- Enhanced the `build_recovery_dashboard_kpi_tiles` function to conditionally merge heart and autonomic tiles based on new parameters, refining the dashboard's insights.
- Integrated new analytics features in the `RecoveryDashboardOverview` component, including consolidated paragraphs for better narrative context and visual representation of trends.
- Improved the handling of vital signs data in the frontend, ensuring clearer messaging and enhanced user experience when displaying vital metrics.
2026-04-20 10:29:43 +02:00
e7bcdc3228 feat: add vitals history analytics to recovery dashboard
All checks were successful
Deploy Development / deploy (push) Successful in 1m0s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Integrated the `build_vitals_history_and_analytics` function into the recovery dashboard to provide historical insights on vital signs.
- Updated the `get_recovery_dashboard_viz_bundle` function to include a new chart for vitals history, enhancing the data visualization capabilities.
- Enhanced the `RecoveryDashboardOverview` component to render vitals history, including improved messaging for insufficient data and visual representation of trends.
2026-04-20 09:36:10 +02:00
6743814904 Merge pull request 'Fitness History + recovery' (#96) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Reviewed-on: #96
2026-04-20 08:46:25 +02:00
819914b7cc refactor: improve vital signs data handling and frontend display
All checks were successful
Deploy Development / deploy (push) Successful in 59s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Introduced a new function `_merge_vitals_baseline_rows` to streamline the retrieval and merging of vital signs data, ensuring the latest non-empty values are prioritized.
- Updated SQL queries in `build_vital_signs_matrix_chart_payload` to enhance data retrieval efficiency and accuracy.
- Refactored the `renderVitalSigns` function in the `RecoveryDashboardOverview` component to improve handling of vital signs data, including better fallback messaging and chart rendering logic.
- Enhanced user feedback by providing clearer messages when no vital data is available, improving overall user experience.
2026-04-20 08:44:25 +02:00
d4868b3797 feat: enhance vital signs matrix chart payload and visualization
All checks were successful
Deploy Development / deploy (push) Successful in 1m2s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Introduced new functions to handle vital signs data retrieval and processing, including fallback mechanisms for missing values.
- Updated SQL queries in `build_vital_signs_matrix_chart_payload` to improve date filtering and data accuracy.
- Enhanced the frontend `RecoveryDashboardOverview` component to display vital signs with contextual coloring based on health tones.
- Adjusted the data structure for chart rendering, ensuring a more informative and visually appealing representation of vital metrics.
2026-04-20 08:36:45 +02:00
6ef07a77a5 Merge pull request 'Fitness historie' (#95) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 57s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #95
2026-04-20 08:26:46 +02:00
d3cb9d4ad9 fix: update SQL query in recovery chart payloads for accurate date filtering
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Modified the SQL query in `build_vital_signs_matrix_chart_payload` to use `measured_at::date` for date comparisons, ensuring correct data retrieval based on the measurement date.
- Adjusted the order of results to sort by `measured_at` instead of `date`, improving the accuracy of the latest vital signs data fetched.
2026-04-20 08:24:23 +02:00
33b08a8d82 fix: update sleep chart payloads to use duration_minutes and quality_score
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Changed SQL queries in `build_sleep_duration_quality_chart_payload` and `build_sleep_debt_chart_payload` to select `duration_minutes` instead of `total_sleep_min`.
- Updated calculations for sleep duration and quality scores to reflect the new field names, ensuring accurate data representation in the recovery charts.
2026-04-20 08:21:50 +02:00
f42d3a9c92 feat: introduce recovery dashboard visualization and refactor recovery charts
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 9s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Added a new endpoint for the recovery dashboard visualization in `charts.py`, integrating multiple recovery metrics and insights.
- Implemented the `get_recovery_dashboard_viz` function to streamline data retrieval for recovery-related charts.
- Refactored the `RecoveryCharts` component to utilize the new `RecoveryDashboardOverview`, simplifying the component structure and enhancing maintainability.
- Updated the `RecoveryChartsPanelWidget` and `History` page to reflect the new recovery dashboard, improving user navigation and experience.
- Deprecated the old recovery charts component, encouraging the use of the new overview for better data presentation.
2026-04-20 08:11:23 +02:00
bf84e3c2a5 feat: enhance fitness dashboard with new metrics and insights
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Refactored the `calculate_proxy_internal_load_7d` function to `calculate_proxy_internal_load_window`, allowing for dynamic day range input.
- Introduced new functions for calculating training volume deltas and building fitness progress insights, enhancing user feedback on training metrics.
- Updated the fitness dashboard to include new charts for quality sessions and load monitoring, improving data visualization.
- Integrated these new metrics into the fitness dashboard overview, providing users with comprehensive insights into their training performance.
- Streamlined the router to utilize the new chart-building functions, ensuring consistency and maintainability across the application.
2026-04-20 08:04:50 +02:00
22c5f695c9 refactor: update fitness dashboard integration and terminology
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Changed the fitness overview path from `/activity` to `/history` and updated related navigation labels to reflect this change.
- Refactored the `FitnessDashboardOverview` component to accept external period control and conditionally display the period selector.
- Integrated the `FitnessDashboardOverview` into the `History` page, enhancing the user experience with consistent terminology and layout.
- Removed the fitness overview from the `ActivityPage` to streamline the interface and focus on activity data collection.
2026-04-19 21:37:12 +02:00
b5c5f2f612 feat: introduce fitness dashboard overview and enhance activity metrics
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Added new functions to build fitness dashboard visualizations, including weekly training volume and training type distribution charts.
- Updated the `charts.py` router to include a new endpoint for the fitness dashboard, integrating data from activity metrics.
- Refactored existing activity-related functions to improve modularity and maintainability.
- Updated frontend components to reflect the new fitness terminology and integrate the fitness dashboard overview, enhancing user experience.
2026-04-19 21:27:12 +02:00
aa6644f44b Merge pull request 'Ernährungsasuwertungen' (#94) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 58s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 18s
Reviewed-on: #94
2026-04-19 21:02:28 +02:00
d7304c1a44 feat: implement energy availability warning and enhance nutrition visualization
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 9s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Added `get_energy_availability_warning_payload` function to assess energy availability and provide contextual warnings based on multiple health indicators.
- Integrated energy availability KPI tile into the nutrition history visualization, enhancing user insights on energy balance.
- Updated frontend components to conditionally display the energy availability warning, improving user experience and data interpretation.
- Refactored existing logic in `charts.py` to utilize the new energy availability functionality, streamlining data handling.
2026-04-19 17:43:29 +02:00
fc816da335 feat: enhance KPI tiles with contextual hints and improve chart legends
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Added contextual hints to KPI tiles in the nutrition interpretation to provide users with actionable insights regarding protein intake and weight assessment.
- Updated the KpiTilesOverview component to display these hints, improving user understanding of nutrition metrics.
- Introduced a new KcalVsWeightLegend component to clarify chart data representation, enhancing the overall user experience in the history visualization.
2026-04-19 17:36:45 +02:00
31fbf33031 refactor: update nutrition chart colors and enhance layout
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Changed color codes for macro nutrients in the nutrition interpretation and metrics files to improve visual consistency.
- Added new CSS styles for uniform chart height and layout adjustments in the frontend components, enhancing the overall user experience.
- Refactored the NutritionCharts component to utilize the new macro chart theme for better maintainability and readability.
2026-04-19 17:28:41 +02:00
b96b1931db feat: implement nutrition history visualization bundle and related API endpoint
All checks were successful
Deploy Development / deploy (push) Successful in 57s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Added a new `nutrition_interpretation.py` file to handle KPI tile generation for nutrition history.
- Introduced `nutrition_viz.py` to create a visualization bundle for nutrition data, integrating metrics and historical analysis.
- Implemented `get_nutrition_history_viz` endpoint in `charts.py` to serve the new visualization data.
- Updated frontend components to fetch and display nutrition history data, enhancing user experience with detailed insights.
- Refactored existing logic to streamline data handling and improve overall performance.
2026-04-19 17:20:24 +02:00
a8eafa8ba4 feat: add weekly macro distribution panel and enhance nutrition charts
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Introduced the WeeklyMacroDistributionPanel component to visualize weekly macro distribution alongside existing nutrition charts.
- Updated the NutritionCharts component to conditionally load the weekly macro data based on a new prop.
- Enhanced CSS styles for better layout and responsiveness of the new macro distribution panel.
- Added a new NutritionGoalsStrip component to display active nutrition-related goals with progress indicators in the History page.
- Refactored existing components to improve data handling and user experience.
2026-04-19 17:13:59 +02:00
08b7aa0ca1 refactor: integrate KpiTilesOverview component for enhanced KPI display
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced the KpiTilesOverview component to streamline the presentation of KPI tiles, replacing the previous BodyKpiOverview implementation.
- Updated the PilotKpiBoard and History components to utilize the new KpiTilesOverview for better touch and hover interactions.
- Refactored CSS styles to accommodate the new component structure, ensuring a responsive design across devices.
- Enhanced the logic for generating KPI tiles, improving data handling and user experience.
2026-04-19 17:00:05 +02:00
8c60601ed1 feat: implement touch-friendly KPI details with bottom sheet interaction
All checks were successful
Deploy Development / deploy (push) Successful in 1m1s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Added a new button for displaying KPI details on touch devices, replacing hover functionality.
- Introduced a bottom sheet component to present detailed information when the info button is clicked.
- Enhanced the BodyKpiOverview component to detect touch UI and adjust interactions accordingly.
- Updated CSS styles for new touch elements, ensuring a responsive and user-friendly design.
2026-04-19 16:46:05 +02:00
319a9cfafd Merge pull request 'Verlauf - Körper' (#93) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 59s
Build Test / pytest-backend (push) Successful in 9s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #93
2026-04-19 16:32:32 +02:00
8fc7d9c1c4 refactor: enhance body history visualization logic and frontend labels
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated the `get_body_history_viz_bundle` function to retrieve the two most recent circumference measurements for improved data accuracy.
- Refactored the handling of previous measurement data to ensure comprehensive interpolation for body metrics.
- Modified frontend labels in the `buildBodyKpiTiles` function to provide clearer descriptions in German, enhancing user understanding of body metrics.
2026-04-19 16:27:59 +02:00
b2175b9018 refactor: update KPI overview and evaluation tile components
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Renamed and refactored CSS classes for better clarity and consistency in the KPI overview section.
- Introduced a new `BodyKpiOverview` component to display KPI tiles with detailed hover information.
- Enhanced the `buildBodyKpiTiles` function to generate tiles based on various body metrics, improving data presentation.
- Updated styles for the KPI cards to enhance user interaction and visual appeal.
- Removed the old `EvaluationTileGrid` component in favor of the new structure for better maintainability.
2026-04-19 16:21:37 +02:00
461c358dc2 feat: add body history visualization endpoint and frontend integration
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced a new API endpoint `/body-history-viz` to retrieve body history visualization data.
- Updated the frontend to fetch and display body history data in the `BodySection` component.
- Enhanced the `EvaluationTileGrid` to include related placeholder keys for improved data interpretation.
- Refactored existing logic to streamline data handling and improve user experience.
2026-04-19 16:06:07 +02:00
157afd10b9 feat: add compact evaluation tiles and body goals section
All checks were successful
Deploy Development / deploy (push) Successful in 1m2s
Build Test / pytest-backend (push) Successful in 9s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced a new `EvaluationTileGrid` component for displaying compact evaluation tiles with interactive features.
- Added a `BodyGoalsStrip` component to showcase active body-related goals with progress indicators.
- Enhanced CSS styles for the new components to ensure responsive design and improved user experience.
- Updated the `BodySection` to integrate the new components and manage grouped goals effectively.
2026-04-19 15:55:46 +02:00
0ab91416d0 Merge pull request 'feat: add reference values snapshot endpoints and data layer functions' (#92) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m1s
Build Test / pytest-backend (push) Successful in 12s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 15s
Reviewed-on: #92
2026-04-19 15:34:20 +02:00
42ae796448 feat: add reference values snapshot endpoints and data layer functions
All checks were successful
Deploy Development / deploy (push) Successful in 1m3s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Introduced `get_profile_reference_values_current_snapshot` and `get_profile_reference_values_recent_snapshot` functions to retrieve current and recent reference values for profiles.
- Updated the placeholder resolver to include new placeholders for current and recent reference values.
- Added new API endpoints for fetching current and recent reference values snapshots.
- Enhanced the frontend API utility to support the new snapshot endpoints.
- Improved unit tests to validate the new data layer functions and their behavior.
2026-04-19 10:52:31 +02:00
5fbaa7cc8b Merge pull request 'feat: add relaxed arm circumference measurement and update related features' (#91) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
Reviewed-on: #91
2026-04-19 10:44:18 +02:00
df0165bee3 feat: add relaxed arm circumference measurement and update related features
All checks were successful
Deploy Development / deploy (push) Successful in 1m0s
Build Test / pytest-backend (push) Successful in 9s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
- Introduced `c_arm_relaxed` to the CircumferenceEntry model for tracking relaxed arm measurements.
- Updated database schema to include `c_arm_relaxed` in the circumference_log table.
- Implemented calculation for 28-day relaxed arm circumference change with `calculate_arm_relaxed_28d_delta`.
- Enhanced placeholder resolver and registration to support new relaxed arm measurement.
- Updated frontend components to accommodate the new measurement, including forms and CSV exports.
- Improved documentation and guide data to reflect the addition of relaxed arm measurements.
2026-04-19 10:34:51 +02:00
9b53a4ba68 Merge pull request 'feat: enhance photo upload and management features' (#90) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m0s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #90
2026-04-19 10:20:04 +02:00
0035d08149 feat: enhance photo upload and management features
All checks were successful
Deploy Development / deploy (push) Successful in 1m4s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Added `taken_at` timestamp to the photos table for improved photo metadata.
- Updated the photo upload API to support optional EXIF data extraction and file last modified timestamp.
- Enhanced the photo upload process to allow skipping EXIF data, defaulting to today's date if no other date is provided.
- Improved the photo display in various components to utilize a unified caption format.
- Refactored photo sorting and grouping logic for better organization in the UI.
2026-04-19 10:13:22 +02:00
9720cb57ec Merge pull request 'feat: implement photo management features in the application' (#89) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m1s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Reviewed-on: #89
2026-04-19 09:24:08 +02:00
c91317df8e feat: implement photo management features in the application
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 24s
- Added a new `resolve_photo_path` function to handle legacy and new photo paths effectively.
- Updated the photo upload process to store only filenames in the database, improving path resolution.
- Enhanced the photo retrieval and deletion processes to utilize the new path resolution logic.
- Introduced a dedicated PhotosCapturePage for managing photo uploads and viewing.
- Updated the dashboard and navigation to include links to the new photo management features.
- Improved the photo grid display with sorting and deletion capabilities for better user experience.
2026-04-19 09:20:28 +02:00
1e1605f878 Merge pull request 'Optimierung Platzhalter Umfang' (#88) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m0s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #88
2026-04-18 10:54:36 +02:00
7676897fda feat: enhance normalization of metric values for improved handling
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Updated `_normalize_metric_value_for_read` to compact numeric strings and ensure consistent formatting for string data types.
- Enhanced `normalize_prompt_number` to handle numeric strings and non-finite float values effectively.
- Improved unit tests to validate the new normalization behavior for session metrics and scalar formatting.
2026-04-18 10:43:21 +02:00
178534e9eb feat: enhance formatting and normalization of activity metrics
All checks were successful
Deploy Development / deploy (push) Successful in 57s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced `format_scalar_for_prompt_text` function to standardize the representation of scalar values in activity summaries and details.
- Updated `get_activity_summary` and `get_activity_detail` functions to utilize the new formatting for improved readability.
- Added normalization for float values in session metrics to prevent excessively long representations.
- Enhanced unit tests to verify the new formatting and normalization behavior.
2026-04-18 10:32:29 +02:00
6756dc60f3 feat: enhance session metrics handling in activity summaries
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
- Integrated compact JSON payload generation for session metrics in `get_training_sessions_recent_weeks_data`.
- Updated the registration of activity session insights to reflect the new compact format for session metrics.
- Improved documentation to clarify the structure and semantics of the session metrics in the JSON output.
- Added normalization for prompt numbers to ensure consistent formatting in the metrics.
2026-04-18 10:24:44 +02:00
7226e04e9c feat: implement effective CSV delimiter resolution for imports
All checks were successful
Deploy Development / deploy (push) Successful in 1m0s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Added `resolve_effective_csv_delimiter` function to determine the correct delimiter based on the uploaded file and template.
- Updated CSV import logic to utilize the new delimiter resolution method, ensuring accurate parsing of CSV files with varying delimiters.
- Enhanced documentation to reflect changes in delimiter handling.
- Added unit tests for the new delimiter resolution functionality.
2026-04-18 10:12:33 +02:00
4575bb23ee Merge pull request 'Bug-Fixing Analyse Fehler' (#87) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #87
2026-04-18 09:54:12 +02:00
0ad3ddd627 fix: update progress callback and event types for workflow execution
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Changed progress callback from "execution_complete" to "workflow_graph_finished" to provide intermediate updates.
- Updated documentation to clarify the distinction between "workflow_graph_finished" and "execution_complete".
- Adjusted frontend API handling to accommodate new event structure and ensure proper result serialization.
2026-04-18 09:11:07 +02:00
a002781ef9 chore: remove debug logging from require_auth_flexible
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 17s
Cleanup after successful route ordering fix. SSE authentication is
now working correctly via ssetoken query parameter.
2026-04-18 08:58:36 +02:00
879a3a58d7 fix: move /execute-stream route BEFORE /{prompt_id} catch-all (FastAPI route ordering)
All checks were successful
Deploy Development / deploy (push) Successful in 58s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
Root cause: FastAPI matches routes in definition order. The /{prompt_id}
catch-all at line 257 was intercepting /execute-stream requests before
the specific route handler could match.

Fix: Moved execute-stream definition (with section header + imports)
to line 257, before the catch-all route (now at line 414).

This resolves the 'Connection to server lost' error in SSE streaming.
2026-04-18 08:55:43 +02:00
09d1b6f967 fix: move /execute-stream route BEFORE /{prompt_id} catch-all
Some checks failed
Deploy Development / deploy (push) Successful in 57s
Build Test / pytest-backend (push) Failing after 0s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 19s
- /execute-stream now at line 260 (was 1448)
- /{prompt_id} now at line 410 (was 257)
- FastAPI will now match /execute-stream correctly
- Fixes 'Connection to server lost' error in analysis page
2026-04-18 08:45:04 +02:00
35ba2d7fdb fix: identify route ordering issue - execute-stream must come before /{prompt_id}
ROOT CAUSE FOUND:
FastAPI matches routes in ORDER. The catch-all route /{prompt_id} at line 257
matches /execute-stream BEFORE the specific route at line 1448 can match.

Result: /api/prompts/execute-stream gets routed to get_prompt() which tries
to parse 'execute-stream' as a UUID, causing the error we've been seeing.

SOLUTION: Move /execute-stream route definition to BEFORE line 257 (before /{prompt_id})

This explains why require_auth_flexible was never called - the wrong endpoint
was being invoked entirely.
2026-04-18 08:42:30 +02:00
a5aad0da7e debug: add logging to execute_unified_prompt_stream function
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 18s
2026-04-18 08:34:35 +02:00
ce5b96f373 debug: add module load and function entry logging
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
2026-04-18 08:32:31 +02:00
11fac3d123 debug: use print and logger.warning for auth debug
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
2026-04-18 08:28:31 +02:00
f0ad900565 debug: add logging to require_auth_flexible
All checks were successful
Deploy Development / deploy (push) Successful in 59s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 14s
2026-04-18 08:24:32 +02:00
36478863a2 fix: restore prompts.py with correct ASCII quotes (Edit tool introduced smart quotes)
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
2026-04-18 08:22:37 +02:00
ec667a75b6 fix: remove test endpoint with syntax error
Some checks failed
Deploy Development / deploy (push) Successful in 52s
Build Test / pytest-backend (push) Failing after 0s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
2026-04-18 08:20:56 +02:00
f864f9894d debug: add POST test endpoint
Some checks failed
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Failing after 1s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 21s
2026-04-18 08:16:51 +02:00
73104a1a4c cleanup: Remove debug logging and test endpoint
All checks were successful
Deploy Development / deploy (push) Successful in 1m2s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
2026-04-18 08:04:00 +02:00
d66e68a5df fix: SSE auth with ssetoken query parameter - WORKING
Some checks failed
Build Test / pytest-backend (push) Waiting to run
Build Test / lint-backend (push) Waiting to run
Build Test / build-frontend (push) Waiting to run
Deploy Development / deploy (push) Has been cancelled
Root Cause:
- FastAPI cannot use same parameter name in endpoint and dependency
- Query param 'token' conflicted between endpoint and require_auth_flexible
- FastAPI cached dependency signatures at startup

Solution:
- Renamed to 'ssetoken' in require_auth_flexible (backend/auth.py)
- Updated frontend to use ssetoken (frontend/src/utils/api.js)
- Removed debug logging
- Added test endpoint /test-ssetoken

Testing:
 Header auth: X-Auth-Token works
 Query auth: ?ssetoken=XXX works
 SSE streaming: Ready for testing

Note: Required full rebuild, not just restart

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-18 08:03:36 +02:00
d2b4f74cd2 fix: Query parameter conflict in require_auth_flexible
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
Root Cause Analysis:
- FastAPI cannot distinguish between endpoint Query params and Dependency Query params
- When endpoint has Query(...), dependency Query(default=None, name='token') is ignored
- Token went to endpoint, not to require_auth_flexible

Solution:
- Renamed internal parameter to auth_token with alias='token'
- Now FastAPI correctly routes ?token=XXX to the dependency
- Uses Query(default=None, alias='token') to maintain API compatibility

Testing:
- Header auth: Works (X-Auth-Token)
- Query auth: Now works (?token=XXX)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-18 07:53:18 +02:00
1a826973a9 debug: Add logging to require_auth_flexible
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
2026-04-18 07:38:15 +02:00
d13e7cda26 fix: execute-stream nutzt require_auth_flexible
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Backend:
- Ersetzt manuelle Token-Validierung durch Depends(require_auth_flexible)
- Nutzt get_session() mit expires_at Check + profiles JOIN
- Token-Parameter nicht mehr nötig (require_auth_flexible holt ihn)

Root Cause (Live-Logs):
- Request kam an mit Token: 401 Unauthorized
- Manuelle Auth: SELECT profile_id FROM sessions WHERE token = %s
- Fehlte: expires_at Check + profiles JOIN
- require_auth_flexible nutzt vollständige get_session() Logik

Fixes:
- "Connection to server lost" - Token-Validierung funktioniert jetzt

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-18 07:24:49 +02:00
ec85d5f5f6 fix: Token-Abfrage in executeUnifiedPromptStream
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 18s
Frontend:
- api.js Zeile 487: localStorage.getItem('token') → getToken()
- Token heißt 'bodytrack_token', nicht 'token'
- SSE-Requests bekamen undefined token → 401 Unauthorized

Root Cause:
- Admin verwendet executeUnifiedPrompt (normaler Request mit Header-Auth)
- Analyse verwendet executeUnifiedPromptStream (SSE mit Token im URL)
- SSE bekam keinen Token wegen falschem localStorage key

Fixes:
- "Connection to server lost" in Analyse-Seite

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-18 07:13:47 +02:00
1139b00743 fix: execute-stream POST → GET für EventSource
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Backend:
- prompts.py: @router.post → @router.get für /execute-stream
- EventSource unterstützt nur GET-Requests
- modules/timeframes nutzen Defaults (SSE kann keine komplexen Params)

Fixes:
- "Connection to server lost" bei Analyse-Ausführung

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-18 07:07:16 +02:00
e9712cef23 fix: BASE_URL typo + nginx timeout für Workflows
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 18s
Frontend:
- api.js Zeile 499: BASE_URL → BASE (executePromptStreaming)
- nginx.conf: proxy_read_timeout 300s für lange Workflow-Ausführungen

Fixes:
- "BASE_URL is not defined" Fehler in Analyse-Seite
- 504 Gateway Timeout bei Workflow-Ausführung (>60s)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-18 07:03:48 +02:00
a62c952097 Merge pull request 'Erste Version Platzhalter EAV' (#86) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 52s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #86
2026-04-17 21:52:13 +02:00
1220ee54fb feat: Enhance activity session handling and schema retrieval
All checks were successful
Deploy Development / deploy (push) Successful in 59s
Build Test / pytest-backend (push) Successful in 9s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 15s
- Updated `get_activity_session_logical_unit` to support optional parameters for form training context, allowing for more flexible schema resolution.
- Introduced a new endpoint `/attribute-schema` to fetch activity attribute schemas without an existing session, improving manual data entry capabilities.
- Enhanced the `getActivitySession` API method to accept query parameters for training category and type, facilitating dynamic schema retrieval.
- Updated the frontend `ActivityPage` to utilize the new schema fetching logic, ensuring a smoother user experience when managing activity sessions and metrics.
2026-04-17 21:48:37 +02:00
92e334dcd2 feat: Enhance Admin Activity Attribute Profiles UI and styling
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
- Introduced a new layout for the Admin Activity Attribute Profiles page, improving the user interface with a dedicated class for styling.
- Added new CSS styles for input fields, labels, and layout structures to enhance the visual presentation and usability of the attribute profiles.
- Updated the form structure to include clearer labels and organization for input fields, ensuring better accessibility and user experience.
- Improved responsiveness of the layout for mobile devices, ensuring a consistent experience across different screen sizes.
2026-04-17 20:57:31 +02:00
bc8e9fb7fa feat: Enhance training parameters handling and documentation
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced new fields for descriptions in training parameters, improving clarity for AI context in `training_sessions_recent_json`.
- Added a glossary placeholder `{{training_parameters_glossary_md}}` to provide a Markdown table of active training parameters, including names and descriptions.
- Updated the `placeholder_resolver.py` and `activity_metrics.py` to support the new glossary functionality.
- Enhanced the `AdminActivityAttributeProfilesPage` to allow input for descriptions in both German and English, ensuring better context for metrics.
- Revised tests to validate the inclusion of description fields in parameter schema merges and metrics handling.
2026-04-17 20:42:11 +02:00
c3be745efa feat: Enhance activity metrics documentation and registry updates
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Added details for Issue #53 regarding the audit of activity placeholders between Layer 1 and Layer 2a in `CLAUDE.md` and `README.md`.
- Updated the `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md` to reflect the new registry checks and dynamic session metrics handling.
- Revised the `placeholder_resolver.py` and `activity_metrics.py` to clarify the registration of activity metrics and session insights, ensuring consistency in the handling of dynamic keys and metrics.
- Improved descriptions and semantic contracts in `activity_session_insights.py` to better outline the structure and limitations of session data.
2026-04-17 20:28:58 +02:00
680ecd1c06 feat: Update activity metrics handling to prioritize legacy columns over EAV
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Enhanced the `merge_column_backed_and_eav_metrics` function to ensure that when both legacy columns and EAV values are present, the legacy column takes precedence.
- Revised documentation in `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` and `ACTIVITY_SCALAR_KANON_TABLE.md` to reflect the new reading logic and clarify the handling of metrics.
- Updated the `activity_data_canon.py` to specify the new merge behavior, ensuring consistency in data retrieval.
- Added unit tests to validate the new logic, confirming that legacy columns are preferred when available.
2026-04-17 15:49:38 +02:00
38797d687d feat: Enhance export functionality and documentation for activity metrics
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Implemented JSON and CSV export features in `routers/exportdata.py`, including enriched session metrics for activity data.
- Updated `CLAUDE.md` to reflect new export capabilities and added details about the inclusion of `session_metrics_json` in the `activity.csv` file.
- Revised `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` to document the integration of export features and their relationship with session metrics.
- Improved the overall structure and clarity of the documentation to support the new export functionalities.
2026-04-17 13:09:49 +02:00
fa3e66fb31 feat: Update activity documentation and enhance API responses with session metrics
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 18s
- Added new updates for Phase A and Phase B in `CLAUDE.md`, detailing the completion of Phase A and the introduction of enriched session metrics in the API response for `GET /api/activity`.
- Enhanced the README to include references to new documentation files for scalar canon and composite metrics implementation.
- Updated `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` to reflect the current status of phases and added navigation rules for data access.
- Improved `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md` with links to new implementation concepts for composite metrics.
- Refactored the activity router to integrate enriched session metrics into the activity list responses, ensuring a more comprehensive data presentation.
2026-04-17 12:55:12 +02:00
cc0f57758a feat: Implement sorting and categorization for activity profile schema rows
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Introduced a new sorting mechanism for activity profile schema rows based on defined categories and UI groups, enhancing the organization of displayed metrics.
- Added constants for training parameter categories and their German labels to improve clarity in the UI.
- Refactored the `SessionMetricsFields` component to utilize the new sorting logic, replacing the previous mapping approach for better maintainability and user experience.
- Ensured that orphan metrics are sorted correctly for consistent display alongside the main metrics.
2026-04-16 13:46:29 +02:00
2a6c437a08 feat: Introduce activity schema headline binding for improved metrics handling
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 17s
- Added a new function `activitySchemaHeadlineBinding` to streamline the binding of profile parameters to their corresponding headline columns, enhancing clarity in the metrics display logic.
- Refactored the `SessionMetricsFields` component to utilize the new binding function, simplifying the filtering of schema entries and improving maintainability.
- Updated the logic in `ActivityPage` to leverage the binding function for determining the appropriate column for metrics, ensuring consistent data handling across the application.
2026-04-16 13:15:41 +02:00
c9d71c0179 fix: Refine EAV writing logic in session metrics upsert function
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated the `upsert_session_metrics_from_csv_mapped` function to ensure EAV writes are only skipped when the `source_field` is populated, preventing duplicate storage.
- Enhanced unit tests to cover scenarios where the `source_field` is set but the corresponding column is empty, ensuring correct EAV behavior.
- Adjusted test cases to reflect changes in the handling of `hr_avg` and other metrics, improving overall test coverage and accuracy.
2026-04-16 13:01:32 +02:00
9d5e16455c refactor: Update session metrics handling to improve EAV logic and filtering
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Revised the `upsert_session_metrics_from_csv_mapped` function to clarify EAV writing conditions, ensuring only relevant parameters are processed.
- Enhanced the `merge_column_backed_and_eav_metrics` function to exclude EAV rows for parameters not present in the schema, improving data integrity.
- Updated unit tests to reflect changes in EAV handling and ensure correct functionality when parameters are mapped or not mapped in the profile schema.
- Improved frontend logic to prevent duplicate display of metrics already handled in the entry form, enhancing user experience.
2026-04-16 12:53:14 +02:00
2a26e4fecf refactor: Remove source field handling from activity session metrics logic
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Eliminated checks for `source_field` in the `replace_activity_session_metrics` function to streamline EAV row replacement, ensuring consistency with existing logic.
- Updated frontend logic to simplify the filtering of metrics during payload construction, enhancing maintainability.
- Removed outdated unit tests related to `source_field` handling, reflecting the updated logic in the codebase.
2026-04-16 12:35:55 +02:00
94bb4a8199 feat: Update activity session metrics handling to skip source field inserts
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Modified the `replace_activity_session_metrics` function to skip EAV inserts for parameters with a defined `source_field`, aligning with the existing logic in `upsert_session_metrics_from_csv_mapped`.
- Enhanced the frontend logic to filter out metrics associated with `source_field` during payload construction, improving data integrity and user experience.
- Added unit tests to validate the new behavior, ensuring that metrics with `source_field` are correctly excluded from inserts.
2026-04-16 12:29:01 +02:00
fd7a2dac6d feat: Improve session metrics upsert logic and add unit tests for source field handling
All checks were successful
Deploy Development / deploy (push) Successful in 53s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Enhanced the `upsert_session_metrics_from_csv_mapped` function to skip EAV writes when a `source_field` is provided, ensuring canonical handling of activity logs.
- Updated the docstring to clarify the behavior regarding `source_field` and EAV logic.
- Added unit tests to validate the new behavior, ensuring correct functionality when `source_field` is set or not set during CSV imports.
2026-04-16 12:22:44 +02:00
8d0a6dd487 feat: Refactor activity data handling to use dynamic registry fields
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Replaced hardcoded keys in `activity_data_canon.py` with a dynamic retrieval method from the module registry, ensuring that `ACTIVITY_MODULE_REGISTRY_FIELD_KEYS` reflects the current configuration.
- Updated `activity_persistence_orchestrator.py` to utilize the new dynamic field retrieval function, enhancing consistency across the data layer.
- Modified `activity_session_metrics.py` to reference the dynamic field keys, improving maintainability and reducing redundancy in the codebase.
2026-04-16 12:14:39 +02:00
06f83e2ffc revert: Wiederherstellung Codezustand von ca8cee9 (ohne Branch-Historie zu überschreiben)
All checks were successful
Deploy Development / deploy (push) Successful in 53s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reverts cd29c7d..026c51b per git revert. Alle zwischenliegenden Commits bleiben in Gitea sichtbar; der Arbeitsbaum entspricht wieder dem Stand von ca8cee9.

Made-with: Cursor
2026-04-16 11:59:23 +02:00
026c51b6b5 feat: Add CSV import support for additional training parameters
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced `resolve_activity_attribute_schema_for_csv_import` to enhance the handling of training parameters during CSV imports, allowing for the inclusion of active parameters not present in the category/type profile.
- Updated `apply_activity_mapped_column_aliases` and `upsert_session_metrics_from_csv_mapped` to utilize the new CSV import function, ensuring comprehensive mapping and insertion of metrics.
- Added unit tests to validate the new functionality and ensure correct behavior when handling mapped training parameters during CSV imports.
2026-04-16 11:32:16 +02:00
7d6fdab812 feat: Enhance activity import functionality with additional metrics
All checks were successful
Deploy Development / deploy (push) Successful in 58s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Updated the `_import_activity` function to include new metrics: duration_min, kcal_active, kcal_resting, hr_avg, hr_max, and distance_km during CSV imports.
- Modified the `insert_activity_csv_minimal` function to accept and store these additional metrics in the activity log.
- Enhanced the `run_activity_post_write_hooks_import` function to utilize the new metrics for auto-evaluation after activity imports.
- Updated the activity import router to pass the new metrics from the CSV file to the database functions, ensuring comprehensive data handling.
- Improved frontend handling of activity entry forms to accommodate the new metrics, enhancing user experience during activity log edits.
2026-04-16 11:04:43 +02:00
5cda485458 feat: Refactor activity data handling and improve CSV import logic
All checks were successful
Deploy Development / deploy (push) Successful in 53s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` to clarify the derivation of `ACTIVITY_MODULE_REGISTRY_FIELD_KEYS` from `csv_parser.module_registry`.
- Enhanced `activity_data_canon.py` to eliminate hardcoded key lists, ensuring all registry fields are derived dynamically.
- Refactored the `_import_activity` function to remove redundant parameters and streamline the import process.
- Improved the `insert_activity_csv_minimal` function to handle metrics exclusively through `update_activity_columns`, preventing hardcoded values.
- Updated frontend components to manage editable activity log fields more effectively, ensuring proper handling of metrics during CSV imports.
- Added unit tests to validate the new logic and ensure consistency in activity session metrics handling.
2026-04-16 10:35:08 +02:00
cd29c7d433 feat: Enhance activity session metrics handling and CSV import logic
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 9s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Updated the `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE` with new details on CSV import processes and EAV handling, improving documentation clarity.
- Refactored the `_import_activity` function to utilize `apply_activity_mapped_column_aliases`, ensuring proper mapping of training parameters and reducing redundancy.
- Introduced validation for numeric bounds in the `activity_csv_registry_updates_from_mapped` function, enhancing data integrity during CSV imports.
- Added new utility functions to manage column aliasing and streamline the upsert process for session metrics, preventing duplicate entries.
- Implemented unit tests to validate the new aliasing logic and ensure correct behavior during session metrics updates.
2026-04-16 07:25:39 +02:00
ca8cee990b feat: Enhance activity metrics handling and documentation
All checks were successful
Deploy Development / deploy (push) Successful in 1m1s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated the README to include new activity production architecture and phases, improving clarity on the development roadmap.
- Enhanced the `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE` with details on the target architecture and phase plan for production readiness.
- Introduced a new function `merge_column_backed_and_eav_metrics` to streamline the merging of metrics from column-backed and EAV sources, ensuring data integrity and reducing duplication.
- Refactored session metrics handling to eliminate deprecated synchronization methods, improving the overall efficiency of data processing.
- Added unit tests for the new merging logic, ensuring robust validation of metrics handling.
2026-04-15 16:59:11 +02:00
a7859f0050 Merge pull request 'Erste Version - Universal CSV Importer für EAV und activity_log' (#85) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m1s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Reviewed-on: #85
2026-04-15 11:46:30 +02:00
58ddde6b1e feat: Add time input fields for activity log and enhance time handling
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 15s
- Introduced start_time and end_time fields in the activity log entry form, allowing users to input specific times for activities.
- Implemented utility functions to format and validate time inputs from the API and user input, ensuring proper handling of time data.
- Updated the activity display to show formatted start and end times, improving clarity for users reviewing their activity logs.
2026-04-15 11:39:39 +02:00
08eae86ddc feat: Refactor activity import logic and enhance CSV handling
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Replaced the deprecated `resolve_activity_log_column_patch_from_csv` function with `activity_csv_registry_updates_from_mapped` to streamline updates from CSV mappings.
- Updated the `_import_activity` function to utilize the new registry updates, improving data integrity during activity imports.
- Enhanced the activity module registry by adding German labels for various fields, improving localization support.
- Refactored the session metrics handling to ensure only relevant fields are processed, enhancing the overall robustness of CSV imports.
2026-04-15 10:35:48 +02:00
9d47c4ef84 feat: Update session metrics handling for CSV-mapped values
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Enhanced the docstring for `upsert_session_metrics_from_csv_mapped` to clarify the handling of schema parameters and EAV logic.
- Modified the condition for skipping updates based on `source_field` to ensure only patchable columns are processed, improving data integrity during session metrics upsert operations.
2026-04-15 10:28:13 +02:00
e4e8c70cd2 feat: Enhance CSV header normalization and mapping for activity data
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced a new utility function `canonical_csv_header_label` to standardize CSV header labels, improving consistency in field mapping.
- Updated the `_lookup_db_field` function to support prefix matching for longer manual keys, enhancing the accuracy of field resolution.
- Added tests to validate handling of non-breaking space characters in CSV headers and ensure correct mapping to normalized keys, improving robustness of CSV parsing.
2026-04-15 10:04:32 +02:00
c570e67a09 feat: Enhance activity session metrics handling and frontend display
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 20s
- Updated the `ACTIVITY_LOG_PATCHABLE_COLUMNS` and `ACTIVITY_LOG_PATCH_FORBIDDEN` sets to improve validation of CSV imports, ensuring only allowed fields are patched.
- Refactored the `_coerce_raw_value_for_parameter` function to handle string inputs for integer and float types, enhancing data coercion accuracy.
- Modified the `SessionMetricsFields` component to display orphan metrics that do not match the current schema, improving user visibility of imported data discrepancies.
- Enhanced the frontend to handle and display additional metrics, ensuring a more comprehensive representation of session data.
2026-04-15 08:55:43 +02:00
574af61349 feat: Enhance CSV import and validation for activity module
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated the CSV import logic to merge active training parameters with static fields for the activity module, improving field mapping accuracy.
- Enhanced validation functions to incorporate dynamic field definitions based on active training parameters, ensuring better data integrity during imports.
- Refactored related functions to streamline the process of handling CSV templates and field mappings, improving maintainability and clarity.
- Added new utility functions for resolving activity log column patches and upserting session metrics from CSV, enhancing the overall import functionality.
2026-04-15 08:12:58 +02:00
934b915357 First Version EAV Importer. feat: Enhance activity detail retrieval with EAV metrics and refactor activity import logic
All checks were successful
Deploy Development / deploy (push) Successful in 53s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated the `get_activity_detail` function to include session metrics in the activity detail output, allowing for enriched data representation.
- Refactored the activity import logic to streamline the process of inserting and updating activity records, utilizing new helper functions for better maintainability.
- Improved the handling of duplicate activity entries by implementing a more robust identification mechanism.
- Enhanced the metadata for activity detail registration to reflect the inclusion of EAV metrics and updated source tables.
2026-04-15 07:25:39 +02:00
c6e8371d5a feat: Implement session deduplication in activity listing
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Added a new query parameter `collapseDuplicateSessions` to the activity listing endpoint to enable deduplication of sessions based on date, type, start time, duration, and calories.
- Enhanced backend logic to handle deduplication and return the most recent entry for duplicate sessions.
- Updated frontend to support the new deduplication feature, improving the clarity of displayed activity data.
- Modified API utility to include the new parameter in requests for activity data.
2026-04-14 16:19:34 +02:00
f718785145 feat: Add monthly activity fetching and improve activity listing
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced a new query parameter for the activity listing endpoint to fetch entries by calendar month (format: YYYY-MM), excluding days and offset.
- Implemented backend validation for the month parameter to ensure correct format and range.
- Enhanced the frontend to support month selection, allowing users to load activities for specific months and dynamically update the displayed entries.
- Improved the user interface to show the selected month and the range of loaded months, enhancing user experience.
2026-04-14 14:34:10 +02:00
9fdb02ff8b feat: Refactor activity session metrics handling and enhance activity listing
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated the `replace_activity_session_metrics` function to improve validation logic and error handling for required fields.
- Enhanced the activity listing query to order results by date, start time, and ID, ensuring consistent output.
- Modified the frontend to handle null values in metrics payload and improved the display of activity statistics, including total entries in profile and sample size.
2026-04-14 14:25:17 +02:00
1f51c32521 feat: Enhance activity listing and statistics retrieval with pagination and quality filter options
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Added pagination support to the activity listing endpoint with `limit` and `offset` parameters.
- Introduced a `skip_quality_filter` option to allow retrieval of all entries without applying the quality filter.
- Updated the frontend to implement dynamic loading of activity entries and statistics without the quality filter.
- Improved user experience with a "Load More" button for fetching additional entries on the ActivityPage.
2026-04-14 14:11:01 +02:00
766b64cd64 feat: Expand ActivityEntry model and enhance activity log handling
All checks were successful
Deploy Development / deploy (push) Successful in 53s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Added new fields to the ActivityEntry model for improved tracking: hr_min, pace_min_per_km, cadence, avg_power, elevation_gain, temperature_celsius, humidity_percent, avg_hr_percent, and kcal_per_km.
- Updated the create_activity function to accommodate the new fields in the activity log.
- Modified session metrics handling to ensure accurate data retrieval and merging based on the updated schema.
2026-04-14 12:59:47 +02:00
3296dfca28 feat: Enhance activity log handling and session metrics synchronization
All checks were successful
Deploy Development / deploy (push) Successful in 53s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 18s
- Added a new function to synchronize session metrics with activity log entries, ensuring data consistency.
- Updated the create and update activity endpoints to call the synchronization function after inserting or modifying activity logs.
- Introduced a set of allowed keys for activity log payloads to streamline data handling in the frontend.
- Improved data coercion logic for various data types in the frontend to ensure accurate data submission.
2026-04-14 12:53:35 +02:00
db9952525a feat: Add endpoints for activity statistics and uncategorized activities
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Implemented a new endpoint to retrieve activity statistics for the last 30 entries, including total calories and duration by activity type.
- Added an endpoint to list activities without assigned training types, grouped by activity type.
- Removed deprecated versions of the statistics and uncategorized activities endpoints for cleaner code.
2026-04-14 12:32:38 +02:00
196b6c5cf1 feat: Add update functionality for training category and type parameters
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced new endpoints for updating training category and type parameters in the backend.
- Added corresponding update functions in the frontend API utility.
- Enhanced the Admin Activity Attribute Profiles page to support editing and saving changes for category and type parameters.
- Implemented state management for editing parameters and improved error handling during updates.
2026-04-14 12:26:52 +02:00
cf7379b2f6 feat: Implement Activity Attribute Profiles and session metrics editing
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
- Added new Admin UI for managing Activity Attribute Profiles.
- Enhanced ActivityPage to support dynamic loading and editing of session metrics.
- Updated API utility functions to handle new endpoints for training parameters and metrics.
- Improved form handling for session metrics, including validation and error management.
- Updated documentation to reflect new features and changes in session metrics handling.
2026-04-14 11:56:16 +02:00
48508c164e feat: Add Activity Session Metrics functionality
All checks were successful
Deploy Development / deploy (push) Successful in 59s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced Activity Session Metrics for enhanced tracking of session data.
- Updated backend to support new API endpoints for managing session metrics.
- Added new Pydantic models for activity metrics and replaced metrics functionality.
- Enhanced data layer to include session metrics in recent training session data.
- Updated documentation to reflect changes in session metrics handling.
2026-04-14 11:49:14 +02:00
19a88e4f97 Merge pull request 'feat: Enhance goal progress tracking and display' (#84) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 53s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #84
2026-04-14 11:39:58 +02:00
1b01f5e6d0 feat: Enhance goal progress tracking and display
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Added a function to calculate goal progress percentage based on start, target, and current values.
- Updated GoalsPage to display progress in a user-friendly format, including visual progress bars.
- Implemented error handling for goal progress updates in the backend to ensure robustness.
2026-04-14 10:43:49 +02:00
424270f0e8 Merge pull request 'bug fix und Debug Workflow' (#83) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m2s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #83
2026-04-13 18:15:06 +02:00
df8e732709 fix: Use correct field 'label' instead of 'name' for node display
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Frontend saves node name as 'label' (workflowSerializer.js:19)
- Changed WorkflowNode.name to WorkflowNode.label
- Changed node.name to node.label in workflow_executor.py
- Priority: node.label > prompt_slug > node_type-id
- Verified against frontend serialization code
2026-04-13 18:09:12 +02:00
d5325acee6 fix: Use node.name in node_label calculation (minimal change)
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Add name field to WorkflowNode model
- Extend node_label priority: node.name > prompt_slug > node_type-id
- No new fields in NodeExecutionState (uses existing debug_prompt_slug)
- Simpler approach than previous attempt to avoid 504 timeout
2026-04-13 18:03:02 +02:00
b7062d32bf Revert "feat: Show node.name from workflow editor in debug panel"
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
This reverts commit 5fa2ea2e6b.
2026-04-13 15:54:22 +02:00
5fa2ea2e6b feat: Show node.name from workflow editor in debug panel
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 17s
- Add name field to WorkflowNode model
- Add node_name field to NodeExecutionState
- Set node_name in execute_workflow from node.name
- Display priority: node_name > debug_prompt_slug > node_label > node_id

User sees 'Qualitätseinschätzung' instead of 'node_abc123'
2026-04-13 15:43:42 +02:00
f97d15288d fix: Show debug_prompt_slug instead of node_id
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Priority: debug_prompt_slug > node_label > node_type-shortid > node_id
2026-04-13 15:36:50 +02:00
736dc58d81 feat: Show debug info in WorkflowResultViewer
All checks were successful
Deploy Development / deploy (push) Successful in 59s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
Display per node:
- debug_prompt (prompt sent to AI)
- debug_raw_response (raw AI response)
- analysis_core (parsed results)
- normalized_signals (decision signals with status)
- Failed nodes: red border + red background

NO other changes - executeWorkflow still used
2026-04-13 15:31:37 +02:00
0a27533262 feat: Highlight failed nodes in WorkflowDebugPanel
Some checks failed
Build Test / lint-backend (push) Waiting to run
Build Test / build-frontend (push) Waiting to run
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Has been cancelled
- Failed nodes now have:
  - Red border (2px instead of 1px)
  - Light red background (#D85A3010)
  - Red shadow/glow effect

Makes it immediately obvious which nodes had errors.
2026-04-13 12:58:25 +02:00
7388776b29 fix: Add human-readable labels to workflow nodes in debug output
All checks were successful
Deploy Development / deploy (push) Successful in 53s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- workflow_executor.py: Store prompt_slug or generated label in debug_prompt_slug for all nodes
  - This makes it easy to identify nodes in the debug panel
  - Example: 'wf_nutrition_basis' instead of 'node_5'

- Helps identify which node is which when debugging workflows
2026-04-13 12:52:29 +02:00
a515a5d563 feat: Add WorkflowDebugPanel component to display per-node debug information
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Created WorkflowDebugPanel.jsx: Collapsible panel showing debug info for each workflow node
  - Shows prompt sent to AI
  - Shows raw AI response
  - Shows parsed results
  - Shows normalized signals
  - Color-coded status (executed/failed/skipped)
  - Expandable/collapsible per node

- Updated Analysis.jsx:
  - Added WorkflowDebugPanel import
  - Store node_states in newResult for debugging
  - Display WorkflowDebugPanel below InsightCard (both locations)

This makes it easy to debug workflow issues by seeing exactly what happened at each node.
2026-04-13 12:41:12 +02:00
12d4d7c63b feat: Add comprehensive debug information for workflow nodes
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
Backend changes:
- workflow_models.py: Add debug_prompt, debug_raw_response, debug_node_type, debug_prompt_slug, metadata fields to NodeExecutionState
- workflow_executor.py: Capture and store debug info for analysis, logic, and join nodes when enable_debug=True
  - Analysis nodes: store full prompt + raw AI response
  - Logic nodes: store expression + evaluation result
  - Join nodes: store strategy + path statistics

Frontend changes:
- Analysis.jsx: Enable debug mode by default (debug=true) for all workflow executions

This allows developers to see exactly what prompt was sent to the AI, what response was received, and how each node was processed - essential for debugging workflow issues.
2026-04-13 12:38:55 +02:00
f34e46b04f Merge pull request 'Async Workflow' (#82) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m3s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #82
2026-04-13 11:58:01 +02:00
3664f53c51 fix: Use NodeStatus.EXECUTED instead of COMPLETED
All checks were successful
Deploy Development / deploy (push) Successful in 53s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
NodeStatus enum has EXECUTED, not COMPLETED. Fixed in workflow_executor.py progress callback.
2026-04-13 11:49:31 +02:00
fb2e0803c0 fix: SSE streaming - WorkflowNode label attribute and ai_insights column name
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- workflow_executor.py: Generate node_label from prompt_slug or node.type (WorkflowNode has no label attribute)
- prompts.py: Fix INSERT statement - use 'created' column instead of 'created_at'

SSE endpoint now works correctly for workflow execution streaming.
2026-04-13 11:47:31 +02:00
bb01283727 fix: Correct except/finally indentation in SSE endpoint
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
2026-04-13 11:41:56 +02:00
bc60b9f5c9 fix: Correct indentation in SSE execute_workflow_async function
Some checks failed
Deploy Development / deploy (push) Successful in 49s
Build Test / pytest-backend (push) Failing after 1s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
2026-04-13 11:27:44 +02:00
fbeabcde97 fix: IndentationError in prompts.py SSE endpoint
Some checks failed
Deploy Development / deploy (push) Successful in 52s
Build Test / pytest-backend (push) Failing after 1s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
2026-04-13 11:25:34 +02:00
ba474b0a57 feat: Implement Server-Sent Events (SSE) for long-running workflows
Some checks failed
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Failing after 1s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Backend:
- workflow_executor.py: Add progress_callback parameter, emit events for execution_started, node_complete, execution_complete, execution_failed
- prompt_executor.py: Thread progress_callback through execute chain
- routers/prompts.py: New /execute-stream endpoint with asyncio Queue for SSE

Frontend:
- utils/api.js: New executeUnifiedPromptStream() function with EventSource
- pages/Analysis.jsx: Use SSE with live progress display (X/Y Nodes)

Fixes:
- No more gateway timeouts for complex workflows (10+ nodes)
- Live progress feedback for users
- Unlimited workflow complexity

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-13 11:23:16 +02:00
790e6df8ef fix: Make debug parameter work as Query parameter in /api/prompts/execute
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 17s
Bug: debug=true in URL was ignored because FastAPI expected it in
request body (POST without Query() expects body params by default).

Result: node_states were never returned, even with ?debug=true

Fix: Changed debug and save to Query parameters:
- debug: bool = Query(False, ...)
- save: bool = Query(False, ...)

Now ?debug=true in URL correctly enables debug output with node_states.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 09:14:30 +02:00
057df0afc8 fix: Support UI-format edge routing with sourceHandle
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 24s
Logic-Nodes evaluated correctly but activated_edges was empty because
_get_edges_by_label() only checked e.label, which is null in UI format.

UI format uses:
- sourceHandle: "true" / "false" (instead of label: "then" / "else")
- targetHandle: "in" / "path_1" / etc.

Changes:
1. Added source_handle/target_handle fields to WorkflowEdge model
   - With aliases sourceHandle/targetHandle for camelCase JSON
2. Updated _get_edges_by_label() to check both formats:
   - Legacy: e.label == "then" / "else"
   - UI: e.source_handle == "true" / "false"

Now Logic-Nodes correctly activate outgoing edges → Join-Node receives
completed paths → End-Node executes → Workflow completes!

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 09:07:50 +02:00
ba04e0c0b6 fix: Add extra='forbid' to Condition for proper Union resolution
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Critical fix: Without extra='forbid', Pydantic accepted UI format
{operator: "and", operands: [...]} as valid Condition by ignoring
unknown fields, resulting in Condition(expression=None).

With extra='forbid':
- Condition rejects unknown fields → fails
- Union tries next type → LogicExpression → success

Test Results (9/9 passed):
- Simple comparisons (eq, neq, gt, lt, in) 
- AND/OR combinations 
- Deep nesting (3+ levels) 
- NOT operator 
- All operators (eq, neq, in, not_in, gt, lt, gte, lte, and, or, not) 
- Legacy format (Condition wrapper) 
- Complex real-world scenarios 

Added comprehensive test suite in:
- test_condition_parsing.py (9 test cases)
- test_condition_union.py (Union resolution verification)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 09:01:53 +02:00
f5ce1ec941 refactor: Proper type-safe condition handling with Union types
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Previous fix used Any type, breaking type safety and only handling
simple cases. This is the correct implementation:

Changes:
1. LogicExpression.operands: List[Any] → List['LogicExpression']
   - Enables recursive/nested expressions
   - Proper type checking for all operator combinations

2. WorkflowNode.condition: Any → Union[LogicExpression, Condition]
   - Type-safe deserialization
   - Supports both UI format (direct LogicExpression) and legacy (Condition wrapper)
   - Pydantic automatically tries LogicExpression first, then Condition

3. Executor: Simplified with isinstance() checks
   - Clean type detection without dict manipulation
   - Fallback for edge cases

This now correctly handles:
- Simple conditions: {operator: "eq", ref: "...", value: "..."}
- Combined: {operator: "and", operands: [...]}
- Nested: {operator: "or", operands: [{operator: "and", ...}, ...]}
- All operators: eq, neq, in, not_in, gt, lt, gte, lte, contains, and, or, not
- Legacy format: {expression: {...}, then_path: "...", else_path: "..."}

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 08:45:55 +02:00
2deb6510f8 fix: Support UI-format LogicExpression in Logic-Node condition field
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 13s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Root cause: UI saves LogicExpression directly as condition:
  {operands: [...], operator: "and"}

But Pydantic model expected Condition with wrapped expression:
  {expression: {operands: [...], operator: "and"}}

Result: Pydantic deserialized it as Condition with expression=None
→ Logic-Nodes failed with "'NoneType' object has no attribute 'operator'"

Fix:
1. Changed WorkflowNode.condition type from Condition to Any
2. Executor now handles both dict and Pydantic model formats
3. Detects UI format (operator+operands) vs legacy format (expression wrapper)
4. Converts dict to LogicExpression before evaluation

Fixes: Logic-Node execution failures in Training-Tiefenanalyse workflow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 08:40:43 +02:00
0eac40abf6 fix: Add None-check for Logic-Node condition/expression
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Previous fix handled hasattr() but didn't check for None values.
Now explicitly checks that operator/expression is not None before using it.

Error was: "'NoneType' object has no attribute 'operator'"

Clearer error message: "condition is None or missing"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 08:32:54 +02:00
e915d3fb13 fix: Support both Logic-Node condition serialization formats
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Logic-Nodes were timing out because UI saves condition as:
  {operands: [...], operator: "and"}

But Backend expected:
  {expression: {operands: [...], operator: "and"}}

This caused node.condition.expression to be None, triggering:
- Logic-Node failures
- Join-Node wait_all timeout
- 504 Gateway Timeout

Fix: Accept both formats by checking for operator/operands attributes
directly on condition, falling back to condition.expression.

Fixes: 504 Gateway Timeout in Training-Tiefenanalyse workflow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 08:26:43 +02:00
60f6cf3c6d fix: Add null check for logic node expression to prevent AttributeError
All checks were successful
Deploy Development / deploy (push) Successful in 58s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Problem: Logic nodes without logic_expression defined caused AttributeError
"'NoneType' object has no attribute 'operator'" when evaluating condition.

Solution: Check both node.condition AND node.condition.expression before
calling evaluate_logic_expression(). Return clear FAILED state with error
message instead of crashing.

Impact: Workflows with incomplete logic node definitions now fail gracefully
with clear error message instead of cryptic AttributeError.
2026-04-13 08:16:06 +02:00
46b703e5a2 Merge pull request 'Bug Fixes. Workflow Engine' (#81) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m0s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #81
2026-04-12 14:08:43 +02:00
e09cbc112e fix: Preserve case in question IDs during parsing
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Problem: Parser converted question IDs to lowercase ('qAnalyst' → 'qanalyst'),
causing normalization to fail because id_catalog lookup is case-sensitive.

Impact: All workflow question signals were lost - normalized_signals stayed empty,
so template placeholders like {{node_2.signal_qAnalyst}} remained unresolved.

Solution: Removed .lower() call in parse_decision_questions() to preserve
original case from AI response.

Root cause: Line 162 in result_container_parser.py
Fixes: Question augmentation signals not appearing in workflow end nodes
2026-04-12 14:04:14 +02:00
f6b3182a80 fix: Add wrapper in prompts.py execute endpoint for workflow signature mismatch
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Problem: Workflows executed via /api/prompts/execute (not /api/workflows/execute)
were passing call_openrouter directly to execute_prompt_with_data, which then
passes it to workflow_executor. workflow_executor expects (prompt, model) signature
but call_openrouter has (prompt, max_tokens=4096) signature.

Previous fix in workflows.py was correct but unused - workflows use prompts.py endpoint.

Solution: Added workflow_llm_call() wrapper in execute_unified_prompt() endpoint
that matches expected (prompt, model) -> str signature.

Related: cb3aa48 (workflows.py fix for different endpoint)
2026-04-12 13:44:08 +02:00
cb3aa48999 fix: Add wrapper function for workflow LLM calls to prevent max_tokens signature mismatch
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Problem: workflow_executor calls openrouter_call_func(prompt, model) but
call_openrouter expects (prompt, max_tokens=4096). This caused the model string
'anthropic/claude-sonnet-4' to be passed as max_tokens, resulting in OpenRouter
requesting 64000 tokens and failing with 402 credit errors.

Solution: Added workflow_llm_call() wrapper in workflows.py that matches the
expected (prompt, model) -> str signature and calls call_openrouter correctly.

Fixes: All workflows failing with 402 'insufficient credits' errors
2026-04-12 13:37:31 +02:00
77f1ed14c5 fix: Cursor-Problem beim Frage-ID Editieren
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
Problem: Cursor springt nach jedem Tastendruck aus dem ID-Feld

Ursache: key={q.id} in QuestionEditor map
- Wenn ID geändert wird, ändert sich der React Key
- React unmountet alte Component und mountet neue
- Focus geht verloren

Lösung: key={idx} verwenden
- Stabiler Key während Editing
- Komponente bleibt gemountet
- Cursor bleibt im Feld

UX: Jetzt kann man IDs flüssig editieren ohne Unterbrechung

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-12 12:29:52 +02:00
25c4ecfd48 Merge pull request 'Verbesserung für Tests von Prompts' (#80) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m2s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 15s
Reviewed-on: #80
2026-04-12 11:58:07 +02:00
08c9cccdcc feat: Add expandable collapsible component for improved content display
All checks were successful
Deploy Development / deploy (push) Successful in 53s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced `ExpandableCollapsible` component to manage the visibility of lengthy content, allowing users to toggle between expanded and collapsed views.
- Updated `renderTestOutput` to utilize the new component for displaying test results, JSON outputs, and object representations, enhancing user experience by reducing clutter.
- Enhanced `Markdown` component to support fenced code blocks, improving the rendering of code snippets with language labels and better styling.

These changes improve the readability and organization of content within the application, providing users with a more interactive and manageable interface.
2026-04-12 11:10:39 +02:00
4b6e1bed11 feat: Enhance OpenRouter API interaction and error handling
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Increased the maximum token limit in the `call_openrouter` function from 1500 to 4096 to allow for more extensive responses.
- Implemented robust error handling for API requests, including timeout and request errors, with detailed HTTP exceptions for better debugging.
- Improved JSON response handling to ensure valid data is returned, with specific error messages for missing content in the response.
- Enhanced the overall reliability of the OpenRouter API integration, providing clearer feedback for users in case of issues.

These changes improve the user experience by ensuring more comprehensive responses and clearer error reporting during API interactions.
2026-04-12 11:03:07 +02:00
72eb94d186 Merge pull request 'feat: Improve float parsing logic for enhanced accuracy in numeric conversions' (#79) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
Reviewed-on: #79
2026-04-12 07:30:44 +02:00
90a27846ca feat: Improve float parsing logic for enhanced accuracy in numeric conversions
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated the `_parse_float_auto` function in `type_converter.py` to better handle various decimal and thousand separators, particularly for cases with long decimal parts from sources like Apple Health.
- Enhanced the logic for splitting and processing numeric strings to ensure correct interpretation of values, including edge cases with multiple separators.
- Added handling for cases where numeric strings may contain both commas and periods, improving overall robustness in float parsing.

These changes enhance the accuracy of numeric conversions, ensuring more reliable data processing across the application.
2026-04-12 07:28:24 +02:00
4d81ea2cf3 Merge pull request 'feat: Update Gitea issues index and enhance data layer metrics' (#78) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m4s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Reviewed-on: #78
2026-04-11 22:17:18 +02:00
d7cefdd9e9 feat: Update Gitea issues index and enhance data layer metrics
All checks were successful
Deploy Development / deploy (push) Successful in 1m3s
Build Test / pytest-backend (push) Successful in 9s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated the Gitea issues index to reflect the latest state as of 2026-04-11, adding issue #76 to the list.
- Refined data handling in `activity_metrics.py`, `body_metrics.py`, `nutrition_metrics.py`, and `scores.py` to ensure consistent float conversions for calculations, improving accuracy in metric evaluations.
- Enhanced the calculation logic for various metrics to handle potential None values more robustly, ensuring smoother data processing and improved reliability across the application.

These changes improve the clarity of the Gitea issues documentation and enhance the overall accuracy and reliability of health and fitness metrics.
2026-04-11 22:14:45 +02:00
caeed3fbaa Merge pull request 'Platzhalter finalisiert - Option |d und Option |x implementiert' (#77) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m3s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #77
2026-04-11 22:10:10 +02:00
4868e44882 feat: Refine placeholder resolution with enhanced modifiers support
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Updated `resolve_placeholders` in `prompt_executor.py` to support combined modifiers for placeholders, allowing for more flexible output formats.
- Enhanced `build_ai_placeholder_caption` in `placeholder_registry.py` to clarify the generation of AI context captions, focusing on descriptions and explanations.
- Introduced new helper functions in `placeholder_resolver.py` to streamline the retrieval of descriptions and explanations for placeholders.
- Modified tests to cover new functionality, ensuring accurate behavior for combined modifiers and improved placeholder resolution.

These changes enhance the usability and clarity of placeholder outputs, providing users with richer contextual information.
2026-04-11 21:58:29 +02:00
a9a414b956 feat: Enhance placeholder caption generation and formatting
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated `build_ai_placeholder_caption` in `placeholder_registry.py` to improve the generation of AI context captions by prioritizing descriptions and avoiding redundancy.
- Introduced `format_value_with_d_modifier` in `placeholder_resolver.py` to format values with contextual information, enhancing the clarity of exported placeholder values.
- Modified `export_placeholder_values` in `prompts.py` to utilize the new formatting function, ensuring that exported data includes both raw values and contextual descriptions.
- Added tests for the new formatting function and updated existing tests to ensure accurate caption generation.

These changes improve the contextual relevance of placeholder data and enhance the user experience when interacting with exported values.
2026-04-11 21:47:08 +02:00
baeddd7c13 feat: Enhance placeholder system with AI context support
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced `build_ai_placeholder_caption` function in `placeholder_registry.py` to generate AI context captions based on placeholder metadata.
- Updated `resolve_placeholders` in `placeholder_resolver.py` to support modifiers for AI context, allowing for enhanced descriptions when placeholders are resolved.
- Modified `get_placeholder_catalog` to include AI captions in the output, improving the metadata available for placeholders.
- Adjusted `export_placeholder_values` to include AI captions in the exported data, enhancing the information provided to users.

These changes improve the flexibility and functionality of the placeholder system, enabling richer context generation for dynamic content.
2026-04-11 21:36:29 +02:00
41bf593d4c feat: Refactor sleep metrics calculations and improve error handling
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 3s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated `get_sleep_avg_duration` and `get_sleep_avg_quality` functions in `placeholder_resolver.py` to provide clearer error messages when data is unavailable.
- Enhanced sleep quality calculations in `recovery_metrics.py` to handle cases with insufficient data more robustly.
- Improved data handling in various metrics files (`activity_metrics.py`, `body_metrics.py`, `nutrition_metrics.py`, `recovery_metrics.py`, and `scores.py`) to ensure consistent float conversions for calculations.
- Added utility functions in `recovery_metrics.py` for parsing and normalizing sleep segment data, enhancing the accuracy of sleep quality assessments.

These changes improve the reliability and clarity of sleep-related metrics and enhance overall data handling across the application.
2026-04-11 21:27:49 +02:00
04e23d8115 feat: Enhance placeholder resolution and error handling
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Updated `extract_value_raw` to improve JSON parsing and handle unavailable data more effectively.
- Introduced new functions in `placeholder_resolver.py` for standardized responses when data is unavailable, enhancing clarity for users and AI.
- Modified various data retrieval functions to utilize the new response format, providing detailed reasons for unavailability.
- Improved availability checks in `export_placeholder_values_extended` to account for new response formats.

These changes enhance the robustness of the placeholder system and improve user experience by providing clearer error messages and data handling.
2026-04-11 21:22:27 +02:00
052ba195cc feat: Update placeholder metadata and nutrition metrics
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 15s
- Adjusted the total number of placeholders from 116 to 114 across various documentation and code files to reflect the current state of the system.
- Enhanced TDEE calculation logic in `nutrition_metrics.py` to prioritize Mifflin–St Jeor BMR with PAL when demographic data is available, with a fallback to a weight-based estimate.
- Updated placeholder registrations to ensure consistency with the new metadata structure and improved data handling.
- Revised documentation to clarify the authoritative source of placeholder metadata and the implications of the changes on existing functionalities.

These updates improve the accuracy and consistency of the placeholder system and enhance the nutritional assessment capabilities within the application.
2026-04-11 21:11:05 +02:00
2ea5f905c4 feat: Add new profile and time period placeholders in placeholder_resolver.py
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
- Introduced functions to retrieve profile name, age, height, and gender for better placeholder resolution.
- Added functions for displaying current date and time period labels (last 7, 30, and 90 days).
- Updated PLACEHOLDER_MAP to utilize new functions for improved readability and maintainability.
- Enhanced placeholder registrations in __init__.py to include new modules for sleep, vital metrics, and profile time periods.

These changes enhance the flexibility and functionality of the placeholder system, allowing for more dynamic content generation.
2026-04-11 21:08:34 +02:00
e9e094c6a4 feat: Enhance nutrition and activity metrics with new data layers
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Added new functions for BMI and goal weight/body fat percentage retrieval in `body_metrics.py`.
- Introduced training frequency and inter-session gap calculations in `activity_metrics.py`.
- Updated placeholder registrations to include new metrics for nutrition and activity.
- Improved data handling in `placeholder_resolver.py` for better integration of new metrics.
- Enhanced documentation across modules to reflect the new functionalities.

These updates improve the accuracy and comprehensiveness of health and fitness assessments within the application.
2026-04-11 20:46:17 +02:00
61a5bb39ae feat: Update nutrition metrics and energy balance calculations
All checks were successful
Deploy Development / deploy (push) Successful in 59s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced a single TDEE calculation based on current weight, replacing the fixed 2500 kcal value.
- Updated `get_energy_balance_data` to use daily totals for intake calculations and improved energy balance logic.
- Enhanced `get_nutrition_average_data` to calculate averages over calendar days instead of raw log entries.
- Adjusted placeholder resolution to ensure consistent metadata usage across requests.
- Fixed issues in the charts router to reflect the new energy balance logic and TDEE calculations.

These changes improve the accuracy of nutritional assessments and streamline data handling in the application.
2026-04-11 19:04:27 +02:00
b5f745fc3e Merge pull request 'Workflow 1.1 bug fixes' (#74) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m5s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Reviewed-on: #74
2026-04-11 15:39:23 +02:00
549c31431e feat: Validierungs-Panel mit Details und Click-to-Jump
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
Issue #1 + #3: Validierung zeigt keine Details / Fehler-Lokalisierung

NEU: ValidationPanel Component
- Zeigt alle Fehler und Warnungen mit vollständigen Details
- Gruppiert nach Severity (Fehler/Warnungen)
- Aufklappbar pro Gruppe (collapsible)
- Click-to-Jump: Fehler mit nodeId sind klickbar
- Klick selektiert betroffene Node → Config-Panel öffnet sich
- Schließbar, öffnet sich automatisch bei neuen Fehler/Warnungen

Features:
- Fixed position (bottom-right, über Canvas)
- Farb-Kodierung: Rot (Errors) / Gelb (Warnings)
- Hover-Effekt auf klickbare Items
- Type-Labels (structure, isolation, etc.)
- Scrollbar bei vielen Fehler/Warnungen
- X-Button zum Schließen

UX-Verbesserungen:
- Kein Raten mehr: Zeigt WAS der Fehler ist
- Kein Suchen mehr: Klick springt direkt zur Node
- Übersichtlich auch bei vielen Fehler/Warnungen
- Funktioniert in großen Workflows

Technisch:
- handleValidationNodeClick: setSelectedNodeId
- Auto-show bei errors.length > 0 || warnings.length > 0
- State: showValidationPanel (closable)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 15:27:14 +02:00
3fa01dd686 feat: Warnung bei ungespeicherten Workflow-Änderungen
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
Issue #0: Ungespeicherte Änderungen gehen verloren beim "Zurück"-Klick

Implementiert:
- hasUnsavedChanges State tracking
- Warnung beim "Zurück"-Button (navigate zu /admin/prompts)
- Warnung beim "Neu"-Button (nur wenn unsaved changes)
- Browser beforeunload Event (warnt bei Browser-Back/Refresh)

Tracking für alle Änderungen:
- onNodesChange/onEdgesChange (Node-Bewegung, Löschen via Delete-Taste)
- onConnect (neue Edges)
- handleAddNode (Node hinzufügen)
- handleNodeUpdate (Node-Daten ändern)
- handleDeleteNode (Node löschen via Button)
- workflowName onChange (Titel ändern)

Flag wird cleared:
- Nach erfolgreichem Save (Update/Create)
- Nach erfolgreichem Load
- Bei "Neu" (nach User-Bestätigung)

UX:
- Klare Warnung: "Du hast ungespeicherte Änderungen"
- Kein Datenverlust mehr durch versehentliches Zurück
- Browser warnt auch bei Refresh/Close

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 15:21:31 +02:00
c9357d4c0e feat: Import Dialog mit 3 Buttons (Ja/Nein/Abbrechen)
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Ersetzt zwei aufeinanderfolgende confirm()-Dialoge durch einen
Custom Dialog mit drei klaren Optionen:

- "Ja, überschreiben" → bestehende Prompts aktualisieren
- "Nein, nur neue" → existierende überspringen
- "Abbrechen" → Import komplett abbrechen

UX-Verbesserung:
- Alle Optionen auf einen Blick sichtbar
- Kein Raten mehr was "OK" oder "Abbrechen" bedeutet
- Klare Beschreibungstexte unter jedem Button
- Vollbildschirm-Modal mit Overlay

Technisch:
- importDialogData State für Dialog-Daten
- handleImportChoice verarbeitet yes/no/cancel
- Custom Modal-JSX statt Browser confirm()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 14:57:48 +02:00
f3a61091c7 fix: Import confirmation UX - two-step process
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Admin-Prompts Import hatte unklare Abbrechen-Logik:
- Nutzer erwartete: Abbrechen = Import komplett abbrechen
- Vorher: Abbrechen = overwrite=false, Import lief weiter

Lösung: Zwei-Schritt-Bestätigung
1. "X Prompts importieren?" → Abbrechen = kompletter Abbruch
2. "Existierende überschreiben?" → Abbrechen = nur neue importieren

UX: Klare Trennung zwischen "Import abbrechen" und "Modus wählen"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 14:54:53 +02:00
10d24bbef7 fix(workflow): Duplicate - JSON-encode JSONB fields
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
**Error:**
```
psycopg2.ProgrammingError: can't adapt type 'dict'
```

**Root Cause:**
- duplicate_prompt passed Python dicts directly to SQL INSERT
- JSONB fields from r2d() are already deserialized by psycopg2
- PostgreSQL expects JSON strings for JSONB columns

**Fix:**
- Added json.dumps() for all JSONB fields before INSERT:
  - stages, output_schema, question_augmentations, graph_data
- Same pattern as import function

Files changed:
- backend/routers/prompts.py: JSON-encode JSONB in duplicate_prompt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 14:46:13 +02:00
ff8104a533 fix(workflow): Route precedence - move export/import before path param
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
**Root Cause:**
- FastAPI route matching: /{prompt_id} caught ALL requests including /export-all
- Specific routes MUST be defined BEFORE path parameter routes

**Error:**
```
psycopg2.errors.InvalidTextRepresentation: invalid input syntax for type uuid: "export-all"
LINE 1: SELECT * FROM ai_prompts WHERE id='export-all'
```

**Fix:**
- Moved /export-all and /import endpoints to line 106 (BEFORE /{prompt_id} at ~260)
- Added warning comments to both functions
- Fixed typo: for r in → for row in

**Affected:**
- /export-all: Internal Server Error → now works 
- /import: Would have had same issue → preemptively fixed 

Files changed:
- backend/routers/prompts.py: Reordered route definitions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 14:42:55 +02:00
3b7f89a214 fix(workflow): UnboundLocalError in execute_end_node - graph not defined
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Critical bug fix from pytest failures:

**Problem:**
- execute_end_node() tried to use 'graph' variable without defining it
- UnboundLocalError at line 602: "if graph:"
- Caused 2 test failures in test_end_node_template.py

**Root Cause:**
- In Issue #5 fix, added graph lookup for node labels in AUTO mode
- But forgot to get graph from context first
- TEMPLATE mode already had: graph = context.get("graph")

**Fix:**
- Added: graph = context.get("graph") at start of AUTO mode block
- Same pattern as TEMPLATE mode
- graph is optional (None if not in context), so if-check is safe

**Tests:**
- test_auto_mode_concatenates_all_analyses - should pass now
- test_auto_mode_skips_skipped_nodes - should pass now

Files changed:
- backend/workflow_executor.py: Added graph = context.get("graph") line 596

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 14:28:19 +02:00
ba773e677b fix(workflow): Test-Suite Fixes - Issues #5, #8, #9, #11, #12
Some checks failed
Deploy Development / deploy (push) Successful in 1m1s
Build Test / pytest-backend (push) Failing after 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Addressed test results from Test_status_Wkf.md:

**Issue #5: End-Node Überschriften**
- Fixed aggregate_results to show node labels instead of "Node 10"
- Added graph lookup to get node.data.label from node objects
- Modified backend/workflow_executor.py (2 locations)

**Issue #8: Löschen-Taste funktioniert nicht**
- Added Delete key support to WorkflowCanvas
- Set deleteKeyCode={['Backspace', 'Delete']}
- Frontend: WorkflowCanvas.jsx

**Issue #9: Mehrere End-Nodes verhindern**
- Added validation error when multiple End-Nodes exist
- Backend supports only 1 End-Node (aggregate_results takes last)
- Frontend: workflowValidation.js

**Issue #11: Export Fehler "Internal Server Error"**
- Added missing fields to export-all endpoint:
  - graph_data (workflow node graph)
  - question_augmentations (analysis prompts)
- Added missing fields to import endpoint
- Proper JSON serialization for all JSONB fields
- Backend: routers/prompts.py

**Issue #12: Workflow duplizieren funktioniert nicht**
- Fixed duplicate endpoint to include all prompt fields:
  - type, stages, output_format, output_schema
  - question_augmentations, graph_data (critical for workflows!)
- Backend: routers/prompts.py

Files changed:
- backend/workflow_executor.py: Node label lookup in aggregate_results
- backend/routers/prompts.py: Export/import/duplicate fixes
- frontend/src/components/workflow/WorkflowCanvas.jsx: Delete key
- frontend/src/utils/workflowValidation.js: Max 1 End-Node validation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 14:15:57 +02:00
2443b5ac3a Merge pull request 'Workflow Analysen V1.1' (#73) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 15s
Reviewed-on: #73
2026-04-11 12:38:08 +02:00
4c9e0e3c98 refactor: Simplify StartNode component to improve clarity
All checks were successful
Deploy Development / deploy (push) Successful in 57s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Removed the trimming of the analysis title, now displaying only the node label or defaulting to 'Start'.
- Updated documentation to clarify the purpose of properties, specifically distinguishing between display on the canvas and analysis metadata.

These changes enhance the readability and maintainability of the StartNode component in the workflow editor.
2026-04-11 12:30:10 +02:00
0ce98e8973 feat: Enhance StartNode and Workflow Editor with analysis metadata
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated StartNode to display a trimmed analysis title if available, falling back to the label or 'Start'.
- Refactored WorkflowEditorPage to include analysis metadata (title, description, category) in the start node configuration.
- Improved serialization and deserialization of workflow graphs to handle new analysis fields.
- Enhanced user interface to allow setting and displaying analysis metadata for better clarity in the workflow editor.

These changes improve the user experience by providing clearer metadata handling in workflows and ensuring consistent display in analysis components.
2026-04-11 12:19:06 +02:00
d803f39de3 feat: Refactor workflow result handling in prompts and analysis components
All checks were successful
Deploy Development / deploy (push) Successful in 53s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Introduced a new utility function to streamline the extraction of user-facing content from aggregated workflow results.
- Updated backend prompt handling to utilize the new function for improved clarity and maintainability.
- Adjusted frontend analysis component to leverage the utility for consistent content display across different workflow result formats.

These changes enhance the overall user experience by ensuring more reliable and readable output from workflow executions.
2026-04-11 12:04:35 +02:00
300d96a9d8 feat: Enhance prompt execution for workflows and analysis offers
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Added support for handling aggregated results in workflow prompts, allowing for various data formats (string, object).
- Introduced a utility function to filter active prompts for both pipeline and workflow types in the analysis page.
- Updated content handling in the analysis component to accommodate new workflow data structures.

This improves the flexibility and usability of the prompt execution process in both backend and frontend components.
2026-04-11 11:42:54 +02:00
28b6fb28d5 neuer Viewport für Admin-Seiten
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
2026-04-11 11:32:46 +02:00
8b731313df Merge pull request 'Workflow V1' (#72) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m1s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Reviewed-on: #72
2026-04-11 10:59:39 +02:00
3541c416f9 feat: Workflow Editor UX improvements - validation and notifications
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
**Problem 1: Validation footer covers mobile menu**
- Fixed bottom validation panel (z-index 1000) overlapped mobile nav
- Solution: Removed bottom panel, added inline validation in config panel header

**Problem 2: Alert dialogs for save success**
- alert() blocks UI and requires OK click for every save
- Solution: Toast notifications (auto-close after 3s, non-blocking)

**Problem 3: Validation shows only counts, not details**
- Footer showed "1 Error, 2 Warnings" without details
- Solution: Inline display shows all error/warning messages with click-to-navigate

**New Components:**
- Toast.jsx: Auto-closing notifications (success/error/warning/info)
- ConfirmDialog.jsx: Modal confirmation dialogs (for future save-on-close)

**Changes:**
- WorkflowEditorPage: Inline validation in config panel, toast state
- Removed fixed bottom .validation-panel (no mobile overlap)
- Toast for save success instead of alert()

**Still TODO (separate commit):**
- Save confirmation when closing/switching nodes with unsaved changes
- Dirty state tracking

Part 3: Inline Prompts - UX polish (validation + notifications)
2026-04-11 10:48:28 +02:00
8d89b23db1 fix: UX improvements for inline template mode switching
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
**Issue 1: Prompt selector loses value**
- When switching Reference→Inline→Reference, the dropdown was empty
- Root cause: Switching to Inline deleted prompt_slug
- Fix: Keep prompt_slug when activating inline_template
- Now: Both modes preserve their values independently

**Issue 2: Workflow overview shows 'kein Prompt'**
- Nodes with inline templates showed misleading 'kein Prompt' text
- Root cause: AnalysisNode only checked prompt_name/prompt_slug
- Fix: Check inline_template and display '✏️ Inline-Template'
- Now: Clear visual distinction between modes

Files:
- WorkflowEditorPage.jsx: Preserve prompt_slug on mode switch
- AnalysisNode.jsx: Add isInlineMode detection and display

Part 3: Inline Prompts - UX polish
2026-04-11 10:31:05 +02:00
c0525cf2d2 feat: Extend JoinNode to support 8 input paths
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
- Increased from 3 to 8 input handles (path_1 through path_8)
- Evenly distributed across top edge (11%, 22%, 33%, ..., 89%)
- Backend already supports unlimited inputs dynamically
- Unused handles are ignored (no edges = no check)

Join strategies for missing inputs:
- wait_all: Fails if any connected path fails
- wait_any: Succeeds if at least 1 path succeeds
- best_effort: Always succeeds

User can still chain multiple Joins if >8 inputs needed.
Part 3: Inline Prompts - workflow flexibility
2026-04-11 10:25:28 +02:00
88f0b5a0a4 fix: Add workflow node outputs as placeholders in inline templates
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
ISSUE: Inline templates referencing node outputs ({{ node_id.analysis_core }},
{{ node_id.signal_xyz }}) were not resolved - AI received empty data from
previous workflow stages.

ROOT CAUSE: load_prompt_template() only loaded system placeholders
(name, age, etc.) but not node execution results from context['node_results'].

FIX:
- Extract node outputs from context['node_results']
- Add as placeholders: node_id.analysis_core, node_id.signal_xyz, node_id.question_xyz
- Format matches PlaceholderPicker extraction logic
- Debug logging shows which node placeholders are added

TESTING:
- System placeholder test:  SUCCESS (name, age, geschlecht resolved)
- Node output placeholders: Fixed (previously missing)
- User workflow: Join → Analysis → End now receives upstream data

Part 3: Inline Prompts - placeholder resolution completion
2026-04-11 10:13:03 +02:00
aeb0ee6ad9 debug: Add comprehensive placeholder resolution logging to workflow executor
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 15s
- Log placeholder loading (count, sample keys)
- Log key cleaning process (before/after)
- Log sample values (name, age, geschlecht)
- Log template before/after resolution
- Log resolved and unresolved placeholders
- Add .strip() to key cleaning to handle spaces

This will help diagnose why {{ name }}, {{ age }}, {{ geschlecht }} are not resolving in inline templates.
Issue: Part 3 Inline Prompts - placeholder resolution debugging
2026-04-11 09:38:18 +02:00
a4c8b4bd9a fix: Syntax error in WorkflowEditorPage IIFE
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
QuestionAugmentationPanel und FallbackConfig waren außerhalb der IIFE.
Müssen innerhalb sein, vor dem schließenden Fragment.

Build lokal getestet: ✓ erfolgreich

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 09:03:10 +02:00
8f6d60681e fix: Inline Prompts - UX-Verbesserungen
Some checks failed
Deploy Development / deploy (push) Failing after 39s
Build Test / pytest-backend (push) Successful in 3s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Failing after 11s
Problem 1: Selbst-Referenzierung verhindern
- PlaceholderPicker erhält currentNodeId prop
- Node kann sich nicht mehr selbst in Placeholders sehen
- extractWorkflowPlaceholders() filtert aktuellen Node aus

Problem 2: Radio-Button State-Management
- IIFE mit Helper-Funktion für Mode-Bestimmung
- isInlineMode/isReferenceMode basierend auf data.inline_template
- Korrekte Conditional Rendering Logic
- Beim Wechsel Reference→Inline bleibt prompt_slug erhalten
- Beim Wechsel Inline→Reference bleibt inline_template erhalten

Problem 3: Layout-Breite optimiert
- Sidebar: 250px → 220px (schmaler)
- Config Panel: 400px → 520px (breiter für bessere Lesbarkeit)
- Responsive: Config Panel bei <1200px: 450px statt 350px

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 08:58:46 +02:00
65500c899b fix: Add missing WorkflowNode import in workflow_executor
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Import war vergessen nach Umstellung von load_prompt_template() auf WorkflowNode Parameter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 08:47:45 +02:00
a1723db387 feat: Workflow Engine Part 3 - Inline Prompts (v0.9q)
Some checks failed
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Failing after 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
Ermöglicht Analysis Nodes zwischen zwei Prompt-Modi zu wählen:
- Reference Mode: Basis-Prompt aus DB referenzieren (bestehend)
- Inline Mode: Template direkt im Node editieren (NEU)

Frontend:
- InlineTemplateEditor Component (~80 Zeilen)
- Radio Buttons in WorkflowEditorPage für Mode-Auswahl
- Placeholder Picker für beide Modi (End Node + Inline Template)
- Cursor-Position Tracking mit textareaRef
- Conditional Rendering basierend auf promptSource
- Validation: Entweder prompt_slug ODER inline_template

Backend:
- load_prompt_template() akzeptiert ganzen WorkflowNode (statt nur slug)
- Unterstützt inline_template (Mode 1) und prompt_slug (Mode 2)
- WorkflowNode.inline_template Feld hinzugefügt
- Validation: HTTPException wenn weder slug noch template

Serialization:
- inline_template in graph_data speichern/laden
- Backward-compatible mit bestehenden Workflows

Version: 0.9q
Module: workflow 0.7.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 08:45:00 +02:00
b453ce63c6 feat(universal-csv-import): Introduce Universal CSV Import module and related documentation
All checks were successful
Deploy Development / deploy (push) Successful in 53s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Added the Universal CSV Import module, including the `UNIVERSAL_CSV_IMPORT_AGENT_GUIDE.md` for guidelines on new import modules, executors, and templates.
- Updated relevant rules in `ARCHITECTURE.md` and `CODING_RULES.md` to include references to the new import module and its requirements.
- Revised the Gitea Issues Index to reflect the latest updates and added context for ongoing issues related to the CSV import functionality.
- Enhanced the README files to provide clearer navigation and documentation for the Universal CSV Import features.
2026-04-11 08:14:20 +02:00
12893cba78 Merge pull request 'Universal CSV Importer' (#70) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Reviewed-on: #70
2026-04-11 07:06:47 +02:00
ebca44829e fix(csv_parser): Normalize header comparison in CSV template validation
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated the `validate_csv_template` function to normalize both the column signature and field mappings for accurate comparison, preventing false warnings about mismatches.
- Enhanced warning messages to provide clearer guidance on the relationship between normalized signatures and raw field mappings.
- Added a new test to ensure that normalized signatures do not trigger false warnings when compared to raw mappings.
2026-04-11 06:52:17 +02:00
0629f88b37 feat(csv-templates): Add CSV template validation endpoint and enhance error handling
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Introduced a new endpoint for validating CSV templates without saving, allowing users to check field mappings and type conversions.
- Updated the `create_system_template` and `update_system_template` functions to include validation reports in responses.
- Enhanced error handling in CSV import processes by integrating `enrich_row_error` for more informative error messages.
- Improved the AdminCsvTemplateEditorPage to support format checking and display validation results, enhancing user experience.
- Incremented version numbers for `csv_import` and `admin_csv_templates` to reflect these updates.
2026-04-11 06:47:27 +02:00
6945b748cb feat(schema, csv_parser): Update activity log schema and parsing logic
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 3s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Increased precision for `kcal_active`, `kcal_resting`, `hr_avg`, and `hr_max` fields in the activity log schema.
- Added a new function `_activity_hr_bpm` to validate heart rate values during CSV import, ensuring they fall within plausible ranges.
- Updated the CSV parser to utilize the new heart rate validation function for improved data integrity.
- Enhanced the type converter to accommodate additional aliases for energy fields in CSV imports.
- Added a test to verify conversion of active energy from kJ to kcal, ensuring accurate data handling.
2026-04-11 06:41:23 +02:00
08a2485f43 refactor(csv_parser): Implement SAVEPOINT handling for activity import
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / pytest-backend (push) Successful in 9s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
- Added SAVEPOINT management to the `_import_activity` function to improve error handling during CSV imports.
- Moved the training type resolution logic to occur within a transaction block, ensuring that errors can be rolled back without affecting the entire import process.
- Enhanced error logging to capture evaluation failures, providing better insights during CSV import operations.
2026-04-11 06:31:42 +02:00
894ee1dd02 refactor(csv_parser): Update training type resolution to use existing database cursor
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Modified `_resolve_training_type_for_activity` to accept a database cursor, improving efficiency and avoiding potential deadlocks during CSV imports.
- Introduced `get_training_type_for_activity_with_cursor` to handle training type resolution with an existing cursor, streamlining database interactions.
- Updated related calls in the activity import logic to utilize the new function, ensuring consistent behavior across the application.
2026-04-11 06:27:11 +02:00
a9bd3faabb Bug Fix für type_converter.py und executor.py
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
2026-04-10 16:52:11 +02:00
5b96bd4f75 feat(csv-import): Add blood pressure and activity row diagnosis functionality
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Introduced `diagnose_blood_pressure_row` and `diagnose_activity_row` functions to validate and analyze blood pressure and activity data from CSV imports.
- Updated the CSV import logic to handle combined datetime columns for blood pressure and activity, improving data integrity during import.
- Enhanced type conversion specifications to include `start_time` for blood pressure and activity, ensuring accurate data mapping.
- Added tests to validate the new diagnosis functions and their integration with existing import processes, ensuring robustness and reliability.
- Updated frontend messages to provide clearer guidance on blood pressure and activity data handling during CSV imports.
2026-04-10 16:43:00 +02:00
c5b0540b11 feat(csv-import): Add CSV import diagnosis endpoint and related functionality
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Implemented a new endpoint for diagnosing CSV imports without writing to the database, allowing users to validate mappings and type conversions.
- Introduced the `diagnose_vitals_row` function to analyze vital metrics and provide detailed feedback on data validity.
- Enhanced the CSV import logic to include alias handling for vital fields, improving compatibility with different CSV formats.
- Updated the frontend to support the new diagnosis feature, including UI elements for displaying diagnosis results and error details.
- Added tests to ensure the correctness of the new diagnosis functionality and its integration with existing import processes.
2026-04-10 16:35:31 +02:00
1855f6e57a refactor(migrations): Improve idempotency and constraint handling for vitals_baseline source
All checks were successful
Deploy Development / deploy (push) Successful in 57s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 18s
- Updated migration scripts to ensure idempotent behavior for the source CHECK constraint, allowing for consistent application even if previous migrations were partially successful.
- Enhanced SQL logic to drop existing constraints safely and re-add them, ensuring compatibility with the universal CSV import.
- Clarified comments for better understanding of migration context and functionality.
2026-04-10 16:17:35 +02:00
5a0c71dd90 feat(csv-import): Implement SAVEPOINT handling for vitals baseline import
Some checks failed
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Failing after 1s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 17s
- Updated the CSV import logic to include SAVEPOINT management, allowing for better error handling during the vitals baseline import process.
- Enhanced the SQL migration script to drop existing CHECK constraints related to the 'source' field, ensuring compatibility with the new universal CSV import.
- Incremented DB_SCHEMA_VERSION to "20260409c" to reflect these changes and improve the import process reliability.
2026-04-10 16:11:08 +02:00
e60976e1cc chore(version): Update database schema version for CSV import enhancements
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 18s
- Incremented DB_SCHEMA_VERSION to "20260409b" to reflect changes related to the vitals_baseline.source CSV migration.
- Updated comments to clarify the migration context for better maintainability.
2026-04-10 16:05:51 +02:00
b7cd710c32 feat(csv-import): Enhance row aggregation and validation features
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
- Updated the aggregate_mapped_rows function to support multiple row policies, allowing for flexible handling of duplicate keys during CSV imports.
- Introduced deduplication of identical rows before aggregation, improving data integrity.
- Enhanced validation for multi_row_policy and dedupe_identical_rows in import_row_processing specifications.
- Updated the AdminCsvTemplateEditorPage to include options for multi-row policies and deduplication settings, improving user experience in template management.
- Added comprehensive tests to validate new aggregation behaviors and ensure correct error handling for multiple rows.
2026-04-10 15:36:12 +02:00
ad7aa2d255 feat(csv-import): Add custom row aggregation options in AdminCsvTemplateEditorPage
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
- Introduced a new section for row aggregation settings, allowing users to customize aggregation functions for imported CSV data.
- Implemented functionality for users to save custom aggregation configurations and select key fields for aggregation.
- Enhanced user interface with detailed instructions and options for managing row aggregation, improving overall usability in template management.
2026-04-10 15:26:59 +02:00
a51ee1d304 feat(csv-import): Update versioning and enhance row processing features
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 3s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Bumped version numbers for csv_import to 0.3.1 and admin_csv_templates to 0.2.0, reflecting recent enhancements.
- Added support for import_row_processing_default in the CSV modules endpoint, improving data handling capabilities.
- Introduced new row aggregation operations in the AdminCsvTemplateEditorPage, allowing for more flexible data processing options.
- Implemented parsing and validation for custom row processing configurations, enhancing user experience in template management.
2026-04-10 15:22:31 +02:00
e35d167055 feat(csv-import): Enhance CSV import processing and validation
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
- Updated the CSV import logic to support new row processing specifications for weight and vitals baseline, allowing for better data aggregation and validation.
- Implemented handling for multiple rows on the same day, enabling aggregation of values such as averages for vitals and last values for weight.
- Enhanced test coverage for the new import functionalities, ensuring correct behavior during data processing and validation.
- Refactored the module registry to include default import row processing options for better flexibility in handling CSV data.
2026-04-10 15:09:34 +02:00
c0fcdea1fe refactor(csv-import): Enhance nutrition data processing and template rendering
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend (push) Successful in 3s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated the nutrition import logic to utilize a new row processing specification, improving data aggregation and validation.
- Refactored the template rendering process in the workflow executor to use Jinja2's Environment with ChainableUndefined for better handling of missing attributes.
- Added backward-compatible shortcuts for accessing decision signals in node contexts, enhancing flexibility in template usage.
- Introduced import row processing options in CSV templates, allowing for more customizable data handling during imports.
2026-04-10 11:56:43 +02:00
8b67f7ab55 refactor(csv-import): Simplify test execution and enhance custom equivalence handling
Some checks failed
Deploy Development / deploy (push) Successful in 57s
Build Test / pytest-backend (push) Failing after 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated the test execution command in the CI workflow to run all tests excluding slow ones, improving efficiency.
- Enhanced the AdminCsvTemplateEditorPage to support custom equivalence for unit conversions, allowing for more flexible data handling.
- Added markers in pytest configuration for categorizing tests, facilitating better test management.
2026-04-10 11:38:54 +02:00
8ee9fb84ba fix(metadata): Update extraction logic and enhance circumference detection
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend (push) Successful in 3s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Adjusted the extract_value_raw function to return failure for unavailable values in strict mode.
- Expanded the circumference detection logic in infer_unit_strict to include additional terms for better accuracy in unit inference.
2026-04-10 11:25:38 +02:00
fe7a69fb07 feat(csv-import): Enhance source unit handling and custom conversion options
Some checks failed
Deploy Development / deploy (push) Successful in 52s
Build Test / pytest-backend (push) Failing after 2s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Updated the source_unit_choices_for_field function to include a custom option for user-defined conversion factors, improving flexibility in unit conversions.
- Modified the AdminCsvTemplateEditorPage to support custom conversion factors, allowing users to input specific scaling factors for their data.
- Added tests to ensure the custom option is correctly included in the source unit choices and functions as expected in the template editor.
2026-04-10 11:19:44 +02:00
bb6eefc837 fix(csv-import): Normalize source unit representation and update CI workflows
Some checks failed
Deploy Development / deploy (push) Successful in 49s
Build Test / pytest-backend (push) Failing after 3s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Changed source unit representation from "kJ" to "kj" for consistency across CSV templates and migrations.
- Updated CI workflow to enhance testing conditions, ensuring tests run in the correct environment based on deployment context.
- Improved job steps for backend testing and syntax checking by utilizing deployed application directories, streamlining the CI process.
2026-04-10 10:42:59 +02:00
0d0ab62674 feat(workflows): Update CI configuration and enhance testing conditions
Some checks failed
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend-csv (push) Failing after 24s
Build Test / lint-backend (push) Failing after 3s
Build Test / build-frontend (push) Successful in 1m25s
- Added workflow_run triggers for "Deploy Development" and "Deploy Production" to ensure tests run only after successful deployments.
- Updated Python version in CI from 3.12 to 3.11 for better compatibility with the Debian 12 ARM64 runner.
- Enhanced job conditions to skip tests on failed workflow runs.
- Improved frontend build process by updating Node.js setup and ensuring correct directory navigation.
- Refined CSV parsing logic to handle custom and unknown source units, enhancing conversion flexibility.
- Added new tests for custom source unit handling in CSV conversions, ensuring accurate processing.
2026-04-10 10:27:59 +02:00
d6d7e738a5 feat(csv-import): Refactor CSV import logic and enhance data handling
Some checks failed
Deploy Development / deploy (push) Successful in 48s
Build Test / pytest-backend-csv (push) Failing after 3s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
- Updated the CSV import architecture to clarify the distinction between import and data layer responsibilities, as outlined in the new section of ARCHITECTURE.md.
- Enhanced the build_row_after_mapping function to include module-specific context for improved data processing.
- Introduced source unit options in the admin CSV template editor to facilitate user-defined conversions, improving flexibility in handling various data formats.
- Added new tests to validate the handling of source units and ensure accurate conversions during CSV imports.
- Updated module definitions to include unit specifications for nutritional and activity data fields, enhancing data integrity.
2026-04-10 09:54:32 +02:00
41cc0ed2a8 feat(csv-import): Enhance Apple sleep CSV import functionality
Some checks failed
Deploy Development / deploy (push) Successful in 54s
Build Test / pytest-backend-csv (push) Failing after 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Integrated date parsing improvements using dateutil for better handling of various date formats in sleep data.
- Added total sleep hours to the nights dictionary for comprehensive sleep analysis.
- Updated the import logic to handle cases where sleep duration is zero, providing appropriate warnings.
- Enhanced the CSV import interface to detect Apple sleep CSV format and provide user feedback on template selection.
- Improved the admin CSV template editor to accommodate new sleep import requirements and clarify usage instructions.
2026-04-10 07:52:04 +02:00
26ab11eb7b feat(csv-import): Enhance CSV import functionality with new modules and tests
Some checks failed
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend-csv (push) Failing after 1m4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Added support for new CSV import modules: sleep and vitals_baseline, expanding the import capabilities.
- Implemented backend logic for handling CSV imports related to sleep and vitals baseline, including error handling and data processing.
- Updated frontend components to include new modules in the CSV import interface, improving user experience.
- Introduced unit tests for the new import functionalities to ensure reliability and correctness.
- Enhanced existing CSV analysis features to accommodate the new modules, ensuring consistent behavior across the application.
2026-04-10 07:30:48 +02:00
b4cc3cb934 feat(csv-parser): Introduce header signature ranking metrics for enhanced CSV analysis
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Added new functions for calculating header signature recall and ranking metrics, improving the analysis of CSV templates.
- Updated existing CSV analysis endpoints to utilize the new ranking metrics, enhancing the accuracy of template matching.
- Refactored related code to replace Jaccard score calculations with the new metrics, providing a more comprehensive evaluation of CSV structure.
- Improved documentation for new functions to clarify their purpose and usage in the context of CSV template analysis.
2026-04-10 07:08:21 +02:00
c10da55ec6 feat(csv-templates): Introduce CSV template analysis and validation features
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 15s
- Added a new endpoint for analyzing uploaded CSV files, providing suggestions for field mappings and type conversions.
- Implemented validation for required field targets to ensure all mandatory fields are mapped correctly.
- Enhanced the admin CSV templates interface with new routes and navigation options in the frontend.
- Updated API utility functions to support the new CSV analysis functionality.
- Improved error handling for CSV uploads, including file size and row count checks.
2026-04-10 06:39:41 +02:00
338163ac0b feat(csv-parser): Enhance CSV parsing with header normalization and flexible date handling
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 17s
- Added a new function to strip header keys of unwanted characters, improving CSV import consistency.
- Updated CSV row iteration to utilize the new header normalization function, ensuring cleaner data processing.
- Enhanced date parsing capabilities to support flexible formats, accommodating various date representations in CSV files.
- Introduced additional tests to validate the new header normalization and date parsing functionalities.
2026-04-10 06:23:46 +02:00
5e5f3b4e5a feat(csv-import): Update CSV import functionality and enhance analysis features
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 17s
- Bumped version of csv_import to 0.3.0, reflecting new analysis capabilities.
- Modified analyze_csv endpoint to allow optional module filtering, improving flexibility in template selection.
- Enhanced the import process to support both system and user-defined templates, ensuring backward compatibility.
- Updated frontend to streamline mapping choices and improve user experience during CSV analysis and import.
- Added detailed error handling and user feedback for import operations.
2026-04-10 06:15:21 +02:00
7e9da46fe5 feat(csv-import): Add Universal CSV Import page and navigation tile
All checks were successful
Deploy Development / deploy (push) Successful in 57s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
- Introduced a new route for the Universal CSV Import page in App.jsx.
- Added a corresponding navigation tile in captureNav.js for easy access to the CSV import functionality.
2026-04-10 06:10:06 +02:00
66979f3f51 feat(api): Rename importCsv to importUniversalCsv for clarity and documentation
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 15s
- Updated the function name from importCsv to importUniversalCsv to better reflect its purpose.
- Added documentation comment to clarify the parameters used in the universal CSV import process.
2026-04-10 06:05:19 +02:00
851018b3b9 feat(csv_import): Enhance CSV import functionality with new endpoint and parsing improvements
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
- Updated version for csv_import to 0.2.0, reflecting new features.
- Implemented a new POST endpoint for universal CSV import, supporting nutrition, weight, and blood pressure modules.
- Added CSV parsing function to yield rows as dictionaries for easier data handling.
- Enhanced error handling and logging for import operations.
- Introduced tests for the new CSV parsing functionality to ensure reliability.
2026-04-10 06:03:21 +02:00
36417bfdf3 refactor: Rename csv_import to data_import and update foreign key references
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 17s
- Changed feature ID from 'csv_import' to 'data_import' in the features table.
- Updated foreign key references in tier_limits, user_feature_restrictions, user_feature_usage, and widget_feature_requirements.
- Removed the old 'csv_import' feature entry after ensuring all references are updated.
- Simplified the migration process by using an INSERT with ON CONFLICT for the new feature entry.
2026-04-09 21:42:11 +02:00
4a771f6a83 feat(csv-parser): Implement CSV import functionality with mapping and type conversion
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 15s
- Added permissions for editing and deleting CSV field mappings.
- Created type converter for CSV cells to handle various data types.
- Implemented database migrations for CSV field mappings and import logs.
- Seeded initial system templates for nutrition and activity data imports.
- Developed admin endpoints for managing system CSV templates.
- Introduced user endpoints for CSV import analysis and mapping retrieval.
- Added tests for core CSV parser functionalities, including delimiter detection and value conversion.
2026-04-09 21:37:19 +02:00
73963e7140 fix: ImportError - normalize_signal_value does not exist
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Root Cause:
- Tried to import normalize_signal_value from normalization_engine
- Function does not exist (only normalize_decision_signal)
- Caused 500 Internal Server Error on workflow execution

Backend workflow_executor.py:
- Changed import: normalize_signal_value → normalize_decision_signal
- normalize_decision_signal returns NormalizedSignal (not dict)
- Use returned object directly (no .get() calls)
- Simplified logic

Fix:
```python
# BEFORE (broken):
normalized = normalize_signal_value(...)
normalized_signals.append(NormalizedSignal(..., normalized.get('status')))

# AFTER (working):
normalized_signal = normalize_decision_signal(...)
normalized_signals.append(normalized_signal)
```

Issue: 500 Internal Server Error on workflow execution
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Import Fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 21:17:34 +02:00
de5b8cbf15 fix: CRITICAL - Use question ID (not type) for LLM communication
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
ROOT ARCHITECTURAL CHANGE:
Multiple questions with same type are now supported!

Problem:
- question_augmenter used q.type as LLM key
- If two questions had type="unsicherheit":
  - LLM saw duplicate keys: "- unsicherheit: [ja/nein]"
  - Could only answer one
  - Signals were ambiguous

Solution:
- Use question.id as LLM key (unique by design)
- Keep type for normalization logic
- Map id → type internally

Backend question_augmenter.py:
- format_question_list() now uses q.id as key
- Format: "- **q21**: [ja/nein]  # Question text"
- Question text as comment for LLM context

Backend workflow_executor.py:
- Removed type→id mapping (no longer needed)
- decision_signals now keyed by id (from LLM)
- Build id→type catalog for normalization
- NormalizedSignal.question_type stores id (not type!)
- End Node template: signal_{id} directly available

Flow:
1. Questions sent to LLM: "- q21: [ja/nein]  # Ist Protein unsicher?"
2. LLM answers: "- q21: nein"
3. Normalization: id→type lookup for spectrum/rules
4. Template: {{ node_4.signal_q21 }} = "nein"

Example (TWO unsicherheit questions):
Questions:
- q21: type=unsicherheit, question="Ist Protein unsicher?"
- q22: type=unsicherheit, question="Ist Energie unsicher?"

LLM Prompt:
```
## Entscheidungsfragen
- **q21**: [ja/nein]  # Ist Protein unsicher?
- **q22**: [ja/nein]  # Ist Energie unsicher?
```

LLM Response:
```
- q21: nein
- q22: ja
```

Template:
```
{{ node_4.signal_q21 }} → "nein"
{{ node_4.signal_q22 }} → "ja"
```

BREAKING CHANGE:
- Old workflows with decision_signals keyed by type will break
- Need to re-execute workflows after update

Issue: Cannot have multiple questions with same type
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - ARCHITECTURAL FIX

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 21:13:50 +02:00
29a3dbceb5 fix: Simplified signal→ID mapping (direct lookup)
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 15s
Root Cause:
- Previous index-based mapping assumed signals come in same order as questions
- But LLM response order can differ from question configuration order
- Led to signal values being assigned to wrong question IDs

Old Logic (BUGGY):
1. Build question_type → [list of IDs]
2. Track index per type
3. Get Nth ID from list
→ Assumes LLM answers in question definition order 

New Logic (CORRECT):
1. Build question_type → question_id (direct mapping)
2. For each signal: lookup type → get ID
→ Order-independent 

Backend workflow_executor.py:
- Removed index tracking (type_counts)
- Direct lookup: question_type_to_id[signal.question_type]
- Added ERROR log if duplicate question types found
- Added INFO log for each mapped signal (debugging)

Important:
- Each question MUST have a UNIQUE type
- If two questions share same type: ERROR logged
- System designed for unique types (LLM can't answer duplicates)

Example Debug Output:
```
Mapped signal: protein_ausreichend → signal_q21 = 'nein'
Mapped signal: kohlenhydrate_strategie → signal_q1775... = 'von Proteinen'
```

Issue: Signal values assigned to wrong question IDs
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Signal Mapping Fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 21:09:17 +02:00
3b4902dc11 fix: CRITICAL - Use question ID in placeholders, not type
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 15s
Root Cause:
- Multiple questions with same type (e.g. "unsicherheit") created duplicate placeholders
- {{ node_4.signal_unsicherheit }} could refer to q21 OR q22
- Later signal overwrote earlier one in template context

Solution:
- Placeholders now use question ID: {{ node_4.signal_q21 }}
- Unique even with multiple questions of same type

Frontend PlaceholderPicker.jsx:
- Changed placeholder: signal_${questionType} → signal_${questionId}
- Changed placeholder: question_${questionType} → question_${questionId}
- Description shows both: "q21 (unsicherheit): Question text"

Backend workflow_executor.py:
- Build question_type → question_id mapping from graph
- Map normalized_signals (by type) to question IDs
- Handles duplicate types with index tracking
- Creates signal_${id} and question_${id} in template context

Example:
Questions configured:
- q21: type="unsicherheit", question="Ist Protein unsicher?"
- q22: type="unsicherheit", question="Ist Energie unsicher?"

Placeholders generated:
- {{ node_4.signal_q21 }} → "nein"
- {{ node_4.signal_q22 }} → "ja"
- {{ node_4.question_q21 }} → "Ist Protein unsicher?"
- {{ node_4.question_q22 }} → "Ist Energie unsicher?"

Issue: Duplicate question types cause placeholder conflicts
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - CRITICAL FIX

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 21:01:24 +02:00
f9c244bf48 improve: Show question ID in placeholder descriptions
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 15s
Frontend PlaceholderPicker.jsx:
- Placeholder descriptions now include question ID (q.id)
- Format: "NodeLabel (q21) - Signal type: Question text"
- Makes it easier to identify which question a placeholder belongs to

Example:
Before: "Analysis 4 - Signal: Wie ist die Kalorienbilanz?"
After:  "Analysis 4 (q21) - Signal kalorienbilanz: Wie ist die Kalorienbilanz?"

Shows:
- Node label: "Analysis 4"
- Question ID: "(q21)" ← User-assigned ID
- Question type: "kalorienbilanz" ← Used in placeholder
- Question text: "Wie ist..."

Placeholder stays: {{ node_4.signal_kalorienbilanz }}
But description shows q21 for better identification

Version: 0.9p (workflow module)
Part 3: End Node Template Engine - UX Improvement

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 20:54:43 +02:00
3e93dbbc89 fix: Placeholder field name mismatch + debug logging
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Root Cause:
- PlaceholderPicker used q.id for signal placeholders
- Backend template context used question_type
- Placeholders never matched → empty values

Frontend PlaceholderPicker.jsx:
- Changed signal_${q.id} → signal_${q.type} (matches backend)
- Added question_${q.type} placeholders (question texts)
- New category: "Workflow - Questions"

Backend workflow_executor.py:
- Added extensive debug logging for template context
- Logs all signal_* and question_* keys + values
- Helps diagnose template rendering issues

Example:
- Question configured with type="kalorienbilanz"
- Frontend now shows: {{ node_4.signal_kalorienbilanz }}
- Frontend now shows: {{ node_4.question_kalorienbilanz }}
- Backend creates: template_context['node_4']['signal_kalorienbilanz']
- Should match and render correctly

Issue: Signal placeholders show empty values
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Field Name Fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 20:49:45 +02:00
76b4b36617 feat: End Node template placeholders + clean output display
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Three major improvements for workflow templates:

1. **Normalized Signal Placeholders:**
   - Signals now available as {{ node_4.signal_kalorienbilanz }}
   - Uses normalized_value (not raw decision_signals)
   - Enables structured decision-based outputs

2. **Question Text Placeholders:**
   - Question texts available as {{ node_4.question_kalorienbilanz }}
   - Extracted from workflow graph (question_augmentations)
   - Allows displaying questions alongside answers

3. **Clean End Node Output:**
   - End Node output no longer duplicated with "## node_4" headers
   - aggregate_results() detects End Nodes via graph.nodes
   - Only shows final template-rendered output
   - Backward compatible: Falls back to combined_analysis if no End Node

Backend workflow_executor.py:
- execute_end_node(): Added normalized signals to template context
- execute_end_node(): Added question texts to template context
- execute_workflow(): Added graph to context for End Node access
- aggregate_results(): Signature change to accept graph
- aggregate_results(): Detects End Nodes and uses only their output

Frontend WorkflowResultViewer.jsx:
- Now uses aggregated.analysis_core (primary output)
- Removed fallback to combined_analysis (was showing duplicates)

Example Template:
```jinja2
**Frage:** {{ node_4.question_kalorienbilanz }}
**Antwort:** {{ node_4.signal_kalorienbilanz }}

---
{{ node_4.analysis_core }}
```

Issue: Signal placeholders empty, question texts unavailable, duplicate output
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Complete

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 20:45:08 +02:00
9c8859b1ae fix: React error #31 - Cannot render signal objects directly
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 15s
Root Cause:
- WorkflowResultViewer tried to render NormalizedSignal objects directly
- React Error #31: "Objects are not valid as a React child"
- Caused white screen crash after workflow execution

Frontend WorkflowResultViewer.jsx:
- Fixed signal rendering in "All Signals" section
- Now displays: question_type: normalized_value (status)
- Proper formatting for signal objects

Before:
  • {signal}   renders [object Object]

After:
  • protein_intake: optimal (valid) 

Impact:
- Workflow execution no longer crashes the UI
- Signals are properly displayed
- Users can see normalized decision signals

Issue: White screen after workflow execution
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - UI Fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 18:38:09 +02:00
856a82ec1d fix: Frontend-Backend field name mismatch for workflow questions
All checks were successful
Deploy Development / deploy (push) Successful in 57s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Root Cause:
- Frontend serialized as "questions"
- Backend expected "question_augmentations"
- Analysis Nodes WITH questions configured sent empty array to backend
- Questions were never added to LLM prompt

Frontend workflowSerializer.js:
- Serialization: questions → question_augmentations (Backend field name)
- Deserialization: question_augmentations → questions (Frontend data object)
- Backward compatible: Falls back to "questions" for old workflows

Backend workflow_executor.py:
- Removed incorrect load_prompt_questions() function (was a misunderstanding)
- Back to original logic: Only use node.question_augmentations
- Simplified normalization logging

Impact:
- Analysis Node questions are now correctly sent to backend
- Questions augment the base prompt as intended
- LLM receives structured questions
- Decision signals are generated and accessible as placeholders

Example:
- Node configures question with id="q21"
- Signal becomes accessible as {{ node_2.signal_q21 }}
- Can be used in Logic Nodes and End Node templates

Issue: Workflow questions not sent to LLM (field name mismatch)
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Critical Fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 18:28:54 +02:00
b17bec3340 fix: Load base prompt questions in workflow (Hybrid Model)
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Backend workflow_executor.py:
- New function: load_prompt_questions() loads questions from base prompt
- execute_node() now implements Hybrid Model correctly:
  * IF node has question_augmentations → use those (override)
  * ELSE load questions from referenced base prompt (fallback)
- Normalization now uses `questions` variable (not node.question_augmentations)
- This fixes base prompts having questions that were ignored in workflows

Root Cause:
- Phase 1 Hybrid Model was incomplete
- Node-specific questions worked, but base prompt questions were ignored
- augment_prompt_with_questions() was only called when node.question_augmentations existed

Impact:
- Analysis Nodes WITHOUT custom questions now use base prompt questions
- LLM receives proper question augmentation
- Decision signals are generated and normalized correctly

Issue: Workflow questions not sent to LLM
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Critical Fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 18:18:08 +02:00
857c55aeb8 fix: Workflow placeholder resolution + complete catalog display
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
Backend workflow_executor.py:
- load_prompt_template() now uses modern resolve_placeholders() from prompt_executor
- Calls get_placeholder_example_values() to populate ALL registered placeholders
- Passes catalog for |d modifier support
- Fixes issue where basis prompts had empty/null placeholder values in workflows

Backend placeholder_resolver.py:
- get_placeholder_catalog() now includes ALL placeholders from PLACEHOLDER_MAP
- Uncategorized placeholders added to "Sonstiges" category
- Fixes discrepancy: 111 total placeholders but only ~30 shown in picker

Root Cause:
- Workflow used old resolve_placeholders() (only PLACEHOLDER_MAP, no variables)
- Isolated execution used modern resolve_placeholders() (full variables dict)
- Catalog excluded non-registry placeholders from PLACEHOLDER_MAP

Impact:
- All placeholders now resolve correctly in workflow execution
- PlaceholderPicker shows all 111+ placeholders (not just registry ones)

Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Bug Fixes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 18:10:04 +02:00
1a9fb99411 fix: FastAPI routing conflict for /placeholders endpoint
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 15s
Backend:
- Moved /placeholders endpoint BEFORE /{prompt_id} catch-all
- Prevents "placeholders" being parsed as UUID parameter
- Fixes 500 Internal Server Error preventing placeholder loading

Frontend:
- PlaceholderPicker can now load ~120+ system placeholders

Root Cause:
- FastAPI matches routes in order
- Generic /{prompt_id} was catching /placeholders first
- psycopg2 error: invalid input syntax for type uuid: "placeholders"

Version: 0.9p (workflow module)
Part 3: End Node Template Engine

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 16:19:46 +02:00
d2eaab277e debug: Add extensive logging to PlaceholderPicker
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 15s
**Issue Investigation:**
User reports:
1. Backend placeholders (120+) not appearing
2. Node names showing as 'node_2' instead of 'Körper-Analyse (node_2)'

**Debug Changes:**
- Console logging for backend API call
- Log catalog structure and keys
- Log flattened placeholders count
- Error state displayed in UI (not just console)
- Log each node extraction with label/data
- Safe navigation operator for node.data?.label

**Expected Console Output:**
🔄 Loading placeholders from backend...
 Catalog received: {...}
📊 Catalog keys: ['Profil', 'Körper', ...]
📁 Category "Profil": 10 items
 Loaded 120 system placeholders
🔍 Extracting workflow placeholders from nodes: [...]
📦 Node node_2: {label: 'Körper-Analyse', ...}
   Adding placeholder: {{ node_2.analysis_core }} → "Körper-Analyse (node_2) - Hauptausgabe"

Next: Check browser console for error messages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 16:12:42 +02:00
b779c2f2a8 fix: Part 3 - PlaceholderPicker enhancements (4 critical fixes)
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 15s
**User Feedback Issues Fixed:**

1. **Registrierte Platzhalter fehlten** 
   - PlaceholderPicker lädt jetzt ~120+ Platzhalter vom Backend
   - Endpoint: GET /api/prompts/placeholders (get_placeholder_catalog)
   - Kategorisiert nach: Profil, Körper, Ernährung, Training, etc.
   - Icons pro Kategorie (👤 💪 🍎 🏃 😴 ❤️ 🎯)

2. **Node-Namen nicht sichtbar** 
   - Vorher: "{{ node_2.analysis_core }}"
   - Jetzt: "Körper-Analyse (node_2) - Hauptausgabe"
   - Node-Label wird in Beschreibung angezeigt

3. **Cursor-Position ignoriert** 
   - Platzhalter werden jetzt an Cursor-Position eingefügt
   - textareaRef von WorkflowEditorPage an EndNodeConfig übergeben
   - textarea.selectionStart/End für exakte Position
   - Cursor wird nach Einfügen an korrekte Stelle gesetzt
   - Focus zurück auf Textarea

4. **Fragen-Kontext unklar** ⚠️
   - Signal-Platzhalter zeigen jetzt Frage-Text
   - Format: "Körper-Analyse - Signal: Ist Gewichtstrend positiv?"
   - Frage wird auf 50 Zeichen gekürzt wenn zu lang

**Komponenten-Änderungen:**

PlaceholderPicker.jsx:
- useEffect zum Laden von Backend-Platzhaltern
- Gruppierung nach Kategorien (System + Workflow)
- System-Platzhalter: ~120+ aus placeholder_registrations
- Workflow-Platzhalter: Node Outputs + Signals
- Bessere Beschreibungen mit Node-Label
- Stats-Anzeige: "X Platzhalter gefunden (Y Workflow, Z System)"
- Loading State während Backend-Call

EndNodeConfig.jsx:
- useRef für Textarea
- textareaRef Prop (optional, Fallback zu lokalem ref)
- ref an Textarea gebunden

WorkflowEditorPage.jsx:
- useRef Hook importiert
- endNodeTextareaRef erstellt
- handlePlaceholderSelect umgebaut:
  - Liest selectionStart vom Textarea
  - Fügt an Cursor-Position ein (before + placeholder + after)
  - Setzt Cursor nach Platzhalter
  - Fokussiert Textarea wieder
  - Fallback: Am Ende einfügen wenn ref nicht verfügbar
- textareaRef an EndNodeConfig übergeben

**UX-Verbesserungen:**
- Suchfunktion durchsucht jetzt auch Kategorie-Namen
- Sticky Category Headers beim Scrollen
- Example-Werte in Beschreibung (wenn vorhanden)
- AutoFocus auf Suchfeld beim Öffnen
- Gruppiert: Workflow-Outputs immer oben, dann System-Platzhalter

**Testing Required:**
- [ ] End Node öffnen → Template Mode → Platzhalter-Button klicken
- [ ] Prüfen: ~120+ Platzhalter sichtbar (nicht nur 2-3 Workflow-Outputs)
- [ ] Prüfen: Node-Namen in Beschreibungen ("Körper-Analyse (node_2)")
- [ ] Cursor an beliebige Stelle setzen → Platzhalter einfügen
- [ ] Prüfen: Einfügen an Cursor-Position (nicht am Ende)

Part 3 Bugfixes - User Feedback Complete

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 16:04:39 +02:00
228010a6d3 feat: Part 3 - End Node Template Editor
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
**Neue Features:**
- End Node Output Mode: AUTO vs. TEMPLATE
- Jinja2 Template Editor mit Syntax-Beispiel
- Placeholder Picker Modal (dynamische Node-Liste)
- Template Serialisierung/Deserialisierung

**Komponenten (NEU):**
1. EndNodeConfig.jsx (~150 Zeilen)
   - Output Mode Toggle (AUTO/TEMPLATE)
   - Template Textarea (monospace, 12 Zeilen)
   - Placeholder-Button (öffnet Picker)
   - Help-Text mit Beispiel-Syntax
   - Auto-Insert Default Template beim Wechsel zu TEMPLATE

2. PlaceholderPicker.jsx (~260 Zeilen)
   - Modal mit Suchfunktion
   - Dynamische Placeholder-Liste aus Workflow-Nodes
   - Kategorien: Global, Node Outputs, Signals
   - Click-to-Insert (schließt Modal automatisch)
   - Icons pro Node-Typ (🚀🤖🔀🏁)

**Integration:**
- WorkflowEditorPage.jsx
  - EndNodeConfig im Config Panel (wenn type='end')
  - PlaceholderPicker State + Modal
  - handlePlaceholderSelect (fügt in Template ein)

**Serialisierung:**
- workflowSerializer.js
  - Serialize: output_mode + template für End Nodes
  - Deserialize: output_mode + template laden
  - Fallback: auto Mode wenn nicht gesetzt

**Backend Status:**
-  Backend bereits fertig (execute_end_node() in workflow_executor.py)
-  Beide Modi (AUTO/TEMPLATE) funktionieren
-  Jinja2 Template Rendering implementiert

**Part 3 Status:** Frontend Complete
-  End Node Config UI
-  Template Editor
-  Placeholder Picker
- ⏸️ Testing ausstehend

**Nächster Schritt:**
Browser-Test auf dev.mitai.jinkendo.de

Version: v0.9p
Date: 2026-04-09

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 15:52:19 +02:00
2994df54ad fix: Complete prompt_id → prompt_slug migration
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 15s
**Remaining Issues Found:**
1. Validierung prüfte noch prompt_id → Speichern blockiert
2. AnalysisNode zeigte noch prompt_id → "Kein Prompt" obwohl gesetzt
3. Deserializer hatte keinen Fallback für alte Workflows

**Fixes:**
- workflowValidation.js: Line 91
  - if (!node.data.prompt_slug) statt prompt_id

- AnalysisNode.jsx: Line 15
  - Verwendet jetzt data.prompt_slug
  - Fallback: "Prompt: ${slug}" statt "Prompt #${id}"
  - Kommentar aktualisiert (data.prompt_slug statt prompt_id)

- workflowSerializer.js: Line 81
  - Fallback: node.prompt_slug || node.prompt_id || null
  - Backwards-compatible für alte Workflows

**Testing:**
1. Neuen Workflow erstellen
2. Analysis Node hinzufügen
3. Prompt auswählen
4. Node sollte Prompt-Namen zeigen
5. Beim Öffnen: Dropdown sollte Wert anzeigen
6. Speichern sollte funktionieren (keine Validierungsfehler)
7. Execute sollte funktionieren (kein "Prompt not found")

Part 2 Complete Bugfix - Workflow Execution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 15:39:11 +02:00
af7c5ca55a fix: Workflow execute - prompt_id → prompt_slug
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 22s
**Problem:**
Execute-Button funktionierte, aber Ausführung scheiterte mit
"Prompt not found: none" im Analysis Node.

**Root Cause:**
Mismatch zwischen Frontend (speicherte prompt_id/UUID) und
Backend (erwartete prompt_slug/String).

Backend WorkflowNode Model (workflow_models.py:193):
  prompt_slug: Optional[str] = Field(...)

**Änderungen:**
- WorkflowEditorPage.jsx: Dropdown auf slug umgestellt
  - value: prompt_slug statt prompt_id
  - onChange: selectedPrompt.slug statt .id
  - handleNodeUpdate: prompt_slug speichern

- workflowSerializer.js: Serialization/Deserialization
  - Serialize: prompt_slug statt prompt_id
  - Deserialize: node.prompt_slug lesen

**Testing:**
- Workflow mit Analysis Node neu erstellen
- Execute-Button sollte jetzt funktionieren

Part 2 Bugfix - Workflow Execution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 13:59:54 +02:00
46d39bad38 feat: Part 2 - Workflow Frontend Execute Integration
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 18s
Frontend-Komponenten für Workflow-Ausführung implementiert:

**Neue Komponenten:**
- WorkflowExecutePanel.jsx (~140 Zeilen)
  - Execute Button mit Loading State
  - Debug Mode Toggle
  - Error Handling Display

- WorkflowResultViewer.jsx (~300 Zeilen)
  - Fixed Panel (rechts, 600px)
  - Final Output mit Copy-Button
  - Node States (collapsible, Debug Mode)
  - All Signals Display
  - Error Display

**Integration:**
- WorkflowEditorPage.jsx
  - ExecutePanel in Toolbar
  - executionResult State
  - handleExecutionComplete Handler
  - Slug wird beim Erstellen gespeichert

**API:**
- api.executeWorkflow(slug, variables, debug, save)
  - Nutzt /prompts/execute Endpoint
  - Debug Mode Default: true

**Part 2 Status:** ~80% abgeschlossen
-  Execute Button
-  Result Viewer
- ⏸️ Execution History (später entscheiden)

Version: v0.9o
Date: 2026-04-09

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 12:58:03 +02:00
01e328b6b4 docs(issue-53): kanonische Pfade Data Layer / Doku-Checkliste
Made-with: Cursor
2026-04-08 13:02:14 +02:00
7940dc7560 docs: Struktur .claude/docs versionieren, working/, Gitea-Index, Regeln
- .gitignore: .claude/docs, rules, commands tracken; settings.local weiter ignorieren
- DOCUMENTATION.md: verbindliche Ablage functional/technical/working/issues
- .claude/README.md: Agent-Einstieg; GITEA_ISSUES_INDEX aus MCP (Stand 2026-04-08)
- Arbeitspapiere von docs/ nach .claude/docs/working/ verschoben
- docs/MEMBERSHIP_SYSTEM.md als Stub; kanonisch technical/MEMBERSHIP_SYSTEM.md
- CLAUDE.md Pflichtlektüre und Links angepasst; docs/README.md vereinfacht

Made-with: Cursor
2026-04-08 13:01:49 +02:00
24daeeb83c feat: Implement widget-feature assignment management in admin 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 15s
- Added new API endpoints for listing and updating widget-feature assignments, allowing for custom feature requirements.
- Introduced a new admin page for managing widget-feature assignments, enhancing the admin interface.
- Updated navigation to include a link to the new widget-feature assignments page.
- Refactored widget access logic to support AND-based feature requirements for widgets.
- Bumped app_dashboard version to 1.11.0 to reflect these changes and improvements.
2026-04-08 12:26:28 +02:00
09439ad1a5 Merge pull request 'Indvidual Dashboard V0.9' (#67) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 1m0s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Reviewed-on: #67
2026-04-08 10:56:02 +02:00
365ce49c6a feat: Introduce admin dashboard product standard management
All checks were successful
Deploy Development / deploy (push) Successful in 57s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
- Added new API endpoints for managing the product dashboard standard, including retrieval, update, and deletion functionalities.
- Enhanced the DashboardConfigurePage to support admin mode for configuring the product dashboard standard.
- Updated the admin navigation to include a link for the product dashboard standard configuration.
- Refactored the dashboard layout logic to utilize the new product standard management features.
- Bumped app_dashboard version to 1.10.0 to reflect these enhancements and changes.
2026-04-08 10:32:18 +02:00
ff95ef63c7 feat: Enhance DashboardConfigurePage with drag-and-drop functionality and improved widget search
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 15s
- Added drag-and-drop support for widget reordering in the dashboard configuration.
- Introduced a new search input for filtering widgets, enhancing user experience.
- Updated layout editor with a new function to move widgets between indices.
- Improved responsiveness by implementing viewport detection for drag-and-drop features.
- Refactored state management for better handling of widget visibility and search functionality.
2026-04-08 07:58:52 +02:00
e4e2f23d7f feat: Enhance dashboard layout and widget configuration
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 17s
- Updated dashboard layout schema to introduce separate default layouts for product and lab dashboards.
- Added new functions for managing product and lab default layouts, improving user customization options.
- Updated app_dashboard version to 1.9.0 to reflect the introduction of product vs lab layout defaults and new API fields for dashboard configuration.
- Enhanced tests to validate new layout functionalities and ensure proper widget visibility based on user settings.
2026-04-08 07:41:16 +02:00
9bc0cf70da feat: Update widget catalog and enhance dashboard layout features
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 15s
- Added new "Dashboard-Lab-Widgets" entry to the documentation for better guidance on widget configuration.
- Updated the app_dashboard version to 1.8.0 to reflect the introduction of widget catalog features and layout entitlements.
- Enhanced widget catalog entries to include optional feature requirements for better visibility and access control.
- Improved the DashboardLabPage to manage widget visibility based on feature entitlements, ensuring a more tailored user experience.
2026-04-08 07:21:49 +02:00
bc91396885 feat: Add new widgets and enhance configuration validation
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 14s
- Introduced "nutrition_detail_charts", "recovery_charts_panel", and "progress_photos" widgets to the dashboard.
- Updated widget configuration validation to support new widgets, including chart days for nutrition and recovery charts.
- Enhanced the widget catalog and dashboard layout to include the new features.
- Bumped app_dashboard version to 1.7.0 to reflect these additions and improvements.
2026-04-07 20:58:44 +02:00
7f833b2cb1 feat: Introduce quick capture widget configuration and validation
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 16s
- Added support for the "quick_capture" widget, allowing users to configure visibility for weight and baseline vitals (resting HR, HRV, VO₂max).
- Implemented validation logic to ensure correct configuration input and prevent errors.
- Updated the widget catalog and dashboard layout to reflect the new quick capture features.
- Removed the "training_type_distribution" widget from the catalog as part of the refactor.
- Bumped app_dashboard version to 1.6.2 to incorporate these enhancements.
2026-04-07 18:02:18 +02:00
3d498d03c1 feat: Enhance dashboard widget configuration and introduce new widgets
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 16s
- Updated the dashboard layout schema to include new widgets: DashboardGreeting, QuickWeightToday, BodyStatStrip, StatusPills, ProfileGoalsProgress, TrendKcalWeight, NutritionActivitySummary, RecoverySleepRest, and TrainingTypeDistribution.
- Improved widget configuration validation to support new features, including chart days for trend and distribution widgets.
- Refactored the default lab layout to align with the updated widget catalog and ensure proper default activation.
- Bumped app_dashboard version to 1.6.0 to reflect the addition of new widgets and configuration enhancements.
2026-04-07 14:19:45 +02:00
c0c512e942 feat: Revamp KPI board configuration and validation
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 15s
- Enhanced the KPI board widget to support tile configuration, allowing users to select and order tiles.
- Updated validation logic to ensure proper handling of tile IDs and configuration fields.
- Removed legacy chart_days support, transitioning to a fixed analysis window for KPI metrics.
- Improved the DashboardLabPage to integrate the new KpiBoardConfigEditor for managing tile selections.
- Bumped app_dashboard version to 1.5.0 to reflect these significant changes.
2026-04-07 12:46:18 +02:00
096d896166 fix: Correct syntax error in PilotKpiBoard component
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
- Fixed a syntax error in the recentNutr filter function by adding a closing parenthesis.
- Ensured proper calculation of kcal based on recent nutrition data.
2026-04-07 12:39:41 +02:00
de99856a28 feat: Extend widget configuration for KPI board and enhance validation
Some checks failed
Deploy Development / deploy (push) Failing after 44s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
- Added support for the "kpi_board" widget in the dashboard configuration, allowing for chart_days validation.
- Updated the widget catalog description to reflect the new configuration options for KPI tiles.
- Enhanced the DashboardLabPage to manage chart_days input for the KPI board, improving user experience.
- Introduced normalization functions for KPI kcal window days to maintain consistent behavior.
- Bumped app_dashboard version to 1.4.0 to reflect these enhancements.
2026-04-07 12:37:04 +02:00
97f9aa696e feat: Enhance activity API feat: Enhance sleep data import functionality with support for multiple CSV formats and improved data parsing
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 15s
- Added functions to handle Apple Health sleep data in both segment and summary formats.
- Implemented robust error handling for date parsing and data conversion.
- Updated documentation to reflect new CSV format support and data aggregation logic.
- Bumped version in version.py to reflect the changes in the activity module.
2026-04-07 12:28:59 +02:00
b617212145 feat: Extend widget configuration for activity overview and improve validation
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 16s
- Added support for the "activity_overview" widget in the dashboard configuration, allowing for chart_days validation.
- Refactored validation logic to streamline error handling for both "body_overview" and "activity_overview" widgets.
- Updated the widget catalog description to reflect the new configuration options.
- Enhanced the DashboardLabPage to manage chart_days input for both widgets, improving user experience.
- Bumped app_dashboard version to 1.3.0 to reflect these enhancements.
2026-04-07 12:20:23 +02:00
4493b140bd feat: Improve body chart days configuration in DashboardLabPage
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 15s
- Introduced a draft state for body chart days input to allow for temporary edits without immediate clamping.
- Updated input handling to support numeric input mode and improved accessibility with aria-label.
- Enhanced save and reset functionalities to manage the new draft state effectively.
- Refactored layout normalization to accommodate changes in body chart days configuration.
2026-04-07 12:05:05 +02:00
87c4cbc4b4 feat: Enhance Dashboard widget configuration and layout management
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 14s
- Added validation for widget configuration in the DashboardWidgetEntry model to ensure proper data structure.
- Updated the DashboardLayoutPayload to include widget configuration in the serialized output.
- Improved the PilotBodySection and DashboardLabPage components to support dynamic chart days configuration for the body overview widget.
- Refactored layout editor functions to normalize widget configurations for better handling.
- Bumped app_dashboard version to 1.2.0 to reflect the new features and improvements.
2026-04-07 11:58:07 +02:00
f6c5f96768 feat: Enhance Dashboard-Lab with widget catalog integration and layout updates
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 14s
- Integrated a new API endpoint for fetching the widget catalog in the Dashboard-Lab.
- Updated the dashboard layout schema to utilize the widget catalog for dynamic widget management.
- Refactored DashboardLabPage and PilotVizPage to leverage the new widget rendering system.
- Removed deprecated widget metadata from the frontend, streamlining the widget management process.
- Bumped app_dashboard version to 1.1.0 to reflect the new features and improvements.
2026-04-07 11:47:16 +02:00
e5f6e6c10d feat: Integrate Dashboard-Lab layout and enhance settings navigation
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 15s
- Added new routes and API endpoints for the Dashboard-Lab layout in the app.
- Updated main.py to include the app_dashboard router for backend integration.
- Enhanced App.jsx to include a route for the DashboardLabPage.
- Modified SettingsPage to add a link to the new Dashboard-Lab layout, improving user access to dashboard features.
- Updated version.py to reflect the new app_dashboard module version.
2026-04-07 11:38:35 +02:00
c0cb995a7b feat: Remove deprecated pilot widgets and layout management
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 23s
- Deleted unused components: GoalsSnapshotWidget, ReferenceValuesSummaryWidget, WeightKpiWidget, and PilotVizAdminCard.
- Removed associated layout storage and widget registry logic to streamline the pilot visualization module.
- Updated PilotVizPage to integrate new components for improved user experience and functionality.
2026-04-07 11:07:33 +02:00
8c8f595385 feat: Refactor PilotVizPage and widget registry for improved layout and rendering
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
- Replaced the previous widget retrieval method with a new layout-based approach in PilotVizPage.
- Introduced a PilotVizAdminCard for layout configuration and management.
- Updated widget definitions in the registry to include new components and default order.
- Enhanced user feedback for widget visibility with a message when no widgets are active.
2026-04-07 10:21:11 +02:00
932bceb1e1 feat: Update reference values and introduce pilot visualization module
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 23s
- Bumped version of reference_values module to 1.3.0.
- Added new imports and functionality for reference values in the backend, enhancing data retrieval.
- Introduced a new PilotVizPage in the frontend for visualizing data, linked from the SettingsPage for easy access.
- Updated routing in App.jsx to include the new pilot visualization route.
2026-04-07 10:15:13 +02:00
3e916c082c feat: Add profile reference values summary endpoint and UI enhancements
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
- Introduced a new API endpoint for fetching a summary of profile reference values, providing the latest and previous entries for each reference type.
- Updated ProfileReferenceValuesPage to display summary tiles with trend indicators for better user insights.
- Enhanced CSS for responsive layout of reference value tiles, improving the overall user experience on different screen sizes.
- Implemented trend calculation logic to visually represent changes between the latest and previous reference values.
2026-04-07 06:30:22 +02:00
c152721fe8 feat: Refactor settings navigation and enhance profile reference values display
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 15s
- Introduced a new SettingsShell layout for improved navigation within the settings section.
- Updated ProfileReferenceValuesPage to display the latest entry with enhanced styling and information.
- Removed the direct link to settings from ProfileReferenceValuesPage for a cleaner UI.
- Adjusted SettingsPage to streamline the layout and focus on essential settings options.
2026-04-07 06:24:47 +02:00
296e79c3b3 feat: Implement reference value types reordering and confidence level sorting
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 14s
- Added a new API endpoint for reordering reference value types based on user-defined order.
- Updated the AdminReferenceValueTypesPage to allow users to reorder types using up/down buttons.
- Introduced a consistent confidence level sorting mechanism across the application.
- Refactored related components to remove unused sort order fields and improve user experience.
2026-04-06 21:40:55 +02:00
45e4e64f15 feat: Enhance reference value types management with validation rules and metadata
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 14s
- Updated the backend to include new fields for validation rules and metadata in reference value types.
- Enhanced the AdminReferenceValueTypesPage to support new validation rules for different data types.
- Improved the ProfileReferenceValuesPage to handle validation and metadata for profile reference values.
- Added API endpoint for fetching reference value metadata enums to support frontend validation.
- Refactored frontend forms to incorporate new fields and validation logic for a better user experience.
2026-04-06 21:25:42 +02:00
f04318f76a - Updated the AdminReferenceValueTypesPage to enhance text alignment and styling for form fields.
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 15s
- Refactored ProfileReferenceValuesPage to apply consistent styling for form elements and improve layout.
- Adjusted button styles for better visual consistency across the forms.
2026-04-06 20:01:23 +02:00
ab616ba044 feat: Introduce admin reference value types management in API and UI
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Added new routes and API endpoints for managing reference value types in the admin section.
- Updated the frontend to include navigation and components for reference value types management.
- Enhanced the backend to support the new reference value types in the data layer and versioning.
2026-04-06 19:51:23 +02:00
f0e6fd04fb feat: Add personal reference values management in settings and API
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 15s
- Introduced new routes and API endpoints for managing personal reference values.
- Updated the SettingsPage to include a section for reference values with navigation to manage them.
- Enhanced the backend to support reference values in the data layer and versioning.
- Added necessary imports and UI components for a seamless user experience.
2026-04-06 19:45:06 +02:00
e7dedd527f feat: Implement focus area usage types management in API and UI
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
- Added endpoints for listing and updating focus area usage types in the backend.
- Enhanced the AdminFocusAreasPage to display and manage allowed usage types for focus areas.
- Introduced a new state for usage types catalog and integrated it into the focus area editing process.
- Updated API utility functions to support new usage types operations.
2026-04-06 07:28:19 +02:00
75736dadec Merge pull request 'feat: Integrate caliper data enrichment and weight loading in API responses' (#64) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 57s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
Reviewed-on: #64
2026-04-06 06:10:39 +02:00
49e9c9c214 feat: Integrate caliper data enrichment and weight loading in API responses
All checks were successful
Deploy Development / deploy (push) Successful in 1m0s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s
- Enhanced the caliper listing and export functionalities to include enriched data from weight logs.
- Updated the upsert and update operations to utilize new composition functions for body composition calculations.
- Refactored the CaliperScreen component to streamline payload construction by removing unnecessary parameters.
2026-04-06 06:08:37 +02:00
8d56c352fc Merge pull request 'Bug Fixes' (#63) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 50s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
Reviewed-on: #63
2026-04-05 17:54:00 +02:00
00437a92ab feat: Enhance sleep module with CSV import functionality and date parsing improvements
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 15s
2026-04-05 17:35:48 +02:00
24f60c0a6d feat: Update documentation for GUI, Admin navigation, and responsive UI integration
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 16s
2026-04-05 12:25:28 +02:00
fdaf4471da feat: Adjust navigation height and padding for improved layout and responsiveness
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
2026-04-05 12:16:24 +02:00
6e952f9277 feat: Enhance navigation and dashboard with goals integration and UI improvements
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 14s
2026-04-05 12:07:11 +02:00
952cb90973 feat: Update deployment scripts to use git fetch and reset for more reliable state management
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 15s
2026-04-05 11:39:15 +02:00
ebea9946a7 Merge pull request 'feat: Add admin access denial alert to Dashboard with timeout handling' (#62) from develop into main
All checks were successful
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Deploy Production / deploy (push) Successful in 55s
Reviewed-on: #62
2026-04-05 11:29:03 +02:00
bd694b30a6 feat: Add admin access denial alert to Dashboard with timeout handling
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
2026-04-05 11:28:33 +02:00
9fb04af7df Merge pull request 'Responsive Gui - partially Workflow' (#61) from develop into main
Some checks failed
Deploy Production / deploy (push) Failing after 1s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Reviewed-on: #61
2026-04-05 11:27:43 +02:00
430a928df6 feat: Update settings page layout with improved field structure and accessibility
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
2026-04-05 11:19:35 +02:00
c63ec5f700 feat: Enhance profile update functionality with email validation and improved error handling
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
2026-04-05 11:14:01 +02:00
b7f2e2adbe feat: Add Admin Group Hub page and update navigation structure for improved admin management
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 14s
2026-04-05 11:05:45 +02:00
bbc59457ac feat: Refactor admin settings and user management
All checks were successful
Deploy Development / deploy (push) Successful in 53s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 14s
- Removed Admin Panel from SettingsPage and adjusted related logic.
- Added EmailSettings component for SMTP configuration and testing.
- Created admin navigation structure in adminNav.js for better organization.
- Implemented AdminShell layout for consistent admin UI.
- Added RequireAdmin component to protect admin routes.
- Developed AdminHomePage for admin dashboard with navigation links.
- Created AdminSystemPage for SMTP settings and placeholder metadata export.
- Implemented AdminUsersPage for user management, including profile creation and editing.
2026-04-05 10:32:43 +02:00
190c0dd7fa feat: Standardize capture page layout to a unified content width across all relevant pages
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
2026-04-05 10:21:06 +02:00
a4376d1cd8 feat: Implement CaptureShell layout with sub-navigation for capture section
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 13s
2026-04-05 10:17:47 +02:00
a639d08037 feat: Update capture page layout for improved responsiveness and organization across multiple screens
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
2026-04-05 10:14:07 +02:00
630a3de88a feat: Refactor analysis navigation to use category-based grouping and update state management
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
2026-04-05 10:06:29 +02:00
6d0e2de66d Gruppierung Analysen
All checks were successful
Deploy Development / deploy (push) Successful in 59s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
2026-04-05 09:04:08 +02:00
1fa0edb3b5 feat: Implement responsive analysis page layout with horizontal navigation for mobile and vertical navigation for desktop
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
2026-04-05 08:52:40 +02:00
ac31c5e014 feat: Implement responsive history page layout with horizontal tabs for mobile and vertical tabs for desktop
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
2026-04-05 08:46:37 +02:00
422a117026 feat: Refactor dashboard layout with new DashboardSection and DashboardTile components for improved responsiveness and organization
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 14s
2026-04-05 08:42:07 +02:00
d51bfd3daa feat: Update dashboard layout to use grid for responsive stat cards
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
2026-04-05 08:12:10 +02:00
c2b2c71ccd feat: Enhance Dashboard layout with responsive greeting and metrics display
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 15s
2026-04-05 08:03:53 +02:00
7e8422cbd7 feat: Implement responsive desktop sidebar navigation and update app structure
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
2026-04-05 07:58:38 +02:00
922c846b03 chore: Remove generated test results file
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
2026-04-05 07:47:00 +02:00
7deca6c64d test: Add unit tests for End Node Template Engine
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
- test_end_node_template.py: Tests for execute_end_node()
- Tests AUTO mode (backward compatible concatenation)
- Tests TEMPLATE mode (Jinja2 rendering, conditionals)
- Tests error handling (missing template, syntax errors)

Note: Tests require Jinja2, run in Docker or CI/CD environment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 07:46:49 +02:00
fac76c28da fix: Handle None workflow_id in success path
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
Also use 'N/A' placeholder in ExecutionResult when workflow_id is None
(when using graph_data directly instead of workflow_definitions).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 07:28:30 +02:00
6016eec250 fix: Add ON CONFLICT to workflow_executions insert
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
Prevents duplicate key violation when save_execution_state is called
multiple times with the same execution_id (e.g., during error handling).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 07:26:10 +02:00
c95b4e185d fix: Edge format normalization and nullable workflow_id
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
Fixes:
1. Edge Format Mismatch:
   - graph_data uses React Flow format (source/target)
   - WorkflowEdge expects backend format (from/to)
   - Added normalization in parse_workflow_graph()

2. UUID Validation Error:
   - workflow_id can be None when using graph_data (Phase 5)
   - save_execution_state now accepts Optional[str]
   - ExecutionResult uses "N/A" placeholder when None

Changes:
- workflow_engine.py: normalize edges before Pydantic validation
- workflow_executor.py: Optional[str] for workflow_id parameter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 07:22:32 +02:00
fe28cce921 fix: Workflow executor graph parsing and error handling
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 14s
Fixes:
- graph_data was incorrectly json.dumps() encoded (should stay as dict)
- workflow_id=None in error handler caused ValidationError
- parse_workflow_graph expects Dict, not str

Changes:
- Use graph_dict directly instead of json.dumps(graph_data)
- Set workflow_id="" when None in error handler

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 07:18:43 +02:00
b888f5d3c8 feat: Phase 4 - End Node Template Engine (v0.9n)
All checks were successful
Deploy Development / deploy (push) Successful in 52s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
Backend:
- workflow_models.py: EndNodeOutputMode enum (AUTO, TEMPLATE)
- workflow_executor.py: execute_end_node() with Jinja2 rendering
- Template Context: {{node_id.analysis_core}}, {{node_id.decision_signals.key}}
- Conditional Rendering: {% if node_id %} for optional paths
- AUTO Mode: Backward compatible (concatenates all analyses)
- TEMPLATE Mode: Custom Jinja2 templates with placeholders

Features:
- Access node results: {{node_id.analysis_core}}
- Access signals: {{node_id.decision_signals.relevanz}}
- Optional paths: {% if node_id %}...{% endif %}
- Default values: {{node_id|default("N/A")}}

Version: 0.9n
Module: workflow 0.6.0
Konzept: konzept_workflow_engine_konsolidated.md (Section 11)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 07:07:49 +02:00
cab5758b0d fix: Save prompt_name in graph_data for readable node display
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 14s
Bug:
- Analysis nodes showed "Prompt #7edc6d6b-6cd5..." in canvas
- After re-selecting prompt, showed readable name "Pipeline: Ernährungs-Analyse"
- After loading workflow, showed UUID again

Root Cause:
- Serializer saved only prompt_id, not prompt_name
- Deserializer expected prompt_name but got null
- AnalysisNode fallback logic: data.prompt_name || `Prompt #{prompt_id}`
- Result: Showed UUID as fallback

Fix:
- workflowSerializer.js line 25: Added prompt_name to serialization
- Now saves both prompt_id AND prompt_name in graph_data
- On load: prompt_name is restored → AnalysisNode shows readable name

Testing:
- Create workflow with analysis node + prompt selection
- Save → Canvas should show "Pipeline: Körper-Analyse" (not UUID)
- Reload → Canvas should still show readable name (not UUID)
2026-04-04 22:50:40 +02:00
d9bcaaaac6 fix: Add missing GET /api/prompts/{id} endpoint
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
Critical Backend Bug:
- Frontend calls api.getPrompt(id) → GET /api/prompts/{uuid}
- Backend had NO endpoint for single prompt retrieval by ID
- Result: 405 Method Not Allowed

Backend Endpoints Before:
✓ GET /api/prompts - List all
✓ POST /api/prompts - Create
✓ PUT /api/prompts/{id} - Update
✗ GET /api/prompts/{id} - MISSING!

Backend Endpoints After:
✓ GET /api/prompts - List all
✓ GET /api/prompts/{id} - Get single (NEW)
✓ POST /api/prompts - Create
✓ PUT /api/prompts/{id} - Update

Implementation:
- Added get_prompt(prompt_id: str) function
- Returns single prompt by UUID
- 404 if not found
- Requires auth (admin or user)

This fixes:
- Workflow loading after save (loadWorkflow calls getPrompt)
- Workflow editing from admin list (Edit button calls getPrompt)
- All 405 Method Not Allowed errors

Root Cause: Backend was incomplete, missing basic CRUD read-by-id endpoint
2026-04-04 22:43:07 +02:00
84c1fa3c1d fix: UUID handling - remove parseInt() for prompt IDs
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 13s
Critical Bug Fixes:
1. Prompt IDs are UUIDs (strings), NOT numbers
2. parseInt(UUID) produces wrong results:
   - parseInt("3b4d7d64-...") = 3 (truncates at first non-digit)
   - parseInt("aa291dde-...") = NaN
3. This caused:
   - Prompt selection: saved as NaN instead of UUID
   - Load workflow: GET /api/prompts/3 instead of /api/prompts/3b4d7d64-...
   - 405 Method Not Allowed errors

Changes:
- useEffect: loadWorkflow(id) instead of loadWorkflow(parseInt(id))
- Prompt onChange: prompt_id: promptId (string) instead of parseInt(promptId)
- Removed NaN check (unnecessary for UUID strings)

Root Cause: Backend uses UUID primary keys, frontend assumed integer IDs

Testing: Console logs still active for verification
2026-04-04 22:39:08 +02:00
2b8bebd381 debug: Add comprehensive console logging for workflow editor debugging
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
Debug Logs Added:
- useEffect: Log ID validation and loadWorkflow calls
- loadWorkflow: Log API response, graph_data, deserialization results
- handleNodeUpdate: Log updates and resulting node state
- handleSave: Log serialization, API calls, navigation

Bug Fixes:
- useEffect: Add !isNaN(parseInt(id)) check to prevent /api/prompts/NaN calls
- Prompt selection: String conversion for value prop (Number vs String mismatch)
  - <select value={String(selectedNode.data.prompt_id)}>
  - <option value={String(prompt.id)}>
  - onChange: find with String(p.id) === promptId

Issues to Debug:
- Why does useEffect run with id=undefined after navigate?
- Why does loadWorkflow not populate nodes/edges?
- Why does prompt selection not persist?

Next Step: User tests with Browser Console open, reports logs
2026-04-04 22:30:43 +02:00
2f70a39052 fix: Phase 5 - Workflow Editor UX Fixes (Round 3)
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 14s
Frontend Fixes:
- AdminPromptsPage: Edit button navigates to workflow-editor for workflow type prompts
- WorkflowEditorPage: Fixed save navigation (alert before navigate)
- WorkflowEditorPage: selectedNode derived from selectedNodeId (eliminates stale state)
- FallbackConfig: Show node labels instead of IDs in fallback edge dropdown
- WorkflowCanvas: Enable edge deletion with deletable: true
- WorkflowEditorPage: Hide sidebar when config panel is open

Bugs Fixed:
- C1: Save error "Method Not Allowed" after success
- C2: Edit button in admin doesn't open workflow editor
- H1: Prompt selection not displayed when re-editing node
- H2: Fallback edge dropdown shows node_1/node_2 instead of names
- H3: Cannot delete edges
- M1: Sidebar takes space when config panel open

Technical Changes:
- Replaced useState(selectedNode) with useState(selectedNodeId) + derived selectedNode
- Removed sync useEffect (no longer needed with derived state)
- Added nodes prop to FallbackConfig for label lookup
- Swapped alert/navigate order to prevent navigation errors

Testing: Manual testing required (see manual test cases)
2026-04-04 21:16:15 +02:00
7d22b052dd fix: Phase 5 - Workflow save + node persistence bugs
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
KRITISCHE FIXES:

1. Backend: Workflow-Type Support
   - models.py: graph_data Feld hinzugefügt
   - models.py: slug Optional (auto-generiert)
   - prompts.py: 'workflow' in erlaubten Typen
   - prompts.py: graph_data in INSERT/UPDATE
   - prompts.py: Auto-Slug-Generierung aus Name
   - FIX: "Field required: slug" Error behoben

2. Frontend: Node-Updates Persistence
   - selectedNode sync mit nodes array (useEffect)
   - FIX: Änderungen gingen verloren (stale state)
   - FIX: Prompt-Auswahl nicht sichtbar nach Edit
   - FIX: Fallback-Strategy nicht gespeichert
   - FIX: Node-Name Änderungen nicht übernommen

BEHOBEN:
-  Save fehlgeschlagen →  Workflows speicherbar
-  Node-Name ignoriert →  Live-Update
-  Prompt verschwindet →  Bleibt sichtbar
-  Fallback nicht saved →  Persistiert

Tested: Backend API akzeptiert jetzt type='workflow'

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 19:17:41 +02:00
e3ef18674a fix: Phase 5 - Critical UX bugs in Workflow Editor
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
Behebt 5 kritische Bugs die Editor unbenutzbar machten:

BUG-01: Config Panel - Close Button hinzugefügt (×)
- User war im Config Panel "gefangen"
- Jetzt: Click × zum Deselektieren

BUG-02: Save UX - Validierungs-Feedback verbessert
- Speichern-Button zeigt Lock-Icon (🔒) bei Fehlern
- Tooltip erklärt warum Speichern blockiert ist
- Error-Message mit Hinweis auf Validierung

BUG-03: Analysis Node - Prompt-Auswahl implementiert
- Dropdown zum Auswählen von Basis-Prompts
- Lädt verfügbare Prompts via API
- Zeigt gewählten Prompt-Namen an

BUG-04: Label-Input - UX verbessert
- Header zeigt "Node-Konfiguration" (nicht Label)
- Input hat Placeholder und Hilfetext
- "Änderungen automatisch übernommen" Hinweis

BUG-05: Admin Page - "Neuer Workflow" Button
- Button neben "+ Neuer Prompt"
- Navigiert zu /workflow-editor/new
- Workflow-Filter im Type-Filter hinzugefügt

Tested: Manuell durch User (alle Bugs bestätigt gefixt)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 18:59:47 +02:00
dc59596f01 feat: Phase 5 - Visual Workflow Editor (Option B)
Some checks failed
Deploy Development / deploy (push) Failing after 1s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 14s
Backend (Mini-Backend 1-2h):
- Migration 016: ai_prompts.graph_data JSONB column
- workflow_executor: graph_data parameter support (backward-compatible)
- prompt_executor: execute_workflow_prompt uses graph_data

Frontend (Main effort 25-35h):
- WorkflowCanvas: React Flow wrapper component
- 5 Custom Nodes: Start, End, Analysis, Logic, Join
- 4 Config Panels: QuestionAugmentation, LogicExpression, Fallback, Join
- workflowValidation: Structural + logical validation
- workflowSerializer: Canvas ↔ JSONB conversion
- WorkflowEditorPage: Main orchestration (420 LOC)
- Route: /workflow-editor/:id
- CSS: workflowEditor.css (300 LOC)

Architecture:
- Option B: ai_prompts.type='workflow' (not separate table)
- panels/ subdirectory for clean separation
- WorkflowCanvas reusable component
- User GUI identical (Workflows = Prompts)
- Backward-compatible (type='pipeline' unchanged)

Version: v0.9m → v0.9n (Phase 5 complete)
Module: workflow 0.5.0 → 0.6.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 17:56:00 +02:00
a7058c30be feat: Enhance EmojiIconPicker with search functionality and keyword support
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
2026-04-04 14:22:44 +02:00
2101080719 feat: Expand EmojiIconPicker with additional curated emoji groups and enhance functionality for custom groups
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 15s
2026-04-04 14:17:35 +02:00
5aae999a65 feat: Add EmojiIconPicker component and integrate it into Admin pages for icon selection
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 13s
2026-04-04 14:07:54 +02:00
dc87e7f3b8 cursor_Setup
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
2026-04-04 14:05:50 +02:00
c607cd1833 fix: Convert joined signals Dict to List for NodeExecutionState
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 22s
NodeExecutionState expects normalized_signals as List[NormalizedSignal],
but join_evaluator returns Dict[str, NormalizedSignal].

Fix: Convert dict to list before returning NodeExecutionState.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 12:33:58 +02:00
e2a132353d feat: Phase 4 - Join Nodes and Path Consolidation
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 Implementation (v0.9m, workflow 0.5.0):
- join_evaluator.py (394 lines): Join-Strategie-Evaluator
  - evaluate_join_node(): Hauptlogik für Join-Node Execution
  - Join-Strategien: wait_all, wait_any, best_effort
  - Skip-Handling: ignore_skipped, use_placeholder, require_minimum
  - Result Consolidation: merge analysis_cores, combine signals
  - Partial Execution: korrekte Behandlung von SKIPPED/FAILED Pfaden

- workflow_executor.py: execute_join_node() Integration
  - BFS-Traversierung erweitert für Join-Nodes
  - NodeExecutionState List → Dict Konvertierung für Signale
  - Signal-Name-Kollisionen via node_id Präfix gelöst

Testing (49 Tests passing):
- test_phase4_join_nodes.py: 18 neue Unit Tests
  - Join-Strategien (wait_all, wait_any, best_effort)
  - Skip-Handling (ignore, placeholder)
  - Result Consolidation (merge, combine)
  - Partial Execution (mixed status paths)
  - Helper Functions (collect, check, merge, combine)

- Backward Compatibility: 31 Phase 2/3 Tests (alle passing)
  - test_phase2_workflow_executor.py: 1 Test aktualisiert
  - test_phase3_logic_evaluator.py: 20 Tests unverändert

Konzept: konzept_workflow_engine_konsolidated.md (Sektion 8.8)
Anforderungsanalyse: phase4_anforderungsanalyse.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 12:27:31 +02:00
2ce0874dcb feat: Phase 3 - Logic Nodes + Conditional Branching
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
Backend:
- logic_evaluator.py (NEU, 307 Zeilen): Deterministischer Logic Evaluator
  - Vergleichsoperatoren: EQ, NEQ, IN, NOT_IN, GT, LT, GTE, LTE, CONTAINS
  - Logische Operatoren: AND, OR, NOT mit Verschachtelung
  - Resolve signal references (node_id.question_type)
  - Error handling für UNCLEAR/INVALID/NOT_DECIDABLE Signale

- workflow_executor.py (ERWEITERT):
  - execute_logic_node(): Bedingungen evaluieren, Pfade aktivieren/deaktivieren
  - execute_workflow(): BFS-Traversierung mit Edge-Activation statt Sequential
  - _apply_fallback(): 4 Fallback-Strategien (CONSERVATIVE_SKIP, DEFAULT_PATH, UNCERTAINTY_PATH, DOCUMENT_ONLY)
  - _has_active_incoming_edge(): Prüft ob Node erreichbar ist
  - _get_edges_by_label(): Findet then/else/uncertainty Pfade

- workflow_models.py (ERWEITERT):
  - LogicOperator.CONTAINS hinzugefügt

- version.py: 0.9k → 0.9l, workflow 0.3.0 → 0.4.0

Tests:
- test_phase3_logic_evaluator.py (NEU): 20 Unit Tests (alle passing)
  - Comparison operators (EQ, NEQ, IN, GT, LT, CONTAINS)
  - Logical operators (AND, OR, NOT)
  - Nested expressions
  - Error handling (missing refs, UNCLEAR/INVALID signals)

- test_phase2_workflow_executor.py (AKTUALISIERT): 11 Tests (alle passing)
  - execute_node() graph parameter hinzugefügt (Phase 3 requirement)
  - test_execute_node_unknown_type: logic → join (logic jetzt implementiert)

- test_phase3_workflow_branching.py (NEU): Integration Tests vorbereitet
  - Erfordert vollständige DB-Mock-Strategie (wird in E2E-Test nachgeholt)

Phase 2 Backward Compatibility:  Alle Phase 2 Tests bestehen weiterhin

Konzept: .claude/task/Workflow_engine_prompting_engine/konzept_workflow_engine_konsolidated.md
Anforderungsanalyse: .claude/task/Workflow_engine_prompting_engine/phase3_anforderungsanalyse.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 08:02:22 +02:00
16dc08cd7d test: Add regression test for hybrid model - node spectrum overrides catalog
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
2026-04-03 21:55:19 +02:00
c588372f3a fix: Hybrid model - node-specific question spectrums override catalog (Phase 1 requirement)
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 21s
2026-04-03 21:49:13 +02:00
585f189b13 fix: Remove extra_vars parameter from resolve_placeholders call - function doesn't support it yet
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
2026-04-03 21:44:39 +02:00
acd4830795 fix: Access topological_order directly from engine, not from non-existent validator attribute
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 14s
2026-04-03 21:38:45 +02:00
ac2e7cf5bb fix: Use dict keys for all RealDictCursor row access in Phase 2 code
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 15s
2026-04-03 21:36:44 +02:00
0725461056 fix: Use dict keys instead of numeric indices for RealDictCursor rows
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
2026-04-03 21:34:47 +02:00
ce4666a535 fix: Import call_openrouter from routers.prompts instead of non-existent openrouter module
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
2026-04-03 21:33:09 +02:00
1f8791f4dd feat: Phase 2 - Normalisierung + Workflow Executor
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 14s
Backend:
- normalization_engine.py (200 Zeilen): Synonym-Mapping, 5 Statuswerte
  * normalize_decision_signal(): Kaskade (exact → case → synonym → invalid)
  * apply_synonym_mapping(): DB-basierte Synonyme (case-insensitive)
  * normalize_all_signals(): Batch-Processing gegen Katalog
  * load_question_catalog(): Lädt normalization_rules aus DB
- workflow_executor.py (440 Zeilen): Sequenzielle Workflow-Ausführung
  * execute_workflow(): Traversiert DAG in topologischer Reihenfolge
  * execute_node(): Führt analysis nodes aus (start/end = no-op)
  * aggregate_results(): Kombiniert analysis_core + normalized_signals
  * save_execution_state(): Persistiert in workflow_executions
- workflow_models.py: Erweitert um Phase 2 Models
  * SignalStatus Enum (valid, normalized, unclear, invalid, not_decidable)
  * NormalizedSignal (question_type, raw_value, normalized_value, status)
  * NodeExecutionState (node_id, status, analysis_core, normalized_signals)
  * ExecutionResult (execution_id, workflow_id, status, node_states, aggregated_result)
- workflow_engine.py: Neue Funktion get_execution_order()
  * Flattened topological sort für sequenzielle Execution
  * Phase 7: Wird zu levels (parallele Execution)
- prompt_executor.py: execute_workflow_prompt() Implementierung
  * Ruft workflow_executor.execute_workflow() auf
  * Konvertiert ExecutionResult zu API-Response
- routers/workflows.py (230 Zeilen): Workflow Execution API
  * POST /api/workflows/{id}/execute (mit enable_debug)
  * GET /api/workflows/executions/{id} (lädt gespeicherten State)
  * GET /api/workflows (listet alle aktiven Workflows)
  * GET /api/workflows/{id} (lädt einzelnen Workflow mit Graph)
- main.py: Router-Registrierung (workflows.router)

Tests:
- test_phase2_normalization.py (17 Tests): Alle Normalisierungs-Szenarien
  * Exact match, case-insensitive, synonym mapping, invalid, whitespace
  * Batch-Normalisierung, not_in_catalog, mixed validity
- test_phase2_workflow_executor.py (10 Tests): Executor + Aggregation
  * aggregate_results mit verschiedenen Konstellationen
  * execute_node für start/end/analysis/unknown
  * Integration mit question_augmenter + result_container_parser

Alle 27 Unit-Tests bestanden.

version: 0.9k (backend)
module:  workflow 0.3.0

Konzept: .claude/task/Workflow_engine_prompting_engine/anforderungsanalyse_umsetzungsplan.md (Phase 2)
2026-04-03 21:20:23 +02:00
ca562b7130 feat: Phase 1 - Fragenergänzung + Strukturierter Container
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
Backend:
- question_augmenter.py (290 Zeilen): Hybrid-Modell für Fragenergänzungen
  * merge_question_augmentations(): Knotengebundene Fragen überschreiben Prompt-Defaults
  * augment_prompt_with_questions(): Markdown-formatierte Fragenergänzung
  * parse_question_augmentations_from_jsonb(): JSONB → QuestionAugmentation[]
- result_container_parser.py (250 Zeilen): Markdown-Sektionen-Parsing
  * parse_result_container(): Extrahiert Analysekern, Entscheidungsanteil, Begründungsanker
  * validate_decision_signal(): Normalisierung gegen answer_spectrum
  * Fallback-Parsing bei unstrukturierten Antworten
- routers/workflow_questions.py (236 Zeilen): CRUD für workflow_question_catalog
  * GET /api/workflow/questions (mit active_only Filter)
  * POST/PUT/DELETE (Admin only, Soft Delete)
- prompt_executor.py: Integration in execute_base_prompt()
  * Fragenergänzung vor LLM-Call (wenn node_questions oder catalog vorhanden)
  * Result-Container-Parsing nach LLM-Response
- main.py: Router-Registrierung (workflow_questions)

Tests:
- test_phase1_question_augmenter.py (8 Tests): Hybrid-Modell, Formatierung, JSONB-Parsing
- test_phase1_result_container_parser.py (17 Tests): Sektion-Extraktion, Decision-Parsing, Validierung

Alle 25 Unit-Tests bestanden.

version: 0.9j (backend)
module:  workflow 0.2.0

Konzept: .claude/task/Workflow_engine_prompting_engine/konzept_workflow_engine_konsolidated.md (Phase 1)
2026-04-03 18:02:25 +02:00
b5be6e21a5 feat: Phase 0 - Workflow Engine Foundation
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:
- DB-Migration 034: workflow_definitions, workflow_question_catalog, workflow_executions
- ai_prompts.question_augmentations JSONB-Spalte (Hybridmodell: Prompt-Defaults)
- 6 Grundtypen Fragenergänzungen mit Normalisierungsregeln (Seed-Daten)
- Pydantic-Modelle (16 Models, 11 Enums) in workflow_models.py
- Workflow-Engine: Graph-Parsing, Topologische Sortierung, DAG-Validierung
- Dispatcher-Erweiterung type='workflow' (Stub für Phase 1-3)
- Adjacency Lists, Erreichbarkeits-Prüfungen, Zyklen-Erkennung

Testing:
- 22 Unit-Tests (alle bestanden): Graph-Parsing, Validierung, Topologische Sortierung
- Fixtures: simple_valid_graph, parallel_graph, branching_graph

Version:
- APP_VERSION 0.9i
- DB_SCHEMA_VERSION 20260403
- Module: workflow 0.1.0

Anforderungsanalyse: .claude/task/Workflow_engine_prompting_engine/anforderungsanalyse_umsetzungsplan.md
Konzept-Basis: .claude/task/Workflow_engine_prompting_engine/konzept_workflow_engine_konsolidated.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 16:55:51 +02:00
504 changed files with 114245 additions and 6927 deletions

62
.claude/README.md Normal file
View File

@ -0,0 +1,62 @@
# Mitai Jinkendo Claude-Arbeitsumgebung
Dieser Ordner ist der **primäre Orientierungspunkt** für Claude Code / Cursor-Agenten. Dauerhafte Spezifikationen liegen unter **`.claude/docs/`** (`functional/`, `technical/` …). Das Repository **`docs/`** (Projektroot) ist u.a. für **`docs/issues/`** nicht verwechseln.
---
## Pflichtlektüre (vor größeren Änderungen)
| Reihenfolge | Datei |
|-------------|--------|
| 1 | `../CLAUDE.md` |
| 2 | **`rules/DOCUMENTATION.md`** Ablage- und Dokumentationsregeln |
| 3 | `rules/ARCHITECTURE.md`, `rules/CODING_RULES.md`, `rules/LESSONS_LEARNED.md` |
| 4 | Issue-Landkarte: **`.claude/docs/GITEA_ISSUES_INDEX.md`** |
| 5 | **Universal CSV Import** (Modul/Executor/Vorlagen): **`docs/technical/UNIVERSAL_CSV_IMPORT_AGENT_GUIDE.md`** (unter `.claude/`) |
Themen mit UI/Nav/PWA: siehe `../docs/issues/GUI_IA_ADMIN_NAV_2026-04-05.md` (im **Projekt**-`docs/`, nicht hier).
---
## Verzeichnisbaum (Kurz)
```
.claude/
├── README.md ← Diese Datei
├── rules/ ← Verbindliche Regeln (versioniert, wenn konfiguriert)
├── docs/ ← Spezifikationen + Arbeitspapiere
│ ├── functional/ ← Fachlich (WAS)
│ ├── technical/ ← Technisch (WIE)
│ ├── architecture/ ← Querschnitt
│ ├── working/ ← Zwischenstände, Analysen (nicht allein „Wahrheit“)
│ ├── audit/ ← Audits, Matrizen
│ ├── README.md ← Katalog aller Spec-Dateien
│ └── GITEA_ISSUES_INDEX.md
├── commands/ ← Slash-Befehle (optional versioniert)
├── task/ ← Lokale Arbeitspakete (meist nur lokal)
├── handover/ ← Session-Notizen (meist nur lokal)
├── skills/ ← Skills (lokal)
└── settings.json ← Editor-Konfiguration (lokal)
.settings.local.json ← Nicht committen
```
---
## Wo neue Inhalte ablegen
Siehe **`rules/DOCUMENTATION.md`** (Tabelle „Ablagepflicht“). Kurz:
- Langfristige **fachliche** Spec → `docs/functional/` (innerhalb von `.claude`, siehe Baum oben).
- Langfristige **technische** Spec → `docs/technical/`.
- **Session-Analyse / grobe Notizen**`docs/working/`.
- **Epic/Issue lang**`../docs/issues/` im Repository.
---
## Projekt-`docs/` (Repository)
`../docs/issues/` enthält issue-nummerierte Markdown-Dateien und Abnahme-Dokumente **parallel** zu diesem Ordner, für alle sichtbar die das Repo klonen.
---
**Stand:** 2026-04-08

View File

@ -0,0 +1,32 @@
# Add Endpoint
Füge einen neuen API-Endpoint zum Backend hinzu.
## Template:
```python
@app.get("/api/mein-endpoint")
def mein_endpoint(
limit: int = 100,
session: dict = Depends(require_auth) # ← IMMER als separater Parameter!
):
pid = session['profile_id']
with get_db() as conn:
rows = conn.execute(
"SELECT * FROM meine_tabelle WHERE profile_id=? LIMIT ?",
(pid, limit)
).fetchall()
return [r2d(r) for r in rows]
```
## Regeln:
- `session: dict = Depends(require_auth)` IMMER als letzter/separater Parameter
- NIEMALS innerhalb von `Header(default=None, ...)` einbetten
- Profile-ID immer aus `session['profile_id']` nie aus Header
- Admin-Endpoints: `session=Depends(require_admin)`
- Rate-Limiting für sensitive Endpoints: `@limiter.limit("5/minute")`
## Nach dem Endpoint:
api.js um neue Methode ergänzen:
```javascript
meinEndpoint: (params) => req(`/mein-endpoint?limit=${params}`),
```

View File

@ -0,0 +1,174 @@
# Check Issues
Prüfe offene Gitea Issues und schlage Fixes vor.
## Automatische Ausführung
Dieser Skill wird bei jeder Session automatisch ausgeführt und zeigt:
- Anzahl offener Issues
- High-Priority Issues (Bugs + Features)
- Vorschlag welches Issue als nächstes angegangen werden sollte
## Workflow
### 1. Offene Issues abrufen
```bash
curl -s -H "Authorization: token $GITEA_TOKEN" \
"http://192.168.2.144:3000/api/v1/repos/Lars/mitai-jinkendo/issues?state=open&labels=develop" \
| python3 -c "
import sys, json
issues = json.load(sys.stdin)
print(f'📋 {len(issues)} offene Issues in develop:\n')
for issue in issues:
labels = {l['name'] for l in issue['labels']}
priority = 'high' if 'high' in labels else 'low' if 'low' in labels else 'medium'
itype = 'bug' if 'bug' in labels else 'feature' if 'feature' in labels else 'other'
icon = '🐛' if itype == 'bug' else '✨'
prio_icon = '🔥' if priority == 'high' else '💤' if priority == 'low' else '📌'
print(f\"{icon} {prio_icon} Issue #{issue['number']}: {issue['title']}\")
print(f\" {issue['html_url']}\n\")
"
```
### 2. Issues nach Priorität sortieren
**High Priority Issues (Bugs + Features):**
- Bugs mit Label `bug` + `high`
- Features mit Label `feature` + `high`
**Low Priority:**
- Features mit Label `low`
### 3. Issue-Details anzeigen
```bash
# Für ein spezifisches Issue (z.B. #13):
curl -s -H "Authorization: token $GITEA_TOKEN" \
http://192.168.2.144:3000/api/v1/repos/Lars/mitai-jinkendo/issues/13 \
| jq -r '.body'
```
### 4. Fix vorschlagen
**Frage den User:**
- "Soll ich Issue #X angehen?"
- Zeige Beschreibung + betroffene Dateien
- Schätze Aufwand (Quick Win < 30min, Medium < 2h, Large > 2h)
### 5. Bei Fix: Issue referenzieren im Commit
**WICHTIG:** Verwende dieses Format für automatisches Issue-Schließen:
```bash
git commit -m "fix: resolve training type creation error (#13)
- Fixed POST endpoint validation
- Improved frontend error handling
Closes #13"
```
**Gitea Keywords die Issues automatisch schließen:**
- `Closes #123`
- `Fixes #123`
- `Resolves #123`
Das Issue wird automatisch geschlossen wenn der Commit in den main Branch gemerged wird!
### 6. Issue manuell schließen (falls nötig)
```bash
curl -X PATCH -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"state":"closed"}' \
http://192.168.2.144:3000/api/v1/repos/Lars/mitai-jinkendo/issues/13
```
## Issue-Wartung (Standard-Task)
**WICHTIG:** Bei jeder Session Issue-Liste pflegen:
### 1. Veraltete Issues schließen
Wenn Features implementiert wurden, zugehörige Issues schließen:
```bash
# Issue schließen
curl -s -X PATCH -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"state":"closed"}' \
"http://192.168.2.144:3000/api/v1/repos/Lars/mitai-jinkendo/issues/17" > /dev/null
# Kommentar mit Commit-Referenz hinzufügen
curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"body":"✅ Erledigt in v9d Phase 2d. Commits: 548a5a4, bf87e03"}' \
"http://192.168.2.144:3000/api/v1/repos/Lars/mitai-jinkendo/issues/17/comments" > /dev/null
```
### 2. Duplikate entfernen
```bash
# Duplikat schließen
curl -s -X PATCH -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"state":"closed"}' \
"http://192.168.2.144:3000/api/v1/repos/Lars/mitai-jinkendo/issues/19" > /dev/null
# Duplikat-Kommentar
curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"body":"Duplikat von #21"}' \
"http://192.168.2.144:3000/api/v1/repos/Lars/mitai-jinkendo/issues/19/comments" > /dev/null
```
### 3. Issue-Prioritäten aktualisieren
```bash
# Label ändern (z.B. von medium zu high)
curl -s -X PUT -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"labels":[2,3,5]}' \
"http://192.168.2.144:3000/api/v1/repos/Lars/mitai-jinkendo/issues/15/labels"
```
**Checkliste nach jeder Implementation:**
- [ ] Zugehörige Issues mit Commit-Hash kommentieren
- [ ] Issues auf `closed` setzen
- [ ] Duplikate entfernen
- [ ] Neue Issues bei Bedarf erstellen
## Automatisierung (Hook)
**Optional:** Hook in `.claude/settings.json` für Session-Start:
```json
{
"hooks": {
"session-start": "check-issues"
}
}
```
→ Bei jeder neuen Session werden automatisch offene Issues geprüft.
## Issue erstellen (neue Bugs/Features)
```bash
curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "[BUG-XXX] Titel",
"body": "Beschreibung",
"labels": [1, 3, 5]
}' \
http://192.168.2.144:3000/api/v1/repos/Lars/mitai-jinkendo/issues
```
**Label-IDs:**
- 1 = bug
- 2 = feature
- 3 = high
- 4 = low
- 5 = develop

View File

@ -0,0 +1,23 @@
# DB Add Column
Füge eine neue Spalte zur SQLite-Datenbank hinzu.
## Vorgehen in backend/main.py:
1. Spalte in CREATE TABLE Statement hinzufügen
2. Spalte in `_safe_alters` Liste hinzufügen:
```python
_safe_alters = [
("profiles", "neue_spalte TEXT DEFAULT NULL"),
# ... weitere
]
```
Die `_safe_alters` Funktion fügt Spalten sicher hinzu ohne
bestehende Daten zu verlieren (ALTER TABLE IF NOT EXISTS).
## Wichtig:
- Immer DEFAULT Wert angeben
- Nie bestehende Spalten umbenennen oder löschen
- Nach Änderung Backend neu starten: `docker compose restart mitai-api`

View File

@ -0,0 +1,85 @@
# Deploy Commit, Test und Push
Führt Tests durch, bumpt die Version, committet und pusht auf develop.
Gitea startet dann automatisch den Dev-Deploy.
## Schritt 1: Syntax prüfen
```bash
python3 -m py_compile backend/main.py backend/routers/*.py 2>&1 && echo "Syntax OK"
```
## Schritt 2: Versions-Bump prüfen
Prüfe ob version.py und version.js aktualisiert wurden:
```bash
git diff --name-only | grep -E "version\.(py|js)"
```
Wenn NICHT aktualisiert → Stopp und fragen:
"Welche Version soll ich setzen? (aktuell: X.Y.Z)"
Dann version.py und version.js aktualisieren.
## Schritt 3: Smoke Tests auf Dev ausführen
```bash
npx playwright test 2>&1
```
Wenn Tests fehlschlagen:
- Screenshot analysieren: `start test-results\...\test-failed-1.png`
- Fehler korrigieren
- Tests erneut ausführen
- Erst wenn alle grün → weiter
## Schritt 4: Git Status prüfen
```bash
git status
git diff --stat
```
## Schritt 5: Commit
```bash
git add -A
git commit -m "COMMIT_MESSAGE
version: X.Y.Z
module: MODUL_NAME X.Y.Z"
```
## Schritt 6: Push auf develop
```bash
git push origin develop
```
## Schritt 7: Deploy-Status prüfen
```bash
# 30 Sekunden warten
# Dann Dev-System prüfen
ssh pi "docker logs dev-mitai-api --tail 10"
curl -sf https://dev.mitai.jinkendo.de/api/version | python3 -c "import sys,json; d=json.load(sys.stdin); print('Version:', d.get('app_version'))"
```
## Schritt 8: Gitea PR Link ausgeben
```bash
echo "PR erstellen: http://192.168.2.144:3000/Lars/mitai-jinkendo/compare/main...develop"
```
---
## Checkliste vor jedem Commit
```
[ ] backend/version.py aktualisiert (APP_VERSION + MODULE_VERSION)
[ ] frontend/src/version.js aktualisiert (APP_VERSION + PAGE_VERSION)
[ ] Changelog-Eintrag in version.py hinzugefügt
[ ] DB_SCHEMA_VERSION aktualisiert (wenn Schema geändert)
[ ] Alle Playwright Tests grün
[ ] Auth auf alle neuen Endpoints
[ ] api.js für alle neuen Frontend API-Calls
```
---
## Prod bleibt unberührt
Prod-Änderungen NUR über:
Gitea PR → Review → Merge → deploy-prod.yml
NIEMALS direkt auf Prod deployen.

View File

@ -0,0 +1,191 @@
# Dokumentation erstellen
Erstelle oder aktualisiere die technisch-fachliche Dokumentation der App.
Lies zuerst den aktuellen Code, dann generiere die Dokumentation.
## Wichtig
- Dokumentation basiert auf dem ECHTEN Code nicht auf Annahmen
- Jede Datei einzeln erstellen, nicht alles auf einmal
- Bestehende Dateien aktualisieren wenn sie existieren
## Schritt 1: Architektur-Übersicht
Lies folgende Dateien:
- `backend/main.py`
- `backend/db.py`
- `backend/auth.py`
- `backend/schema.sql`
- `frontend/src/App.jsx`
- `frontend/src/app.css`
- `frontend/src/utils/api.js`
- `docker-compose.yml`
Erstelle `.claude/docs/technical/ARCHITECTURE.md` mit:
```markdown
# Architektur-Übersicht Mitai Jinkendo
## System-Überblick
[Kurze Beschreibung der Gesamtarchitektur]
## Tech-Stack
[Tabelle mit allen Technologien + Versionen]
## Deployment-Architektur
[Infrastruktur: Raspberry Pi, Docker, Synology, Domains]
## Komponenten-Übersicht
[Alle Module/Router mit Kurzbeschreibung]
## Datenfluss
[Wie fließen Daten: Frontend → API → DB]
## Sicherheitsarchitektur
[Auth, CORS, Rate Limiting, bcrypt]
## Versions-Historie
[v9a, v9b, v9c was wurde wann eingeführt]
```
## Schritt 2: Frontend-Seiten + Komponenten
Lies alle Dateien in:
- `frontend/src/pages/`
- `frontend/src/context/`
- `frontend/src/utils/`
Erstelle `.claude/docs/technical/FRONTEND.md` mit:
```markdown
# Frontend-Dokumentation
## Seiten-Übersicht
[Tabelle: Seite | Route | Beschreibung | Auth erforderlich]
## Komponenten
[Wiederverwendbare Komponenten mit Props]
## Context / State Management
[AuthContext, ProfileContext was wird wo verwaltet]
## API-Integration (api.js)
[Alle API-Methoden mit Parametern]
## CSS-System
[CSS-Variablen, globale Klassen, Design-Tokens]
## PWA-Konfiguration
[Service Worker, Manifest, Icons]
```
## Schritt 3: Auth-Flow + Sicherheit
Lies:
- `backend/auth.py`
- `backend/routers/auth.py`
- `frontend/src/context/AuthContext.jsx`
Erstelle `.claude/docs/technical/AUTH.md` mit:
```markdown
# Auth-Flow & Sicherheit
## Login-Flow (Schritt für Schritt)
[Sequenz: Frontend → Backend → DB → Token]
## Session-Management
[Token-Format, Lebensdauer, Speicherort]
## Passwort-Sicherheit
[bcrypt, SHA256-Migration, Salting]
## Rate Limiting
[Welche Endpoints, Limits, slowapi-Konfiguration]
## CORS-Konfiguration
[Allowed Origins, Umgebungsvariablen]
## Öffentliche vs. geschützte Endpoints
[Tabelle: Endpoint | Public/Protected | Admin-only]
## Bekannte Sicherheitsentscheidungen
[Warum welche Entscheidung getroffen wurde]
```
## Schritt 4: API-Referenz
Lies alle Dateien in `backend/routers/`.
Erstelle `.claude/docs/technical/API_REFERENCE.md` mit:
```markdown
# API-Referenz
## Basis-URL
- Prod: https://mitai.jinkendo.de/api
- Dev: https://dev.mitai.jinkendo.de/api
## Authentifizierung
[Header-Format, Token-Handling]
## Endpoints nach Modul
### Auth (/api/auth/...)
| Method | Path | Auth | Parameter | Response |
...
### Profile (/api/profiles/...)
...
### Gewicht (/api/weight/...)
...
[alle 14 Router]
## Fehler-Codes
[Standard-Fehlercodes und Bedeutung]
## Rate Limits
[Tabelle: Endpoint | Limit | Zeitfenster]
```
## Schritt 5: Datenbankschema
Lies `backend/schema.sql`.
Erstelle `.claude/docs/technical/DATABASE.md` mit:
```markdown
# Datenbankschema
## Übersicht
[Alle Tabellen mit Kurzbeschreibung]
## Tabellen-Details
[Je Tabelle: Spalten, Typen, Constraints, Indizes]
## Beziehungen
[Foreign Keys, Beziehungsdiagramm als ASCII]
## Migrations-Historie
[Was wurde wann geändert]
## Design-Entscheidungen
[Warum PostgreSQL, warum welche Struktur]
## Wichtige Abfragen
[Häufig verwendete Queries als Referenz]
```
## Nach jeder Datei
Sage mir:
- Welche Datei wurde erstellt/aktualisiert
- Wie viele Zeilen
- Was war überraschend oder unklar im Code
## Starten
Beginne mit Schritt 1 (ARCHITECTURE.md).
Frage nach jedem Schritt ob du weitermachen sollst.
EOF

100
.claude/commands/fix-bug.md Normal file
View File

@ -0,0 +1,100 @@
# Fix Bug
Strukturierter Workflow für Fehlerbehebung mit Bug-Tracking.
## Workflow
### 1. Bug in KNOWN_ISSUES.md finden
```bash
cat .claude/docs/KNOWN_ISSUES.md | grep -A 20 "BUG-XXX"
```
### 2. Status auf "In Bearbeitung"
```markdown
**Status:** 🟡 In Bearbeitung
```
### 3. Logs analysieren
**Docker Logs:**
```bash
docker logs -f dev-mitai-api | grep "ERROR\|Exception"
docker logs dev-mitai-api --tail 100
```
**Feature-Logs:**
```bash
tail -f backend/logs/feature-usage.log | jq .
```
### 4. Bug reproduzieren
- Schritte aus KNOWN_ISSUES.md nachstellen
- Fehler verifizieren
- Root Cause identifizieren (nicht nur Symptom!)
### 5. Fix implementieren
- Minimal invasive Änderung
- Keine "Verbesserungen" nebenbei
- Kommentiere komplexe Fixes
### 6. Testen
```bash
# Backend Syntax
python3 -m py_compile backend/[file].py
# Frontend Build
cd frontend && npm run build
```
### 7. Commit
```bash
git add [files]
git commit -m "fix: [BUG-XXX] Kurzbeschreibung
Root Cause: [Ursache]
Lösung: [Was geändert]
Tested: [Wie getestet]
Closes: BUG-XXX"
```
### 8. KNOWN_ISSUES.md aktualisieren
Nach Deploy:
- Status: ✅ Behoben (Commit `hash`)
- Ins Archiv verschieben
## Debugging-Checkliste
### Frontend-Bugs
- Browser Console (F12) → Fehler lesen
- Network Tab → API-Call prüfen
- Häufig:
- 401: Token fehlt → api.js nutzen
- undefined: Optional chaining `?.` verwenden
- Weißer Screen: JS-Fehler in Console
### Backend-Bugs
- Docker Logs → Traceback analysieren
- Syntax: `python3 -m py_compile backend/[file].py`
- Häufig:
- TypeError: Type-Konvertierung fehlt
- 404: Router nicht registriert
- 500: Unbehandelte Exception
### Häufige Fehler
- `session=Depends(require_auth)` in `Header()` → separater Parameter!
- `dayjs.week()` → Native ISO-Wochenberechnung
- `datetime.date` vs. `str` → Type-Check
- PostgreSQL Boolean: `true` nicht `1`
## Commit-Format
```
fix: [BUG-XXX] Kurze Beschreibung
Problem: TypeError in /api/nutrition/weekly
Root Cause: d['date'] ist datetime.date, nicht str
Lösung: Check if already datetime.date object
Tested: /nutrition Tab lädt ohne Error
Closes: BUG-XXX
```

View File

@ -0,0 +1,280 @@
---
description: Strukturierter Workflow für konzept-basierte Feature-Implementierung mit Requirement Analysis + User Approval
args: <feature-name> <konzept-file>
model: sonnet
---
# Feature-Implementierung Workflow
Du wurdest aufgerufen mit:
- **Feature:** {{feature-name}}
- **Konzept:** {{konzept-file}}
Dieser Skill führt den strukturierten 5-Stufen-Prozess aus `.claude/rules/IMPLEMENTATION_RULES.md` aus.
---
## STUFE 1: Anforderungsanalyse
**Aufgabe:**
1. Lies das Konzept-Dokument `{{konzept-file}}` VOLLSTÄNDIG
2. Finde alle Anforderungen für `{{feature-name}}`
3. Erstelle eine detaillierte Checkliste
**Gehe dabei wie folgt vor:**
### 1.1 Konzept lesen
- Öffne `{{konzept-file}}` mit dem Read tool
- Suche nach Abschnitten die `{{feature-name}}` betreffen
- Lies ALLE relevanten Abschnitte vollständig (nicht nur überfliegen)
### 1.2 Anforderungs-Matrix erstellen
Erstelle eine Tabelle mit folgenden Spalten:
| Anforderung | Datenquelle | Status | Notizen |
|-------------|-------------|--------|---------|
| Kalorienaufnahme täglich | nutrition_log.kcal | ✓ Vorhanden | - |
| Trainingskalorien | activity_log.kcal | ✗ Fehlt | Muss aggregiert werden |
| ... | ... | ... | ... |
**Status-Codes:**
- ✓ Vorhanden: Bereits implementiert (data_layer Funktion existiert)
- ⚠ Partial: Teilweise vorhanden, muss erweitert werden
- ✗ Fehlt: Muss neu gebaut werden
### 1.3 Gap-Analyse
Listen auf:
- Welche data_layer Funktionen existieren bereits?
- Welche data_layer Funktionen müssen neu geschrieben werden?
- Welche Tabellen werden benötigt?
- Welche Berechnungen sind nötig? (Formeln dokumentieren)
### 1.4 Offene Fragen
Dokumentiere alle Unklarheiten:
- Interpretation unklar?
- Mehrere Umsetzungsmöglichkeiten?
- Fehlende Informationen im Konzept?
**OUTPUT:** Zeige dem User die Anforderungs-Matrix und Gap-Analyse.
---
## STUFE 2: Umsetzungskonzept erstellen
**Aufgabe:**
Erstelle ein detailliertes technisches Umsetzungskonzept mit:
### 2.1 Backend-Design
**Neue Endpoints:**
```
GET /api/charts/{{feature-name}}?param1=value1
Args:
param1: Beschreibung (default=X, range Y-Z)
session: Auth session (injected)
Returns:
Chart.js-compatible JSON (siehe unten)
```
**Neue data_layer Funktionen:**
```python
def get_xyz_data(profile_id: str, days: int) -> Dict:
"""
Beschreibung was die Funktion tut.
Berechnung:
1. Schritt 1 (SQL Query oder Formel)
2. Schritt 2
Returns:
{"key": value, ...}
"""
```
**Datenquellen:**
- Welche Tabellen? (nutrition_log, activity_log, etc.)
- Welche Spalten?
- Welche JOINs?
**Berechnungen:**
- Formeln dokumentieren (z.B. "7d avg = sum(values[-7:]) / 7")
- Aggregationen beschreiben
- Edge Cases behandeln (keine Daten, Division durch 0, etc.)
### 2.2 Response-Format
Zeige ein **vollständiges Beispiel** der JSON-Response:
```json
{
"chart_type": "line" | "bar" | "mixed" | "scatter",
"data": {
"labels": ["2026-01-01", "2026-01-02", ...],
"datasets": [
{
"type": "line", // nur bei chart_type: mixed
"label": "Label für Legende",
"data": [100, 105, 103, ...],
"borderColor": "#1D9E75",
"backgroundColor": "rgba(29, 158, 117, 0.1)",
"borderWidth": 2,
"tension": 0.3,
"fill": false,
"yAxisID": "y1" // bei Dual-Axis
}
]
},
"metadata": {
"confidence": "high" | "medium" | "low" | "insufficient",
"data_points": 28,
"avg_value": 123.4,
"custom_field": "..."
}
}
```
### 2.3 Frontend-Design
**Component:**
- Welche Datei? (z.B. `NutritionCharts.jsx`)
- Welche Funktion? (z.B. `renderEnergyBalance()`)
**Chart-Library:**
- Recharts oder Chart.js?
- Welcher Chart-Typ? (LineChart, BarChart, ComposedChart, etc.)
- Welche Features? (Tooltip, Legend, Dual-Axis, etc.)
**API-Integration:**
- API-Funktion in `api.js` hinzufügen
- State-Management (useState, useEffect)
- Loading + Error Handling
### 2.4 Dependencies
- Müssen andere Module angepasst werden?
- Neue npm-Pakete nötig?
- DB-Migrationen nötig?
**OUTPUT:** Zeige dem User das vollständige Umsetzungskonzept.
---
## STUFE 3: User-Approval einholen
**Aufgabe:**
1. Zeige Anforderungs-Matrix (Stufe 1)
2. Zeige Umsetzungskonzept (Stufe 2)
3. Liste offene Fragen auf
4. Frage explizit: **"Soll ich mit der Implementierung beginnen? (ja/nein/Änderungen)"**
**WICHTIG:**
- **Warte auf die Antwort des Users**
- Beginne NICHT mit der Implementierung ohne explizites "ja"
- Bei Änderungswünschen: Passe das Konzept an und zeige es erneut
---
## STUFE 4: Implementierung
**NUR ausführen wenn User "ja" gesagt hat!**
### 4.1 Backend implementieren
1. **Neue data_layer Funktionen:**
- Erstelle/erweitere Dateien in `backend/data_layer/`
- Implementiere genau nach Konzept (Stufe 2.1)
- Docstrings mit Beschreibung + Args + Returns
2. **Neue Endpoints:**
- Erstelle/erweitere Router in `backend/routers/`
- Implementiere genau nach Konzept (Stufe 2.1)
- Response-Format exakt wie spezifiziert (Stufe 2.2)
3. **Tests (falls vorhanden):**
- Unit-Tests für data_layer Funktionen
- Integration-Tests für Endpoints
### 4.2 Frontend implementieren
1. **API-Funktion hinzufügen:**
- Ergänze `frontend/src/utils/api.js`
- Syntax: `getXyzChart: (days=28) => req(\`/charts/xyz?days=${days}\`)`
2. **Component erstellen/erweitern:**
- Implementiere Chart-Darstellung
- Verwende Chart-Library wie spezifiziert
- Loading + Error Handling
3. **Integration:**
- Füge Component in Parent-Page ein
- Teste UI-Flow
### 4.3 Commit
```
feat: {{feature-name}} (konzept-konform)
Backend:
- data_layer: [Liste neue Funktionen]
- Endpoint: [Liste neue Endpoints]
Frontend:
- Component: [Beschreibung]
- Chart-Type: [Typ]
Konzept: {{konzept-file}}
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
```
---
## STUFE 5: Compliance-Check
**Aufgabe:**
Prüfe JEDE Anforderung aus der Anforderungs-Matrix (Stufe 1):
```
□ Anforderung 1: [Beschreibung] - Status: ✓ / ✗
□ Anforderung 2: [Beschreibung] - Status: ✓ / ✗
...
```
**Alle Checkboxen müssen ✓ sein vor Push!**
Falls ✗:
- Identifiziere was fehlt
- Implementiere nach
- Erneut prüfen
**OUTPUT:** Zeige dem User die Final-Checkliste.
---
## WICHTIG: Workflow-Reihenfolge
```
Stufe 1 (Anforderungen) → Stufe 2 (Konzept) → Stufe 3 (Approval)
User sagt "ja"?
Stufe 4 (Implementierung) → Stufe 5 (Compliance-Check) → Push
```
**Niemals:**
- Stufen überspringen
- Ohne Approval implementieren
- "Ähnliches" statt Gefordertes bauen
---
## Los geht's!
Beginne jetzt mit **STUFE 1: Anforderungsanalyse**.
Lies `{{konzept-file}}` und erstelle die Anforderungs-Matrix für `{{feature-name}}`.

View File

@ -0,0 +1,60 @@
# Merge to Production
Erstelle einen Pull Request in Gitea: develop -> main
## Checkliste vor dem PR:
- [ ] dev.mitai.jinkendo.de funktioniert
- [ ] Login funktioniert
- [ ] Alle neuen Features getestet
- [ ] Keine Console-Fehler im Browser
- [ ] KI-Analyse funktioniert
- [ ] Backend-Syntax OK: `python3 -m py_compile backend/main.py`
## Schritt 1: Sicherstellen dass develop aktuell ist
```bash
git checkout develop
git status
git push origin develop
```
## Schritt 2: Pull Request in Gitea erstellen
Öffne im Browser:
http://192.168.2.144:3000/Lars/mitai-jinkendo/compare/main...develop
Oder:
```
Gitea ? Repository ? Pull Requests ? "Neuer Pull Request"
Basis: main
Vergleich: develop
Titel: beschreibung der Änderungen
? Pull Request erstellen
```
## Schritt 3: PR mergen
```
Gitea ? Pull Request ? "Merge Pull Request"
? "Merge Commit" wählen (NICHT "Squash" oder "Rebase")
? develop Branch NICHT löschen (Häkchen deaktivieren!)
```
## Schritt 4: Nach dem Merge
- Gitea Action `deploy-prod.yml` startet automatisch
- Prüfe: https://mitai.jinkendo.de
- Prüfe Gitea Actions ob alles grün ist
- Lokal auf develop zurückwechseln und aktualisieren:
```bash
git checkout develop
git pull origin develop
```
## Rollback falls nötig:
```
Gitea ? Commits auf main ? "Revert" auf dem letzten Merge-Commit
? neuer PR wird automatisch erstellt
? PR mergen ? Prod wird zurückgesetzt
```
## Wichtig:
- NIEMALS direkt auf main pushen
- develop Branch niemals löschen
- Immer über PR mergen nie `git merge` lokal auf main

View File

@ -0,0 +1,19 @@
# New Feature
Erstelle ein neues Feature für Mitai Jinkendo.
## Checkliste:
1. Backend: Neuer Endpoint in `backend/main.py`
- Mit `session: dict = Depends(require_auth)` absichern
- Neue DB-Spalten via `_safe_alters` hinzufügen
2. Frontend: Neue Seite oder Komponente
- API-Calls immer über `frontend/src/utils/api.js`
- Token wird automatisch injiziert
3. Syntax prüfen: `python3 -m py_compile backend/main.py`
4. CLAUDE.md aktualisieren wenn nötig
## Wichtige Regeln:
- Passwörter: bcrypt (nicht SHA256)
- API-Calls: api.js nutzen (nie direktes fetch ohne Token)
- dayjs.week(): nicht verwenden → native ISO-Wochenberechnung
- session=Depends(require_auth): immer als separater Parameter

47
.claude/commands/pi-db.md Normal file
View File

@ -0,0 +1,47 @@
# Pi Datenbank
Direkter Zugriff auf PostgreSQL Datenbanken auf dem Raspberry Pi.
## Verwendung
Sage was du prüfen möchtest, z.B.:
- "Zeige alle Profile"
- "Wie viele Gewichtseinträge hat Lars?"
- "Zeige die letzten 10 Schlafeinträge"
- "Prüfe ob die Tabelle sleep_log existiert"
## Prod-Datenbank Abfrage
```bash
ssh pi "docker exec mitai-db-prod psql -U mitai_prod -d mitai_prod -c 'DEINE_SQL_ABFRAGE'"
```
## Dev-Datenbank Abfrage
```bash
ssh pi "docker exec dev-mitai-postgres psql -U mitai_dev -d mitai_dev -c 'DEINE_SQL_ABFRAGE'"
```
## Nützliche Standard-Abfragen
### Alle Tabellen anzeigen
```bash
ssh pi "docker exec mitai-db-prod psql -U mitai_prod -d mitai_prod -c '\dt'"
```
### Tabellen-Größen
```bash
ssh pi "docker exec mitai-db-prod psql -U mitai_prod -d mitai_prod -c \"SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size FROM pg_tables WHERE schemaname='public' ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;\""
```
### Profile anzeigen
```bash
ssh pi "docker exec mitai-db-prod psql -U mitai_prod -d mitai_prod -c 'SELECT id, name, email, role, tier FROM profiles;'"
```
### DB-Version prüfen
```bash
ssh pi "docker exec mitai-db-prod psql -U mitai_prod -d mitai_prod -c 'SELECT version();'"
```
## Wichtig
- Nur SELECT-Abfragen ohne explizite Genehmigung
- Keine DELETE/DROP/TRUNCATE ohne ausdrückliche Bestätigung
- Prod-DB mit besonderer Vorsicht behandeln

View File

@ -0,0 +1,60 @@
# Pi Dev Entwicklungssystem Zugriff
Direkter Zugriff auf das Dev-System (dev.mitai.jinkendo.de).
**NUR für Dev niemals auf Prod anwenden!**
## Container Status
```bash
ssh pi "docker ps --filter name=dev-mitai --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'"
```
## Backend neu starten (Dev)
```bash
ssh pi "docker restart dev-mitai-api && sleep 5 && docker logs dev-mitai-api --tail 20"
```
## Frontend neu starten (Dev)
```bash
ssh pi "docker restart dev-mitai-ui"
```
## Beide neu starten (Dev)
```bash
ssh pi "cd /home/lars/docker/bodytrack-dev && docker compose -f docker-compose.dev-env.yml restart"
```
## Komplett neu bauen (Dev)
```bash
ssh pi "cd /home/lars/docker/bodytrack-dev && git pull origin develop && docker compose -f docker-compose.dev-env.yml build --no-cache && docker compose -f docker-compose.dev-env.yml up -d"
```
## Backend Logs live (10 Sekunden)
```bash
ssh pi "timeout 10 docker logs dev-mitai-api --follow 2>&1 || true"
```
## Dev-DB Abfrage (nur SELECT ohne Genehmigung)
```bash
ssh pi "docker exec dev-mitai-postgres psql -U mitai_dev -d mitai_dev -c 'DEINE_ABFRAGE'"
```
## Health Check Dev
```bash
ssh pi "curl -sf http://localhost:8099/api/auth/status && echo '✓ DEV API OK' || echo '✗ DEV API FEHLER'"
ssh pi "curl -sf http://localhost:3099 | grep -c 'Mitai' && echo '✓ DEV UI OK' || echo '✗ DEV UI FEHLER'"
```
## Umgebungsvariablen prüfen (Dev)
```bash
ssh pi "docker exec dev-mitai-api env | grep -v PASSWORD | grep -v SECRET | grep -v KEY"
```
## ⛔ PROD-SCHUTZ
Folgende Befehle sind für Prod VERBOTEN:
- docker restart mitai-api
- docker restart mitai-ui
- docker exec mitai-api ...schreibend...
- Direkte Dateiänderungen in /home/lars/docker/bodytrack/
- Änderungen an Prod-DB außer SELECT
Prod-Änderungen NUR über: git push → Gitea PR → deploy-prod.yml

View File

@ -0,0 +1,43 @@
# Pi Logs
Zeigt Logs der Mitai-Container auf dem Raspberry Pi.
## Backend Logs (Prod)
```bash
ssh pi "docker logs mitai-api --tail 50 --timestamps"
```
## Backend Logs (Dev)
```bash
ssh pi "docker logs dev-mitai-api --tail 50 --timestamps"
```
## Frontend Logs (Prod)
```bash
ssh pi "docker logs mitai-ui --tail 20"
```
## Logs nach Fehler filtern
```bash
ssh pi "docker logs mitai-api --tail 100 2>&1 | grep -i 'error\|exception\|traceback'"
```
## Logs live verfolgen (10 Sekunden)
```bash
ssh pi "timeout 10 docker logs mitai-api --follow 2>&1 || true"
```
## Gitea Runner Logs
```bash
ssh pi "sudo journalctl -u gitea-runner --lines 30 --no-pager"
```
## Letzter Deploy-Status
```bash
ssh pi "cat /home/lars/docker/bodytrack/.last-deploy 2>/dev/null || echo 'Keine Deploy-Info'"
```
## System-Logs (Fehler letzte Stunde)
```bash
ssh pi "sudo journalctl --since '1 hour ago' --priority err --no-pager | tail -20"
```

View File

@ -0,0 +1,37 @@
# Pi Status
Zeigt den aktuellen Status aller Mitai-Container und Logs auf dem Raspberry Pi.
## Container Status
```bash
ssh pi "docker ps --filter name=mitai --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'"
```
## Letzte Backend-Logs (Prod)
```bash
ssh pi "docker logs mitai-api --tail 30"
```
## Letzte Backend-Logs (Dev)
```bash
ssh pi "docker logs dev-mitai-api --tail 30"
```
## API Health Check
```bash
ssh pi "curl -sf http://localhost:8002/api/auth/status && echo '✓ PROD OK' || echo '✗ PROD FEHLER'"
ssh pi "curl -sf http://localhost:8099/api/auth/status && echo '✓ DEV OK' || echo '✗ DEV FEHLER'"
```
## Datenbank Status
```bash
ssh pi "docker exec mitai-db-prod pg_isready -U mitai_prod && echo '✓ DB PROD OK'"
ssh pi "docker exec dev-mitai-postgres pg_isready -U mitai_dev && echo '✓ DB DEV OK'"
```
## Disk Space
```bash
ssh pi "df -h /home/lars/docker"
```
## Führe alle Checks aus und zeige Zusammenfassung

View File

@ -0,0 +1,81 @@
# Refactor
Refactore den Code ohne die Funktionalität zu ändern.
## Wichtige Regel:
**Erst planen, dann umsetzen niemals beides gleichzeitig.**
Zeige den Plan und warte auf Bestätigung bevor du Code schreibst.
## Backend Refactoring (main.py aufteilen):
### Zielstruktur:
```
backend/
├── main.py # Nur App-Setup, Middleware, Router-Import (~100 Zeilen)
├── database.py # DB-Verbindung, init_db, safe_alters, r2d()
├── auth.py # require_auth, require_admin, hash_pin, verify_pin, sessions
├── models.py # Alle Pydantic Models
├── email.py # SMTP, send_email, email_html_wrapper
├── utils.py # make_token(), helper functions
└── routers/
├── __init__.py
├── weight.py
├── caliper.py
├── circumference.py
├── nutrition.py
├── activity.py
├── photos.py
├── insights.py
├── prompts.py
├── admin.py
└── export.py
```
### Vorgehen:
1. Analysiere main.py vollständig
2. Erstelle Plan welche Zeilen wohin kommen
3. Warte auf Bestätigung
4. Erstelle neue Dateien eine nach der anderen
5. Nach jeder Datei: Syntax prüfen
6. main.py anpassen (imports + router registrierung)
7. Finaler Test: Backend startet ohne Fehler
### Syntax-Check nach jedem Schritt:
```bash
python3 -m py_compile backend/main.py
python3 -m py_compile backend/database.py
# etc.
```
### Test nach Refactoring:
```bash
# Auf dem Pi:
docker compose build --no-cache backend
docker compose up -d
docker logs mitai-api --tail 20
curl -s http://localhost:8002/api/auth/status
```
## Frontend Refactoring (Komponenten extrahieren):
### Wiederverwendbare Komponenten extrahieren nach:
```
frontend/src/components/
├── MetricCard.jsx # Kennzahl-Karte
├── ChartCombo.jsx # Kombinations-Chart
├── LoadingSpinner.jsx # Ladekreis
├── EmptyState.jsx # Leerer Zustand
├── Avatar.jsx # Nutzer-Avatar
└── ConfirmDialog.jsx # Bestätigungs-Dialog
```
### Vorgehen:
1. Identifiziere wiederholte Code-Muster
2. Extrahiere in eigene Komponenten
3. Ersetze in allen Pages
4. Frontend Build testen: `cd frontend && npm run build`
## Nach dem Refactoring:
- Commit mit `refactor:` Prefix
- CLAUDE.md Verzeichnisstruktur aktualisieren
- Kein neues Feature in diesem Commit!

226
.claude/commands/test.md Normal file
View File

@ -0,0 +1,226 @@
# Test Vollständige Test-Suite
Führt Backend-Tests (API + Logs) und Frontend-Tests (Playwright) durch.
Claude Code schreibt, führt aus und korrigiert bis alle Tests grün sind.
## Workflow für neue Features
Nach jeder Implementierung:
1. Backend-Tests schreiben und ausführen
2. Frontend-Tests schreiben und ausführen
3. Logs auf Fehler prüfen
4. Alle grün → committen
---
## TEIL 1: Backend API-Tests (schnell, immer zuerst)
### 1.1 Login + Token holen
```bash
TOKEN=$(curl -s -X POST https://dev.mitai.jinkendo.de/api/auth/login \
-H "Content-Type: application/json" \
-d "{\"email\":\"$TEST_EMAIL\",\"pin\":\"$TEST_PASSWORD\"}" \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('token','KEIN_TOKEN'))")
echo "Token: ${TOKEN:0:30}..."
```
### 1.2 Basis-Endpoints prüfen
```bash
# Version
curl -sf https://dev.mitai.jinkendo.de/api/version \
| python3 -c "import sys,json; d=json.load(sys.stdin); print('Version:', d.get('app_version'), '| DB:', d.get('db_schema_version'))"
# Auth Status
curl -sf https://dev.mitai.jinkendo.de/api/auth/status \
&& echo "Auth OK" || echo "Auth FEHLER"
# Stats (mit Token)
curl -sf https://dev.mitai.jinkendo.de/api/stats \
-H "X-Auth-Token: $TOKEN" \
| python3 -c "import sys,json; d=json.load(sys.stdin); print('Stats OK:', list(d.keys())[:5])"
```
### 1.3 CRUD-Test für neues Modul
Template für jeden neuen Router:
```bash
# CREATE
ID=$(curl -s -X POST https://dev.mitai.jinkendo.de/api/MODUL \
-H "Content-Type: application/json" \
-H "X-Auth-Token: $TOKEN" \
-d '{"date":"2026-01-01","FELD":"WERT"}' \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('id','FEHLER'))")
echo "CREATE: ID=$ID"
# READ
curl -sf https://dev.mitai.jinkendo.de/api/MODUL?limit=5 \
-H "X-Auth-Token: $TOKEN" \
| python3 -c "import sys,json; d=json.load(sys.stdin); print('READ: Einträge:', len(d))"
# DELETE (Test-Eintrag aufräumen)
curl -s -X DELETE https://dev.mitai.jinkendo.de/api/MODUL/$ID \
-H "X-Auth-Token: $TOKEN" \
&& echo "DELETE OK" || echo "DELETE FEHLER"
```
### 1.4 Auth-Schutz prüfen
```bash
# Endpoint OHNE Token muss 401 zurückgeben
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://dev.mitai.jinkendo.de/api/stats)
[ "$STATUS" = "401" ] && echo "Auth-Schutz OK (401)" || echo "WARNUNG: Auth-Schutz fehlt! ($STATUS)"
```
### 1.5 Admin-Endpoint prüfen
```bash
# Admin-Endpoint mit normalem Token muss 403 zurückgeben
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
https://dev.mitai.jinkendo.de/api/admin/profiles \
-H "X-Auth-Token: $TOKEN")
echo "Admin-Schutz: $STATUS (erwartet 403 für nicht-Admin)"
```
---
## TEIL 2: Backend Logs prüfen
### 2.1 Letzte Logs auf Fehler prüfen
```bash
ssh pi "docker logs dev-mitai-api --tail 50 2>&1 | grep -i 'error\|exception\|traceback\|warning' | head -20"
```
### 2.2 Nach Test-Requests: Logs prüfen
```bash
# Direkt nach API-Tests ausführen
ssh pi "docker logs dev-mitai-api --tail 20 --timestamps 2>&1"
```
### 2.3 Alle neuen Endpoints im Log sichtbar?
```bash
# Prüft ob Router korrekt registriert
ssh pi "docker logs dev-mitai-api 2>&1 | grep 'router\|route\|endpoint' | head -10"
```
### 2.4 DB-Verbindung gesund?
```bash
ssh pi "docker exec dev-mitai-postgres pg_isready -U mitai_dev && echo 'DB OK'"
```
### 2.5 Neue Tabellen vorhanden?
```bash
ssh pi "docker exec dev-mitai-postgres psql -U mitai_dev -d mitai_dev -c '\dt' 2>/dev/null | grep -E 'TABELLEN_NAME'"
```
---
## TEIL 3: Frontend Playwright-Tests
### 3.1 Alle Smoke Tests
```bash
npx playwright test
```
### 3.2 Nur neues Feature testen
```bash
npx playwright test --grep "FEATURE_NAME"
```
### 3.3 Mit sichtbarem Browser
```bash
npx playwright test --headed
```
### 3.4 Screenshot bei Fehler ansehen
```bash
start test-results\TESTNAME\test-failed-1.png
```
---
## TEIL 4: Tests schreiben
### Backend-Test Template (in test-Abschnitt einfügen)
```bash
# Für jeden neuen Endpoint:
echo "=== Test: MODUL_NAME ==="
TOKEN=$(curl -s -X POST https://dev.mitai.jinkendo.de/api/auth/login \
-H "Content-Type: application/json" \
-d "{\"email\":\"$TEST_EMAIL\",\"pin\":\"$TEST_PASSWORD\"}" \
| python3 -c "import sys,json; print(json.load(sys.stdin).get('token',''))")
# GET Test
curl -sf https://dev.mitai.jinkendo.de/api/MODUL \
-H "X-Auth-Token: $TOKEN" \
&& echo "GET OK" || echo "GET FEHLER"
# POST Test
curl -s -X POST https://dev.mitai.jinkendo.de/api/MODUL \
-H "Content-Type: application/json" \
-H "X-Auth-Token: $TOKEN" \
-d '{"date":"2026-01-01"}' \
| python3 -c "import sys,json; d=json.load(sys.stdin); print('POST OK, id:', d.get('id'))"
# Auth-Schutz
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://dev.mitai.jinkendo.de/api/MODUL)
[ "$STATUS" = "401" ] && echo "Auth-Schutz OK" || echo "Auth-Schutz FEHLER ($STATUS)"
```
### Frontend-Test Template (in dev-smoke-test.spec.js)
```javascript
test('MODUL: Seite lädt und Grundfunktion', async ({ page }) => {
await login(page);
// Navigation
await page.click('text=NAV_TEXT');
await page.waitForLoadState('networkidle');
await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });
// Formular ausfüllen
await page.fill('input[name="FELD"]', 'TESTWERT');
await page.click('button:has-text("Speichern")');
// Ergebnis prüfen
await expect(page.locator('text=gespeichert')).toBeVisible({ timeout: 5000 });
await page.screenshot({ path: 'screenshots/MODUL-test.png' });
console.log('MODUL OK');
});
```
---
## TEIL 5: Vollständiger Test-Lauf (vor jedem Deploy)
```bash
echo "=== BACKEND TESTS ===" && \
TOKEN=$(curl -s -X POST https://dev.mitai.jinkendo.de/api/auth/login \
-H "Content-Type: application/json" \
-d "{\"email\":\"$TEST_EMAIL\",\"pin\":\"$TEST_PASSWORD\"}" \
| python3 -c "import sys,json; print(json.load(sys.stdin).get('token',''))") && \
curl -sf https://dev.mitai.jinkendo.de/api/version | python3 -c "import sys,json; d=json.load(sys.stdin); print('Version:', d.get('app_version'))" && \
curl -sf https://dev.mitai.jinkendo.de/api/stats -H "X-Auth-Token: $TOKEN" > /dev/null && echo "Stats OK" && \
echo "" && \
echo "=== LOGS PRUEFEN ===" && \
ssh pi "docker logs dev-mitai-api --tail 20 2>&1 | grep -i 'error\|exception' | head -5 || echo 'Keine Fehler in Logs'" && \
echo "" && \
echo "=== FRONTEND TESTS ===" && \
npx playwright test && \
echo "" && \
echo "=== ALLE TESTS BESTANDEN ==="
```
---
## Credentials setzen (einmalig pro Session)
```bash
$env:TEST_EMAIL="lars@stommer.com"
$env:TEST_PASSWORD="5112"
```
---
## Prod-Schutz
Tests laufen AUSSCHLIESSLICH gegen:
- https://dev.mitai.jinkendo.de
- http://192.168.2.49:8099
NIEMALS gegen:
- https://mitai.jinkendo.de
- http://192.168.2.49:8002

View File

@ -0,0 +1,42 @@
# UI Component
Erstelle eine neue React-Komponente im Mitai Jinkendo Design-System.
## Design-Regeln:
- Hintergrund: `var(--bg)` oder `var(--surface)`
- Akzentfarbe: `var(--accent)` = #1D9E75
- Text: `var(--text1)` (primary), `var(--text2)` (secondary), `var(--text3)` (muted)
- Border: `var(--border)`
- Border-Radius: 12px für Cards, 8px für Buttons/Inputs
- Kein TypeScript reines JavaScript/JSX
- Inline-Styles bevorzugt, keine externen CSS-Dateien
- Keine neuen npm-Pakete ohne Absprache
## Komponenten-Struktur:
```jsx
function MeineKomponente({ prop1, prop2 }) {
const [state, setState] = useState(null)
return (
<div className="card" style={{padding:16}}>
...
</div>
)
}
```
## Vorhandene CSS-Klassen:
- `.card` weißer Container mit Schatten
- `.btn .btn-primary` grüner Button
- `.btn .btn-secondary` grauer Button
- `.btn-full` volle Breite
- `.form-input` Eingabefeld
- `.form-label` Label
- `.form-row` Label + Input + Unit nebeneinander
- `.section-gap` vertikaler Abstand
- `.spinner` Ladeindikator
## API-Calls:
- Immer über `import { api } from '../utils/api'`
- Nie direktes `fetch()` verwenden
- Token wird automatisch injiziert

View File

@ -0,0 +1,59 @@
# UI Page
Erstelle eine neue vollständige Seite für Mitai Jinkendo.
## Seiten-Struktur:
```jsx
import { useState, useEffect } from 'react'
import { api } from '../utils/api'
import { useAuth } from '../context/AuthContext'
export default function MeineSeite() {
const { session } = useAuth()
const [data, setData] = useState([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
useEffect(() => { load() }, [])
const load = async () => {
try {
setLoading(true)
const result = await api.meinEndpoint()
setData(result)
} catch(e) {
setError(e.message)
} finally {
setLoading(false)
}
}
if (loading) return <div className="spinner"/>
if (error) return <div style={{color:'var(--danger)'}}>{error}</div>
return (
<div style={{padding:'0 0 80px'}}>
{/* Titelzeile */}
<div style={{display:'flex',alignItems:'center',
justifyContent:'space-between',marginBottom:20}}>
<div style={{fontSize:20,fontWeight:700}}>Seitentitel</div>
</div>
{/* Inhalt */}
</div>
)
}
```
## Navigation einbinden:
In `App.jsx` unter den bestehenden Routen hinzufügen.
## Backend-Endpoint:
Neuen Endpoint in `backend/main.py` mit:
```python
@app.get("/api/mein-endpoint")
def mein_endpoint(session: dict = Depends(require_auth)):
pid = session['profile_id']
with get_db() as conn:
...
```

View File

@ -0,0 +1,121 @@
# UI Responsive
Mache die App vollständig responsive Mobile, Tablet und Desktop.
## Ziel-Design
```
iPhone (<768px): Bottom Navigation, volle Breite (wie jetzt)
iPad (768-1024px): Bottom Navigation, 2-spaltige Cards
Desktop (>1024px): Sidebar Navigation links, Content rechts, volle Breite
```
## Wichtige Regel:
**Erst planen, dann umsetzen.** Zeige den Plan und warte auf Bestätigung.
## Schritt 1: Analyse
Analysiere folgende Dateien:
- `frontend/src/app.css` aktuelle CSS-Variablen und globale Styles
- `frontend/src/App.jsx` Navigation und Layout-Struktur
- `frontend/src/pages/Dashboard.jsx` repräsentative Seite
## Schritt 2: Plan vorlegen
Zeige:
1. Welche CSS-Breakpoints werden eingeführt
2. Wie ändert sich die Navigation (Bottom ? Sidebar)
3. Welche Komponenten müssen angepasst werden
4. Geschätzter Aufwand
## Schritt 3: CSS-Variablen und Breakpoints
Neue Breakpoints in `app.css`:
```css
/* Breakpoints */
--bp-mobile: 768px;
--bp-tablet: 1024px;
/* Layout */
--sidebar-width: 220px;
--content-max-width: 1200px;
```
## Schritt 4: Layout-Komponente erstellen
Neue Datei `frontend/src/components/AppLayout.jsx`:
```jsx
// Erkennt Screen-Größe und rendert:
// - Mobile/Tablet: Bottom Navigation (wie jetzt)
// - Desktop: Sidebar Navigation + Content-Bereich
```
## Schritt 5: Navigation anpassen
**Mobile (wie jetzt):**
```jsx
<nav style={{position:'fixed', bottom:0, ...}}>
{navItems}
</nav>
```
**Desktop (neu):**
```jsx
<aside style={{
position:'fixed', left:0, top:0,
width:'var(--sidebar-width)',
height:'100vh',
background:'var(--surface)',
borderRight:'1px solid var(--border)'
}}>
{/* Logo */}
{/* Nav Items vertikal */}
{/* User Info unten */}
</aside>
<main style={{
marginLeft:'var(--sidebar-width)',
padding:'24px',
minHeight:'100vh'
}}>
{children}
</main>
```
## Schritt 6: Cards responsiv machen
```css
/* Mobile: 1 Spalte */
.metric-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
/* Desktop: 4 Spalten */
@media (min-width: 1024px) {
.metric-grid {
grid-template-columns: repeat(4, 1fr);
}
}
```
## Schritt 7: Testen
```bash
# Frontend build testen
cd frontend && npm run build
```
Browser-Test auf:
- iPhone (375px) Safari
- iPad (768px) Browser DevTools
- Desktop (1440px) Browser normal
## Jinkendo Design-Regeln beibehalten:
- Farben: var(--accent) #1D9E75, var(--bg), var(--surface)
- Border-Radius: 12px Cards, 8px Buttons
- Keine externen CSS-Frameworks
- Inline-Styles + globale CSS-Variablen
- PWA auf iPhone muss weiterhin funktionieren
## Nach dem Umbau:
- Commit mit `feat: responsive layout sidebar on desktop`
- Push auf develop
- Testen auf dev.mitai.jinkendo.de auf verschiedenen Screens
- Erst nach Freigabe: /merge-to-prod

242
.claude/docs/BACKLOG.md Normal file
View File

@ -0,0 +1,242 @@
# Mitai Jinkendo Feature Backlog
Vollständige Übersicht aller geplanten Features nach Versionen.
**Dokumentationsstruktur:**
- 📚 `functional/` - Fachliche Specs (WAS wird gebaut)
- 📚 `technical/` - Technische Specs (WIE wird es gebaut)
- 🎯 **Konkrete Tasks & Issues** → [Gitea Issues](http://192.168.2.144:3000/Lars/mitai-jinkendo/issues)
- 📋 **Strategische Planung**`ROADMAP.md`
**Aktueller Fokus:** v9d → v9e Transition (Ruhetage abgeschlossen, Vitalwerte in Arbeit, Entwicklungsrouten vorbereiten)
---
## v9c Membership & Subscription ✅ KOMPLETT
📚 **Specs:** `technical/MEMBERSHIP_SYSTEM.md` (kombiniert fachlich + technisch)
**Deployed:** 21. März 2026 (Production)
### Features
- ✅ Feature-Enforcement-System (4-Phasen-Modell)
- ✅ Selbst-Registrierung mit E-Mail-Verifizierung
- ✅ Trial-System UI (Countdown-Banner mit 3 Urgency-Level)
- ✅ Tier-basiertes Zugriffsmanagement
- ✅ Coupons & Access-Grants
- ✅ Usage-Badges in allen relevanten Screens
**Bugfixes v9c:**
- ✅ BUG-001: TypeError in `/api/nutrition/weekly` (datetime.date handling)
- ✅ BUG-002: Ernährungs-Daten Tab fehlte
- ✅ BUG-003: Korrelations-Chart Extrapolation (gestrichelte Linien)
- ✅ BUG-004: Import-Historie Refresh (Force remount)
- ✅ BUG-005: Login → leere Seite
- ✅ BUG-006: Email-Verifizierung → leere Seite
- ✅ BUG-007: Doppelklick Verifizierungslink → generischer Fehler
- ✅ BUG-008: Dashboard infinite loading bei API-Fehlern
---
## v9d Schlaf + Sport-Vertiefung
📚 **Specs:**
- `functional/SLEEP_MODULE.md` (Schlaf-Tracking)
- `functional/TRAINING_TYPES.md` (Trainingstypen + Abilities)
- `functional/DEVELOPMENT_ROUTES.md` (Routen-System, später v9e)
**Status:** 🟡 In Arbeit (Deployed: Schlaf, Trainingstypen, Ruhetage, Vitalwerte | Offen: HF-Zonen)
### Phase 1: Trainingstypen ✅ DEPLOYED (21.03.2026)
- ✅ 29 Trainingstypen in 7 Kategorien
- ✅ Lernendes Mapping-System (DB-basiert, Auto-Learning)
- ✅ 40+ Standard-Mappings (Deutsch + Englisch)
- ✅ Admin-UI für Trainingstypen-CRUD
- ✅ Admin-UI für Activity-Mappings (inline editing)
- ✅ TrainingTypeDistribution Chart in History
- ✅ Bulk-Kategorisierung (selbstlernend)
- ✅ Apple Health Import mit automatischem Mapping
### Phase 2a: Ruhetage ✅ DEPLOYED (23.03.2026)
- ✅ Multi-Dimensional Rest Days (Kraft, Cardio, Entspannung)
- ✅ Quick Mode Presets + Custom Entry
- ✅ Validierung gegen geplante Aktivitäten
- ✅ Dashboard Widget mit aktuellen Ruhetagen
- ✅ Multiple Rest Types pro Date
### Phase 2b: Schlaf-Modul ✅ DEPLOYED (23.03.2026)
- ✅ sleep_log Tabelle mit JSONB sleep_segments
- ✅ Schlafphasen (Deep, REM, Light, Awake)
- ✅ Apple Health CSV Import
- ✅ Schlaf-Statistiken & Trends
- ✅ Schlafschuld-Berechnung
### Phase 2d: Vitalwerte ✅ DEPLOYED (23.03.2026)
- ✅ **3-Tab Architektur:** Baseline (morgens) / Blutdruck (mehrfach täglich) / Import
- ✅ **Baseline Vitals:** Ruhepuls, HRV, VO2 Max, SpO2, Atemfrequenz
- ✅ **Blutdruck:** Systolisch/Diastolisch + Puls, WHO/ISH-Klassifizierung
- ✅ **Context-Tagging:** 8 Kontexte (nüchtern, nach Essen, Training, Stress, etc.)
- ✅ **Inline-Editing:** Alle Messungen direkt in der Liste bearbeitbar
- ✅ **Smart Upsert:** Baseline lädt existierende Einträge automatisch
- ✅ **CSV Import:** Omron (Deutsch) + Apple Health (Deutsch/Englisch)
- ✅ **Mobile-optimiert:** Volle Breite Felder, Sektions-Überschriften
- ✅ Unregelmäßiger Herzschlag & AFib-Warnungen
- ✅ Trend-Analyse (7d/14d/30d)
### Phase 2e: HF-Zonen + Erholung 🔲 OFFEN
- 🔲 HF-Zonen-Verteilung pro Training
- 🔲 Recovery Score basierend auf Ruhepuls + HRV + Schlaf
- 🔲 Übertraining-Warnung
**Migrations:**
- ✅ 004: training_types Tabelle + 23 Basis-Typen
- ✅ 005: Extended types (Gehen, Tanzen, Geist & Meditation)
- ✅ 006: abilities JSONB column (Platzhalter für v9f)
- ✅ 007: activity_type_mappings (lernendes System)
- ✅ 010: sleep_log Tabelle (JSONB segments)
- ✅ 011: rest_days Tabelle
- ✅ 012: Unique constraint rest_days
- ✅ 015: Vitals Refactoring (vitals_baseline + blood_pressure_log)
**Bugfixes v9d (23.03.2026):**
- ✅ Import-Zählung korrigiert (skipped vs. updated)
- ✅ Deutsche Spaltennamen für CSV-Imports
- ✅ Dezimalwerte-Parsing (safe_int/safe_float)
- ✅ Error-Details in Import-Response
---
## v9e Entwicklungsrouten & Wochenplanung ⭐ NEU
📚 **Specs:** `functional/DEVELOPMENT_ROUTES.md`
**Status:** 🔲 Geplant (Spezifikation vorhanden, nach v9d Phase 2)
### Geplante Features
- 🔲 **6 Entwicklungsrouten:** Kraft, Kondition, Mental, Koordination, Mobilität, Technik
- 🔲 Activity-Types → Routen-Zuordnung (training_types.route Spalte)
- 🔲 Multi-Route Rest Day Validation (Konflikt-Check für alle Routen)
- 🔲 Wochenplanung: Routen-basierte Soll/Ist-Übersicht
- 🔲 Regel-Engine: Auto-Ruhetag bei Poor Recovery
- 🔲 Dashboard: Route-Balance Widget
**Tracking:** Siehe [Gitea Milestone v9e](http://192.168.2.144:3000/Lars/mitai-jinkendo/milestones)
---
## v9f Ziele & KI-Prompts
📚 **Specs:**
- `functional/GOALS_VITALS.md` (Ziele-System)
- `functional/AI_PROMPTS.md` (KI-Prompt-Flexibilisierung)
**Status:** 🔲 Geplant (nach Phase 0 Infrastruktur)
### Ziele-System
- 🔲 Primärziele (Gewichtsabnahme, Muskelaufbau, Kondition, Wettkampf)
- 🔲 Ziel-spezifische Dashboard-Ansicht
- 🔲 Fortschrittsbalken & Prognose (lineare Regression)
- 🔲 KI-Integration: Ziel-Abgleich & Handlungsempfehlungen
### KI-Prompt Flexibilisierung
- 🔲 Prompt-Bibliothek mit Kategorien
- 🔲 Platzhalter-Browser (kategorisiert + Beispielwerte)
- 🔲 Prompt-Vorschau mit echten Daten
- 🔲 Pipeline konfigurierbar (Module, Gewichtung, Zeitraum)
- 🔲 Mehrere Pipeline-Konfigurationen speichern
### Vitalwerte erweitert
- 🔲 Erweiterte Vitalwerte (SpO2, Körpertemperatur, Atemfrequenz) - teilweise in v9d implementiert
- 🔲 Hydration-Tracking
- 🔲 Medikamenten-Tracking
**Tracking:** Siehe ROADMAP.md Phase 0-2
---
## v9g Habits & Meditation
📚 **Specs:**
- `functional/MEDITATION.md` (Meditation & Selbstwahrnehmung)
- `functional/DEVELOPMENT_ROUTES.md` (Habits pro Route)
**Status:** 🔲 Geplant (Spezifikation vorhanden)
### Geplante Features
- 🔲 **Habits pro Entwicklungsroute** (route_habits Tabelle)
- 🔲 Streak-Tracking pro Route (z.B. Mental: Meditation 🔥12 Tage)
- 🔲 Dashboard: Route-Habits Widget
- 🔲 Täglicher Check-in (Energie, Stimmung, Stress 1-5)
- 🔲 Meditationssessions erfassen (Dauer, Art)
- 🔲 Journal (Freitext täglich)
- 🔲 Korrelations-Analysen (Meditation ↔ Stresslevel, Schlafqualität)
- 🔲 → Basis für **miken.jinkendo.de** (Meditations-App)
**Tracking:** Siehe [Gitea Milestone v9g](http://192.168.2.144:3000/Lars/mitai-jinkendo/milestones)
---
## v9h Connectoren & Gamification
**Status:** 🔲 Konzept (keine Spezifikation vorhanden)
### Geplante Features
- 🔲 OAuth2-Grundgerüst
- 🔲 Strava, Withings, Garmin Integration
- 🔲 Bonus-System (Streaks → Punkte → Coupons)
- 🔲 Stripe-Integration (Zahlungsabwicklung)
---
## Responsive UI (parallel zu allen Versionen)
📚 **Specs:** `functional/RESPONSIVE_UI.md`
**Status:** 🔲 Geplant (parallel implementierbar)
### Geplante Features
- 🔲 Desktop: Sidebar Navigation
- 🔲 Tablet: 2-spaltige Cards
- 🔲 Mobile: Bottom Navigation (bleibt wie jetzt)
- 🔲 **Admin-Bereich separieren** (eigene Route `/admin`, nur für Admins)
- Tab-basierte Struktur: Benutzerverwaltung, Feature-Limits, System-Settings, Coupons, AI-Prompts
- Settings-Page: Nur noch persönliche Einstellungen
**Tracking:** Siehe [Gitea Issues mit Label "responsive"](http://192.168.2.144:3000/Lars/mitai-jinkendo/issues?labels=responsive)
---
## UX-Verbesserungen & Quick Wins
**Status:** Verschiedene kleine Verbesserungen, siehe Gitea Issues
**Beispiele:**
- Keyboard Shortcuts (Enter für Submit, Esc für Cancel)
- Toast-Notifications statt confirm() Dialoge
- Loading-States bei langsamen API-Calls
- Mehrere Fotos pro Tag hochladen (aktuell nur 1 Foto/Tag)
- Fotos löschbar machen (aktuell keine Delete-Funktion)
📋 **Tracking:** [Gitea Issues mit Label "ux" oder "quick-win"](http://192.168.2.144:3000/Lars/mitai-jinkendo/issues?labels=ux,quick-win)
---
## Versions-Übersicht (Zusammenfassung)
| Version | Status | Kernfeatures | Deployed |
|---------|--------|--------------|----------|
| **v9c** | ✅ KOMPLETT | Membership, Feature-Enforcement, Trial-System | 21.03.2026 |
| **v9d** | 🟡 In Arbeit | Schlaf, Trainingstypen, Ruhetage, Vitalwerte | 23.03.2026 (partial) |
| **v9e** | 🔲 Geplant | Development Routes, Wochenplanung | TBD |
| **v9f** | 🔲 Geplant | Ziele, KI-Prompts, Charts | TBD |
| **v9g** | 🔲 Geplant | Habits, Meditation, Streaks | TBD |
| **v9h** | 🔲 Konzept | Connectoren, Gamification, Stripe | TBD |
---
**Dokumentiert:** 23. März 2026 (Initial) · 24. März 2026 (Konsolidiert)
**Tracking:**
- Konkrete Issues → [Gitea](http://192.168.2.144:3000/Lars/mitai-jinkendo/issues)
- Feature-Specs → `.claude/docs/functional/*.md`
- Strategische Planung → `ROADMAP.md`
- Versions-Übersicht → Diese Datei

View File

@ -0,0 +1,374 @@
# Dokumentations-Bereinigung & Struktur-Konzept
**Erstellt:** 2026-03-23
**Ziel:** Redundanzen entfernen, klare Trennung zwischen Gitea (Tracking) und Docs (Spezifikationen)
---
## Problem-Analyse
### Aktuelle Situation
**Planungs-/Tracking-Dokumente (.claude/docs/):**
- `BACKLOG.md` (~138 Zeilen) - Feature-Übersicht v9c-v9h
- `ROADMAP.md` (~414 Zeilen) - Detaillierte Phasenplanung (Phase 0-3, Issues #24-#30)
- `KNOWN_ISSUES.md` (~100+ Zeilen) - Bug-Tracking (BUG-009, BUG-003, etc.)
- `PENDING_FEATURES.md` (~50+ Zeilen) - Feature-Enforcement-TODOs
- `TODO_V9D_PHASE2.md` - Spezifische Phase-2-TODOs
- `ISSUES_TO_CREATE.md` - Temporär (Issues bereits erstellt)
- `.claude/feature-requests/logout-button-header.md` - Einzelner Feature Request
**Spezifikationen:**
- `functional/` - SLEEP_MODULE.md, TRAINING_TYPES.md, DEVELOPMENT_ROUTES.md, etc.
- `technical/` - MEMBERSHIP_SYSTEM.md, DATABASE.md, ARCHITECTURE.md, etc.
- `architecture/` - FEATURE_ENFORCEMENT.md
- `rules/` - ARCHITECTURE.md, CODING_RULES.md, LESSONS_LEARNED.md
### Redundanzen & Probleme
1. **Doppeltes Tracking:**
- ROADMAP.md enthält Issues #24-#30
- Diese sollten primär in Gitea sein
- ROADMAP.md enthält außerdem strategische Planung (Phase 0-3)
2. **Bug-Tracking außerhalb Gitea:**
- KNOWN_ISSUES.md dokumentiert Bugs
- BUG-009 ist offen, sollte als Gitea-Issue existieren
3. **Feature-Requests verstreut:**
- BACKLOG.md listet große Features
- PENDING_FEATURES.md listet TODOs
- .claude/feature-requests/ hat einzelne Requests
- Unklare Prioritäten
4. **TODOs ohne Kontext:**
- TODO_V9D_PHASE2.md ist phasenspezifisch
- Nach Phase-Abschluss veraltet
5. **Temporäre Dateien:**
- ISSUES_TO_CREATE.md (bereits erledigt, kann weg)
---
## Vorgeschlagene Struktur
### Prinzip: Gitea für Tracking, Docs für Spezifikationen
```
┌─────────────────────────────────────────────────────────────┐
│ GITEA ISSUES │
│ (Primäres Tracking für Tasks, Bugs, kleine Features) │
├─────────────────────────────────────────────────────────────┤
│ - Konkrete implementierbare Tasks │
│ - Bugs (BUG-001, BUG-002, ...) │
│ - Kleine Features (≤ 1 Tag Aufwand) │
│ - Phase-Tasks (#24-#30) │
│ - Technical Debt (#32-#35) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ .claude/docs/functional/ │
│ (Fachliche Spezifikationen für große Features) │
├─────────────────────────────────────────────────────────────┤
│ - SLEEP_MODULE.md (v9d) │
│ - TRAINING_TYPES.md (v9d) │
│ - DEVELOPMENT_ROUTES.md (v9e) │
│ - MEDITATION.md (v9g) │
│ - AI_PROMPTS.md (v9f) │
│ - GOALS_VITALS.md (v9f) │
│ - RESPONSIVE_UI.md │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ .claude/docs/technical/ │
│ (Technische Spezifikationen & Referenz-Dokumentation) │
├─────────────────────────────────────────────────────────────┤
│ - ARCHITECTURE.md (System-Übersicht) │
│ - FRONTEND.md (Seiten, Komponenten, API-Integration) │
│ - AUTH.md (Auth-Flow, Sicherheit) │
│ - API_REFERENCE.md (Alle Endpoints) │
│ - DATABASE.md (Schema, Tabellen) │
│ - MEMBERSHIP_SYSTEM.md (v9c Membership) │
│ - MIGRATIONS.md (falls vorhanden) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ .claude/docs/ (Root-Level Meta-Dokumentation) │
├─────────────────────────────────────────────────────────────┤
│ - README.md (Dokumentations-Index + Konventionen) │
│ - CONTRIBUTING.md (Entwickler-Onboarding) │
│ - CHANGELOG.md (Versions-Historie, generiert aus git) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ .claude/rules/ │
│ (Verbindliche Entwicklungsregeln) │
├─────────────────────────────────────────────────────────────┤
│ - ARCHITECTURE.md (Architektur-Regeln, Versionierung) │
│ - CODING_RULES.md (Code-Standards) │
│ - LESSONS_LEARNED.md (Fehler, die nicht wiederholt werden) │
└─────────────────────────────────────────────────────────────┘
```
---
## Konkrete Bereinigungsaktionen
### 1. LÖSCHEN (Redundant oder temporär)
| Datei | Grund | Aktion |
|-------|-------|--------|
| `ISSUES_TO_CREATE.md` | Temporär, Issues bereits erstellt (#32-#35) | **DELETE** |
| `TODO_V9D_PHASE2.md` | Phasenspezifisch, veraltet nach Abschluss | **DELETE** (oder archivieren) |
| `.claude/feature-requests/logout-button-header.md` | Einzelner Request, gehört in Gitea | **→ Gitea Issue, dann DELETE** |
### 2. MIGRIEREN zu Gitea Issues
| Quelle | Inhalt | Ziel-Aktion |
|--------|--------|-------------|
| `KNOWN_ISSUES.md` | BUG-009 (offen) | **→ Gitea Issue #36** (Bug) |
| `KNOWN_ISSUES.md` | BUG-003 (behoben) | **→ Archiv oder DELETE** (bereits behoben) |
| `PENDING_FEATURES.md` | Feature-Enforcement TODOs | **→ Gitea Issues #37-#39** (enhancement) |
| `feature-requests/logout-button-header.md` | Logout-Button Request | **→ Gitea Issue #40** (Quick Win) |
### 3. KONSOLIDIEREN
#### 3.1. ROADMAP.md → Aufteilen
**Problem:** Enthält sowohl strategische Planung als auch konkrete Issues
**Lösung:**
**BEHALTEN in ROADMAP.md (strategisch):**
- Phase-Übersicht (Phase 0-3)
- Meilensteine (M0.1-M3.x)
- Abhängigkeiten-Graph
- Timeline (KW-Planung)
- Risiken & Mitigationen
- Erfolgsmetriken
**MIGRIEREN zu Gitea (operativ):**
- Konkrete Issue-Beschreibungen (#24-#30) → Gitea Issues (bereits vorhanden?)
- Aufwands-Schätzungen → in Gitea Issue-Feldern
- Checklisten → in Gitea Issue-Beschreibungen
**RESULTAT:** ROADMAP.md wird zum strategischen Phasenplan (ohne Issue-Details)
#### 3.2. BACKLOG.md → Reduzieren
**Problem:** Mischung aus Feature-Übersicht und TODO-Listen
**Lösung:**
**BEHALTEN in BACKLOG.md:**
- Version-Übersicht (v9c-v9h Features)
- Links zu functional/-Specs
- Status-Übersicht (✅ KOMPLETT, 🟡 In Arbeit, 🔲 Geplant)
**ENTFERNEN aus BACKLOG.md:**
- Detaillierte Checklisten (gehören in Gitea Issues)
- "Offene Issues" Listen (primär in Gitea)
- Quick Wins (→ Gitea mit Label "quick-win")
**RESULTAT:** BACKLOG.md wird zum Feature-Katalog (Verweis auf Specs + Gitea)
#### 3.3. KNOWN_ISSUES.md → Archivieren oder löschen
**Vorschlag 1 (empfohlen):** DELETE
- Aktive Bugs → Gitea Issues
- Behobene Bugs → git commit messages + CHANGELOG.md
- Lessons Learned → `.claude/rules/LESSONS_LEARNED.md`
**Vorschlag 2:** Archivieren
- Umbenennen zu `KNOWN_ISSUES_ARCHIVE.md`
- Nur für Referenz (nicht aktiv gepflegt)
#### 3.4. PENDING_FEATURES.md → DELETE
**Grund:** Feature-Enforcement-TODOs sind konkrete Tasks
**Aktion:**
1. TODOs in Gitea Issues überführen (#37-#39)
2. Datei löschen
---
## Gitea Issues erstellen (aus existierenden Docs)
### Aus KNOWN_ISSUES.md
**#36: BUG-009 - Trainingstyp-Erstellung führt zu Internal Server Error**
- Priorität: High
- Label: bug, admin
- Aufwand: 1-2h
### Aus PENDING_FEATURES.md
**#37: Feature-Enforcement für Activity CSV-Import**
- Priorität: Medium
- Label: enhancement, feature-enforcement
- Aufwand: 2-3h
**#38: Feature-Enforcement für Nutrition CSV-Import UI**
- Priorität: Low
- Label: enhancement, feature-enforcement, ui
- Aufwand: 1h
**#39: Usage-Badges im Dashboard-Assistenten**
- Priorität: Low
- Label: enhancement, ux
- Aufwand: 1-2h
### Aus feature-requests/
**#40: Logout-Button im App-Header (neben Avatar)**
- Priorität: Low
- Label: quick-win, ux
- Aufwand: 15min
---
## Vorgeschlagene Konventionen
### Was gehört in Gitea Issues?
✅ **JA:**
- Bugs (alle Prioritäten)
- Konkrete implementierbare Tasks (≤ 5 Tage Aufwand)
- Quick Wins (≤ 1h Aufwand)
- Technical Debt Items
- Phase-spezifische Tasks (#24-#30)
- Refactorings
❌ **NEIN:**
- Große Feature-Pakete (v9e, v9f, v9g) → bleiben in functional/-Specs
- Strategische Planung (Phasen, Meilensteine) → bleibt in ROADMAP.md
- Architektur-Entscheidungen → bleiben in technical/-Docs
- Lessons Learned → bleiben in rules/LESSONS_LEARNED.md
### Was gehört in functional/-Specs?
✅ **Große Feature-Pakete (> 5 Tage Aufwand):**
- SLEEP_MODULE.md (v9d Phase 2b)
- TRAINING_TYPES.md (v9d Phase 1)
- DEVELOPMENT_ROUTES.md (v9e)
- AI_PROMPTS.md (v9f)
- MEDITATION.md (v9g)
**Format:**
- Fachliche Anforderungen (WAS wird gebaut)
- User Stories
- Use Cases
- Datenmodell (Konzept)
- UI-Mockups (optional)
- Verweis auf Gitea Epic/Milestone
### Was gehört in technical/-Specs?
✅ **Referenz-Dokumentation & Implementierungsdetails:**
- ARCHITECTURE.md (System-Übersicht)
- DATABASE.md (Schema-Referenz)
- API_REFERENCE.md (Endpoint-Katalog)
- Modul-spezifische Docs (MEMBERSHIP_SYSTEM.md)
**Format:**
- Technische Entscheidungen (WIE wird es gebaut)
- API-Spezifikationen
- Datenbank-Schema
- Code-Beispiele
- Design-Patterns
---
## Migrations-Plan
### Phase 1: Gitea Issues erstellen (1h)
1. **BUG-009** → Gitea Issue #36
2. **PENDING_FEATURES TODOs** → Gitea Issues #37-#39
3. **Logout-Button Request** → Gitea Issue #40
### Phase 2: Dokumentation bereinigen (30min)
1. **DELETE:**
- `ISSUES_TO_CREATE.md`
- `TODO_V9D_PHASE2.md`
- `.claude/feature-requests/logout-button-header.md`
- `KNOWN_ISSUES.md`
- `PENDING_FEATURES.md`
2. **KONSOLIDIEREN:**
- `ROADMAP.md` → Entferne Issue-Details, behalte Strategie
- `BACKLOG.md` → Entferne Checklisten, behalte Feature-Katalog
### Phase 3: README.md erstellen (30min)
**Datei:** `.claude/docs/README.md`
**Inhalt:**
- Dokumentations-Index (Was finde ich wo?)
- Konventionen (Gitea vs. Docs)
- Wie lege ich Issues an?
- Wie erstelle ich Spezifikationen?
---
## Ergebnis nach Bereinigung
### Datei-Reduktion
**Vorher:**
- 7 Tracking-Dokumente (.claude/docs/)
- 1 Feature-Request-Datei
- ~700+ Zeilen redundante Informationen
**Nachher:**
- 2 Meta-Dokumente (ROADMAP.md, BACKLOG.md) - deutlich schlanker
- 1 README.md (Dokumentations-Index)
- ~5-7 Gitea Issues (primäres Tracking)
### Klare Trennung
```
Gitea Issues (Tracking)
Konkrete Tasks, Bugs, Quick Wins
Labels: bug, enhancement, quick-win
Aufwand: ≤ 5 Tage
.claude/docs/functional/ (Spezifikationen)
Große Feature-Pakete (> 5 Tage)
Format: Fachliche Anforderungen
Verweis auf Gitea Epic/Milestone
.claude/docs/technical/ (Referenz)
Implementierungsdetails
Format: Technische Spezifikationen
Generiert/aktualisiert nach Implementierung
.claude/rules/ (Regeln)
Verbindliche Entwicklungsstandards
Format: Architektur-Regeln, Code-Standards
```
---
## Nächste Schritte
1. **Review:** User-Zustimmung zu diesem Plan einholen
2. **Gitea:** Issues #36-#40 anlegen
3. **Cleanup:** Dateien löschen/konsolidieren
4. **README:** `.claude/docs/README.md` erstellen
5. **ROADMAP/BACKLOG:** Kürzen auf strategische Infos
6. **Commit:** "docs: cleanup and consolidate documentation structure"
---
**Frage an User:**
- Sollen große Feature-Pakete (v9e, v9f, v9g) als Gitea **Milestones** angelegt werden?
- Pro: Alle Tasks/Issues zuordenbar
- Contra: Specs bleiben trotzdem in functional/
- **Empfehlung:** Ja, Milestones in Gitea + Verweis in functional/-Specs

View File

@ -0,0 +1,109 @@
# Gitea Issues Landkarte (Auswertung)
**Quelle:** Gitea `Lars/mitai-jinkendo`, Stand **2026-04-11** (Abfrage `state=all`, ergänzt: #71, #76).
**URL:** http://192.168.2.144:3000/Lars/mitai-jinkendo/issues
Dieses Dokument ist ein **Orientierungs-Index** für Agenten und Entwickler. Verbindliches Tracking bleibt **in Gitea**; hier: Kategorien, Dubletten-Hinweise, grobe Prioritätseinschätzung.
---
## Kurzdiagnose
- **Offene Issues (Stand Abfrage):** 28
- **Auffällig:** mehrere **titelgleiche oder nahezu gleiche** Einträge (z.B. Body Cluster, Placeholder Registry, Debug UI) in Gitea konsolidieren oder schließen.
- **#25 „Ziele-System“** wahrscheinlich **veraltet** (laut Projektstatus Goals/Focus bereits fortgeschritten) mit Produkt-Owner abgleichen und schließen oder umbenennen.
---
## Offene Issues nach Thema
### Architektur / Plattform
| # | Titel |
|---|--------|
| 68 | Architektur: durchgängige Feature-/Entitlement-Schicht (Ist → Zielbild, Phasen) |
| 32 | Version-System: /api/version, Frontend, main.py-Konsistenz |
| 34 | External Volumes dokumentieren (bodytrack_* Legacy-Cleanup) |
| 35 | Deprecated Tabelle „subscriptions“ entfernen |
### Dashboard & Widgets
| # | Titel |
|---|--------|
| 65 | Dashboard: Nutzer-konfigurierbare Übersicht (Widget-System, Persistenz, Standard-Reset) |
| 66 | Dashboard-Widgets: Feature-Gate-Zuordnung aus Admin/DB statt hardcodiertem Katalog |
| 39 | Usage-Badges im Dashboard-Assistenten |
### KI / Prompts / Transparenz
| # | Titel |
|---|--------|
| 49 | Feature: Prompt-Zuordnung zu Verlaufsseiten |
| 45 | Feature: KI Prompt-Optimierer |
| 46 | Feature: KI Prompt-Ersteller (Guided Creator) |
| 42 | Enhanced Debug/Prompt Analysis UI (Issue #28 Phase C) |
| 43 | Enhanced Debug/Prompt Analysis UI (Issue #28 Phase C) |
| 47 | Enhancement: Wertetabelle Optimierung |
### Placeholder / Registry
| # | Titel |
|---|--------|
| 54 | Placeholder Registry: UNRESOLVED & TO_VERIFY Metadaten prüfen |
| 55 | Placeholder Registry: UNRESOLVED & TO_VERIFY Metadaten prüfen |
### Data / Body / Cluster (Dubletten)
| # | Titel |
|---|--------|
| 56 | Body Cluster - Restarbeiten & Metadaten-Verifizierung |
| 57 | Body Cluster - Restarbeiten & Metadaten-Verifizierung |
| 58 | Body Cluster - Restarbeiten & Metadaten-Verifizierung |
### Frontend / UX
| # | Titel |
|---|--------|
| 30 | [FEAT] Responsive UI - Desktop Sidebar + 2-spaltige Layouts |
| 29 | [FEAT] Abilities-Matrix UI (v9f) |
| 40 | Logout-Button im App-Header (neben Avatar) |
| 26 | [FEAT] Charts & Visualisierungen erweitern |
| 27 | [FEAT] Korrelationen & Insights erweitern |
### Ziele / Product (prüfen)
| # | Titel |
|---|--------|
| 25 | [FEAT] Ziele-System (Goals) - v9e Kernfeature |
### Feature-Enforcement / Import
| # | Titel |
|---|--------|
| 37 | Feature-Enforcement für Activity CSV-Import |
| 38 | Feature-Enforcement für Nutrition CSV-Import UI |
### Qualität / Sonstiges
| # | Titel |
|---|--------|
| 15 | [FEAT-002] Quality-Filter für KI-Auswertungen & Charts integrieren |
| 76 | Trainings-Qualität: zielbezogene Logik + Listen-Filter statt globalem „Hochwertig“-Hide |
| 36 | BUG-009: Trainingstyp-Erstellung führt zu Internal Server Error |
---
## Geschlossene Bereiche (Referenz, Auszug)
Bereits geschlossen u.a.: #28 AI-Prompts Flexibilisierung, #24 Quality-Filter (Variante), #48 Flexibles Prompt-System, #50/#51 Goals, #53 Goals/Platzhalter/Data Layer (laut Titel), #60 Platzhalter Ernährung/Körper/Aktivität, diverse Releases.
---
## Pflege
- Nach größeren Issue-Aufräumaktionen: diese Datei **aktualisieren** oder Datum im Kopf erhöhen.
- Dubletten (#42/#43, #54/#55, #56#58): in Gitea **zusammenführen** (ein Issue offen lassen).
---
**Ende Index**

186
.claude/docs/README.md Normal file
View File

@ -0,0 +1,186 @@
# Mitai Jinkendo Dokumentations-Index
Willkommen zur Entwicklerdokumentation von **Mitai Jinkendo** (身体 Jinkendo).
**Parallel im Repository:** Issue-Epics und Placeholder-Governance im Projekt-[`docs/`](../../docs/) · siehe [`docs/README.md`](../../docs/README.md).
**Ablage-Regeln:** [`.claude/rules/DOCUMENTATION.md`](../rules/DOCUMENTATION.md) · **Issue-Landkarte:** [`GITEA_ISSUES_INDEX.md`](./GITEA_ISSUES_INDEX.md).
_Dieser Ordner `.claude/docs/` ist per `.gitignore`-Ausnahme **versioniert** (Specs + Regeln)._
---
## Dokumentationsstruktur (Ist-Stand)
```
.claude/docs/
├── README.md ← Index (diese Datei)
├── GITEA_ISSUES_INDEX.md ← Themen-Landkarte zu Gitea (lokal gepflegt)
├── BACKLOG.md ← Feature-Katalog nach Versionen
├── ROADMAP.md ← Strategische Phasen (03)
├── CLEANUP_PLAN.md ← Historie Bereinigung März 2026
├── prompts/ ← Exportierte Prompt-Artefakte (JSON)
├── functional/ ← Fachliche Spezifikationen (WAS)
├── technical/ ← Technische Spezifikationen & Referenz (WIE)
├── working/ ← Arbeitspapiere, Analysen, Session-Snapshots
├── architecture/ ← Querschnitt: Backend/Frontend/Enforcement (kompakt)
└── audit/ ← Audits, Matrizen, Gitea-Vorlagen
```
**Externes Tracking:** [Gitea Issues](http://192.168.2.144:3000/Lars/mitai-jinkendo/issues)
**Erzeugte Library (Kurzreferenz, ggf. `/document`):** `.claude/library/` API-, DB- und Architektur-Übersichten; bei Abweichungen gewinnt der **Code**, dann **`technical/`** bzw. **`functional/`**.
---
## Rollen der Ordner
| Ordner | Zweck | Pflege |
|--------|--------|--------|
| `functional/` | Domäne, UX, fachliche Datenflüsse | Bei Feature-Änderungen / Abnahme |
| `technical/` | APIs, Migrationen, Implementierungsmuster, Agent-Guides | Nach größeren Code-Änderungen |
| `architecture/` | Kompakte Architektur-Snippets (z.B. Frontend-Struktur, Backend-Überblick) | Bei strukturellen Umbauten |
| `audit/` | Snapshots (Code-Audit, Platzhalter-Reconciliation) **nicht** normative Spec | Nur bei neuen Audits erweitern |
| `working/` | Zwischenstände (Migration, Goals-Analysen, STATUS, NEXT_STEPS, PHASE_0C_TASKS, …) | Archivarisch; keine alleinige Norm |
| Root (`ROADMAP`, `BACKLOG`, `GITEA_ISSUES_INDEX`) | Planung, Katalog, Issue-Landkarte | Mit Gitea / `working/` abstimmen |
---
## Abgleich „Dokument ↔ Code“ (Orientierung)
| Thema | Dokument(e) | Prüfpunkt im Repo |
|--------|-------------|-------------------|
| Data Layer / Charts (Phase 0c) | `functional/DATA_ARCHITECTURE.md`, `technical/DATA_LAYER_EXTENSION_GUIDE.md` | `backend/data_layer/`, `backend/routers/charts.py` |
| Platzhalter / Registry | `technical/PLACEHOLDER_REGISTRY_FRAMEWORK.md`, `technical/PLACEHOLDER_DEVELOPMENT_GUIDE.md` | `backend/placeholder_registrations/`, `backend/placeholder_resolver.py` |
| Dashboard-Widgets | `technical/DASHBOARD_WIDGETS_AGENT_GUIDE.md` | Widget-Katalog + Registrierung (siehe Guide) |
| Training Profiler / Resolver | `technical/TRAINING_PROFILE_RESOLVER_LAYER1.md`, `functional/TRAINING_TYPE_PROFILES.md` | Resolver-Module wie im Guide genannt |
| Universal CSV Import | `technical/UNIVERSAL_CSV_IMPORT_AGENT_GUIDE.md` | `backend/csv_parser/`, `routers/csv_import.py`, `routers/admin_csv_templates.py` |
| Aktivität Produktionsreife | `technical/ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` (+ EAV-Guide) | `backend/data_layer/activity_session_metrics.py`, `activity_metrics.py`, CSV-Orchestrierung |
| Mitgliedschaft / Features | `technical/MEMBERSHIP_SYSTEM.md`, `architecture/FEATURE_ENFORCEMENT.md` | `backend/auth.py`, Feature-Logging, Router mit Enforcement |
---
## Projekt-Übersicht & Regeln (außerhalb dieses Ordners)
| Dokument | Inhalt |
|----------|--------|
| `CLAUDE.md` (Root) | Agent-Kontext, Tech-Stack, kritische Regeln |
| `.claude/rules/ARCHITECTURE.md` | Verbindliche Architektur-Regeln |
| `.claude/rules/CODING_RULES.md` | Code-Standards |
| `.claude/rules/LESSONS_LEARNED.md` | Wiederkehrende Fehler vermeiden |
---
## Fachliche Spezifikationen (`functional/`)
| Dokument | Thema | Hinweis |
|----------|--------|---------|
| `ACTIVITY_QUALITY_GATES.md` | Qualitäts-Gates Aktivität | |
| `AI_PROMPTS.md` | KI-Prompts, Pipeline, Platzhalter (fachlich) | |
| `DATA_ARCHITECTURE.md` | **Fachliche** Datenarchitektur, Domänenflüsse | Schema-Details → `.claude/library/DATABASE.md` |
| `DEVELOPMENT_ROUTES.md` | Entwicklungsrouten (Roadmap-Thema) | |
| `GOALS_VITALS.md` | Ziele & Vitalwerte (fachlich) | |
| `mitai_jinkendo_konzept_diagramme_auswertungen.md` | Konzept Diagramme (ältere Linie) | |
| `mitai_jinkendo_konzept_diagramme_auswertungen_v2.md` | Konzept Diagramme v2 | |
| `PHASE_0B_IMPROVEMENTS.md` | Phase-0b-Verbesserungen | |
| `RESPONSIVE_UI.md` | Responsive Layout-Spec | siehe auch `docs/issues/PHASE_PLAN_RESPONSIVE_UI.md` |
| `SLEEP_MODULE.md` | Schlaf-Modul | |
| `TRAINING_TYPES.md` | Trainingstypen, Mapping | |
| `TRAINING_TYPE_PROFILES.md` | Trainings-Profile (fachlich) | Techn. Ergänzung: `technical/TRAINING_TYPE_PROFILES_TECHNICAL.md` |
---
## Technische Spezifikationen (`technical/`)
| Dokument | Thema |
|----------|--------|
| `AGGREGATION_METHODS.md` | Aggregation |
| `API_REFERENCE.md` | HTTP-API-Katalog |
| `ARCHITECTURE.md` | System-Architektur |
| `AUTH.md` | Authentifizierung |
| `CENTRAL_SUBSCRIPTION_SYSTEM.md` | Abo-Zentralismus |
| `DASHBOARD_WIDGETS_AGENT_GUIDE.md` | Dashboard-Widgets für Agents |
| `DATABASE.md` | DB-Referenz (docs-Kopie; Library kann aktueller sein) |
| `DATABASE_MODEL_COMPLETE.md` | Vollständiges Modell (Referenz) |
| `DATA_LAYER_EXTENSION_GUIDE.md` | Erweiterung Data Layer |
| `FEATURE_ENFORCEMENT_MAPPING.md` | Feature-IDs / Mapping |
| `FRONTEND.md` | Frontend ausführlich (Seiten, Patterns) |
| `INTERNAL_API_REFERENCE.md` | Interne APIs |
| `MEMBERSHIP_SYSTEM.md` | Tiers, Grants, Enforcement-Details |
| `MIGRATIONS.md` | Migrations-Prozess |
| `PLACEHOLDER_DEVELOPMENT_GUIDE.md` | Platzhalter entwickeln |
| `PLACEHOLDER_REGISTRY_FRAMEWORK.md` | Registry-Pflicht, Metadaten |
| `PROFILE_REFERENCE_VALUES.md` | Profil-Referenzwerte |
| `TRAINING_PROFILE_RESOLVER_LAYER1.md` | Training-Resolver Schicht 1 |
| `TRAINING_TYPE_PROFILES_TECHNICAL.md` | Trainingsprofile technisch |
| `UNIVERSAL_CSV_IMPORT_AGENT_GUIDE.md` | Universal CSV: Registry, Executor, Vorlagen, Agent-Checkliste |
| `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md` | Session-Metriken EAV, Attributprofile, Layer-1, Prod-Migration |
| `ACTIVITY_COMPOSITE_METRICS_IMPLEMENTATION_CONCEPT.md` | Composite-Metriken in EAV (JSONB), Archetypen, CSV-Slots, Layer-1-Expand, Migration/Test-Checkliste |
| `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` | **Zielarchitektur** Aktivität (Spine/EAV/Composites/Import/Layer 12) + **Phasenplan AF** Produktionsreife |
| `ACTIVITY_LAYER2A_PLACEHOLDER_AUDIT.md` | Issue #53: Aktivitäts-Platzhalter Layer 1 ↔ 2a (Audit Schritt 1) |
| `ACTIVITY_SCALAR_KANON_TABLE.md` | **Skalar-Kanon** Aktivität (eine Semantik → eine Quelle); Phase A |
| *(Code)* `backend/data_layer/activity_data_canon.py` | **Kanon** activity CSV-Modul vs. EAV-primär; Legacy-Lesefallback |
| `V9D_PHASE2_VITALS_SLEEP.md` | v9d Vitalwerte/Schlaf (Release-Bezug) |
---
## Architektur-Kurzdoks (`architecture/`)
| Dokument | Inhalt |
|----------|--------|
| `BACKEND.md` | Backend-Querschnitt |
| `FEATURE_ENFORCEMENT.md` | 4-Phasen Enforcement |
| `FRONTEND.md` | Strukturbaum `frontend/src` (kompakt) |
*Hinweis:* `architecture/FRONTEND.md` ist die **kurze** Strukturübersicht; Details und Seitenliste stehen in `technical/FRONTEND.md`.
---
## Audit (`audit/`)
Siehe [`audit/README.md`](./audit/README.md).
---
## Gitea vs. Docs
**Prinzip:** Gitea für **Tracking**, Docs für **Spezifikationen** und **Referenz**.
### Gehört in Gitea Issues
- Konkrete Tasks (typisch ≤ wenige Tage), Bugs, Quick Wins, Technical Debt
### Gehört in `functional/`
- Größere Feature-Pakete, Domänenanforderungen, Use Cases, Konzeptdiagramme
### Gehört in `technical/`
- API-, DB- und Implementierungsreferenz, Agent-Leitfäden, Migrations-Details
### Gehört in `ROADMAP.md` / `BACKLOG.md`
- Strategische Phasen bzw. Versions-Katalog mit Links auf Specs und Issues
### Nicht dauerhaft in Docs
- Temporäre To-do-Listen ohne Kontext (→ Issue); reine Duplikate anderer Dateien
---
## Workflow nach Feature-Abschluss
1. Gitea Issue schließen (Commit-Referenz).
2. `BACKLOG.md` / `ROADMAP.md` bei Meilensteinen anpassen.
3. Betroffene `functional/` / `technical/` / `.claude/library/`-Dateien aktualisieren.
4. Bei sichtbaren Agent-Regeln: `CLAUDE.md` ergänzen.
---
## Deployment (Kurzreferenz)
| Umgebung | Frontend | Backend |
|----------|----------|---------|
| Production | Port 3002 | Port 8002 |
| Development | Port 3099 | Port 8099 |
**Gitea:** http://192.168.2.144:3000/Lars/mitai-jinkendo
---
**Letzte Aktualisierung:** 9. April 2026 (Universal CSV Agent-Guide, Abgleich-Tabelle)

550
.claude/docs/ROADMAP.md Normal file
View File

@ -0,0 +1,550 @@
# Mitai Jinkendo Entwicklungs-Roadmap
**Version:** 2.2
**Status:** Aktiv - Phase 0a ✅ Complete, Phase 0b ✅ Complete, Phase 0c 🎯 Next
**Letzte Aktualisierung:** 28. März 2026
---
## Überblick
Diese Roadmap transformiert Mitai Jinkendo von einer **Datensammlungs-App** zu einem **aktiven Begleiter** mit Auswertungen, Empfehlungen und gezielten Entwicklungspfaden.
**Strategische Ziele:**
1. ✅ **Infrastruktur schaffen** (v9f) → Flexible KI-Analysen → **DONE (AI Prompts, Training Types)**
2. ✅ **Goals System Foundation** (v0.9g-h) → Strategic + Tactical Goals → **DONE (Phase 0a + Dynamic Focus Areas v2.0)**
3. ✅ **Goal-Aware Intelligence** (Phase 0b) → Platzhalter + Auto-Population → **DONE (28.03.2026)**
4. 🎯 **Data Architecture** (Phase 0c) → Multi-Layer Separation → **NEXT**
5. 🔲 **Visualisierung stärken** → Charts, Diagramme, Trends
6. 🔲 **Aktive Begleitung** → Wochenplanung, Development Routes
**Tracking:**
- Konkrete Tasks und Issues → [Gitea Issues](http://192.168.2.144:3000/Lars/mitai-jinkendo/issues)
- Große Feature-Pakete → `.claude/docs/functional/*.md` Spezifikationen
- Strategische Planung → Diese ROADMAP.md
- Aktueller Status → `docs/STATUS_2026-03-28.md`
---
## Phasen-Übersicht
| Phase | Fokus | Dauer | Status |
|-------|-------|-------|--------|
| **Phase 0a** | Goals System Foundation | 1 Woche | ✅ **COMPLETE** (26-27.03.2026) |
| **Phase 0b** | Goal-Aware Placeholders + Auto-Population | 1 Tag | ✅ **COMPLETE** (28.03.2026) |
| **Phase 0c** | Multi-Layer Data Architecture | 5-7 Tage | 🎯 **NEXT** |
| **Phase 1** | Charts & Visualisierung (Frontend) | 2-3 Wochen | 🔲 Geplant |
| **Phase 2** | Engagement (Korrelationen) | 3-4 Wochen | 🔲 Geplant |
| **Phase 3** | Begleitung (Development Routes) | 4-6 Wochen | 🔲 Später |
**Gesamtdauer (Phase 0-2):** ~11-14 Wochen
**Gesamtaufwand (Phase 0-2):** ~80-100h
**Abgeschlossen:** Phase 0a (Goals System), Phase 0b (Placeholders + Auto-Population)
---
## ✅ Phase 0a: Goals System Foundation (COMPLETE)
**Zeitraum:** 26-27. März 2026
**Aufwand:** 4-5h (tatsächlich)
**Status:** ✅ ABGESCHLOSSEN
### Deliverables (alle ✅)
- ✅ Migration 022: goals, training_phases, fitness_tests tables
- ✅ Migration 027-032: Dynamic Focus Areas v2.0
- 26 Basis-Bereiche in 7 Kategorien
- Many-to-Many: Goals ↔ Focus Areas
- User-spezifische Gewichtungen
- ✅ Backend: goals.py + focus_areas.py Router
- ✅ Frontend: GoalsPage (strategic) + CustomGoalsPage (tactical)
- ✅ Admin: AdminFocusAreasPage (CRUD UI)
### Achievements
- Vollständiges Goal System mit Progress Tracking
- Dynamische Focus Areas (user-extensible)
- Mobile-friendly Design
- **Basis geschaffen für Phase 0b (120+ goal-aware Platzhalter)**
📚 **Dokumentation:**
- `docs/issues/issue-50-phase-0a-goal-system.md`
- `docs/issues/issue-51-dynamic-focus-areas-v2.md`
- `docs/NEXT_STEPS_2026-03-26.md`
---
## ✅ Phase 0b: Goal-Aware Placeholders + Auto-Population (COMPLETE)
**Zeitraum:** 28. März 2026
**Aufwand:** ~8h (tatsächlich)
**Status:** ✅ ABGESCHLOSSEN
### Deliverables (alle ✅)
- ✅ **Neue Platzhalter-Funktionen:**
- `{{body_progress_score}}` - Goal-mode-abhängiger Body Score
- `{{active_goals}}` - JSON Array aktiver Ziele
- `{{focus_areas}}` - JSON Array gewichteter Focus Areas
- `{{health_stability_score}}` - Vitalwerte-Stabilität
- Nutrition-Metriken (avg_per_week_30d, etc.)
- ✅ **Score-System:** `map_focus_to_score_components()` in goal_utils.py
- ✅ **Auto-Population System:**
- `_get_historical_value_for_goal_type()` - Findet erste Messung
- Auto-adjustment von start_date zu tatsächlichem Messdatum
- Windowing-Logik für alle Goal-Typen
- ✅ **Time-Based Tracking:**
- Linear Progress Model: `expected = (elapsed_days / total_days) × 100`
- Deviation Calculation: `actual - expected`
- Hybrid Display: mit/ohne target_date
- ✅ **20+ Bug Fixes:** Decimal/float conversion, column names, dict access
### Achievements
- Goal-aware KI-Platzhalter funktionieren
- Automatische Startwerterkennung aus Historie
- Zeit-basierte Fortschrittsverfolgung
- **Basis geschaffen für Phase 0c (Multi-Layer Architecture)**
### Git Commits
```
20+ commits mit "Phase 0b" prefix (28.03.2026)
30+ commits für Auto-Population + Time-Based Tracking
```
📚 **Dokumentation:**
- `docs/issues/issue-53-phase-0c-multi-layer-architecture.md` (Phase 0b als Blaupause)
- `C:\Users\lars\.claude\projects\...\memory\feedback_goal_system.md` (Learnings)
---
## 🎯 Phase 0c: Multi-Layer Data Architecture (NEXT)
**Zeitraum:** Geplant 29.03 - 03.04.2026
**Aufwand:** 20-27h (5-7 Tage bei 4h/Tag)
**Status:** 🎯 READY FOR IMPLEMENTATION
### Ziel
Refactoring von monolithischer Platzhalter-Logik zu dreischichtiger Architektur mit Separation of Concerns.
### Drei-Schichten-Architektur
```
Layer 1: DATA LAYER (neu)
→ Pure data retrieval + calculations
→ Returns: Structured data (dict/list)
→ Testable, reusable
Layer 2a: KI LAYER (refactored)
→ Formatierung für KI-Prompts
→ Uses data_layer functions
Layer 2b: VISUALIZATION LAYER (neu)
→ Chart.js compatible JSON
→ Uses data_layer functions
```
### Deliverables
- [ ] **Data Layer Module erstellen (8-10h):**
- `backend/data_layer/body_metrics.py` (Gewicht, FM, LBM, Umfänge)
- `backend/data_layer/nutrition_metrics.py` (Protein, Makros, Adherence)
- `backend/data_layer/activity_metrics.py` (Volumen, Qualität, Abilities)
- `backend/data_layer/recovery_metrics.py` (Recovery Score, Sleep, Vitals)
- `backend/data_layer/health_metrics.py` (BP, Health Stability)
- `backend/data_layer/goals.py` (Active goals, progress, projections)
- `backend/data_layer/correlations.py` (Lag-analysis, plateau detection)
- `backend/data_layer/utils.py` (Confidence, baseline, outliers)
- [ ] **Placeholder Resolver Refactoring (3-4h):**
- Von ~1100 Zeilen zu ~400 Zeilen
- Alle Platzhalter nutzen data_layer
- [ ] **Charts Router erstellen (6-8h):**
- `backend/routers/charts.py` (NEU)
- 10+ Chart-Endpoints (K1-K10, E1-E4, A1-A5, V1-V3, R1-R2)
- [ ] **goal_utils.py Refactoring (1h):**
- Nutzt data_layer.goals
- [ ] **Testing (2-3h):**
- Unit tests für Data Layer
- Integration tests für Charts API
- [ ] **Dokumentation (1-2h):**
- `.claude/docs/technical/DATA_LAYER_ARCHITECTURE.md`
- `docs/api/CHARTS_API.md`
### Vorteile
- ✅ **Single Source of Truth:** Jede Berechnung nur einmal
- ✅ **Wiederverwendbarkeit:** Gleiche Daten für KI + Charts + API
- ✅ **Testbarkeit:** Data Layer isoliert testbar
- ✅ **Erweiterbarkeit:** Neue Features ohne Code-Duplikation
- ✅ **Performance:** Caching auf Data Layer Ebene möglich
📚 **Vollständige Spezifikation:**
- `docs/issues/issue-53-phase-0c-multi-layer-architecture.md` (23.000 Tokens)
---
## Phase 0 (Legacy): Infrastruktur (v9f) - TEILWEISE ABGESCHLOSSEN
**Ziel:** Grundlagen schaffen für flexible KI-Analysen und Fähigkeiten-Tracking
### Kernfeatures
| Feature | Aufwand | Gitea Issues |
|---------|---------|--------------|
| Quality-Filter für Charts & KI-Pipeline | 3h | Siehe Gitea |
| AI-Prompts Flexibilisierung (v9f) | 16-20h | Siehe Gitea |
| Abilities-Matrix UI (v9f) | 6-8h | Siehe Gitea |
| Responsive UI | 8-10h | Siehe Gitea |
**Gesamt:** ~33-41h
📚 **Detaillierte Specs:**
- `.claude/docs/functional/AI_PROMPTS.md` (KI-Prompt-System)
- `.claude/docs/functional/RESPONSIVE_UI.md` (Desktop-Optimierung)
- `.claude/docs/functional/TRAINING_TYPES.md` (Abilities-Matrix)
### Meilensteine
#### M0.1: Quality-Filter (1 Woche)
- **Deliverable:** KI-Pipeline filtert nach `quality_label >= acceptable`
- **Deliverable:** History.jsx Toggle "Nur qualitativ hochwertige Aktivitäten"
- **Impact:** Sofort bessere KI-Analysen
#### M0.2: AI-Prompts System (3-4 Wochen)
- **Deliverable:** Prompt-Bibliothek mit 8 Kategorien
- **Deliverable:** Platzhalter-Browser mit Beispielwerten
- **Deliverable:** Pipeline-Konfigurationen (min. 3: Alltags-Check, Schlaf-Fokus, Wettkampf)
- **Deliverable:** 50+ Platzhalter implementiert
- **Deliverable:** Quality-Level Parameter für KI-Analysen (all, quality, very_good, excellent)
- **Impact:** Grundlage für Goals, Korrelationen, alle zukünftigen KI-Features
#### M0.3: Abilities-Matrix (2 Wochen)
- **Deliverable:** Admin-UI mit 5-Dimensionen Fähigkeiten-Matrix
- **Deliverable:** Basis-Mappings für alle 29 Trainingstypen
- **Deliverable:** Endpoint `GET /api/evaluation/abilities`
- **Deliverable:** KI-Platzhalter `{{faehigkeiten_*}}`
- **Impact:** Fähigkeiten-Balance-Analysen, bessere Trainingsempfehlungen
#### M0.4: Responsive UI (2 Wochen, parallel)
- **Deliverable:** Desktop Sidebar Navigation
- **Deliverable:** 2-spaltige Layouts (Verlauf, Analyse)
- **Deliverable:** 4-spaltige Dashboard-Karten
- **Impact:** Professionelle Desktop-Nutzung
### Abhängigkeiten
```
AI-Prompts ─┬─→ Goals (KI-Integration)
├─→ Korrelationen (Pipeline-Configs)
└─→ Zukünftige KI-Features
Abilities ──→ AI-Prompts (Fähigkeiten-Platzhalter)
└─→ Korrelationen (Fähigkeiten-Balance)
Quality ────→ Sofort nutzbar (keine Abhängigkeiten)
Responsive ─→ Parallel, keine funktionalen Abhängigkeiten
```
**Phase 0 Ende:** Vollständige v9f-Infrastruktur, Desktop-optimierte UI, Quality-Filter aktiv
---
## Phase 1: Foundation
**Ziel:** Visualisierung und Ziel-Tracking (Basis ohne volle KI-Integration)
### Kernfeatures
| Feature | Aufwand | Gitea Issues |
|---------|---------|--------------|
| Charts & Visualisierungen erweitern | 8-10h | Siehe Gitea |
| Ziele-System (Basis ohne KI) | 10-12h | Siehe Gitea |
**Gesamt:** ~18-22h
📚 **Detaillierte Specs:**
- `.claude/docs/functional/GOALS_VITALS.md` (Ziele-System)
### Meilensteine
#### M1.1: Charts erweitern (2 Wochen)
- **Deliverable:** Weight Trend Chart mit 7d/30d/90d Filter
- **Deliverable:** Umfänge-Verlauf Multi-Line Chart
- **Deliverable:** Vitals Trends (RHR, HRV, VO2 Max, BP)
- **Deliverable:** Schlaf-Analyse Chart (Dauer, Qualität, Phasen)
- **Deliverable:** Ruhetage-Kalender (Heatmap)
- **Impact:** Daten werden sichtbar, Trends erkennbar
#### M1.2: Ziele-System Basis (2-3 Wochen)
- **Deliverable:** DB-Schema `goals` Tabelle
- **Deliverable:** CRUD-Endpoints
- **Deliverable:** UI: Ziele erstellen/bearbeiten/löschen
- **Deliverable:** Dashboard: Fortschrittsbalken (aktuell vs. Ziel)
- **Deliverable:** Prognose-Berechnung (lineare Regression)
- **Impact:** Nutzer sehen Fortschritt, Motivation steigt
**Hinweis:** KI-Integration für Goals kommt in Phase 2.
### Abhängigkeiten
```
Charts ────→ Keine (sofort machbar)
Goals Basis → Keine (DB + UI ohne KI funktioniert)
Goals KI ──→ AI-Prompts (braucht {{ziel_*}} Platzhalter) [Phase 2]
```
**Phase 1 Ende:** Charts zeigen Trends, Ziele sind verfolgbar (ohne KI-Empfehlungen)
---
## Phase 2: Engagement
**Ziel:** Korrelationen, KI-Integration für Goals, aktive Empfehlungen
### Kernfeatures
| Feature | Aufwand | Gitea Issues |
|---------|---------|--------------|
| Korrelationen & Insights erweitern | 6-8h | Siehe Gitea |
| Goals: KI-Integration vervollständigen | 4h | Siehe Gitea |
**Gesamt:** ~10-12h
📚 **Detaillierte Specs:**
- `.claude/docs/functional/AI_PROMPTS.md` (Pipeline-Configs)
- `.claude/docs/functional/GOALS_VITALS.md` (KI-Integration)
### Meilensteine
#### M2.1: Korrelationen (2 Wochen)
- **Deliverable:** Schlaf ↔ Recovery (Pearson Korrelation)
- **Deliverable:** Training ↔ Vitalwerte (Trainingsvolumen vs. RHR/HRV)
- **Deliverable:** Ernährung ↔ Performance (Protein vs. Kraft, Kalorien vs. Ausdauer)
- **Deliverable:** Blutdruck ↔ Lifestyle (Stress, Schlaf, Aktivität)
- **Deliverable:** Fähigkeiten-Balance ↔ Verletzungen/Plateaus
- **Deliverable:** Pipeline-Config "Schlaf-Fokus"
- **Impact:** Nutzer verstehen Zusammenhänge, gezielte Optimierung möglich
#### M2.2: Goals KI-Integration (1 Woche)
- **Deliverable:** KI-Platzhalter `{{goal_weight}}`, `{{ziel_fortschritt}}`, `{{ziel_prognose}}`
- **Deliverable:** Pipeline-Prompt "Ziel-Abgleich" (Stufe 3)
- **Deliverable:** KI-Empfehlungen: "Erhöhe Protein um 20g für Muskelaufbau-Ziel"
- **Impact:** KI gibt konkrete Schritte zur Zielerreichung
### Abhängigkeiten
```
Korrelationen ─→ AI-Prompts (Pipeline-Configs) [KRITISCH]
└─→ Abilities (Fähigkeiten-Balance)
Goals KI ──────→ AI-Prompts (Platzhalter {{ziel_*}}) [KRITISCH]
```
**Phase 2 Ende:** App gibt aktive Empfehlungen, zeigt Korrelationen, begleitet Ziele mit KI
---
## Phase 3: Begleitung (später, v9g)
**Ziel:** Wochenplanung, Development Routes, Habits & Streaks
### Geplante Features
| Feature | Aufwand | Beschreibung |
|---------|---------|--------------|
| Development Routes | 12-16h | 6 unabhängige Routen (Kraft, Kondition, Mental, Koordination, Mobilität, Technik) |
| Wochenplanung | 8-10h | Routen-basierte Wochenansicht, Regeln-Engine, Auto-Ruhetag |
| Habits & Streaks | 6-8h | Streak-Tracking pro Route, Push-Notifications |
| Weekly Planning AI | 4-6h | KI-generierte Wochenpläne basierend auf Routen-Balance |
**Gesamt:** ~30-40h
📚 **Detaillierte Specs:**
- `.claude/docs/functional/DEVELOPMENT_ROUTES.md` (Routen-System)
- `.claude/docs/functional/MEDITATION.md` (Meditation & Mental-Route)
**Status:** Spezifikation vorhanden, Implementierung nach Phase 2
---
## Abhängigkeiten-Graph (Gesamt)
```
┌─────────────────────┐
│ Phase 0: v9f │
└─────────────────────┘
┌─────────────────────┼─────────────────────┬──────────────┐
▼ ▼ ▼ ▼
Quality-Filter AI-Prompts Abilities Responsive UI
(3h) (16-20h) (6-8h) (8-10h)
│ │ │
│ │ ┌───────────────────┘
│ │ │
│ ┌──────┴─┴──────┐
│ │ Phase 1 │
│ └───────────────┘
│ │
│ ┌──────┴──────┬──────────────┐
│ ▼ ▼ │
│ Charts Goals (Basis) │
│ (8-10h) (10-12h) │
│ │ │
│ ┌──────┴──────┐ │
│ │ Phase 2 │ │
│ └─────────────┘ │
│ │ │
└────────────────────────────┼──────────────┘
┌──────┴──────┬──────────────┐
▼ ▼ │
Korrelationen Goals KI │
(6-8h) (4h) │
┌─────────────────────┘
│ Phase 3 (später)
└──────────────────────
Development Routes
Wochenplanung
Habits & Streaks
```
---
## Timeline (geschätzt)
**Start:** KW 13/2026 (24. März)
| Woche | Phase | Aktivität | Deliverable |
|-------|-------|-----------|-------------|
| **KW 13** | Phase 0 | Quality-Filter | KI-Pipeline filtert, History Toggle |
| **KW 14-17** | Phase 0 | AI-Prompts | Prompt-Bibliothek, Platzhalter-System, Pipeline-Configs |
| **KW 14-15** | Phase 0 | Responsive UI (parallel) | Desktop Sidebar, 2-spaltige Layouts |
| **KW 18-19** | Phase 0 | Abilities-Matrix | Admin-UI, Aggregation, KI-Platzhalter |
| **KW 20-21** | Phase 1 | Charts | Weight/Umfänge/Vitals/Schlaf Charts, Ruhetage-Kalender |
| **KW 22-24** | Phase 1 | Goals Basis | DB, CRUD, UI, Fortschritt, Prognose |
| **KW 25-26** | Phase 2 | Korrelationen | 5 Korrelations-Analysen, Pipeline "Schlaf-Fokus" |
| **KW 27** | Phase 2 | Goals KI | KI-Platzhalter, Pipeline "Ziel-Abgleich" |
| **KW 28+** | Phase 3 | Development Routes | Multi-Route System, Wochenplanung, Habits |
**Phase 0 Ende:** KW 19 (Mitte Mai 2026)
**Phase 1 Ende:** KW 24 (Mitte Juni 2026)
**Phase 2 Ende:** KW 27 (Anfang Juli 2026)
---
## Risiken & Mitigationen
### Risiko 1: AI-Prompts Komplexität unterschätzt
**Wahrscheinlichkeit:** Mittel
**Impact:** Hoch (blockiert Goals, Korrelationen)
**Mitigation:**
- Scope klar definieren: Min. 3 Pipeline-Configs, 50+ Platzhalter
- Platzhalter-Resolver modular bauen (lazy loading, caching)
- Frühzeitig Beispiel-Pipeline testen
### Risiko 2: Ziele-System ohne KI wenig attraktiv
**Wahrscheinlichkeit:** Mittel
**Impact:** Mittel
**Mitigation:**
- Prognose-Berechnung (lineare Regression) bereits in Phase 1
- Dashboard-Integration mit Fortschrittsbalken (visuell ansprechend)
- KI-Integration in Phase 2 schnell nachziehen (nur 4h)
### Risiko 3: Responsive UI bricht Mobile-Experience
**Wahrscheinlichkeit:** Niedrig
**Impact:** Hoch (PWA auf iPhone ist kritisch)
**Mitigation:**
- Mobile Layout bleibt exakt wie es ist (< 1024px)
- Nur Desktop (≥ 1024px) bekommt Sidebar
- Ausführliches Testing auf iPhone nach Implementierung
### Risiko 4: Abilities-Matrix UI zu komplex
**Wahrscheinlichkeit:** Niedrig
**Impact:** Mittel
**Mitigation:**
- 5 Accordion-Sections (eine pro Dimension)
- Checkboxes statt Drag & Drop
- Basis-Mappings per Migration vordefiniert (Admin muss nicht alles manuell machen)
---
## Offene Fragen
### Phase 0
1. **Pipeline-Konfigurationen:** Neue DB-Tabelle oder JSONB in `ai_prompts`?
- **Empfehlung:** Neue Tabelle `pipeline_configs` (flexibler für Zukunft)
2. **Platzhalter-Definitionen:** Statisch im Code oder dynamisch in DB?
- **Empfehlung:** Statisch im Code (einfacher, schneller), DB nur für Custom-Platzhalter später
3. **Responsive UI:** Media Queries in app.css oder CSS-in-JS?
- **Empfehlung:** Media Queries in app.css (konsistent mit bestehendem Ansatz)
### Phase 1
4. **Ziele-System:** Mehrere Ziele parallel oder nur ein Primärziel?
- **Empfehlung:** Mehrere Ziele, eines als primär markiert (flexibler)
5. **Charts:** Welche Library? (Chart.js, Recharts, Custom SVG)
- **Status:** Chart.js bereits genutzt, erweitern
### Phase 2
6. **Korrelationen:** Pearson Korrelation ausreichend oder auch Spearman/Kendall?
- **Empfehlung:** Start mit Pearson, später erweitern wenn nötig
7. **Pipeline "Schlaf-Fokus":** Welche Module? (Schlaf 14T, Vitalwerte 7T, Training 14T?)
- **Empfehlung:** Ja, plus Korrelation Schlaf ↔ Recovery
---
## Meilenstein-Deliverables (Zusammenfassung)
### M0: Phase 0 abgeschlossen (KW 19)
- ✅ Quality-Filter aktiv (KI-Pipeline + History Toggle)
- ✅ Prompt-Bibliothek mit 8 Kategorien, 50+ Platzhalter
- ✅ Min. 3 Pipeline-Konfigurationen
- ✅ Abilities-Matrix mit 29 Basis-Mappings
- ✅ Desktop Sidebar Navigation
- ✅ 2-spaltige Layouts (Verlauf, Analyse)
### M1: Phase 1 abgeschlossen (KW 24)
- ✅ 5 neue Chart-Typen (Weight, Umfänge, Vitals, Schlaf, Ruhetage)
- ✅ Ziele-System: CRUD, Dashboard-Integration, Prognose
### M2: Phase 2 abgeschlossen (KW 27)
- ✅ 5 Korrelations-Analysen
- ✅ Pipeline "Schlaf-Fokus", "Ziel-Abgleich"
- ✅ KI gibt konkrete Handlungsempfehlungen
### M3: Phase 3 abgeschlossen (später)
- ✅ 6 Development Routes
- ✅ Routen-basierte Wochenplanung
- ✅ Habits & Streaks Tracking
- ✅ KI-generierte Wochenpläne
---
## Erfolgsmetriken
### Phase 0
- **Admin nutzt Abilities-Matrix:** Min. 20 von 29 Trainingstypen mit Fähigkeiten versehen
- **Pipeline-Configs genutzt:** Min. 1 Pipeline pro Woche ausgeführt
- **Desktop-Traffic:** Min. 30% der Sessions auf Desktop (≥ 1024px)
### Phase 1
- **Charts genutzt:** Min. 5 verschiedene Chart-Typen pro Nutzer pro Monat
- **Ziele gesetzt:** Min. 50% der aktiven Nutzer haben mind. 1 Ziel
- **Prognose geschätzt:** Min. 80% der Ziele haben realistische Prognose
### Phase 2
- **Korrelationen angeschaut:** Min. 3 verschiedene Korrelationen pro Nutzer pro Monat
- **KI-Empfehlungen umgesetzt:** Min. 30% der KI-Vorschläge führen zu Verhaltensänderung
- **Goals erreicht:** Min. 20% der Ziele werden innerhalb Prognose-Zeitraum erreicht
### Phase 3
- **Routen genutzt:** Min. 3 verschiedene Routen pro Nutzer aktiv
- **Wochenplan erstellt:** Min. 1 Wochenplan pro Nutzer pro Monat
- **Streaks gehalten:** Min. 50% der Habits haben Streak ≥ 7 Tage
---
**Dokumentiert:** 23. März 2026 (Initial) · 24. März 2026 (Konsolidiert)
**Autor:** User-Strategie + Claude-Planung
**Status:** Living Document (wird nach jeder Phase aktualisiert)
**Tracking:**
- Konkrete Issues → [Gitea](http://192.168.2.144:3000/Lars/mitai-jinkendo/issues)
- Feature-Specs → `.claude/docs/functional/*.md`
- Strategische Planung → Diese Datei

View File

@ -0,0 +1,94 @@
# Backend-Architektur
## Struktur
```
backend/
├── main.py # App-Setup + Router-Registration (~75 Zeilen)
├── db.py # PostgreSQL Connection Pool + get_cursor() Helper
├── auth.py # hash_pin · verify_pin · require_auth · require_admin
├── models.py # Alle Pydantic Models (LoginRequest, ProfileUpdate, etc.)
├── schema.sql # Vollständiges PostgreSQL-Schema
└── routers/
├── auth.py # Login, Logout, Password Reset, PIN (7 Endpoints)
├── profiles.py # Profile CRUD + Current User (7 Endpoints)
├── weight.py # Weight Tracking (5 Endpoints)
├── circumference.py # Body Measurements (4 Endpoints)
├── caliper.py # Skinfold Tracking (4 Endpoints)
├── activity.py # Workout Logging + CSV Import (6 Endpoints)
├── nutrition.py # Nutrition + FDDB Import (4 Endpoints)
├── photos.py # Progress Photos (3 Endpoints)
├── insights.py # AI Analysis + Pipeline (8 Endpoints)
├── prompts.py # AI Prompt Management (2 Endpoints)
├── admin.py # User Management (7 Endpoints)
├── stats.py # Dashboard Stats (1 Endpoint)
├── exportdata.py # CSV/JSON/ZIP Export (3 Endpoints)
└── importdata.py # ZIP Import (1 Endpoint)
```
## Router registrieren (main.py Pattern)
```python
from routers import auth, profiles, weight
app.include_router(auth.router, prefix="/api")
app.include_router(profiles.router, prefix="/api")
```
## Neuen Router anlegen
1. `backend/routers/mein_modul.py` erstellen
2. `router = APIRouter()` definieren
3. Endpoints mit `@router.get/post/put/delete` definieren
4. In `main.py` importieren und registrieren
5. Schema-Änderungen in `schema.sql` + Migration
## Datenbank-Zugriff
```python
# ✅ Immer so:
from db import get_db, get_cursor
with get_db() as conn:
cur = get_cursor(conn) # RealDictCursor gibt Dicts zurück
cur.execute("SELECT * FROM weight_log WHERE profile_id = %s", (pid,))
rows = cur.fetchall() # Liste von Dicts
# ❌ Nie so (SQLite-Syntax):
conn.execute("SELECT * FROM weight_log WHERE profile_id=?", (pid,))
```
## Auth-Pattern
```python
# Standard-Endpoint mit Auth:
@router.get("/mein-endpoint")
def mein_endpoint(session: dict = Depends(require_auth)):
pid = session['profile_id']
role = session['role']
# Admin-only:
@router.get("/admin-endpoint")
def admin_endpoint(session: dict = Depends(require_admin)):
pass
# ❌ NIEMALS so (session innerhalb Header eingebettet):
def endpoint(x: str = Header(default=None, session=Depends(require_auth))):
```
## PostgreSQL vs. SQLite Unterschiede
```python
# Platzhalter:
%s # PostgreSQL ✅
? # SQLite ❌
# Boolean:
WHERE active = true # PostgreSQL ✅
WHERE active = 1 # SQLite ❌
# Returning:
INSERT INTO ... RETURNING id # PostgreSQL ✅ (für neue IDs)
# JSON:
JSONB # PostgreSQL (für flexible Felder)
```
## DB-Schema ändern
1. `backend/schema.sql` anpassen
2. Migration schreiben (ALTER TABLE oder neues Skript)
3. Container neu bauen: `docker compose build --no-cache backend`
4. NIEMALS Spalten direkt löschen/umbenennen ohne Datenmigration

View File

@ -0,0 +1,319 @@
# Feature Enforcement Pattern
## Übersicht
Das Membership-System verwendet ein **4-Phasen-Modell** für Feature-Limits:
1. **Phase 1: Cleanup** - Feature-Konsolidierung, DB-Migration
2. **Phase 2: Non-blocking Monitoring** - JSON-Logging, keine Blockierung
3. **Phase 3: Frontend Display** - Usage-Badges, Quota-Übersicht
4. **Phase 4: Enforcement** - Tatsächliche Blockierung bei Limit-Überschreitung
**Status (2026-03-21):** ✅ Alle 11 Features sind in Phase 4 (komplett implementiert)
## Wie neue Features hinzufügen
### 1. Feature in Datenbank registrieren
```sql
INSERT INTO features (id, name, description, category, limit_type, reset_period, default_limit)
VALUES (
'new_feature_id', -- eindeutige ID
'Feature Name', -- Anzeigename
'Beschreibung', -- Beschreibung
'data', -- Kategorie: data, ai, export, integration
'count', -- limit_type: 'count' oder 'boolean'
'monthly', -- reset_period: 'never', 'daily', 'monthly'
50 -- default_limit: INT (NULL = unlimited, 0 = disabled)
);
```
**limit_type:**
- `count`: Zählbare Features (z.B. 50 Einträge pro Monat)
- `boolean`: An/Aus-Features (0 = disabled, 1 = enabled)
**reset_period:**
- `never`: Counter reset sich nie (z.B. Lifetime-Limits)
- `daily`: Reset um Mitternacht
- `monthly`: Reset am 1. des Monats
### 2. Backend-Implementierung
#### a) Router-Endpoint anpassen
```python
from auth import require_auth, check_feature_access, increment_feature_usage
from feature_logger import log_feature_usage
@router.post("/api/resource")
def create_resource(data: dict, x_profile_id: Optional[str]=Header(default=None), session: dict=Depends(require_auth)):
"""Create new resource entry."""
pid = get_pid(x_profile_id)
# Phase 4: Check feature access and ENFORCE
access = check_feature_access(pid, 'new_feature_id')
log_feature_usage(pid, 'new_feature_id', access, 'create')
if not access['allowed']:
logger.warning(
f"[FEATURE-LIMIT] User {pid} blocked: "
f"new_feature_id {access['reason']} (used: {access['used']}, limit: {access['limit']})"
)
raise HTTPException(
status_code=403,
detail=f"Limit erreicht: Du hast das Kontingent für [Feature-Name] überschritten ({access['used']}/{access['limit']}). "
f"Bitte kontaktiere den Admin oder warte bis zum nächsten Reset."
)
# ... Business Logic: INSERT into DB ...
# Phase 2: Increment usage counter (only for NEW entries, not updates!)
increment_feature_usage(pid, 'new_feature_id')
return {"id": resource_id}
```
#### b) Wichtige Regeln
**Counter nur bei INSERT, nicht bei UPDATE:**
```python
cur.execute("SELECT id FROM resource WHERE profile_id=%s AND date=%s", (pid, date))
existing = cur.fetchone()
if existing:
# UPDATE - NICHT incrementieren
cur.execute("UPDATE resource SET ... WHERE id=%s", (..., existing['id']))
else:
# INSERT - incrementieren
cur.execute("INSERT INTO resource (...) VALUES (...)", (...))
increment_feature_usage(pid, 'new_feature_id') # ← Nur hier!
```
**Für Bulk-Operationen (CSV-Import):**
```python
new_entries = 0
for row in csv_data:
cur.execute("SELECT id FROM resource WHERE profile_id=%s AND date=%s", (pid, row['date']))
if not cur.fetchone():
# INSERT
cur.execute("INSERT INTO resource (...) VALUES (...)", (...))
new_entries += 1
# Increment counter für alle neuen Einträge
for _ in range(new_entries):
increment_feature_usage(pid, 'new_feature_id')
```
### 3. Frontend-Implementierung
#### a) Import UsageBadge
```javascript
import UsageBadge from '../components/UsageBadge'
```
#### b) State Management
```javascript
export default function ResourcePage() {
const [saving, setSaving] = useState(false)
const [saved, setSaved] = useState(false)
const [error, setError] = useState(null)
const [resourceUsage, setResourceUsage] = useState(null) // Phase 4
const load = () => api.listResources().then(setResources)
const loadUsage = () => {
api.getFeatureUsage().then(features => {
const feature = features.find(f => f.feature_id === 'new_feature_id')
setResourceUsage(feature)
}).catch(err => console.error('Failed to load usage:', err))
}
useEffect(() => {
load()
loadUsage()
}, [])
const handleSave = async () => {
setSaving(true)
setError(null)
try {
await api.createResource(data)
setSaved(true)
await load()
await loadUsage() // Reload usage nach save
setTimeout(() => setSaved(false), 2000)
} catch (err) {
console.error('Save failed:', err)
setError(err.message || 'Fehler beim Speichern')
setTimeout(() => setError(null), 5000)
} finally {
setSaving(false)
}
}
```
#### c) UI mit Badge und deaktiviertem Button
```javascript
return (
<div className="card">
{/* Titel mit Badge */}
<div className="card-title badge-container-right">
<span>Neuer Eintrag</span>
{resourceUsage && <UsageBadge {...resourceUsage} />}
</div>
{/* Error-Meldung */}
{error && (
<div style={{
padding:'10px',
background:'var(--danger-bg)',
border:'1px solid var(--danger)',
borderRadius:8,
fontSize:13,
color:'var(--danger)',
marginBottom:12
}}>
{error}
</div>
)}
{/* Button mit Tooltip-Wrapper (disabled buttons zeigen keine nativen tooltips!) */}
<div
title={resourceUsage && !resourceUsage.allowed
? `Limit erreicht (${resourceUsage.used}/${resourceUsage.limit}). Kontaktiere den Admin oder warte bis zum nächsten Reset.`
: ''}
style={{display:'inline-block', width:'100%'}}
>
<button
className="btn btn-primary btn-full"
onClick={handleSave}
disabled={saving || !data || (resourceUsage && !resourceUsage.allowed)}
style={{cursor: (resourceUsage && !resourceUsage.allowed) ? 'not-allowed' : 'pointer'}}
>
{saved ? <><Check size={15}/> Gespeichert!</>
: saving ? <><div className="spinner" style={{width:14,height:14}}/></>
: (resourceUsage && !resourceUsage.allowed) ? '🔒 Limit erreicht'
: 'Speichern'}
</button>
</div>
</div>
)
```
#### d) CSS-Styling (bereits vorhanden)
Die Badge-Styles sind zentral in `frontend/src/components/UsageBadge.css`:
```css
/* Badge container rechts-aligniert */
.badge-container-right {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
/* Badge selbst */
.usage-badge {
font-size: 0.65rem;
font-weight: 600;
padding: 2px 6px;
border-radius: 4px;
opacity: 0.6;
white-space: nowrap;
}
.usage-badge--ok { color: #888; background: #f0f0f0; }
.usage-badge--warning { color: #EF9F27; background: #FFF4E5; }
.usage-badge--exceeded { color: #D85A30; background: #FCEBEB; }
```
### 4. Admin-UI (optional)
Wenn das Feature tier-spezifische Limits braucht, in Admin-UI ergänzen:
```javascript
// frontend/src/pages/admin/TierLimitsPage.jsx
const FEATURE_OPTIONS = [
{ value: 'new_feature_id', label: 'Feature Name' },
// ... existing features
]
```
## Checkliste für neue Features
- [ ] Feature in `features` Tabelle registriert
- [ ] Backend: `check_feature_access()` + `log_feature_usage()` vor Business Logic
- [ ] Backend: `raise HTTPException(403, ...)` wenn `!access['allowed']`
- [ ] Backend: `increment_feature_usage()` nach INSERT (nicht bei UPDATE!)
- [ ] Frontend: `UsageBadge` importiert
- [ ] Frontend: `resourceUsage` State mit `loadUsage()`
- [ ] Frontend: Badge im Titel (`badge-container-right`)
- [ ] Frontend: Button deaktiviert bei `!resourceUsage.allowed`
- [ ] Frontend: Tooltip-Wrapper um Button (`<div title="...">`)
- [ ] Frontend: Error-Handling in `handleSave()` mit `catch`
- [ ] Frontend: `loadUsage()` nach erfolgreichem Speichern
- [ ] Feature-ID in CLAUDE.md dokumentiert (falls relevant)
## Bestehende Features (Referenz)
| Feature ID | Typ | Reset | Beschreibung |
|-----------|-----|-------|--------------|
| weight_entries | count | never | Gewichtseinträge |
| circumference_entries | count | never | Umfangseinträge |
| caliper_entries | count | never | Caliper-Messungen |
| activity_entries | count | monthly | Aktivitätseinträge |
| nutrition_entries | count | monthly | Ernährungseinträge (meist CSV-Import) |
| photos | count | monthly | Progress-Fotos |
| ai_calls | count | monthly | KI-Analysen (Einzelanalysen) |
| ai_pipeline | boolean | - | KI-Pipeline (An/Aus) |
| data_export | count | monthly | Daten-Exporte (CSV/JSON/ZIP) |
| data_import | count | monthly | Daten-Importe (ZIP) |
## Debugging
**Log-Datei prüfen:**
```bash
tail -f backend/logs/feature-usage.log | jq .
```
**Struktur:**
```json
{
"timestamp": "2026-03-21T14:23:45.123456",
"profile_id": "uuid",
"feature_id": "weight_entries",
"action": "create",
"allowed": true,
"used": 7,
"limit": 50,
"remaining": 43,
"reason": "within_limit"
}
```
**Datenbank prüfen:**
```sql
-- Aktuelle Usage
SELECT * FROM user_feature_usage WHERE profile_id = 'xxx';
-- Feature-Definition
SELECT * FROM features WHERE id = 'new_feature_id';
-- Tier-Limits
SELECT * FROM tier_limits WHERE feature_id = 'new_feature_id';
-- User-Overrides
SELECT * FROM user_feature_restrictions
WHERE profile_id = 'xxx' AND feature_id = 'new_feature_id';
```
## Weiterführende Dokumentation
- **Membership-System:** `.claude/docs/technical/MEMBERSHIP_SYSTEM.md`
- **Backend-Architektur:** `.claude/docs/architecture/BACKEND.md`
- **Frontend-Architektur:** `.claude/docs/architecture/FRONTEND.md`
- **Coding Rules:** `.claude/docs/rules/CODING_RULES.md`

View File

@ -0,0 +1,126 @@
# Frontend-Architektur
## Struktur
```
frontend/src/
├── App.jsx # Root: Auth-Gates, Navigation, Routing
├── app.css # CSS-Variablen + globale Klassen
├── main.jsx # Vite Entry Point
├── context/
│ ├── AuthContext.jsx # Session, Login, Logout, getToken()
│ └── ProfileContext.jsx # Aktives Profil, Profile-Liste
├── pages/ # Eine Datei pro Screen
├── utils/
│ ├── api.js # Alle API-Calls (Token automatisch injiziert)
│ ├── calc.js # Körperfett-Formeln (Jackson/Pollock etc.)
│ ├── interpret.js # Regelbasierte Auswertungen
│ ├── Markdown.jsx # Eigener Markdown-Renderer
│ └── guideData.js # Messanleitungen (statisch)
└── public/ # Icons (Jinkendo Ensō-Logo)
```
## API-Calls IMMER über api.js
```javascript
// ✅ Richtig Token wird automatisch injiziert:
import { api } from '../utils/api'
const data = await api.listWeight()
await api.upsertWeight(date, weight, note)
// ❌ Falsch kein Token, gibt 401:
const r = await fetch('/api/weight')
```
## Neue API-Methode hinzufügen
In `frontend/src/utils/api.js`:
```javascript
export const api = {
// ...bestehende Methoden...
meinEndpoint: (param) => req(`/mein-endpoint?p=${param}`),
createItem: (data) => req('/items', json(data)),
updateItem: (id, d) => req(`/items/${id}`, jput(d)),
deleteItem: (id) => req(`/items/${id}`, {method:'DELETE'}),
}
```
## Navigation (Haupt-App & Admin)
- **Hauptmenü (Mobile + Desktop):** `frontend/src/config/appNav.js` (`getMainNavItems`) in `App.jsx` (Bottom-Nav) und `DesktopSidebar.jsx` nutzen.
- **Admin-Bereich:** `frontend/src/config/adminNav.js` + `layouts/AdminShell.jsx` + `layouts/RequireAdmin.jsx`; Shell wie Analyse (`.analysis-split*`).
- **Bottom-Nav / Safe Area (PWA):** `--nav-h`, `.bottom-nav`, `.app-main` in `app.css`.
- **Agent-Doku:** `docs/issues/GUI_IA_ADMIN_NAV_2026-04-05.md`
## Neue Seite hinzufügen
1. `frontend/src/pages/MeineSeite.jsx` erstellen
2. In `App.jsx` importieren und Route hinzufügen
3. Navigation: Eintrag in **`config/appNav.js`** (und ggf. Admin in **`adminNav.js`**) nicht mehr nur in `App.jsx` duplizieren
## Komponenten-Pattern
```jsx
export default function MeineSeite() {
const [data, setData] = useState([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
useEffect(() => { load() }, [])
const load = async () => {
try {
setLoading(true)
setData(await api.meinEndpoint())
} catch(e) { setError(e.message) }
finally { setLoading(false) }
}
if (loading) return <div style={{display:'flex',justifyContent:'center',padding:40}}><div className="spinner"/></div>
if (error) return <div style={{color:'var(--danger)',padding:16}}>{error}</div>
return (
<div style={{padding:'0 0 80px'}}>
{/* Inhalt */}
</div>
)
}
```
## CSS-Variablen (Kurzreferenz)
```css
--accent: #1D9E75 --accent-dark: #085041 --accent-light: #E1F5EE
--danger: #D85A30
--bg · --surface · --surface2 · --border · --text1 · --text2 · --text3
```
## CSS-Klassen
```
.card Weißer Container, border-radius 12px
.btn Basis-Button
.btn-primary Grüner Button
.btn-secondary Grauer Button
.btn-full 100% Breite
.form-input Eingabefeld
.form-label Label (klein, uppercase)
.spinner Ladekreis
```
## Bekannte Fallstricke
### dayjs.week() NIEMALS verwenden
```javascript
// ❌ Falsch:
dayjs(date).week()
// ✅ Richtig (ISO 8601):
const weekNum = (() => {
const dt = new Date(date)
dt.setHours(0,0,0,0)
dt.setDate(dt.getDate()+4-(dt.getDay()||7))
return Math.ceil(((dt-new Date(dt.getFullYear(),0,1))/86400000+1)/7)
})()
```
### Recharts Bar fill
```jsx
// ❌ Falsch:
<Bar fill={(entry) => entry.color}/>
// ✅ Richtig:
<Bar fill="#1D9E75"/>
```

View File

@ -0,0 +1,186 @@
# Code-Audit Mitai Jinkendo
| Feld | Wert |
|------|------|
| **Datum** | 2026-04-04 |
| **Bezeichnung** | Vollständige Code-Analyse (Backend FastAPI, Frontend React, Konfiguration) |
| **Umfang** | Stichproben + gezielte Suche (Security-Patterns, Auth, SQL, Hardcoding, Duplikate) |
| **Einschränkung** | Kein Penetrationstest, keine Laufzeit-Fuzzing-Tests; statische Analyse und Architektur-Review |
---
## Kurzfassung
Die Codebasis ist insgesamt strukturiert (modulare Router, parametrisierte SQL-Queries, bcrypt, Rate-Limits auf sensiblen Auth-Endpunkten). Es gibt jedoch **kritische Autorisierungslücken** rund um `X-Profile-Id` und die öffentlichen `/api/profiles`-Routen sowie eine **fehlende Objekt-Zuordnung bei Foto-Downloads**. Zusätzlich fallen **Konfigurations- und Versions-Inkonsistenzen**, **Legacy-/Duplikat-Code** und **Abweichungen von den eigenen Coding Rules** (direktes `fetch` im Frontend) auf.
**Gitea-Issue-Vorlagen** für die wichtigsten Punkte liegen unter `gitea/`.
---
## Kritisch (P0) Sicherheit
### 1. `X-Profile-Id` ohne Abgleich mit der Session (`get_pid`)
**Datei:** `backend/routers/profiles.py` (Hilfsfunktion `get_pid`)
```20:29:backend/routers/profiles.py
def get_pid(x_profile_id: Optional[str] = Header(default=None)) -> str:
"""Get profile_id - from header for legacy endpoints."""
if x_profile_id:
return x_profile_id
with get_db() as conn:
cur = get_cursor(conn)
cur.execute("SELECT id FROM profiles ORDER BY created LIMIT 1")
row = cur.fetchone()
if row: return row['id']
raise HTTPException(400, "Kein Profil gefunden")
```
Ist der Header gesetzt, wird **jede** authentifizierte Session auf die **beliebig gewählte** Profil-ID umgebogen. `get_pid` wird in zahlreichen Routern genutzt (Gewicht, Aktivität, Ernährung, Fotos-Upload/Liste, Vitals, Insights, …). Ein Angreifer mit gültigem Nutzer-Token kann damit **fremde Daten lesen und schreiben** (klassische IDOR-Schwachstelle).
**Empfehlung:** Profil-Kontext ausschließlich aus `session['profile_id']` ableiten; `X-Profile-Id` nur für **Admins** erlauben und gegen eine explizite Admin-Prüfung validieren oder entfernen, wenn nicht mehr benötigt.
**Vorlage:** `gitea/TEMPLATE_P0-profile-scoping-x-profile-id.md`
---
### 2. `/api/profiles`-Endpunkte ohne Admin-Pflicht
**Datei:** `backend/routers/profiles.py`
Endpunkte wie `GET/POST /api/profiles`, `GET/PUT/DELETE /api/profiles/{pid}` nutzen `Depends(require_auth)`, **nicht** `require_admin`. Damit kann jeder eingeloggte Nutzer u. a. **alle Profile auflisten**, **Profildaten abrufen** und unter Umständen **Profile löschen** (wenn mehr als eines existiert).
Das Frontend nutzt `GET /api/profiles` in `ProfileContext.jsx` für die Profilliste funktional erklärbar, **sicherheitstechnisch** aber nur akzeptabel, wenn ausschließlich Admins je Instanz ein Konto haben (Annahme, die im Code nicht erzwungen wird).
**Empfehlung:** Öffentliche/„current user“-API von Admin-CRUD trennen; Listen/Löschen/Anlegen fremder Profile nur mit `require_admin` und expliziter Policy.
**Vorlage:** `gitea/TEMPLATE_P0-profiles-router-authorization.md`
---
### 3. Foto-Abruf ohne Profil-Ownership-Prüfung
**Datei:** `backend/routers/photos.py` `GET /api/photos/{fid}`
Die Route lädt die Datei nur anhand der Foto-`id`, **ohne** zu prüfen, ob `photos.profile_id` zur Session passt. UUIDs erschweren Raten, bieten aber **keinen** Zugriffsschutz, wenn IDs bekannt sind oder geleakt werden.
**Empfehlung:** `SELECT ... WHERE id=%s AND profile_id=%s` mit `session['profile_id']` (bzw. adminseitig explizite Ausnahme).
**Vorlage:** `gitea/TEMPLATE_P1-photo-ownership-enforcement.md`
---
## Hoch (P1)
### 4. CORS: Default `allow_origins=["*"]`
**Datei:** `backend/main.py`
Wenn `ALLOWED_ORIGINS` nicht gesetzt ist, erlaubt die Middleware **`'*'`** in Kombination mit `allow_credentials=True`. Das ist in Browsern problematisch (kann je nach Client zu unerwartetem Verhalten führen) und in Produktion **riskant**, falls die Umgebungsvariable fehlt.
**Empfehlung:** In Produktion kein Wildcard-Default; Startfehler oder restriktive Default-Liste für Dev dokumentieren.
**Vorlage:** `gitea/TEMPLATE_P1-cors-allowed-origins-hardening.md`
---
### 5. Session-Token in der URL (Fotos)
**Datei:** `frontend/src/utils/api.js` Foto-URL mit `?token=...` für `<img>`-Tags; Backend: `require_auth_flexible` mit Query-Parameter.
Token in URLs landen in **Logs, Referer, Browser-Historie** erhöhtes Leak-Risiko.
**Empfehlung:** Kurzlebige signierte URLs, Cookie-Session für Same-Origin, oder dedizierter Download-Endpoint mit Header-Auth und Blob-URL im Frontend (mit Aufwand abzuwägen).
---
### 6. Veraltete / widersprüchliche Versionsangaben
| Ort | Befund |
|-----|--------|
| `backend/main.py` | `FastAPI(..., version="3.0.0")` wirkt wie API-/Framework-Version, nicht App-Version |
| `backend/version.py` | `APP_VERSION = "0.9l"` |
| `backend/routers/auth.py` `/api/auth/status` | `"version": "v9b"` offensichtlich veraltet |
| `CLAUDE.md` | erwähnt `frontend/src/version.js` **Datei im Repo nicht vorhanden** (Dokumentationsdrift) |
**Empfehlung:** Eine Quelle (`version.py` + optional Endpoint `/api/version`), Frontend aus derselben Quelle oder Build-Inject.
---
## Mittel (P2) Inkonsistenzen & Wartung
### 7. Frontend: direktes `fetch` statt `api.js`
Laut `.claude/rules/CODING_RULES.md` sollen alle API-Calls über `api.js` laufen. Tatsächlich gibt es u. a.:
- `frontend/src/context/AuthContext.jsx`, `ProfileContext.jsx`, `PasswordRecovery.jsx`
- `frontend/src/pages/AdminPanel.jsx`, `SettingsPage.jsx`
Risiko: inkonsistente Header/Fehlerbehandlung, schwerer zu auditieren.
**Vorlage:** `gitea/TEMPLATE_P2-consolidate-api-client.md`
---
### 8. Duplikat- und Legacy-Code
| Befund | Hinweis |
|--------|---------|
| `backend/main_old.py` | Großes, nicht eingebundenes Modul verwirrt Reviews und Suche |
| `backend/calculations/*` vs `backend/data_layer/*` | Parallelstruktur; Phase-0c nutzt `data_layer`, aber z. B. `placeholder_resolver.py` importiert noch `calculations.scores` |
| `backend/apply_v9c_migration.py` in `startup_event` | Legacy-Hook neben `db_init` technische Schuld |
**Vorlage:** `gitea/TEMPLATE_P2-dead-code-and-metrics-dedup.md`
---
### 9. Hardcodierte Werte (Auswahl)
- **Tests:** `tests/dev-smoke-test.spec.js` Fallback-Passwort `'5112'` wenn `TEST_PASSWORD` fehlt (nur für lokale/CI-Umgebung akzeptabel, sollte in Doku stehen und nie in Prod-Daten).
- **Playwright:** `playwright.config.js` feste `baseURL: 'https://dev.mitai.jinkendo.de'`.
- **Admin-UI:** `AdminPanel.jsx` Beispielzeile mit `APP_URL=http://192.168.2.49:3002` (Dokumentation im UI).
- **Farben:** Viele Hex-Werte in JSX (z. B. `NutritionCharts.jsx`, `History.jsx`) Verstoß gegen die eigene CSS-Variablen-Regel, aber eher UX/Wartbarkeit als Security.
### 10. Passwortlänge: `/api/auth/pin` vs Registrierung
Registrierung verlangt mindestens **8** Zeichen; PIN-/Passwort-Änderung über `/api/auth/pin` erlaubt **4** Zeichen. Inkonsistent für Sicherheitskommunikation.
### 11. Dynamische SQL-`UPDATE`-Fragmente
Muster `UPDATE ... SET {', '.join(f'{k}=%s' for k in d)}` erscheint in mehreren Routern. **Soweit geprüft**, werden Keys aus kontrollierten Dicts/Pydantic-Modellen gebaut **kein** offensichtlicher SQL-Injection-Pfad durch Rohtext. Risiko steigt, wenn später unkontrollierte Keys eingespeist werden. Whitelist pro Endpoint wäre robuster.
---
## Positiv hervorgehoben
- Parametrisierte Queries (`%s`) durchgängig üblich; keine `execute(f"...{userinput}")` in den geprüften kritischen Pfaden.
- `bcrypt` + Migration von Legacy-SHA256 in `auth.py` / Login.
- Rate Limiting auf Login, Forgot-Password, Register (`slowapi`).
- Forgot-Password gibt keine E-Mail-Existenz preis.
- Admin-Router (`/api/admin/*`) konsequent mit `require_admin`.
- Modulare Router-Registrierung in `main.py`.
---
## Mapping: Vorlagen → Themen
| Priorität | Thema | Datei unter `gitea/` |
|-----------|--------|----------------------|
| P0 | IDOR `X-Profile-Id` / `get_pid` | `TEMPLATE_P0-profile-scoping-x-profile-id.md` |
| P0 | `/api/profiles` ohne Admin | `TEMPLATE_P0-profiles-router-authorization.md` |
| P1 | Foto-Ownership | `TEMPLATE_P1-photo-ownership-enforcement.md` |
| P1 | CORS-Default | `TEMPLATE_P1-cors-allowed-origins-hardening.md` |
| P2 | `fetch` vs `api.js` | `TEMPLATE_P2-consolidate-api-client.md` |
| P2 | Legacy/Duplikate | `TEMPLATE_P2-dead-code-and-metrics-dedup.md` |
---
## Nächste Schritte (empfohlen)
1. **Sofort:** P0-Issues planen und `get_pid` / Profil-Router designen (Session-first, Admin-Override explizit).
2. **Kurzfristig:** Foto-GET mit `profile_id`-Check; CORS in allen Umgebungen prüfen.
3. **Mittelfristig:** Versionierung vereinheitlichen; `fetch`-Calls bündeln; `main_old.py` und Metrik-Duplikate bereinigen oder archivieren.
---
*Erstellt im Rahmen einer statischen Code-Analyse; bei Änderungen am Code bitte Report-Datum und Befunde aktualisieren.*

View File

@ -0,0 +1,8 @@
# Audit 2026-04-04 Code Review
| Inhalt | Pfad |
|--------|------|
| Vollständiger Report | [`CODE_AUDIT_REPORT_2026-04-04.md`](./CODE_AUDIT_REPORT_2026-04-04.md) |
| Gitea-Issue-Vorlagen (Copy & Paste) | [`gitea/`](./gitea/) |
Beim Anlegen in Gitea: **Titel** und **Labels** aus dem YAML-Kopf der jeweiligen Vorlage übernehmen, **Beschreibung** = Rest des Markdown (ohne die `---`-Blöcke, falls gewünscht).

View File

@ -0,0 +1,37 @@
---
# Gitea: Beim Anlegen des Issues Titel und Labels manuell übernehmen (YAML wird von Gitea nicht automatisch geparst dient als Meta-Hinweis).
title: "[Security/P0] X-Profile-Id / get_pid ermöglicht IDOR über alle Datendomänen"
labels: security, backend, priority-critical
---
## Kontext
Code-Audit 2026-04-04 (`/.claude/docs/audit/20260404_code_audit/CODE_AUDIT_REPORT_2026-04-04.md`).
## Problem
Die Funktion `get_pid` in `backend/routers/profiles.py` gibt bei gesetztem Header `X-Profile-Id` diesen Wert **unverändert** zurück, **ohne** Abgleich mit `session['profile_id']` oder Admin-Rolle.
Damit kann jede authentifizierte Session mit gültigem Token Daten eines **beliebigen** Profils über alle Endpunkte ansprechen, die `get_pid(x_profile_id)` nutzen (u. a. Gewicht, Aktivität, Ernährung, Fotos-Upload/Liste, Vitals, Insights, Schlaf, Ruhetage, Export).
## Reproduktion (konzeptionell)
1. Als Nutzer A einloggen, Token erhalten.
2. Profil-ID von Nutzer B ermitteln (z. B. über `GET /api/profiles` siehe separates Issue).
3. Request gegen geschützten Endpoint mit Header `X-Profile-Id: <uuid-von-B>` und Token von A.
## Erwartetes Verhalten
- Standard: `profile_id` **ausschließlich** aus der Session.
- Optional: `X-Profile-Id` nur für **Admins** und mit expliziter Prüfung `require_admin` + dokumentierter Use-Case (Multi-User-Admin-UI).
## Akzeptanzkriterien
- [ ] Alle betroffenen Router verwenden session-basierte Profil-IDs oder einen validierten Admin-Override.
- [ ] Regressionstests oder manuelle Checkliste für mindestens einen Endpoint pro Router-Gruppe.
- [ ] Kurze Doku in `.claude/rules` oder technischer Doc, ob `X-Profile-Id` noch existiert und wann.
## Betroffene Dateien (Ausgangspunkt)
- `backend/routers/profiles.py` (`get_pid`)
- Alle Importe von `get_pid` (z. B. `weight`, `activity`, `nutrition`, `photos`, `insights`, `vitals_baseline`, `blood_pressure`, `rest_days`, `sleep`, …)

View File

@ -0,0 +1,37 @@
---
title: "[Security/P0] /api/profiles CRUD ohne require_admin Datenabfluss und Missbrauch"
labels: security, backend, priority-critical
---
## Kontext
Code-Audit 2026-04-04.
## Problem
In `backend/routers/profiles.py` nutzen u. a. folgende Routen `Depends(require_auth)` **ohne** `require_admin`:
- `GET /api/profiles` Liste aller Profile
- `POST /api/profiles` Profil anlegen
- `GET/PUT/DELETE /api/profiles/{pid}` Abruf/Update/Löschen nach ID
Jeder eingeloggte Nutzer kann damit die Profilliste sehen und je nach Datenbestand auch fremde Profile manipulieren oder löschen (sofern mehr als ein Profil existiert).
Das Frontend (`ProfileContext.jsx`) ruft `GET /api/profiles` für die Profilauswahl auf das erklärt die aktuelle UX, ersetzt aber keine serverseitige Autorisierung.
## Erwartetes Verhalten
- Listen, Anlegen, Löschen und Bearbeiten **fremder** Profile: nur `require_admin`.
- „Aktuelles Profil“: dedizierte Routen (`/api/profile` o. ä.) strikt an `session['profile_id']` gebunden.
## Akzeptanzkriterien
- [ ] Rollenmodell dokumentiert (wer darf `/api/profiles` sehen?).
- [ ] Admin-only für sensible Operationen erzwungen.
- [ ] Frontend angepasst (falls nötig: Admin vs. normaler Nutzer unterschiedliche Endpunkte).
- [ ] Keine Regression für Single-User-Selfhosting ohne unnötige UX-Brüche (optional: Feature-Flag oder Rolle `admin` für ersten User).
## Betroffene Dateien
- `backend/routers/profiles.py`
- `frontend/src/context/ProfileContext.jsx` (und ggf. weitere Aufrufer von `/api/profiles`)

View File

@ -0,0 +1,36 @@
---
title: "[Security/P1] CORS: Default ALLOWED_ORIGINS=* mit allow_credentials=True"
labels: security, backend, configuration, priority-high
---
## Kontext
Code-Audit 2026-04-04.
## Problem
`backend/main.py`:
```python
allow_origins=os.getenv("ALLOWED_ORIGINS", "*").split(","),
allow_credentials=True,
```
Fehlt die Umgebungsvariable, ist die Default-Konfiguration `*`. Zusammen mit `allow_credentials=True` ist das in Produktion unerwünscht und erschwert eine klare Security-Posture.
## Erwartetes Verhalten
- Produktion: explizite Origins aus `ALLOWED_ORIGINS` (kommasepariert), kein stiller Wildcard-Fallback.
- Entwicklung: dokumentierter Default (z. B. `http://localhost:5173`) oder explizite Opt-in-Umgebungsvariable `CORS_ALLOW_ALL=true`.
## Akzeptanzkriterien
- [ ] Verhalten in `.env.example` und Deployment-Doku beschrieben.
- [ ] Optional: Anwendung startet nicht, wenn `ALLOWED_ORIGINS` in `ENV=production` fehlt.
- [ ] Manuelle Prüfung: Browser-Requests von fremden Origins werden blockiert.
## Betroffene Dateien
- `backend/main.py`
- `.env.example`
- ggf. `docker-compose*.yml`

View File

@ -0,0 +1,36 @@
---
title: "[Security/P1] GET /api/photos/{fid} ohne Prüfung auf profile_id (Objekt-Zugriff)"
labels: security, backend, priority-high
---
## Kontext
Code-Audit 2026-04-04.
## Problem
`backend/routers/photos.py`: `GET /{fid}` lädt ein Foto nur anhand der `id` aus der Tabelle `photos`, ohne zu prüfen, ob der Datensatz zu `session['profile_id']` gehört.
Authentifizierung ist vorhanden (`require_auth_flexible`), aber **keine Objekt-Level-Autorisierung**.
## Risiko
Bei bekannter oder erratener Foto-UUID können Inhalte anderer Nutzer derselben Instanz abgerufen werden.
## Erwartetes Verhalten
```sql
SELECT path FROM photos WHERE id = %s AND profile_id = %s
```
mit `profile_id` aus der Session; Admins optional mit separatem Codepfad.
## Akzeptanzkriterien
- [ ] Abruf nur für eigenes Profil (bzw. dokumentierter Admin-Fall).
- [ ] Bestehende Clients (PWA) unverändert nutzbar.
- [ ] Kurzer Testfall oder manuelle Prüfung: Nutzer A kann Foto von B nicht öffnen.
## Betroffene Dateien
- `backend/routers/photos.py`

View File

@ -0,0 +1,30 @@
---
title: "[Tech-Debt/P2] Frontend: direktes fetch statt zentral api.js (Auth, Admin, Import)"
labels: frontend, refactoring, consistency
---
## Kontext
Code-Audit 2026-04-04. Verbindliche Regel: `.claude/rules/CODING_RULES.md` alle API-Calls über `frontend/src/utils/api.js`.
## Problem
Mehrere Komponenten nutzen natives `fetch('/api/...')` mit manuell gesetztem `X-Auth-Token`, u. a.:
- `frontend/src/context/AuthContext.jsx`
- `frontend/src/context/ProfileContext.jsx`
- `frontend/src/pages/PasswordRecovery.jsx`
- `frontend/src/pages/AdminPanel.jsx`
- `frontend/src/pages/SettingsPage.jsx`
Nachteile: doppelte Fehlerbehandlung, schwerere Wartung, leichter zu übersehen bei Security-Reviews.
## Erwartetes Verhalten
Alle Aufrufe über `api.js` (oder ein einziges dünnes Wrapper-Modul), inkl. Upload/Export-Sonderfälle.
## Akzeptanzkriterien
- [ ] Kein direktes `fetch('/api/` mehr außerhalb von `api.js` (Ausnahmen dokumentieren, falls nötig).
- [ ] Einheitliche Fehler- und 401-Behandlung.
- [ ] Kurze Notiz in CODING_RULES oder LESSONS_LEARNED, falls Ausnahmen bleiben.

View File

@ -0,0 +1,34 @@
---
title: "[Tech-Debt/P2] Legacy main_old.py, calculations/ vs data_layer/, Startup-Migration-Hooks"
labels: backend, refactoring, maintenance
---
## Kontext
Code-Audit 2026-04-04.
## Problemstellung (Bündel)
1. **`backend/main_old.py`**: große, nicht in `main.py` eingebundene Datei verwirrt Suche, Reviews und Onboarding.
2. **Parallele Metrik-Pfade**: `backend/data_layer/` (Phase 0c) und `backend/calculations/` existieren nebeneinander; `placeholder_resolver.py` importiert z. B. noch `calculations.scores`.
3. **`startup_event` in `main.py`**: zusätzlicher Hook `apply_v9c_migration` neben `db_init` Legacy-Pfad neben dem Migrations-System.
## Ziele
- Single Source of Truth für Metriken (klar dokumentiert: `data_layer` vs. verbleibende Hilfsmodule).
- Entfernen oder Archivieren (`docs/archive/` oder Git-History-only) von `main_old.py`, sofern nicht mehr referenziert.
4. Migration-Startup vereinheitlichen (nur `db_init` / nummerierte SQL-Migrationen, sofern v9c-Hook obsolet).
## Akzeptanzkriterien
- [ ] Entscheidung dokumentiert: welches Paket autoritativ ist.
- [ ] Keine doppelten Implementierungen für dieselbe Metrik ohne Grund.
- [ ] `main_old.py` entfernt oder klar als „archived“ markiert und aus IDEs/CI-Suche ausgeschlossen (optional).
- [ ] Build/Start ohne v9c-Sonderpfad, falls redundant.
## Betroffene Pfade (Start)
- `backend/main_old.py`
- `backend/main.py` (startup)
- `backend/data_layer/`, `backend/calculations/`
- `backend/placeholder_resolver.py`

View File

@ -0,0 +1,10 @@
# Audit- und Reconcile-Artefakte
Zeitlich begrenzte Reviews, Matrizen und Gitea-Vorlagen. **Keine** verbindlichen Produkt-Spezifikationen die bleiben unter [`functional/`](../functional/) und [`technical/`](../technical/).
| Ordner | Inhalt |
|--------|--------|
| [`20260404_code_audit/`](./20260404_code_audit/) | Code-Audit 2026-04-04, Report + Issue-Vorlagen |
| [`platzhalter/`](./platzhalter/) | Platzhalter-Audits, Kataloge, Reconciliation 2026-03 (JSON/Matrix) |
**Hinweis:** Doppelablagen zu `functional/` wurden entfernt (z.B. fachliche `DATA_ARCHITECTURE`, Konzept-PDF-Markdown v2). Immer die Pfade unter `functional/` bzw. `technical/` als Quelle nutzen.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,147 @@
# Placeholder Catalog (Extended)
**Generated:** 2026-03-29 19:26:40
**Total Placeholders:** 111
## Placeholders by Category
### Ernährung (8 placeholders)
- `{{carb_avg}}` - Durchschn. Kohlenhydrate in g (30d)
- `{{energy_balance_7d}}` - Energiebilanz 7d (kcal/Tag)
- `{{fat_avg}}` - Durchschn. Fett in g (30d)
- `{{kcal_avg}}` - Durchschn. Kalorien (30d)
- `{{macro_consistency_score}}` - Makro-Konsistenz Score (0-100)
- `{{protein_adequacy_28d}}` - Protein Adequacy Score (0-100)
- `{{protein_avg}}` - Durchschn. Protein in g (30d)
- `{{protein_g_per_kg}}` - Protein g/kg Körpergewicht
### Focus Areas (8 placeholders)
- `{{focus_cat_aktivität_progress}}` - Kategorie Aktivität - Progress (%)
- `{{focus_cat_aktivität_weight}}` - Kategorie Aktivität - Gewichtung (%)
- `{{focus_cat_ernährung_progress}}` - Kategorie Ernährung - Progress (%)
- `{{focus_cat_ernährung_weight}}` - Kategorie Ernährung - Gewichtung (%)
- `{{focus_cat_körper_progress}}` - Kategorie Körper - Progress (%)
- `{{focus_cat_körper_weight}}` - Kategorie Körper - Gewichtung (%)
- `{{top_focus_area_name}}` - Top Focus Area Name
- `{{top_focus_area_progress}}` - Top Focus Area Progress (%)
### Körper (11 placeholders)
- `{{bmi}}` - Body Mass Index
- `{{fm_28d_change}}` - Fettmasse Änderung 28d (kg)
- `{{kf_aktuell}}` - Aktueller Körperfettanteil in %
- `{{lbm_28d_change}}` - Magermasse Änderung 28d (kg)
- `{{recomposition_quadrant}}` - Rekomposition-Status
- `{{waist_28d_delta}}` - Taillenumfang Änderung 28d (cm)
- `{{waist_hip_ratio}}` - Taille/Hüfte-Verhältnis
- `{{weight_28d_slope}}` - Gewichtstrend 28d (kg/Tag)
- `{{weight_7d_median}}` - Gewicht 7d Median (kg)
- `{{weight_aktuell}}` - Aktuelles Gewicht in kg
- `{{weight_trend}}` - Gewichtstrend (7d/30d)
### Profil (4 placeholders)
- `{{age}}` - Alter in Jahren
- `{{geschlecht}}` - Geschlecht
- `{{height}}` - Körpergröße in cm
- `{{name}}` - Name des Nutzers
### Schlaf & Erholung (7 placeholders)
- `{{rest_days_count}}` - Anzahl Ruhetage (30d)
- `{{sleep_avg_duration}}` - Durchschn. Schlafdauer (7d)
- `{{sleep_avg_duration_7d}}` - Schlaf 7d (Stunden)
- `{{sleep_avg_quality}}` - Durchschn. Schlafqualität (7d)
- `{{sleep_debt_hours}}` - Schlafschuld (Stunden)
- `{{sleep_quality_7d}}` - Schlafqualität 7d (0-100)
- `{{sleep_regularity_proxy}}` - Schlaf-Regelmäßigkeit (Min Abweichung)
### Scores (Phase 0b) (6 placeholders)
- `{{activity_score}}` - Activity Score (0-100)
- `{{body_progress_score}}` - Body Progress Score (0-100)
- `{{data_quality_score}}` - Data Quality Score (0-100)
- `{{goal_progress_score}}` - Goal Progress Score (0-100)
- `{{nutrition_score}}` - Nutrition Score (0-100)
- `{{recovery_score}}` - Recovery Score (0-100)
### Training (9 placeholders)
- `{{ability_balance_endurance}}` - Ability Balance - Ausdauer (0-100)
- `{{ability_balance_strength}}` - Ability Balance - Kraft (0-100)
- `{{activity_summary}}` - Aktivitäts-Zusammenfassung (7d)
- `{{proxy_internal_load_7d}}` - Proxy Load 7d
- `{{quality_sessions_pct}}` - Qualitätssessions (%)
- `{{rest_day_compliance}}` - Ruhetags-Compliance (%)
- `{{training_frequency_7d}}` - Trainingshäufigkeit 7d
- `{{training_minutes_week}}` - Trainingsminuten pro Woche
- `{{trainingstyp_verteilung}}` - Verteilung nach Trainingstypen
### Unknown (49 placeholders)
- `{{ability_balance_coordination}}` - No description available
- `{{ability_balance_mental}}` - No description available
- `{{ability_balance_mobility}}` - No description available
- `{{active_goals_json}}` - No description available
- `{{active_goals_md}}` - No description available
- `{{activity_detail}}` - No description available
- `{{arm_28d_delta}}` - No description available
- `{{caliper_summary}}` - No description available
- `{{chest_28d_delta}}` - No description available
- `{{circ_summary}}` - No description available
- `{{correlation_energy_weight_lag}}` - No description available
- `{{correlation_load_hrv}}` - No description available
- `{{correlation_load_rhr}}` - No description available
- `{{correlation_protein_lbm}}` - No description available
- `{{correlation_sleep_recovery}}` - No description available
- `{{energy_deficit_surplus}}` - No description available
- `{{focus_area_weights_json}}` - No description available
- `{{focus_areas_weighted_json}}` - No description available
- `{{focus_areas_weighted_md}}` - No description available
- `{{focus_cat_lebensstil_progress}}` - No description available
- `{{focus_cat_lebensstil_weight}}` - No description available
- `{{focus_cat_mental_progress}}` - No description available
- `{{focus_cat_mental_weight}}` - No description available
- `{{focus_cat_recovery_progress}}` - No description available
- `{{focus_cat_recovery_weight}}` - No description available
- `{{focus_cat_vitalwerte_progress}}` - No description available
- `{{focus_cat_vitalwerte_weight}}` - No description available
- `{{goal_bf_pct}}` - No description available
- `{{goal_weight}}` - No description available
- `{{hip_28d_delta}}` - No description available
- `{{intake_volatility}}` - No description available
- `{{monotony_score}}` - No description available
- `{{nutrition_days}}` - No description available
- `{{plateau_detected}}` - No description available
- `{{protein_days_in_target}}` - No description available
- `{{protein_ziel_high}}` - No description available
- `{{protein_ziel_low}}` - No description available
- `{{recent_load_balance_3d}}` - No description available
- `{{strain_score}}` - No description available
- `{{thigh_28d_delta}}` - No description available
- `{{top_3_focus_areas}}` - No description available
- `{{top_3_goals_behind_schedule}}` - No description available
- `{{top_3_goals_on_track}}` - No description available
- `{{top_drivers}}` - No description available
- `{{top_goal_name}}` - No description available
- `{{top_goal_progress_pct}}` - No description available
- `{{top_goal_status}}` - No description available
- `{{weight_90d_slope}}` - No description available
- `{{zeitraum_90d}}` - No description available
### Vitalwerte (6 placeholders)
- `{{hrv_vs_baseline_pct}}` - HRV vs. Baseline (%)
- `{{rhr_vs_baseline_pct}}` - RHR vs. Baseline (%)
- `{{vitals_avg_hr}}` - Durchschn. Ruhepuls (7d)
- `{{vitals_avg_hrv}}` - Durchschn. HRV (7d)
- `{{vitals_vo2_max}}` - Aktueller VO2 Max
- `{{vo2max_trend_28d}}` - VO2max Trend 28d
### Zeitraum (3 placeholders)
- `{{datum_heute}}` - Heutiges Datum
- `{{zeitraum_30d}}` - 30-Tage-Zeitraum
- `{{zeitraum_7d}}` - 7-Tage-Zeitraum

View File

@ -0,0 +1,24 @@
# Placeholder Export Specification
**Version:** 1.0.0
**Generated:** 2026-03-29 19:26:40
## API Endpoints
### Extended Export
```
GET /api/prompts/placeholders/export-values-extended
Header: X-Auth-Token: <token>
```
Returns complete metadata for all 116 placeholders.
### ZIP Export (Admin)
```
GET /api/prompts/placeholders/export-catalog-zip
Header: X-Auth-Token: <token>
```
Returns ZIP with all catalog files.

View File

@ -0,0 +1,66 @@
# Placeholder Metadata Gap Report
**Generated:** 2026-03-29 19:26:40
**Total Placeholders:** 111
## Gaps Summary
### Missing Data Layer Module
Count: 100
- {{name}}
- {{age}}
- {{height}}
- {{geschlecht}}
- {{bmi}}
- {{goal_weight}}
- {{goal_bf_pct}}
- {{nutrition_days}}
- {{protein_ziel_low}}
- {{protein_ziel_high}}
- ... and 90 more
### Missing Semantic Contract
Count: 25
- {{bmi}}
- {{goal_bf_pct}}
- {{rest_days_count}}
- {{vitals_vo2_max}}
- {{data_quality_score}}
- {{top_goal_progress_pct}}
- {{waist_hip_ratio}}
- {{energy_deficit_surplus}}
- {{protein_days_in_target}}
- {{macro_consistency_score}}
- ... and 15 more
### Missing Source Tables
Count: 90
- {{name}}
- {{age}}
- {{height}}
- {{geschlecht}}
- {{bmi}}
- {{goal_weight}}
- {{goal_bf_pct}}
- {{nutrition_days}}
- {{protein_ziel_low}}
- {{protein_ziel_high}}
- ... and 80 more
### Unknown Time Window
Count: 74
- {{bmi}}
- {{caliper_summary}}
- {{goal_weight}}
- {{goal_bf_pct}}
- {{nutrition_days}}
- {{protein_ziel_low}}
- {{protein_ziel_high}}
- {{activity_summary}}
- {{activity_detail}}
- {{trainingstyp_verteilung}}
- ... and 64 more

View File

@ -0,0 +1,386 @@
# Normative Standardspezifikation
## Placeholder-Metadaten, Exportverträge und Governance
**Version:** 1.0.0
**Stand:** 29.03.2026
**Status:** Verbindlicher Standard
**Geltungsbereich:** Alle bestehenden, neuen und zukünftigen Platzhalter des Systems
---
## 1. Normativer Status
Dieses Dokument ist **keine bloße Projektbeschreibung**, sondern eine **verbindliche Standardspezifikation** für das Placeholder-System.
Es gilt für:
- alle aktuell existierenden Platzhalter,
- alle künftig neu eingeführten Platzhalter,
- alle technisch abgeleiteten Exportformate,
- alle Prompt-, Pipeline- und Analyseverwendungen, die auf Placeholders zugreifen,
- alle künftigen Erweiterungen der Placeholder-Registry, des Data Layers und der Exportfunktionen.
### 1.1 Verbindlichkeit
Alle neuen und geänderten Placeholder-Implementierungen **müssen** dieser Spezifikation entsprechen. Abweichungen sind nur zulässig, wenn sie:
1. explizit dokumentiert,
2. versioniert,
3. mit `known_issues` und/oder `deprecated` markiert,
4. und in einem Gap- oder Decision-Log nachvollziehbar begründet werden.
### 1.2 Vorrang
Diese Spezifikation hat Vorrang vor:
- unvollständigen Altbeschreibungen,
- impliziten Verhaltensannahmen in Legacy-Prompts,
- nicht dokumentierten Exportkonventionen,
- informellen Teamabsprachen.
Wenn bestehender Code oder bestehende Exporte von dieser Spezifikation abweichen, ist die Abweichung als **Legacy-Zustand** zu markieren und über Versionierung/Deprecation zu behandeln.
---
## 2. Zielbild
Das System besitzt bereits einen funktionierenden Placeholder-Export und einen Data Layer als Single Source of Truth für Charts, Scores und KI-Platzhalter. Dieser Standard definiert, wie Placeholder künftig **semantisch, technisch und governance-seitig** beschrieben, exportiert und weiterentwickelt werden.
Jeder Placeholder muss als **stabiler, dokumentierter API-Vertrag** behandelbar sein.
Der Standard verlangt, dass zu jedem Placeholder mindestens folgende Ebenen eindeutig bestimmbar oder explizit als unbekannt markiert sind:
1. **Ist-Wert / Beispielwert**
2. **Technische Herkunft**
3. **Semantischer Vertrag**
4. **Fehlwert- und Ausnahmebehandlung**
5. **Qualitäts-/Confidence-Logik**
6. **Verwendungsnachweise**
7. **Versionierung / Deprecation / Nachfolger**
---
## 3. Verbindliche Architekturprinzipien
### 3.1 Placeholder = API-Vertrag
Placeholder sind keine lose Prompt-Hilfe, sondern **stabile API-Verträge**. Semantik, Einheit, Zeitfenster, Rückgabetyp und Fehlwertverhalten müssen dokumentiert und versioniert sein.
### 3.2 Non-breaking first
Bestehende Exporte und bestehende Placeholder-Namen dürfen nicht stillschweigend breaking geändert werden. Änderungen an Semantik, Zeitfenster, Einheit oder Rückgabetyp sind:
- entweder über neue Versionen,
- oder über neue Nachfolger-Platzhalter,
- oder über explizite Deprecation-Pfade
abzubilden.
### 3.3 JSON vor Freitext
Komplexe Metadaten, Rohdaten, strukturierte Diagnosen und technische Hinweise sind primär als JSON bereitzustellen. Freitext darf ergänzen, aber keine strukturierte Pflichtinformation ersetzen.
### 3.4 Zeitfenster explizit
Zeitbezogene Placeholder müssen ein explizites Zeitfenster tragen mindestens als Metadatum. Legacy-Namen ohne eindeutiges Zeitfenster dürfen im Bestand fortbestehen, müssen aber als semantisch unpräzise markiert werden und einen empfohlenen Nachfolger erhalten.
### 3.5 Fehlwerte explizit
Fehlende Werte dürfen im strukturierten Export nicht nur als String wie `"nicht verfügbar"` modelliert werden. Verbindlich sind strukturierte Felder wie:
- `available`
- `value_raw`
- `missing_reason`
- `missing_value_policy`
### 3.6 Typisierung ist Pflicht
Jeder Placeholder muss einem Typ zugeordnet werden:
- `atomic`
- `raw_data`
- `interpreted`
- `legacy_unknown` (nur als Übergang)
### 3.7 Data Layer bleibt Single Source of Truth
Fachliche Berechnungen dürfen nicht im Exporter dupliziert oder neu erfunden werden. Der Exporter sammelt Metadaten und referenziert technische Herkunft; er ersetzt keine fachlichen Kernfunktionen.
### 3.8 Kein stilles Raten
Wenn technische Herkunft, Zeitfenster, Ausnahmebehandlung oder sonstige Metadaten nicht sicher aus dem Code bestimmbar sind, muss der Zustand als `unknown`, `not_resolved` oder `partially_resolved` markiert werden.
### 3.9 Zukunftsgeltung
Jeder neue Placeholder **muss vor produktivem Einsatz** in Registry, Export und Katalog vollständig gegen dieses Dokument validiert werden.
---
## 4. Geltungsbereich und Pflichtanwendung
### 4.1 Diese Spezifikation gilt für
- bestehende produktive Placeholder,
- neue Placeholder in aktiver Entwicklung,
- experimentelle Placeholder, sobald sie außerhalb eines reinen Dev-Modus verwendet werden,
- Placeholder in Multi-Stage-Pipelines,
- Placeholder in Reports, Dashboards, Prompt-Templates und Exporten.
### 4.2 Diese Spezifikation gilt auch für
- neue Goal-/Score-/Correlation-/Driver-Placeholder,
- künftige Trainingstyp-/Subcategory-Placeholder,
- Placeholder für Diagnose-, Risiko- und Recovery-Logik,
- technische Export-Erweiterungen,
- Two-Stage-Artefakte.
### 4.3 Nicht zulässig ohne Standardkonformität
Nicht zulässig ist:
- ein neuer Placeholder ohne dokumentierten Semantikvertrag,
- ein neuer Placeholder ohne Zeitfenster-Metadatum,
- ein strukturierter Placeholder ohne definierten Output-Typ,
- ein produktiver Placeholder ohne dokumentierte Fehlwertbehandlung,
- ein interpretierter Placeholder ohne Kennzeichnung als solcher.
---
## 5. Scope des technischen Auftrags
### 5.1 In Scope
Der Coding Agent soll:
1. alle existierenden Placeholder inventarisieren,
2. die Metadaten je Placeholder technisch erheben oder als unresolved markieren,
3. einen erweiterten Export erzeugen,
4. einen menschenlesbaren und maschinenlesbaren Katalog erzeugen,
5. die Katalog-/Exportstruktur so implementieren, dass sie **für alle zukünftigen Placeholder wiederverwendbar** ist,
6. Tests und Validierungen ergänzen,
7. Gap-Reports für nicht automatisch auflösbare Metadaten erzeugen.
### 5.2 Out of Scope
Nicht gefordert ist:
- sofortige komplette fachliche Neudefinition aller Legacy-Placeholder,
- sofortige Umbenennung aller problematischen Namen,
- Umsetzung aller in anderen Dokumenten vorgeschlagenen neuen Wunsch-Placeholder,
- Neuimplementierung des gesamten Prompt-Systems.
### 5.3 Zukunftsanforderung
Die technische Lösung muss so gebaut sein, dass **jeder zukünftige Placeholder** denselben Katalog- und Exportmechanismus automatisch oder mit minimalem Zusatzaufwand durchlaufen kann.
---
## 6. Ziel-Deliverables
### 6.1 Code / Export
1. **Erweiterter Placeholder-Export**
- neuer Endpoint, CLI, Service-Funktion oder Exportmodus
- Legacy-Export bleibt kompatibel
2. **Zentrales Metadatenmodell / Registry-Erweiterung**
- wiederverwendbar für bestehende und zukünftige Placeholder
3. **Validierungslogik für neue Placeholder**
- technische Prüfung gegen dieses Dokument
### 6.2 Dateien / Dokumentation
4. `PLACEHOLDER_CATALOG_EXTENDED.json`
5. `PLACEHOLDER_CATALOG_EXTENDED.md`
6. `PLACEHOLDER_EXPORT_SPEC.md`
7. `PLACEHOLDER_GAP_REPORT.md`
8. optional: `PLACEHOLDER_VALIDATION_REPORT.md`
### 6.3 Tests
9. Tests für:
- Vollständigkeit des Exports,
- Konsistenz der Metadaten,
- Legacy-Kompatibilität,
- Referenzierbarkeit der Verwendungen,
- Pflichtfeld-Validierung für neue Placeholder,
- normkonforme Typisierung und Zeitfenster-Markierung.
---
## 7. Verbindliches Metadaten-Schema pro Placeholder
Jeder Placeholder im erweiterten Export muss mindestens die folgenden Felder besitzen oder explizit als `unknown`/`null`/leer markiert sein.
```json
{
"key": "weight_aktuell",
"placeholder": "{{weight_aktuell}}",
"category": "Körper",
"type": "atomic",
"description": "Aktuelles Gewicht in kg",
"semantic_contract": "Letzter verfügbarer Gewichtseintrag des Profils, keine Mittelung",
"unit": "kg",
"time_window": "latest",
"output_type": "number_or_string",
"format_hint": "85.8 kg",
"example_output": "85.8 kg",
"value_display": "85.8 kg",
"value_raw": 85.8,
"available": true,
"missing_reason": null,
"missing_value_policy": {
"legacy_display": "nicht verfügbar",
"structured_null": true,
"reason_codes": ["no_data", "insufficient_data", "resolver_error"]
},
"exception_handling": {
"on_error": "return_null_and_reason",
"notes": "Keine Exception bis in Prompt-Ebene durchreichen"
},
"quality_filter_policy": null,
"confidence_logic": {
"supported": false,
"notes": "Für latest-Werte nicht erforderlich"
},
"source": {
"resolver": "get_latest_weight_placeholder",
"module": "placeholder_resolver.py",
"function": "get_latest_weight",
"data_layer_module": "body_metrics.py",
"source_tables": ["weight_log"]
},
"dependencies": ["profile_id"],
"used_by": {
"prompts": ["gesamt", "koerper"],
"pipelines": ["pipeline", "wettkampf-analyse"],
"charts": []
},
"version": "1.0.0",
"deprecated": false,
"replacement": null,
"known_issues": [],
"notes": []
}
```
### 7.1 Pflichtfelder
Pflichtfelder sind:
- `key`
- `placeholder`
- `category`
- `type`
- `description`
- `semantic_contract`
- `unit`
- `time_window`
- `output_type`
- `value_display`
- `available`
- `missing_value_policy`
- `source`
- `version`
- `deprecated`
### 7.2 Erlaubte Werte für `type`
- `atomic`
- `raw_data`
- `interpreted`
- `legacy_unknown`
### 7.3 Erlaubte Werte für `time_window`
- `latest`
- `7d`
- `14d`
- `28d`
- `30d`
- `90d`
- `custom`
- `mixed`
- `unknown`
### 7.4 Erlaubte Werte für `output_type`
- `string`
- `number`
- `integer`
- `boolean`
- `json`
- `markdown`
- `date`
- `enum`
- `unknown`
---
## 8. Exportformat
### 8.1 Legacy-Export bleibt erhalten
Der bestehende Export bleibt unverändert nutzbar.
### 8.2 Neuer erweiterter Export
Zusätzlich muss ein erweiterter Export existieren, z. B. mit:
- `legacy`
- `metadata.by_category`
- `metadata.flat`
- `metadata.summary`
- `metadata.gaps`
- `metadata.schema_version`
### 8.3 Zukunftsfähigkeit
Der erweiterte Export muss so strukturiert sein, dass neue Placeholder ohne Redesign der Gesamtstruktur ergänzt werden können.
---
## 9. Pflichtregeln für neue und zukünftige Placeholder
Jeder neue Placeholder muss vor Freigabe folgende Fragen beantworten können:
1. Was ist die exakte fachliche Semantik?
2. Welches Zeitfenster gilt?
3. Welcher Typ liegt vor?
4. Was ist der Output-Typ?
5. Welche Datenquelle/Funktion berechnet ihn?
6. Wie werden fehlende Werte dargestellt?
7. Welche Ausnahmebehandlung gilt?
8. Welche bekannten Grenzen/Issues gibt es?
9. Wird ein Quality-Filter angewendet?
10. Ist der Placeholder in Prompts/Pipelines referenziert?
Wenn eine dieser Fragen unbeantwortet bleibt, darf der Placeholder nicht als voll standardkonform gelten.
---
## 10. Legacy-, Deprecation- und Abweichungsregeln
### 10.1 Legacy-Markierung
Bestehende problematische Placeholder dürfen als Legacy bestehen bleiben, wenn sie markiert werden durch:
- `deprecated: true/false`
- `known_issues`
- `replacement`
- dokumentierten Semantikhinweis
### 10.2 Deprecation-Pflicht
Wenn ein Placeholder semantisch unpräzise, technisch instabil oder fachlich überholt ist, muss ein Deprecation-Pfad vorgesehen werden.
### 10.3 Abweichungsprozess
Abweichungen von diesem Standard müssen in einem Decision-/Gap-Log dokumentiert werden, mit:
- Begründung,
- Impact,
- geplanter Nachbesserung,
- Verantwortlichkeit.
---
## 11. Validierung und Governance
### 11.1 Pflichtvalidierungen
Für bestehende und neue Placeholder müssen validierbar sein:
- Pflichtfeld-Vollständigkeit,
- gültige Typisierung,
- gültiges Zeitfenster,
- dokumentierte Quelle,
- dokumentiertes Fehlwertverhalten,
- dokumentierte Legacy-/Deprecation-Information.
### 11.2 CI-/Test-Eignung
Die technische Lösung soll so gebaut werden, dass künftige Validierungen automatisierbar sind.
### 11.3 Two-Stage-Artefakte
Interpretierte Outputs aus Basis-Prompts müssen als `interpreted` gekennzeichnet werden und dürfen nicht als rohe Datenplaceholder ausgegeben werden.
---
## 12. Konkrete Arbeitsanweisung an den Coding Agent
Der Coding Agent soll diese Spezifikation als **verbindlichen Standard** behandeln und die Implementierung so auslegen, dass sie:
- den aktuellen Bestand vollständig erfasst,
- für künftige Placeholder wiederverwendbar ist,
- Legacy-Verhalten nicht still bricht,
- technische Lücken transparent markiert,
- und als Grundlage für zukünftige Placeholder-Governance dient.
---
## 13. Akzeptanzkriterien
Die Umsetzung gilt nur dann als erfolgreich, wenn:
1. alle existierenden Placeholder im erweiterten Katalog enthalten sind,
2. der Legacy-Export weiter funktioniert,
3. das Metadatenmodell für neue Placeholder wiederverwendbar ist,
4. Pflichtfelder validiert werden,
5. unresolved Informationen sauber markiert werden,
6. die Dokumentation ausdrücklich festhält, dass der Standard **für alle neuen und zukünftigen Placeholder** gilt.
---
## 14. Schlussregel
Ab Inkrafttreten dieses Dokuments ist ein neuer Placeholder ohne Standardkonformität nur als explizit dokumentierte Ausnahme zulässig. Der Default ist Standardpflicht, nicht informelle Flexibilität.

View File

@ -0,0 +1,5 @@
# Platzhalter-Audits (Archiv)
Enthält Kataloge, Gap-Reports und Reconciliation-Artefakte (2026-03). **Normative Entwicklerregeln** für Platzhalter: `../../technical/PLACEHOLDER_REGISTRY_FRAMEWORK.md`.
**Entfernte Doppelungen:** `DATA_ARCHITECTURE.md` und `mitai_jinkendo_konzept_diagramme_auswertungen_v2.md` lagen identisch auch hier kanonisch sind jetzt nur noch `../../functional/DATA_ARCHITECTURE.md` bzw. `../../functional/mitai_jinkendo_konzept_diagramme_auswertungen_v2.md`.

View File

@ -0,0 +1,463 @@
# Placeholder-Audit: Executive Summary
**Audit-Datum:** 29. März 2026
**Umfang:** 111 Platzhalter (vollständig)
**Normative Basis:** PLACEHOLDER_METADATA_REQUIREMENTS_V2_NORMATIVE.md v1.0.0
**Audit-Methodik:** 4 spezialisierte Agents (Code, Semantik, Zeit/Confidence, Usage)
**Audit-Dauer:** ~590 Sekunden (4 Agents parallel)
---
## Compliance-Übersicht
### Gesamtergebnis: 7% voll normkonform (8/111)
| Compliance-Level | Anzahl | Prozent | Hauptprobleme |
|------------------|--------|---------|---------------|
| **Compliant** | 8 | 7% | Best-Practice-Beispiele (nutrition_avg, weight_aktuell) |
| **Partially Compliant** | 22 | 20% | 1-2 Gaps (meist time_window oder confidence) |
| **Non-Compliant** | 81 | 73% | 3+ kritische Gaps |
---
## Kritische Zahlen
### Systemische Gaps (nach Normative Requirements)
| Gap-Typ | Anzahl | Prozent | Norm-Verstoß |
|---------|---------|---------|--------------|
| **time_window: unknown** | 74 | 67% | §3.4 "Zeitfenster explizit" |
| **Keine Confidence-Logik** | 103 | 93% | §5 "Qualitäts-/Confidence-Logik" |
| **Kein data_layer_module** | 100 | 90% | §7 "Source" vollständig |
| **Keine Mindestdaten definiert** | 99 | 89% | Implizit in §5 |
| **category: Unknown** | 49 | 44% | §7.1 "Pflichtfelder: category" |
| **description: "No description"** | 49 | 44% | §7.1 "Pflichtfelder: description" |
| **Keine source_tables** | 90 | 81% | §7 "Source: source_tables" |
| **metadata_completeness_score: 0** | 111 | 100% | Kein Placeholder produktionsreif |
| **schema_status: draft** | 111 | 100% | §13 Akzeptanzkriterien |
---
## Wichtigste Systemische Schwächen
### 1. Metadaten-Dokumentation fundamental unvollständig
**Problem:**
- 100% der Platzhalter haben `metadata_completeness_score: 0`
- 44% ohne fachliche Kategorie ("Unknown")
- 44% ohne Beschreibung ("No description available")
- Kein einziger Platzhalter hat Status "production"
**Impact:**
- Platzhalter können nicht als stabile API-Verträge genutzt werden
- Prompt-Bibliothek hat keine verlässliche Metadaten-Basis
- Neue Platzhalter haben kein Qualitätsvorbild
**Root Cause:**
- Export-System generiert Struktur, füllt aber nicht alle Felder
- Keine systematische Dokumentationspflicht im Development-Workflow
---
### 2. Zeitfenster-Chaos
**Problem:**
- 67% ohne definiertes Zeitfenster (`time_window: unknown`)
- Code-Inkonsistenzen:
- `activity_summary`: Docs "7d", Code 14d, Metadaten "unknown"
- `weight_trend`: Docs "7d/30d", Code 28d, Metadaten "unknown"
- Namen-Metadaten-Mismatch:
- `zeitraum_7d`, `zeitraum_30d`, `zeitraum_90d` → alle `time_window: unknown`
- `sleep_avg_duration_7d``time_window: unknown`
**Impact:**
- KI kann Zeitfenster nicht interpretieren
- Reports können nicht korrekt zeitlich einordnen
- Vergleiche zwischen Platzhaltern problematisch
**Root Cause:**
- Zeitfenster wird oft im Code definiert, aber nicht in Metadaten übertragen
- Keine automatische Extraktion aus Funktionsnamen/Parametern
---
### 3. Fehlende Confidence-Systeme
**Problem:**
- Nur 8 Platzhalter (7%) haben Confidence-Logik
- 103 ohne jegliche Datenqualitäts-Signale
- Kritisch bei:
- **Trend-Platzhaltern** (slope, delta, change) → keine Warnung bei zu wenig Datenpunkten
- **Score-Platzhaltern** (nutrition_score, activity_score) → keine Reliability-Info
- **Korrelations-Platzhaltern** → keine Min-Data-Thresholds
**Impact:**
- KI kann nicht zwischen "sicher" und "unsicher" unterscheiden
- User erhält keine Warnung bei unreliablen Werten
- Prompt-Logik muss blind vertrauen oder eigene Heuristiken entwickeln
**Root Cause:**
- Nur nutrition_metrics, body_metrics, activity_metrics haben `calculate_confidence()`
- Andere Data-Layer-Module ohne Confidence-Pattern
---
### 4. Unstrukturierte Fehlwertbehandlung
**Problem:**
- 70 Platzhalter mit "nicht verfügbar"-String statt strukturiertem Format
- Verstoß gegen Norm §3.5 "Fehlwerte explizit"
- Legacy-Only: `missing_value_policy.legacy_display: "nicht verfügbar"`
- Keine strukturierten Felder: `available`, `value_raw`, `missing_reason`
**Impact:**
- KI muss String-Parsing betreiben ("nicht verfügbar" vs. "0" vs. "null")
- Keine maschinenlesbare Unterscheidung zwischen Fehlertypen
- Folgeprompts können nicht unterscheiden: Daten fehlen vs. Fehler aufgetreten
**Root Cause:**
- Historisches Legacy-Format aus v1 des Placeholder-Systems
- Kein strukturierter Refactor durchgeführt
---
### 5. 67 Platzhalter noch nicht produktiv eingebunden
**Status:**
- 67 Platzhalter (60%) haben 0 Verwendungen in Prompts/Pipelines/Charts
- **Wichtig:** Dies ist KEIN Technical Debt, sondern erwartbar bei Prompt-Bibliothek im Aufbau
- Viele in Kategorie "Unknown" (41 von 49 Unknown-Platzhaltern ungenutzt)
**Fachliche Klassifizierung (siehe USAGE_ROLE_CLASSIFICATION.md):**
- **30 Platzhalter (45%):** Explizit in Roadmap Phase 0c/1/2 geplant
- Scores (6), Correlations (5), Ability Balance (5), Goals Details (11), Sleep Debt, Plateau Detection, Top Drivers
- **37 Platzhalter (55%):** Fachlich plausibel, noch nicht in Prompts integriert
- Body Deltas, Nutrition Details, Training Quality, Focus Category Weights/Progress, Meta/Convenience
- **0 Platzhalter:** Redundant oder deprecation-würdig
**Interpretation:**
- Prompt-Bibliothek ist in Phase 0b/0c (Goals, Data Architecture)
- Phase 1 (Charts), Phase 2 (Correlations) werden 30+ Platzhalter aktivieren
- Kein Deprecation-Bedarf Integration statt Deletion erforderlich
**Next Steps:**
- Integration-Timeline für 30 geplante Platzhalter (Phase 0c/1/2)
- Prompt-Use-Cases für 10-15 plausible Platzhalter identifizieren
- Nutzungsrate wird von 40% auf 50-60% steigen (organisch)
---
## Größte Risiken für Prompt-Bibliothek und Reporting
### 1. Breaking-Change-Risiko (🔴 HIGH)
**12 produktkritische Platzhalter mit 3-19 Verwendungen:**
| Placeholder | Uses | Risk | Reason |
|-------------|------|------|--------|
| `{{name}}` | 19 | 🔴 EXTREM | In 9 Prompts + 10 Pipelines |
| `{{geschlecht}}` | 14 | 🔴 EXTREM | Gender-specific Logik in 7 Prompts |
| `{{height}}` | 12 | 🔴 EXTREM | BMI-Berechnungen, Body Composition |
| `{{weight_aktuell}}` | 10 | 🔴 HOCH | Numerisch sensitiv, Format-Breaking |
| `{{weight_trend}}` | 10 | 🔴 HOCH | **Code-Docs-Konflikt!** |
| `{{goal_bf_pct}}` | 10 | 🔴 HOCH | Body Composition Goals |
| `{{caliper_summary}}` | 8 | 🟡 MITTEL | Body Fat Summary |
| `{{circ_summary}}` | 8 | 🟡 MITTEL | Circumference Summary |
| `{{goal_weight}}` | 8 | 🟡 MITTEL | Weight Goals |
| `{{protein_ziel_low/high}}` | 7 | 🟡 MITTEL | Nutrition Guidance |
| `{{activity_detail}}` | 4 | 🟡 MITTEL | **Time-Window unklar!** |
**Mitigation:**
- Jede Änderung an diesen 12 erfordert:
1. Identifikation aller betroffenen Prompts/Pipelines
2. Koordinierte Migration über alle Templates
3. Backward-Compatibility-Periode (2-4 Wochen)
4. Full Regression-Tests
---
### 2. Code-Dokumentations-Konflikte (🔴 HIGH)
**Bekannte Inkonsistenzen:**
| Placeholder | Description | Code | Metadaten | Status |
|-------------|-------------|------|-----------|--------|
| `weight_trend` | "7d/30d" | 28d | unknown | 🔴 KONFLIKT |
| `activity_summary` | "7d" | 14d | unknown | 🔴 KONFLIKT |
| `activity_detail` | unklar | 14d (default) | unknown | 🟡 UNKLAR |
**Impact:**
- Kein Single Source of Truth
- KI nutzt evtl. falsche Zeitfenster-Annahmen
- User-Verwirrung bei Zeit-Interpretation
**Mitigation:**
- **P0 Fix:** Code als autoritativ nehmen, Docs/Metadaten aktualisieren
- Automatische Konsistenz-Checks (CI/CD)
---
### 3. Prompt-Fragility (🟡 MEDIUM)
**Problem:**
- Platzhalter ohne Zeitfenster → KI kann Perioden nicht interpretieren
- Fehlende Confidence → KI kann Datenqualität nicht bewerten
- "nicht verfügbar"-Strings → KI muss raten ob Fehler oder kein Wert
**Beispiel-Szenarien:**
```
Prompt: "Analysiere die Gewichtsentwicklung basierend auf {{weight_trend}}"
Problem: KI weiß nicht, ob 7d, 28d oder 90d → falsche Interpretation möglich
Prompt: "Bewerte die Korrelation {{correlation_energy_weight_lag}}"
Problem: Keine Confidence → KI kann nicht warnen "nur 5 Datenpunkte, unreliabel"
```
**Mitigation:**
- Metadata-Enrichment für alle kritischen Platzhalter
- Strukturierte Missing-Value-Policies
---
### 4. Fehlende Produktions-Governance (🟡 MEDIUM)
**Indikatoren:**
- 100% Draft-Status → keine produktionsreifen Platzhalter
- 90% ohne Data-Layer-Module dokumentiert
- Keine Validierungslogik für neue Platzhalter
- Keine klaren Production-Ready-Kriterien
**Langfristige Konsequenzen:**
- Neue Entwickler können nicht erkennen, welche Platzhalter "safe to use" sind
- Keine Guidance für Prompt-Autoren (welche Platzhalter für welchen Use-Case)
- Akkumulation weiterer inkonsistenter Platzhalter
**KEIN Technical Debt:**
- 60% ungenutzte Platzhalter ≠ "tote Codepfade"
- Prompt-Bibliothek ist im Aufbau (Phase 0b/0c/1/2)
- Ungenutzte Platzhalter sind fachlich geplant oder plausibel
---
## Dokumentierte Normkonflikte zwischen Dateien
| Konflikt | Quelle 1 | Quelle 2 | Severity | Resolution |
|----------|----------|----------|----------|------------|
| **Zeitfenster weight_trend** | Description: "7d/30d" | Code: 28d | 🟡 MEDIUM | Code ist autoritativ → Docs aktualisieren |
| **Zeitfenster activity_summary** | Description: "7d" | Code: 14d | 🟡 MEDIUM | Code ist autoritativ → Docs aktualisieren |
| **Neue Platzhalter** | requirements_dev.md: 27 neue P1-P27 | Extended Catalog: 111 existierend | 🟢 INFO | requirements_dev ist Arbeitsdokument, kein Normativ |
| **Bestandszahlen** | Export Spec: 116 | Gap Report/Catalog: 111 | 🟢 INFO | 5 Platzhalter = Metafelder (schema_version, etc.) |
**Rangfolgen-Resolution (aus Audit-Auftrag):**
1. **NORMATIVE.md** (höchste Instanz) - Verbindliche Standardspezifikation
2. **Code** (aktueller Ist-Zustand) - Bei Konflikt Code > Docs
3. **Extended Catalog** (dokumentierter Stand) - Generated Truth
4. **requirements_dev.md** (Arbeitsdokument) - NICHT normativ, nur Planning
---
## Best-Practice-Modelle identifiziert
### Vollständig normkonforme Platzhalter (8):
**1. Nutrition Averages (4):**
- `protein_avg`, `kcal_avg`, `fat_avg`, `carb_avg`
**Warum Best-Practice:**
```
✅ time_window: 30d (explizit)
✅ aggregation: AVG() via nutrition_metrics.py
✅ min_data: 8 (low), 12 (medium), 18 (high)
✅ confidence_logic: calculate_confidence(data_points, 30, 'general')
✅ missing_value_policy: strukturiert (available=false, reason='insufficient_data')
✅ data_layer_module: nutrition_metrics.py
✅ source_tables: ['nutrition_log']
```
**2. Weight Aktuell (1):**
- `weight_aktuell`
**Warum Best-Practice:**
```
✅ time_window: latest
✅ aggregation: Latest entry ORDER BY date DESC LIMIT 1
✅ confidence_logic: high if exists, insufficient if no data
✅ data_layer_module: body_metrics.py
✅ source_tables: ['weight_log']
```
**3. Andere (3):**
- `weight_trend`, `circ_summary`, `age` (verschiedene Best-Practice-Aspekte)
---
## Audit-Methodik-Transparenz
### 4 Spezialisierte Agents (Parallel)
**1. Code-Evidence-Agent** (124s)
- **Aufgabe:** Vollständige Code-Analyse aller Resolver-Funktionen
- **Scope:** `placeholder_resolver.py` (Zeilen 1075-1221), `data_layer/*.py`, `routers/prompts.py`
- **Output:** Technische Herkunft, Source-Tables, Return-Types für alle 111
- **Evidence-Level:** `code_verified` (100%)
**2. Semantic-Contract-Agent** (218s)
- **Aufgabe:** Fachliche Bedeutung aus Dokumentation ableiten
- **Scope:** `DATA_ARCHITECTURE.md`, `mitai_jinkendo_konzept_diagramme_auswertungen_v2.md`, Extended Catalog
- **Output:** Description, Category, Semantic Contract für alle 111
- **Evidence-Level:** `documentation_verified` (56%), `fachlich_abgeleitet` (44%)
**3. Time-Window-Confidence-Agent** (90s)
- **Aufgabe:** Zeitfenster klassifizieren, Confidence-Patterns identifizieren
- **Scope:** Code + Catalog + Normative Spec (erlaubte time_window-Werte)
- **Output:** Zeit-Compliance, Aggregationslogik, Min-Data-Thresholds
- **Evidence-Level:** `code_verified` (75 unklar), `code_inferred` (rest)
**4. Prompt-Usage-Agent** (157s)
- **Aufgabe:** Verwendung in Prompts/Pipelines/Charts analysieren
- **Scope:** `ai_prompts` table (via Catalog), Grep-Suche nach `{{placeholder}}`
- **Output:** Used-By, Criticality, Rename-Risk
- **Evidence-Level:** `catalog_verified` (100%)
**Konsolidierung:**
- Cross-Agent-Validation (4 Perspektiven auf jeden Placeholder)
- Konflikt-Resolution nach Rangfolge (Norm > Code > Catalog > Docs)
- Evidence-Level-Klassifizierung (code_verified > documentation_verified > fachlich_abgeleitet > unclear)
---
## Nächste Kritische Schritte
### P0 (VOR PRODUCTION - BLOCKING)
**1. Zeitfenster-Klassifizierung (74 Platzhalter)**
- **Aufwand:** 8-12 Stunden
- **Methode:**
1. Namen-Analyse (`*_7d`, `*_28d`, etc.) → automatisch
2. Code-Analyse (default days-Parameter) → semi-automatisch
3. Fach-Entscheidung für Unklare (ability_balance, scores) → manuell
- **Deliverable:** Alle `time_window: unknown` → gültige Werte (latest/7d/14d/28d/30d/90d/mixed)
**2. Code-Docs-Konflikte auflösen (3 Platzhalter)**
- **Aufwand:** 2 Stunden
- **Items:**
- `weight_trend`: Description + Metadaten auf "28d" ändern
- `activity_summary`: Description + Metadaten auf "14d" ändern
- `activity_detail`: Default-Zeitfenster dokumentieren
- **Validation:** Automatische Konsistenz-Checks (Code ↔ Catalog)
**3. Kategorie + Beschreibung (49 Platzhalter)**
- **Aufwand:** 4-6 Stunden
- **Methode:** Bulk-Update aus Semantic-Contract-Agent-Report
- **Deliverable:**
- Alle `category: Unknown` → fachliche Kategorien
- Alle `description: "No description available"` → aussagekräftige Beschreibungen
---
### P1 (THIS SPRINT - HIGH PRIORITY)
**4. Confidence-Logik für Trend-/Delta-Platzhalter (11)**
- **Aufwand:** 12-16 Stunden
- **Items:**
- weight_28d_slope, weight_90d_slope, weight_7d_median
- fm_28d_change, lbm_28d_change
- waist_28d_delta, hip_28d_delta, chest_28d_delta, arm_28d_delta, thigh_28d_delta
- vo2max_trend_28d
- **Pattern:** `confidence = calculate_confidence(data_points, time_window_days, 'trend')`
- **Thresholds:** high >= 70%, medium >= 50%, low >= 30% data coverage
**5. Strukturierte Missing-Value-Policy (70 Platzhalter)**
- **Aufwand:** 8-10 Stunden
- **Refactor:**
- Legacy-String "nicht verfügbar" beibehalten (Backward-Compatibility)
- Zusätzlich strukturierte Felder: `available`, `missing_reason`, `value_raw`
- **Deliverable:** Dual-Mode-Support (Legacy + Structured)
**6. Data-Layer-Module dokumentieren (100 Platzhalter)**
- **Aufwand:** 6-8 Stunden
- **Methode:** Code-Trace von Resolver → Data-Layer (aus Code-Evidence-Agent)
- **Deliverable:** Alle `data_layer_module: null` → korrekte Module
---
### P2 (NEXT SPRINT - MEDIUM PRIORITY)
**7. Ungenutzte Platzhalter - Integration planen (67)**
- **Aufwand:** 4-6 Stunden
- **Methode:**
- Produktmanagement-Review: Timeline für 30 geplante Platzhalter (Phase 0c/1/2)
- Technische Review: Prompt-Use-Cases für 37 plausible Platzhalter
- **Deliverable:** Integration-Roadmap, Prompt-Templates (5-10 Quick Wins)
**8. Metadata-Completeness-Score auf >60% (111)**
- **Aufwand:** 10-12 Stunden
- **Methode:** Systematisches Füllen aller Pflichtfelder
- **Target:** Mindestens 60% der Platzhalter mit Score >60
**9. Schema-Status auf production (20-30 Core-Platzhalter)**
- **Aufwand:** 4-6 Stunden
- **Kriterien:**
- Metadata-Completeness >= 80%
- Used-By >= 1
- Keine Known-Issues
- Zeitfenster + Confidence definiert
- **Deliverable:** 20-30 produktionsreife Platzhalter
---
### P3 (LATER - NICE TO HAVE)
**10. Validation-Framework für neue Platzhalter**
- **Aufwand:** 16-20 Stunden
- **Features:**
- Pre-Commit-Hook: Validierung gegen Normative Spec
- CI/CD: Automatische Konsistenz-Checks (Code ↔ Catalog)
- Template-Generator für neue Platzhalter
**11. Migration-Guides für Prompt-Bibliothek**
- **Aufwand:** 8-12 Stunden
- **Content:**
- Best-Practice-Guide (basierend auf nutrition_avg)
- Anti-Patterns (was vermeiden)
- Upgrade-Path für Legacy-Prompts
---
## Geschätzter Gesamt-Remediationsaufwand
| Priority | Aufwand | Timeline | Dependencies |
|----------|---------|----------|--------------|
| **P0** | 14-20h | Week 1 | Keine (sofort startbar) |
| **P1** | 26-34h | Week 2-3 | Nach P0 |
| **P2** | 18-24h | Week 4-5 | Nach P1 |
| **P3** | 24-32h | Later | Nach P2 |
| **TOTAL** | **82-110h** | **4-6 Wochen** | Gestaffelt |
**Mit Team von 2 Entwicklern:** 2-3 Wochen für P0+P1, weitere 1-2 Wochen für P2.
---
## Abschluss-Statement
Der Placeholder-Audit hat **massive systemische Gaps** identifiziert, aber auch einen **klaren Remediation-Pfad** aufgezeigt. Die größten Probleme sind:
1. **Dokumentations-Gaps** (44% ohne Kategorie/Beschreibung)
2. **Zeitfenster-Chaos** (67% ohne definiertes Fenster)
3. **Fehlende Confidence-Systeme** (93% ohne Qualitäts-Signale)
Die **gute Nachricht**: Alle 111 Platzhalter sind im Code implementiert, haben eine saubere Architektur, und 8 dienen bereits als Best-Practice-Modelle. Die Lücken sind primär **dokumentarisch und metadatenbezogen**, nicht funktional.
Mit einem strukturierten P0-P3-Plan (82-110h Aufwand) kann das System in 4-6 Wochen auf **>60% Normkonformität** gebracht werden.
**Empfohlene nächste Schritte:**
1. Review dieses Executive Summary mit Product/Tech Lead
2. P0-Priorisierung bestätigen (Zeitfenster, Code-Docs-Konflikte, Kategorien)
3. Kickoff für P0-Sprint (Ziel: 74 Zeitfenster + 49 Kategorien/Beschreibungen)
---
**Audit durchgeführt von:** Claude Code (Lead Audit Agent)
**Agent-Team:** Code-Evidence, Semantic-Contract, Time-Window-Confidence, Prompt-Usage
**Normative Basis:** PLACEHOLDER_METADATA_REQUIREMENTS_V2_NORMATIVE.md v1.0.0
**Vollständige Artefakte:** Siehe `audit-report-2026-03-29/` für Gap-Cluster, Maßnahmenplan, Prüfmatrix

View File

@ -0,0 +1,651 @@
# Gap-Cluster-Bericht: Placeholder-Audit
**Audit-Datum:** 29. März 2026
**Basis:** 111 Platzhalter, 4-Agent-Analyse
**Normative Referenz:** PLACEHOLDER_METADATA_REQUIREMENTS_V2_NORMATIVE.md v1.0.0
---
## Übersicht
Dieser Bericht gruppiert die identifizierten Gaps nach **systemischen Clustern**, um gezielte Remediation-Strategien zu ermöglichen.
**Gesamtzahl Gaps:** 481 einzelne Gap-Instanzen über alle 111 Platzhalter
**Gap-Verteilung:**
```
Non-Compliant (81): 324 Gaps (durchschnittlich 4.0 pro Placeholder)
Partially Compliant (22): 88 Gaps (durchschnittlich 4.0 pro Placeholder)
Compliant (8): 0 Gaps
```
---
## GAP-CLUSTER
### CLUSTER 1: Missing Semantic Contract
**Anzahl betroffene Platzhalter:** 49 (44%)
**Severity:** 🔴 CRITICAL
**Norm-Verstoß:** §7.1 Pflichtfelder (description, semantic_contract)
**Sub-Kategorien:**
#### 1.1 No Description Available (49)
Alle 49 haben `description: "No description available"`
**Betroffene Kategorien:**
- **Unknown (49):** Alle 49 Non-Compliant sind in "Unknown"-Kategorie
- Ability Balance (5): coordination, endurance, mental, mobility, strength
- Correlations (5): energy_weight_lag, load_hrv, load_rhr, protein_lbm, sleep_recovery
- Body Deltas (5): arm_28d_delta, chest_28d_delta, hip_28d_delta, thigh_28d_delta, waist_28d_delta (doppelt)
- Goals (16): active_goals_json/md, focus_areas, top_goal_*, top_3_goals_*, goal_weight, goal_bf_pct
- Nutrition (6): energy_deficit_surplus, intake_volatility, nutrition_days, protein_days_in_target, protein_ziel_*
- Training (3): activity_detail, monotony_score, strain_score
- Summaries (3): caliper_summary, circ_summary, weight_90d_slope
- Meta (2): zeitraum_90d, recent_load_balance_3d
- Plateau (1): plateau_detected
- Top Drivers (1): top_drivers
**Remediation:**
- **Bulk-Update möglich:** Semantic-Contract-Agent-Report hat Target-Descriptions für alle 49
- **Aufwand:** 4-6 Stunden (Copy-Paste aus Agent-Report)
- **Priority:** P0 (blocking für Production)
---
#### 1.2 Weak Semantic Contract (25)
Haben Beschreibung, aber schwachen/unvollständigen Semantic Contract
**Beispiele:**
- `bmi`: Description OK, aber Semantic Contract = Description (sollte Formel enthalten)
- `rest_days_count`: Description OK, aber Aggregationslogik fehlt
- `vitals_vo2_max`: Description OK, aber Quelle/Berechnungsmethode fehlt
**Remediation:**
- **Individuelle Überarbeitung:** Semantic Contract mit Formeln/Quellen/Aggregationen anreichern
- **Aufwand:** 3-4 Stunden
- **Priority:** P1
---
### CLUSTER 2: Missing Data Layer Module
**Anzahl betroffene Platzhalter:** 100 (90%)
**Severity:** 🔴 CRITICAL
**Norm-Verstoß:** §7 Source vollständig (data_layer_module erforderlich)
**Analyse:**
- Nur 11 Platzhalter haben `data_layer_module` gesetzt
- 100 haben `data_layer_module: null`
**Root Cause:**
- Export-System extrahiert `data_layer_module` nur, wenn explizit in Code-Kommentaren
- Resolver nutzen oft Helper-Funktionen (`_safe_int`, `_safe_float`) statt direkter Data-Layer-Calls
- `_safe_int` ruft intern Data-Layer auf, aber Mapping ist nicht dokumentiert
**Code-Evidence-Agent Findings:**
- **81 nutzen Helper** (`_safe_int`, `_safe_float`, `_safe_str`, `_safe_json`)
- Diese HABEN Data-Layer-Module, sind aber nicht dokumentiert
- Beispiel: `_safe_int('nutrition_score', pid)` → ruft `data_layer.nutrition_metrics.calculate_nutrition_score()`
- **19 haben direkte Data-Layer-Calls** (z.B. nutrition_avg, weight_aktuell)
- **0 echte Fälle ohne Data-Layer** (alle 111 haben technische Herkunft)
**Remediation:**
- **Code-Trace von Resolvern:** Für jede `_safe_*`-Funktion die gerufene Data-Layer-Funktion identifizieren
- **Bulk-Update:** Mapping aus Code-Evidence-Agent-Report übernehmen
- **Aufwand:** 6-8 Stunden
- **Priority:** P1
---
### CLUSTER 3: Missing Source Tables
**Anzahl betroffene Platzhalter:** 90 (81%)
**Severity:** 🔴 CRITICAL
**Norm-Verstoß:** §7 Source vollständig (source_tables erforderlich)
**Analyse:**
- Nur 21 Platzhalter haben `source_tables` gesetzt
- 90 haben `source_tables: []`
**Root Cause:**
- Identisch zu CLUSTER 2: Export-System extrahiert nicht aus Code
- Source-Tables sind in Data-Layer-SQL-Queries definiert, aber nicht in Resolver-Metadaten
**Code-Evidence-Agent Findings:**
- **Alle 111** haben identifizierbare Source-Tables im Code
- **9 Core-Tables:**
1. `profiles` (4 Platzhalter)
2. `weight_log` (11)
3. `nutrition_log` (12)
4. `activity_log` (14)
5. `sleep_log` (6)
6. `vitals_baseline` (8)
7. `circumference_log` (5)
8. `caliper_log` (5)
9. `goals`, `focus_areas`, `rest_days` (11)
**Remediation:**
- **Automatische Extraktion:** SQL-Query-Parsing in Data-Layer-Modulen
- **Bulk-Update:** Mapping aus Code-Evidence-Agent-Report übernehmen
- **Aufwand:** 6-8 Stunden
- **Priority:** P1
---
### CLUSTER 4: Unknown Time Window
**Anzahl betroffene Platzhalter:** 74 (67%)
**Severity:** 🔴 CRITICAL
**Norm-Verstoß:** §3.4 "Zeitfenster explizit"
**Analyse:**
- 74 haben `time_window: unknown`
- 37 haben definiertes Zeitfenster (latest, 7d, 28d, 30d, 90d, mixed)
**Sub-Kategorien:**
#### 4.1 Name enthält Zeitfenster, aber Metadaten unknown (15)
**KRITISCHER MISMATCH:**
| Placeholder | Name-Hint | Code | Metadaten | Fix |
|-------------|-----------|------|-----------|-----|
| `zeitraum_7d` | 7d | Hardcoded "letzte 7 Tage" | unknown | → 7d |
| `zeitraum_30d` | 30d | Hardcoded "letzte 30 Tage" | unknown | → 30d |
| `zeitraum_90d` | 90d | Hardcoded "letzte 90 Tage" | unknown | → 90d |
| `sleep_avg_duration_7d` | 7d | 7 days | unknown | → 7d |
| `sleep_quality_7d` | 7d | 7 days | unknown | → 7d |
| `training_frequency_7d` | 7d | 7 days (inferred) | unknown | → 7d |
| `proxy_internal_load_7d` | 7d | 7 days | unknown | → 7d |
| `energy_balance_7d` | 7d | 7 days | unknown | → 7d |
| `protein_adequacy_28d` | 28d | 28 days | unknown | → 28d |
| `weight_28d_slope` | 28d | 28 days | 28d | ✓ OK |
| `weight_90d_slope` | 90d | 90 days | 90d | ✓ OK |
| `fm_28d_change` | 28d | 28 days | 28d | ✓ OK |
| `lbm_28d_change` | 28d | 28 days | 28d | ✓ OK |
| `vo2max_trend_28d` | 28d | 28 days | 28d | ✓ OK |
| ... | | | | |
**Remediation:**
- **Automatische Regelextraktion:** Name-Pattern (`*_7d`, `*_28d`, etc.) → time_window
- **Aufwand:** 1 Stunde (automatisch)
- **Priority:** P0
---
#### 4.2 Code enthält Default-Zeitfenster (20)
Code nutzt `days=X` Parameter, aber Metadaten unknown
**Beispiele:**
- `activity_summary`: Code `days=14` (default), Metadaten unknown
- `sleep_avg_duration`: Code `days=7`, Metadaten unknown
- `rest_days_count`: Code `days=30`, Metadaten unknown
**Remediation:**
- **Code-Parameter-Extraktion:** Default-Werte aus Funktionssignaturen lesen
- **Aufwand:** 2-3 Stunden (semi-automatisch)
- **Priority:** P0
---
#### 4.3 Fach-Entscheidung erforderlich (39)
Zeitfenster nicht aus Name/Code ableitbar, fachliche Klassifizierung nötig
**Kategorien:**
**A. Scores (6):**
- `activity_score`, `nutrition_score`, `recovery_score`, `body_progress_score`, `goal_progress_score`, `data_quality_score`
- **Vorschlag:** `custom` oder `mixed` (kombinieren verschiedene Zeitfenster)
**B. Ability Balance (5):**
- `ability_balance_coordination`, `ability_balance_endurance`, `ability_balance_mental`, `ability_balance_mobility`, `ability_balance_strength`
- **Vorschlag:** `28d` (Rolling-Window-Balance über 28 Tage)
**C. Correlations (5):**
- `correlation_energy_weight_lag`, `correlation_load_hrv`, `correlation_load_rhr`, `correlation_protein_lbm`, `correlation_sleep_recovery`
- **Vorschlag:** `28d` (Min-Daten für reliable Korrelationen)
**D. Goals & Focus (16):**
- `active_goals_json`, `focus_areas_weighted_json`, `top_goal_*`, `top_3_goals_*`, `focus_cat_*`
- **Vorschlag:** `latest` (Snapshot) oder `custom` (je nach Progress-Berechnung)
**E. Snapshots (7):**
- `bmi`, `goal_weight`, `goal_bf_pct`, `waist_hip_ratio`, `recomposition_quadrant`, `plateau_detected`, `top_drivers`
- **Vorschlag:** `latest` (Momentaufnahme) oder `custom` (bei berechneten Werten)
**Remediation:**
- **Fach-Review mit Product:** Kategorisierungs-Entscheidungen abstimmen
- **Aufwand:** 4-6 Stunden (Meeting + Dokumentation)
- **Priority:** P0
---
### CLUSTER 5: Missing Confidence Logic
**Anzahl betroffene Platzhalter:** 103 (93%)
**Severity:** 🟡 HIGH
**Norm-Verstoß:** §5 "Qualitäts-/Confidence-Logik"
**Analyse:**
- Nur 8 Platzhalter haben `confidence_logic` implementiert
- 103 haben `confidence_logic: null`
**Implementierte Confidence (8):**
1. `protein_avg`, `kcal_avg`, `fat_avg`, `carb_avg` (nutrition_metrics)
2. `weight_aktuell`, `weight_trend` (body_metrics)
3. `caliper_summary`, `circ_summary` (body_metrics)
**Pattern:**
```python
confidence = calculate_confidence(data_points, time_window_days, metric_type)
Thresholds:
- high: >= 60% data coverage (e.g., >= 18/30 days)
- medium: >= 40% data coverage (e.g., >= 12/30 days)
- low: >= 26% data coverage (e.g., >= 8/30 days)
- insufficient: < 26% data coverage
```
**Fehlende Confidence-Logik besonders kritisch für:**
#### 5.1 Trend-Platzhalter (11)
**Warum kritisch:** Slopes/Trends mit nur 2-3 Datenpunkten sind unreliabel
| Placeholder | Time-Window | Min-Data empfohlen | Confidence-Logik |
|-------------|-------------|-------|------------------|
| `weight_28d_slope` | 28d | 18+ | ❌ Fehlt |
| `weight_90d_slope` | 90d | 60+ | ❌ Fehlt |
| `weight_7d_median` | 7d | 5+ | ❌ Fehlt |
| `fm_28d_change` | 28d | 2 (min), 18+ (ideal) | ❌ Fehlt |
| `lbm_28d_change` | 28d | 2 (min), 18+ (ideal) | ❌ Fehlt |
| `waist_28d_delta` | 28d | 2 (min) | ❌ Fehlt |
| `hip_28d_delta` | 28d | 2 (min) | ❌ Fehlt |
| `chest_28d_delta` | 28d | 2 (min) | ❌ Fehlt |
| `arm_28d_delta` | 28d | 2 (min) | ❌ Fehlt |
| `thigh_28d_delta` | 28d | 2 (min) | ❌ Fehlt |
| `vo2max_trend_28d` | 28d | 4+ | ❌ Fehlt |
**Remediation:**
- **Pattern-Anwendung:** `calculate_confidence()` in alle Delta/Slope-Funktionen einbauen
- **Aufwand:** 12-16 Stunden
- **Priority:** P1
---
#### 5.2 Score-Platzhalter (6)
**Warum kritisch:** Composite Scores sollten Confidence der Subkomponenten reflektieren
| Placeholder | Sub-Components | Confidence-Logik |
|-------------|----------------|------------------|
| `activity_score` | training_volume, frequency, quality | ❌ Fehlt |
| `nutrition_score` | energy_balance, protein_adequacy, macro_consistency | ❌ Fehlt |
| `recovery_score` | sleep_duration, sleep_quality, hrv, rhr | ❌ Fehlt |
| `body_progress_score` | weight_trend, bf_change, lbm_change | ❌ Fehlt |
| `goal_progress_score` | weighted goals progress | ❌ Fehlt |
| `data_quality_score` | data availability per domain | ❌ Fehlt |
**Remediation:**
- **Composite-Confidence:** Min(subcomponent_confidences)
- **Aufwand:** 8-10 Stunden
- **Priority:** P1
---
#### 5.3 Korrelations-Platzhalter (5)
**Warum kritisch:** Korrelationen mit <14 Paaren sind statistisch unreliabel
| Placeholder | Min-Pairs empfohlen | Confidence-Logik |
|-------------|---------------------|------------------|
| `correlation_energy_weight_lag` | 21+ | ❌ Fehlt |
| `correlation_load_hrv` | 21+ | ❌ Fehlt |
| `correlation_load_rhr` | 21+ | ❌ Fehlt |
| `correlation_protein_lbm` | 28+ (mit Training moderiert) | ❌ Fehlt |
| `correlation_sleep_recovery` | 21+ | ❌ Fehlt |
**Remediation:**
- **Correlation-Confidence:** Based on n_pairs (high >= 28, medium >= 21, low >= 14)
- **Aufwand:** 4-6 Stunden
- **Priority:** P1
---
### CLUSTER 6: Unstrukturierte Missing-Value-Policy
**Anzahl betroffene Platzhalter:** 110 (99%)
**Severity:** 🟡 MEDIUM
**Norm-Verstoß:** §3.5 "Fehlwerte explizit"
**Analyse:**
- 110 haben nur `missing_value_policy.legacy_display: "nicht verfügbar"`
- Nur 1 hat strukturierte Policy (weight_aktuell mit available=false, reason='no_data')
**Problem:**
- Legacy-String ist nicht maschinenlesbar
- Keine Unterscheidung zwischen Fehlertypen:
- `no_data`: Keine Daten in Datenbank
- `insufficient_data`: Zu wenig Daten für Berechnung
- `resolver_error`: Technischer Fehler
- `calculation_error`: Mathematischer Fehler (z.B. Division by zero)
**Norm-konformes Format (§3.5):**
```json
{
"available": false,
"value_raw": null,
"missing_reason": "insufficient_data",
"missing_value_policy": {
"legacy_display": "nicht verfügbar",
"structured_null": true,
"reason_codes": ["no_data", "insufficient_data", "resolver_error"]
}
}
```
**Remediation:**
- **Dual-Mode-Ansatz:**
- Legacy-String beibehalten (Backward-Compatibility)
- Zusätzlich strukturierte Felder (`available`, `missing_reason`, `value_raw`)
- **Aufwand:** 8-10 Stunden (Pattern-Anwendung auf alle Resolver)
- **Priority:** P1
---
### CLUSTER 7: Metadata Completeness Score 0
**Anzahl betroffene Platzhalter:** 111 (100%)
**Severity:** 🟡 MEDIUM
**Norm-Verstoß:** Kein direkter Verstoß, aber Indikator für fehlende Pflichtfelder
**Analyse:**
- Alle 111 haben `metadata_completeness_score: 0`
- Score-Berechnung (vermutlich):
```
score = (filled_fields / total_required_fields) * 100
```
- Da Score 0 → vermutlich wurden Pflichtfelder nicht als "gefüllt" erkannt
**Pflichtfelder (aus Norm §7.1):**
1. `key` ✅ (alle gefüllt)
2. `placeholder` ✅ (alle gefüllt)
3. `category` ❌ (49 Unknown)
4. `type` ✅ (alle gefüllt)
5. `description` ❌ (49 "No description")
6. `semantic_contract` ❌ (49 "No description")
7. `unit` ✅ (alle gefüllt)
8. `time_window` ❌ (74 unknown)
9. `output_type` ✅ (alle gefüllt)
10. `value_display` ❌ (111 null)
11. `available` ✅ (alle true)
12. `missing_value_policy` ✅ (alle gefüllt, aber schwach)
13. `source` ❌ (100 data_layer_module null, 90 source_tables [])
14. `version` ✅ (alle 1.0.0)
15. `deprecated` ✅ (alle false)
**Score 0 Root Cause:**
- Vermutlich zählen `null`/`unknown`/`[]`/`"No description"` als "nicht gefüllt"
- → 7 von 15 Pflichtfeldern nicht korrekt gefüllt = 0% Score
**Remediation:**
- **Nach P0+P1 Fixes:** Score sollte automatisch auf 40-60% steigen
- **Zusätzlich:** value_display für alle Platzhalter füllen (aus Beispieldaten)
- **Aufwand:** Inkludiert in anderen Clustern
- **Priority:** P2 (Indikator-Fix, nicht eigenständig)
---
### CLUSTER 8: Schema Status "draft"
**Anzahl betroffene Platzhalter:** 111 (100%)
**Severity:** 🟡 MEDIUM
**Norm-Verstoß:** §13 Akzeptanzkriterien (production-ready Platzhalter fehlen)
**Analyse:**
- Alle 111 haben `schema_status: draft`
- Keine Platzhalter im Status `production`, `beta`, oder `stable`
**Erlaubte Werte (vermutlich):**
- `draft`: Work in Progress
- `beta`: In Testing
- `stable`: Production-Ready, aber noch nicht finalisiert
- `production`: Voll produktionsreif, Breaking Changes verboten
**Kriterien für `production` (vorgeschlagen):**
1. `metadata_completeness_score >= 80`
2. `used_by.prompts.length >= 1 OR used_by.pipelines.length >= 1`
3. `time_window != 'unknown'`
4. `category != 'Unknown'`
5. `description != 'No description available'`
6. `confidence_logic != null OR type == 'atomic' with time_window == 'latest'`
7. `known_issues.length == 0`
**Kandidaten für `production` nach P0+P1 Fixes:**
- Nutrition Averages (4): protein_avg, kcal_avg, fat_avg, carb_avg
- Body Metrics (2): weight_aktuell, weight_trend
- Profil (4): name, age, height, geschlecht
- Summaries (2): caliper_summary, circ_summary
- **Total: 12-15 Kandidaten**
**Remediation:**
- **Automatische Bewertung:** Script zur Berechnung von Production-Eligibility
- **Manuelle Review:** Product/Tech Lead bestätigt Production-Status
- **Aufwand:** 4-6 Stunden
- **Priority:** P2
---
### CLUSTER 9: Ungenutzte Platzhalter (Orphans)
**Anzahl betroffene Platzhalter:** 67 (60%)
**Severity:** 🟢 LOW (aber Technical Debt)
**Norm-Verstoß:** Kein direkter Verstoß, aber Governance-Issue
**Analyse:**
- 67 Platzhalter haben `used_by.prompts: []`, `used_by.pipelines: []`, `used_by.charts: []`
- 0 Verwendungen = potentielle Deprecation-Kandidaten
**Kategorisierung:**
#### 9.1 Geplante Features (Phase 1b/1c) - behalten (30)
- Correlations (5): energy_weight_lag, load_hrv, load_rhr, protein_lbm, sleep_recovery
- Goals Details (11): active_goals_json/md, focus_areas, top_goals
- Ability Balance (5): coordination, endurance, mental, mobility, strength
- Scores (6): activity_score, nutrition_score, recovery_score, body_progress_score, goal_progress_score, data_quality_score
- Plateau (1): plateau_detected
- Top Drivers (1): top_drivers
- Sleep Debt (1): sleep_debt_hours
#### 9.2 Redundant/Obsolet - Deprecation prüfen (15)
- Body Deltas (4): arm_28d_delta, chest_28d_delta, hip_28d_delta, thigh_28d_delta (redundant zu waist_28d_delta Pattern)
- Training Load (3): monotony_score, strain_score, recent_load_balance_3d (noch nicht genutzt)
- Meta (3): zeitraum_90d, datum_heute (System-Platzhalter, wenig Wert)
- Vitals Trends (2): hrv_vs_baseline_pct, rhr_vs_baseline_pct (noch nicht genutzt)
- Sleep Regularity (1): sleep_regularity_proxy (experimentell)
- BMI (1): bmi (berechenbar, redundant)
- Waist-Hip-Ratio (1): waist_hip_ratio (berechenbar, redundant)
#### 9.3 Unklar - Product-Review (22)
- Rest: Weitere Ability Balance, Focus Cat Weights, etc.
**Remediation:**
- **Product-Review:** Welche für Phase 1b/1c/2 geplant? Welche streichen?
- **Deprecation-Strategie:** `deprecated: true`, `replacement: "new_placeholder"`, Sunset-Datum
- **Aufwand:** 4-6 Stunden (Meeting + Dokumentation)
- **Priority:** P2
---
### CLUSTER 10: Export-Inkonsistenzen
**Anzahl betroffene Platzhalter:** 5 (Meta-Gap)
**Severity:** 🟢 INFO
**Norm-Verstoß:** Kein direkter Verstoß, aber Governance-Issue
**Problem:**
- Export Spec sagt: "116 Platzhalter"
- Extended Catalog + Gap Report: "111 Platzhalter"
- Differenz: 5 Platzhalter
**Analyse:**
- Die 5 zusätzlichen sind vermutlich **Metafelder** im Export:
1. `schema_version`
2. `generated_at`
3. `normative_standard`
4. `total_placeholders`
5. `metadata.summary` (oder ähnlich)
**Remediation:**
- **Dokumentation:** Export-Spec klarstellen (111 User-Placeholders + 5 Metafelder)
- **Aufwand:** 30 Minuten
- **Priority:** P3
---
### CLUSTER 11: Code-Dokumentations-Konflikte
**Anzahl betroffene Platzhalter:** 3 (kritische Konflikte)
**Severity:** 🔴 CRITICAL
**Norm-Verstoß:** §2 "Vorrang" (Code > Docs bei Konflikt)
**Konflikte:**
#### 11.1 weight_trend
- **Description:** "Gewichtstrend (7d/30d)"
- **Code:** `get_weight_trend_data(profile_id, days=28)`
- **Metadaten:** `time_window: unknown`
- **Used-By:** 10 Prompts/Pipelines
- **Impact:** 🔴 HIGH (Prompts gehen von 7d/30d aus, erhalten aber 28d)
**Fix:**
```
description: "Gewichtstrend 28d (lineare Regression)"
semantic_contract: "Lineare Regression über 28 Tage, Richtung + Delta"
time_window: "28d"
```
---
#### 11.2 activity_summary
- **Description:** "Aktivitäts-Zusammenfassung (7d)"
- **Code:** `get_activity_summary_data(profile_id, days=14)`
- **Metadaten:** `time_window: unknown`
- **Used-By:** 2 Prompts
- **Impact:** 🟡 MEDIUM (weniger Verwendungen, aber Inkonsistenz)
**Fix:**
```
description: "Aktivitäts-Zusammenfassung 14d"
semantic_contract: "Aggregierte Aktivitäts-Metriken über 14 Tage"
time_window: "14d"
```
---
#### 11.3 activity_detail
- **Description:** "Keine explizite Zeitangabe"
- **Code:** `get_activity_detail_data(profile_id, days=14, limit=20)`
- **Metadaten:** `time_window: unknown`
- **Used-By:** 4 Prompts
- **Impact:** 🟡 MEDIUM
**Fix:**
```
description: "Detaillierte Aktivitäts-Liste 14d (max 20 Einträge)"
semantic_contract: "Sortierte Liste letzter 20 Aktivitäten aus 14-Tage-Fenster"
time_window: "14d"
```
---
**Remediation:**
- **Sofortige Korrektur:** Description, semantic_contract, time_window auf Code-Wahrheit setzen
- **Aufwand:** 1 Stunde
- **Priority:** P0
---
## GAP-CLUSTER ZUSAMMENFASSUNG
| Cluster | Platzhalter | Severity | Priority | Aufwand | Abhängigkeiten |
|---------|-------------|----------|----------|---------|----------------|
| **1. Semantic Contract** | 49 | 🔴 CRITICAL | P0 | 4-6h | Keine |
| **2. Data Layer Module** | 100 | 🔴 CRITICAL | P1 | 6-8h | Cluster 1 |
| **3. Source Tables** | 90 | 🔴 CRITICAL | P1 | 6-8h | Cluster 1 |
| **4. Time Window** | 74 | 🔴 CRITICAL | P0 | 6-10h | Keine |
| **5. Confidence Logic** | 103 | 🟡 HIGH | P1 | 24-32h | Cluster 4 |
| **6. Missing-Value-Policy** | 110 | 🟡 MEDIUM | P1 | 8-10h | Cluster 5 |
| **7. Completeness Score 0** | 111 | 🟡 MEDIUM | P2 | Inkludiert | Nach P0+P1 |
| **8. Schema Status draft** | 111 | 🟡 MEDIUM | P2 | 4-6h | Nach P0+P1 |
| **9. Ungenutzte Platzhalter** | 67 | 🟢 LOW | P2 | 4-6h | Product-Review |
| **10. Export-Inkonsistenzen** | 5 | 🟢 INFO | P3 | 0.5h | Keine |
| **11. Code-Docs-Konflikte** | 3 | 🔴 CRITICAL | P0 | 1h | Keine |
**Gesamt-Remediationsaufwand:** 64-87 Stunden (gestaffelt über P0-P3)
---
## REMEDIATION-PRIORISIERUNG
### P0 (BLOCKING - Week 1)
1. **Cluster 11:** Code-Docs-Konflikte (1h)
2. **Cluster 1:** Semantic Contract (4-6h)
3. **Cluster 4:** Time Window (6-10h)
- **Sub:** Name-Pattern (1h, automatisch)
- **Sub:** Code-Parameter (2-3h, semi-automatisch)
- **Sub:** Fach-Entscheidung (4-6h, manuell mit Product)
**Total P0:** 11-17 Stunden
---
### P1 (HIGH - Week 2-3)
1. **Cluster 2:** Data Layer Module (6-8h)
2. **Cluster 3:** Source Tables (6-8h)
3. **Cluster 5:** Confidence Logic (24-32h)
- **Sub:** Trend-Platzhalter (12-16h)
- **Sub:** Score-Platzhalter (8-10h)
- **Sub:** Korrelations-Platzhalter (4-6h)
4. **Cluster 6:** Missing-Value-Policy (8-10h)
**Total P1:** 44-58 Stunden
---
### P2 (MEDIUM - Week 4-5)
1. **Cluster 7:** Completeness Score (inkludiert in P0+P1)
2. **Cluster 8:** Schema Status Production (4-6h)
3. **Cluster 9:** Ungenutzte Platzhalter Review (4-6h)
**Total P2:** 8-12 Stunden
---
### P3 (LOW - Later)
1. **Cluster 10:** Export-Inkonsistenzen Doku (0.5h)
**Total P3:** 0.5 Stunden
---
**GESAMT:** 63.5-87.5 Stunden über 4-6 Wochen
---
## NÄCHSTE SCHRITTE
1. **Review dieses Gap-Reports** mit Tech Lead
2. **Priorisierungs-Bestätigung:** P0-Liste final absegnen
3. **Kickoff P0-Sprint:**
- Code-Docs-Konflikte sofort fixen (1h)
- Semantic Contract Bulk-Update (4-6h)
- Zeitfenster-Klassifizierung (6-10h)
4. **Nach P0:** P1-Sprint planen (Confidence + Data Layer + Missing-Value)
**Zie
l nach P0+P1:** 60-70% Normkonformität erreicht
---
**Audit-Report erstellt von:** Claude Code (Lead Audit Agent)
**Basis:** 4-Agent-Analyse (Code-Evidence, Semantic-Contract, Time-Window-Confidence, Prompt-Usage)

View File

@ -0,0 +1,983 @@
# Priorisierter Maßnahmenplan: Placeholder-Remediation
**Audit-Datum:** 29. März 2026
**Basis:** Gap-Cluster-Analyse, 111 Platzhalter
**Ziel:** Normkonformität auf 60-70% steigern (aktuell 7%)
---
## ROADMAP-ÜBERSICHT
| Phase | Fokus | Dauer | Aufwand | Ziel-Compliance |
|-------|-------|-------|---------|-----------------|
| **P0** | Blocking Issues | Week 1 | 11-17h | 25-30% |
| **P1** | High Priority Gaps | Week 2-3 | 44-58h | 50-60% |
| **P2** | Medium Priority | Week 4-5 | 8-12h | 65-70% |
| **P3** | Nice-to-Have | Later | 0.5h | 70%+ |
| **TOTAL** | | 4-6 Wochen | 63.5-87.5h | 70%+ |
---
## P0: BLOCKING ISSUES (Week 1)
**Ziel:** Kritische Inkonsistenzen und Pflichtfelder beheben
**Aufwand:** 11-17 Stunden
**Team:** 1-2 Entwickler
**Dependencies:** Keine - sofort startbar
---
### P0.1: Code-Dokumentations-Konflikte (SOFORT)
**Gap-Cluster:** 11
**Betroffene Platzhalter:** 3 (weight_trend, activity_summary, activity_detail)
**Severity:** 🔴 CRITICAL
**Aufwand:** 1 Stunde
**Maßnahmen:**
1. **weight_trend Fix**
```diff
# PLACEHOLDER_CATALOG_EXTENDED.json
{
"key": "weight_trend",
- "description": "Gewichtstrend (7d/30d)",
+ "description": "Gewichtstrend 28d (lineare Regression)",
- "semantic_contract": "Gewichtstrend (7d/30d)",
+ "semantic_contract": "Lineare Regression über 28 Tage, Richtung + Delta in kg",
- "time_window": "unknown",
+ "time_window": "28d",
}
```
2. **activity_summary Fix**
```diff
{
"key": "activity_summary",
- "description": "Aktivitäts-Zusammenfassung (7d)",
+ "description": "Aktivitäts-Zusammenfassung 14d",
- "semantic_contract": "Aktivitäts-Zusammenfassung (7d)",
+ "semantic_contract": "Aggregierte Aktivitäts-Metriken über 14 Tage",
- "time_window": "unknown",
+ "time_window": "14d",
}
```
3. **activity_detail Fix**
```diff
{
"key": "activity_detail",
- "description": "No description available",
+ "description": "Detaillierte Aktivitäts-Liste 14d (max 20 Einträge)",
- "semantic_contract": "No description available",
+ "semantic_contract": "Sortierte Liste letzter 20 Aktivitäten aus 14-Tage-Fenster, DESC nach Datum",
- "time_window": "unknown",
+ "time_window": "14d",
}
```
**Validation:**
- Code-Review: Zeitfenster im Code bestätigen
- Prompt-Review: Alle 10+2+4 betroffenen Prompts/Pipelines prüfen
**Owner:** Backend Lead
**Blocker:** Keine
**Output:** 3 Fixed Platzhalter, Updated Catalog
---
### P0.2: Zeitfenster Name-Pattern (AUTOMATISCH)
**Gap-Cluster:** 4.1
**Betroffene Platzhalter:** 15 (zeitraum_*, sleep_*_7d, training_frequency_7d, etc.)
**Severity:** 🔴 CRITICAL
**Aufwand:** 1 Stunde (automatisches Skript)
**Maßnahmen:**
**Skript: `fix_time_window_from_name.py`**
```python
import json
import re
# Regex-Pattern für Zeitfenster im Namen
patterns = {
r'_7d$|_7d_': '7d',
r'_14d$|_14d_': '14d',
r'_28d$|_28d_': '28d',
r'_30d$|_30d_': '30d',
r'_90d$|_90d_': '90d',
}
catalog = load_catalog()
fixes = []
for placeholder in catalog['placeholders'].values():
key = placeholder['key']
# Überspringe bereits definierte
if placeholder['time_window'] != 'unknown':
continue
# Pattern-Match
for pattern, window in patterns.items():
if re.search(pattern, key):
placeholder['time_window'] = window
fixes.append(f"{key}: unknown → {window}")
break
print(f"Fixed {len(fixes)} placeholders")
save_catalog(catalog)
```
**Erwartete Fixes:**
- `zeitraum_7d`: unknown → 7d
- `zeitraum_30d`: unknown → 30d
- `zeitraum_90d`: unknown → 90d
- `sleep_avg_duration_7d`: unknown → 7d
- `sleep_quality_7d`: unknown → 7d
- `training_frequency_7d`: unknown → 7d
- `proxy_internal_load_7d`: unknown → 7d
- `energy_balance_7d`: unknown → 7d
- `protein_adequacy_28d`: unknown → 28d
- ... (insgesamt ~15)
**Validation:**
- Manuelle Review der Auto-Fixes
- Diff-Check vor Commit
**Owner:** DevOps / Automation
**Blocker:** Keine
**Output:** 15 Fixed Platzhalter
---
### P0.3: Zeitfenster Code-Parameter (SEMI-AUTOMATISCH)
**Gap-Cluster:** 4.2
**Betroffene Platzhalter:** ~20 (activity_summary, sleep_avg_duration, rest_days_count, etc.)
**Severity:** 🔴 CRITICAL
**Aufwand:** 2-3 Stunden
**Maßnahmen:**
1. **Code-Parameter-Extraktion**
- Suche in `placeholder_resolver.py` nach `days=X` Parametern
- Greppen in `data_layer/*.py` nach Default-Werten
```bash
# Beispiel-Grep
grep -n "def get_.*_data.*days=" backend/data_layer/*.py
grep -n "lambda.*days=" backend/placeholder_resolver.py
```
2. **Manuelle Zuordnung**
- Für jeden Treffer: Placeholder Key identifizieren
- Default-Wert → time_window setzen
**Erwartete Fixes:**
- `sleep_avg_duration`: Code `days=7` → time_window: 7d
- `rest_days_count`: Code `days=30` → time_window: 30d
- `nutrition_days`: Code `days=30` → time_window: 30d
- ... (~20 total)
**Validation:**
- Code-Review der Mappings
- Stichproben-Tests
**Owner:** Backend Developer
**Blocker:** P0.2 abgeschlossen
**Output:** 20 Fixed Platzhalter
---
### P0.4: Semantic Contract Bulk-Update
**Gap-Cluster:** 1.1
**Betroffene Platzhalter:** 49 ("No description available")
**Severity:** 🔴 CRITICAL
**Aufwand:** 4-6 Stunden
**Maßnahmen:**
**Input:** Semantic-Contract-Agent-Report (bereits vorhanden)
**Prozess:**
1. Für jeden der 49 Platzhalter:
- `description` aus Agent-Report übernehmen
- `semantic_contract` aus Agent-Report übernehmen
- `category` aus Agent-Report setzen (statt "Unknown")
2. Bulk-Update via JSON-Merge-Skript
3. Manuelle Review der Top-10 kritischsten (nach Usage)
**Beispiel-Update (ability_balance_coordination):**
```diff
{
"key": "ability_balance_coordination",
- "category": "Unknown",
+ "category": "Training",
- "description": "No description available",
+ "description": "Koordinationsfähigkeit-Balance-Anteil (%)",
- "semantic_contract": "No description available",
+ "semantic_contract": "Gewichteter Anteil der Trainings-Last für Koordinations-Fähigkeit über 28-Tage-Fenster",
- "time_window": "unknown",
+ "time_window": "28d",
}
```
**Prioritäts-Reihenfolge (nach Usage):**
1. Goals & Focus (16) - 7 produktkritisch
2. Correlations (5) - experimentell, aber wichtig
3. Body Deltas (5) - Körper-Tracking
4. Nutrition (6) - Ernährungs-Metriken
5. Training (8) - Ability Balance, Load
6. Summaries (3) - circ_summary, caliper_summary
7. Meta (2) - zeitraum_90d
8. Plateau (1) - plateau_detected
9. Top Drivers (1) - top_drivers
**Validation:**
- Review der Top-10 produktkritischsten Platzhalter manuell
- Stichprobe 10% der restlichen
- Automated Consistency Check (keine "No description" mehr)
**Owner:** Backend Lead + Product (für fachliche Review)
**Blocker:** Keine
**Output:** 49 Fixed Platzhalter, alle mit Kategorie + Description
---
### P0.5: Zeitfenster Fach-Entscheidung
**Gap-Cluster:** 4.3
**Betroffene Platzhalter:** ~39 (Scores, Ability Balance, Correlations, Goals, Snapshots)
**Severity:** 🔴 CRITICAL
**Aufwand:** 4-6 Stunden (Meeting + Dokumentation)
**Maßnahmen:**
**Phase 1: Kategorisierung (2h)**
- Product + Tech Meeting
- Entscheidung pro Kategorie:
| Kategorie | Platzhalter | Vorschlag | Rationale |
|-----------|-------------|-----------|-----------|
| **Scores (6)** | activity_score, nutrition_score, recovery_score, body_progress_score, goal_progress_score, data_quality_score | `custom` oder `mixed` | Kombinieren verschiedene Zeitfenster |
| **Ability Balance (5)** | coordination, endurance, mental, mobility, strength | `28d` | Rolling-Window über 28 Tage |
| **Correlations (5)** | energy_weight_lag, load_hrv, load_rhr, protein_lbm, sleep_recovery | `28d` | Min-Daten für Reliability |
| **Goals & Focus (16)** | active_goals_json, focus_areas_*, top_goal_*, top_3_goals_*, focus_cat_* | `latest` (Snapshot) oder `custom` | Je nach Progress-Berechnung |
| **Snapshots (7)** | bmi, goal_weight, goal_bf_pct, waist_hip_ratio, recomposition_quadrant, plateau_detected, top_drivers | `latest` oder `custom` | Momentaufnahme vs. Berechnet |
**Phase 2: Dokumentation (2h)**
- Entscheidungen in Decision-Log festhalten
- time_window-Werte in Catalog setzen
- Semantic Contracts anpassen (Zeit-Bezug aufnehmen)
**Phase 3: Validation (1h)**
- Review mit Stakeholdern
- Prompt-Autoren informieren (Breaking Change bei "custom" → spezifisches Fenster)
**Owner:** Product Manager + Tech Lead
**Blocker:** P0.4 Semantic Contract abgeschlossen
**Output:** Decision-Log, 39 Fixed Platzhalter
---
### P0 SUMMARY
**Gesamt-Aufwand:** 11-17 Stunden
**Deliverables:**
- 3 Code-Docs-Konflikte gelöst
- 74 time_window: unknown → definierte Werte
- 49 description/category: Unknown/No description → vollständig
- **Total Fixed:** 77 Platzhalter (15+20+39+3 unique)
**Impact:**
- **Compliance:** 7% → 25-30%
- **Blocked Gaps:** time_window, description, category, code-conflicts
**Next:** P1 kann starten (Confidence, Data Layer, Source Tables)
---
## P1: HIGH PRIORITY (Week 2-3)
**Ziel:** Technische Tiefe hinzufügen (Confidence, Data Layer, Source Tables)
**Aufwand:** 44-58 Stunden
**Team:** 2-3 Entwickler
**Dependencies:** P0 abgeschlossen
---
### P1.1: Confidence-Logik für Trend-Platzhalter
**Gap-Cluster:** 5.1
**Betroffene Platzhalter:** 11 (weight_*_slope, *_28d_delta, vo2max_trend_28d)
**Severity:** 🟡 HIGH
**Aufwand:** 12-16 Stunden
**Maßnahmen:**
**Pattern:**
```python
# In data_layer/body_metrics.py
def calculate_weight_28d_slope(profile_id: int, conn):
"""Gewichtstrend über 28 Tage mit Confidence."""
# 1. Daten holen
rows = fetch_weight_data(profile_id, days=28, conn=conn)
# 2. Confidence berechnen
confidence = calculate_confidence(
data_points=len(rows),
time_window_days=28,
metric_type='trend'
)
if confidence == 'insufficient':
return {
'slope': None,
'confidence': 'insufficient',
'data_points': len(rows),
'min_required': 8 # 28% coverage
}
# 3. Slope berechnen (nur wenn sufficient)
slope = linear_regression_slope(rows)
return {
'slope': slope,
'confidence': confidence, # high/medium/low
'data_points': len(rows),
'r_squared': calculate_r_squared(rows, slope)
}
```
**Thresholds (trend-specific):**
```python
def calculate_confidence(data_points, time_window_days, metric_type):
coverage = data_points / time_window_days
if metric_type == 'trend':
# Strengere Thresholds für Trends
if coverage >= 0.70: # >= 70%
return 'high'
elif coverage >= 0.50: # >= 50%
return 'medium'
elif coverage >= 0.30: # >= 30%
return 'low'
else:
return 'insufficient'
# ... andere Typen
```
**Zu implementieren für:**
1. `weight_28d_slope` (28d, min 8, ideal 20)
2. `weight_90d_slope` (90d, min 27, ideal 63)
3. `weight_7d_median` (7d, min 3, ideal 5)
4. `fm_28d_change` (28d, min 2, ideal 18)
5. `lbm_28d_change` (28d, min 2, ideal 18)
6. `waist_28d_delta` (28d, min 2, ideal 18)
7. `hip_28d_delta` (28d, min 2, ideal 18)
8. `chest_28d_delta` (28d, min 2, ideal 18)
9. `arm_28d_delta` (28d, min 2, ideal 18)
10. `thigh_28d_delta` (28d, min 2, ideal 18)
11. `vo2max_trend_28d` (28d, min 4, ideal 18)
**Testing:**
- Unit-Tests für calculate_confidence() mit verschiedenen Coverages
- Integration-Tests mit real data (0%, 30%, 50%, 70%, 100% coverage)
- Regression-Tests (alte Werte ohne Confidence bleiben gleich)
**Owner:** Backend Developer (Senior)
**Blocker:** P0 time_window abgeschlossen
**Output:** 11 Platzhalter mit Confidence-Logik
---
### P1.2: Confidence-Logik für Score-Platzhalter
**Gap-Cluster:** 5.2
**Betroffene Platzhalter:** 6 (activity_score, nutrition_score, recovery_score, etc.)
**Severity:** 🟡 HIGH
**Aufwand:** 8-10 Stunden
**Maßnahmen:**
**Composite-Confidence-Pattern:**
```python
def calculate_nutrition_score(profile_id: int, conn):
"""Nutrition Score mit Composite Confidence."""
# 1. Sub-Scores berechnen (mit eigenen Confidences)
energy_balance = calculate_energy_balance_7d(profile_id, conn)
protein_adequacy = calculate_protein_adequacy_28d(profile_id, conn)
macro_consistency = calculate_macro_consistency_score(profile_id, conn)
# 2. Composite Confidence = MIN(sub-confidences)
confidence_levels = ['high', 'medium', 'low', 'insufficient']
confidences = [
energy_balance['confidence'],
protein_adequacy['confidence'],
macro_consistency['confidence']
]
# Min-Confidence
min_confidence = min(confidences, key=lambda c: confidence_levels.index(c))
if min_confidence == 'insufficient':
return {
'score': None,
'confidence': 'insufficient',
'sub_scores': {...},
'note': 'Mindestens eine Komponente hat insufficient data'
}
# 3. Score berechnen (gewichtet)
score = (
energy_balance['score'] * 0.4 +
protein_adequacy['score'] * 0.4 +
macro_consistency['score'] * 0.2
)
return {
'score': round(score),
'confidence': min_confidence,
'sub_scores': {
'energy_balance': energy_balance,
'protein_adequacy': protein_adequacy,
'macro_consistency': macro_consistency
}
}
```
**Zu implementieren für:**
1. `activity_score` (training_volume + frequency + quality)
2. `nutrition_score` (energy_balance + protein_adequacy + macro_consistency)
3. `recovery_score` (sleep_duration + sleep_quality + hrv + rhr)
4. `body_progress_score` (weight_trend + bf_change + lbm_change)
5. `goal_progress_score` (weighted goals progress)
6. `data_quality_score` (data availability per domain)
**Testing:**
- Scenario-Tests: alle Sub-Scores high → Composite high
- Scenario-Tests: eine Sub-Score insufficient → Composite insufficient
- Edge-Cases: missing Sub-Components
**Owner:** Backend Developer (Mid/Senior)
**Blocker:** P1.1 Trend-Confidence abgeschlossen (Pattern etabliert)
**Output:** 6 Platzhalter mit Composite Confidence
---
### P1.3: Confidence-Logik für Korrelations-Platzhalter
**Gap-Cluster:** 5.3
**Betroffene Platzhalter:** 5 (correlation_*)
**Severity:** 🟡 HIGH
**Aufwand:** 4-6 Stunden
**Maßnahmen:**
**Correlation-Confidence-Pattern:**
```python
def calculate_lag_correlation(profile_id, metric_a, metric_b, lag_days=[0,3,7,14], conn):
"""Lag-Korrelation mit Pair-basiertem Confidence."""
results = []
for lag in lag_days:
pairs = fetch_paired_data(profile_id, metric_a, metric_b, lag, conn)
n_pairs = len(pairs)
# Confidence basierend auf Anzahl Paare
if n_pairs >= 28:
confidence = 'high'
elif n_pairs >= 21:
confidence = 'medium'
elif n_pairs >= 14:
confidence = 'low'
else:
confidence = 'insufficient'
if confidence == 'insufficient':
correlation = None
else:
correlation = pearson_correlation(pairs)
results.append({
'lag_days': lag,
'correlation': correlation,
'n_pairs': n_pairs,
'confidence': confidence,
'note': 'explorativ, nicht kausal'
})
return {
'correlations': results,
'overall_confidence': min([r['confidence'] for r in results])
}
```
**Zu implementieren für:**
1. `correlation_energy_weight_lag` (min 21 Paare)
2. `correlation_load_hrv` (min 21 Paare)
3. `correlation_load_rhr` (min 21 Paare)
4. `correlation_protein_lbm` (min 28 Paare, Training moderiert)
5. `correlation_sleep_recovery` (min 21 Paare)
**Testing:**
- Synthetic Data: 10, 14, 21, 28, 35 Paare → Confidence-Check
- Real Data: Validate gegen tatsächliche Daten-Dichte
**Owner:** Backend Developer (Senior, Statistik-Know-how)
**Blocker:** P1.1 Confidence-Pattern etabliert
**Output:** 5 Platzhalter mit Correlation-Confidence
---
### P1.4: Data-Layer-Module dokumentieren
**Gap-Cluster:** 2
**Betroffene Platzhalter:** 100 (data_layer_module: null)
**Severity:** 🔴 CRITICAL
**Aufwand:** 6-8 Stunden
**Maßnahmen:**
**Input:** Code-Evidence-Agent-Report (technische Herkunft für alle 111)
**Prozess:**
1. **Mapping-Extraktion:**
- Für jede `_safe_*`-Funktion: Gerufene Data-Layer-Funktion identifizieren
- Mapping: Placeholder Key → Data-Layer-Module
2. **Bulk-Update-Skript:**
```python
# Mapping aus Code-Evidence-Report
data_layer_mapping = {
'goal_progress_score': 'data_layer.scores',
'body_progress_score': 'data_layer.body_metrics',
'nutrition_score': 'data_layer.nutrition_metrics',
'activity_score': 'data_layer.activity_metrics',
'recovery_score': 'data_layer.recovery_metrics',
# ... 95 more
}
# Catalog Update
for key, module in data_layer_mapping.items():
catalog['placeholders'][key]['source']['data_layer_module'] = module
```
3. **Validation:**
- Automated Check: Alle 111 haben data_layer_module gesetzt
- Stichprobe 10%: Manuell im Code validieren
**Owner:** DevOps / Backend Lead
**Blocker:** Code-Evidence-Agent-Report finalisiert (✓)
**Output:** 100 Fixed Platzhalter
---
### P1.5: Source-Tables dokumentieren
**Gap-Cluster:** 3
**Betroffene Platzhalter:** 90 (source_tables: [])
**Severity:** 🔴 CRITICAL
**Aufwand:** 6-8 Stunden
**Maßnahmen:**
**Identisch zu P1.4:**
- Mapping aus Code-Evidence-Report übernehmen
- Bulk-Update-Skript
- Validation
**Mapping-Beispiel:**
```python
source_tables_mapping = {
'weight_aktuell': ['weight_log'],
'weight_trend': ['weight_log'],
'kf_aktuell': ['caliper_log'],
'bmi': ['weight_log', 'profiles'],
'nutrition_score': ['nutrition_log'],
'activity_score': ['activity_log'],
'recovery_score': ['sleep_log', 'vitals_baseline', 'rest_days'],
# ... 83 more
}
```
**Owner:** DevOps / Backend Lead
**Blocker:** Code-Evidence-Agent-Report finalisiert (✓)
**Output:** 90 Fixed Platzhalter
---
### P1.6: Strukturierte Missing-Value-Policy
**Gap-Cluster:** 6
**Betroffene Platzhalter:** 110 (nur legacy_display)
**Severity:** 🟡 MEDIUM
**Aufwand:** 8-10 Stunden
**Maßnahmen:**
**Dual-Mode-Ansatz:**
```python
# Alte Resolver-Return (Backward-Compatible)
def get_weight_trend(profile_id, days=28, conn=None):
data = get_weight_trend_data(profile_id, days, conn)
if data['confidence'] == 'insufficient':
# Legacy: String-Return
return "nicht verfügbar"
return f"{data['direction']} {data['delta']} kg"
# Neue Structured-Return (Parallel)
def get_weight_trend_structured(profile_id, days=28, conn=None):
data = get_weight_trend_data(profile_id, days, conn)
if data['confidence'] == 'insufficient':
return {
'available': False,
'value_raw': None,
'value_display': "nicht verfügbar",
'missing_reason': 'insufficient_data',
'missing_value_policy': {
'legacy_display': "nicht verfügbar",
'structured_null': True,
'reason_codes': ['no_data', 'insufficient_data', 'resolver_error']
},
'metadata': {
'data_points': data['data_points'],
'min_required': data['min_required'],
'time_window': '28d'
}
}
return {
'available': True,
'value_raw': data['slope'],
'value_display': f"{data['direction']} {data['delta']} kg",
'confidence': data['confidence'],
'metadata': {
'data_points': data['data_points'],
'r_squared': data['r_squared'],
'time_window': '28d'
}
}
```
**Migration-Strategie:**
1. **Phase 1:** Neue `*_structured()`-Funktionen neben alten (Parallel)
2. **Phase 2:** Extended Export nutzt structured
3. **Phase 3:** Legacy-Export bleibt unverändert (Backward-Compat)
4. **Phase 4 (Later):** Deprecate alte Funktionen nach 6-12 Monaten
**Zu implementieren für:**
- Alle 110 Platzhalter (außer weight_aktuell, der bereits structured ist)
**Testing:**
- Legacy-Tests: Alte Funktionen bleiben unverändert
- Structured-Tests: Neue Funktionen returnieren korrekte Struktur
- Export-Tests: Extended Export nutzt structured
**Owner:** Backend Team (2 Entwickler)
**Blocker:** P1.1-P1.3 Confidence abgeschlossen
**Output:** 110 Platzhalter mit Dual-Mode-Support
---
### P1 SUMMARY
**Gesamt-Aufwand:** 44-58 Stunden
**Deliverables:**
- 11 Trend-Platzhalter mit Confidence
- 6 Score-Platzhalter mit Composite Confidence
- 5 Correlation-Platzhalter mit Pair-Confidence
- 100 Platzhalter mit data_layer_module
- 90 Platzhalter mit source_tables
- 110 Platzhalter mit Structured Missing-Value-Policy
- **Total Fixed:** 103 unique Platzhalter (alle außer 8 bereits conforme)
**Impact:**
- **Compliance:** 25-30% → 50-60%
- **Blocked Gaps:** Confidence, Data Layer, Source Tables, Missing-Value-Policy
**Next:** P2 Production-Ready + Deprecation
---
## P2: MEDIUM PRIORITY (Week 4-5)
**Ziel:** Production-Status und Deprecation-Strategie
**Aufwand:** 8-12 Stunden
**Team:** Product + Tech Lead
**Dependencies:** P1 abgeschlossen
---
### P2.1: Schema-Status auf Production (Top 20)
**Gap-Cluster:** 8
**Betroffene Platzhalter:** 20-30 Kandidaten
**Severity:** 🟡 MEDIUM
**Aufwand:** 4-6 Stunden
**Maßnahmen:**
**Kriterien für `schema_status: production`:**
1. `metadata_completeness_score >= 80`
2. `used_by.prompts.length >= 1 OR used_by.pipelines.length >= 1`
3. `time_window != 'unknown'`
4. `category != 'Unknown'`
5. `description != 'No description available'`
6. `confidence_logic != null OR (type == 'atomic' AND time_window == 'latest')`
7. `known_issues.length == 0`
**Prozess:**
1. **Automated Eligibility-Check:**
```python
def is_production_ready(placeholder):
checks = [
placeholder['metadata_completeness_score'] >= 80,
len(placeholder['used_by']['prompts']) >= 1 or
len(placeholder['used_by']['pipelines']) >= 1,
placeholder['time_window'] != 'unknown',
placeholder['category'] != 'Unknown',
placeholder['description'] != 'No description available',
placeholder['confidence_logic'] is not None or
(placeholder['type'] == 'atomic' and placeholder['time_window'] == 'latest'),
len(placeholder['known_issues']) == 0
]
return all(checks)
```
2. **Kandidaten-Liste generieren**
3. **Manuelle Review** (Product + Tech Lead)
- Sind diese wirklich production-ready?
- Fehlt noch etwas?
4. **Schema-Status-Update**
**Erwartete Kandidaten (12-15):**
- Nutrition Averages (4): protein_avg, kcal_avg, fat_avg, carb_avg
- Body Metrics (3): weight_aktuell, weight_trend, kf_aktuell
- Profil (4): name, age, height, geschlecht
- Summaries (2): caliper_summary, circ_summary
- Goals (2-3): goal_weight, goal_bf_pct, top_goal_name
**Owner:** Tech Lead + Product Manager
**Blocker:** P1 abgeschlossen (Confidence, Data Layer)
**Output:** 12-15 Platzhalter mit `schema_status: production`
---
### P2.2: Ungenutzte Platzhalter - Integration planen
**Gap-Cluster:** 9 (REINTERPRETIERT: Nicht Deprecation, sondern Integration)
**Betroffene Platzhalter:** 67 (ungenutzt)
**Severity:** 🟡 MEDIUM (Prompt-Bibliothek Vollständigkeit)
**Aufwand:** 4-6 Stunden
**Maßnahmen:**
**Neue Klassifizierung (siehe USAGE_ROLE_CLASSIFICATION.md):**
1. **unused_but_planned (30)** - Explizit in Roadmap Phase 0c/1/2
- Scores (6), Correlations (5), Ability Balance (5), Goals Details (11), etc.
- **Action:** Timeline bestätigen, Prototyping-Prompts erstellen
2. **unused_but_plausible (37)** - Fachlich sinnvoll, noch nicht in Prompts
- Body Deltas, Nutrition Details, Training Quality, Focus Category, Meta
- **Action:** Prompt-Use-Cases identifizieren, Templates für Quick Wins
3. **redundant_or_duplicate (0)** - Keine!
- Alle 67 haben fachliche Berechtigung
**Prozess:**
1. **Meeting (2h):** Product + Tech Review aller 67
- Gruppe A (30 geplant): Timeline bestätigen (Phase 0c/1/2)
- Gruppe B (37 plausibel): Prompt-Use-Cases identifizieren (10-15 Quick Wins)
2. **Dokumentation (1h):** Integration-Roadmap, Prompt-Kandidaten-Liste
3. **Implementation (1-2h):** Prompt-Templates erstellen (5-10 Quick Wins)
4. **Communication (1h):** Prompt-Autoren: "Neue Platzhalter verfügbar"
**Integration-Beispiel (statt Deprecation):**
```json
{
"key": "arm_28d_delta",
"usage_role": "unused_but_plausible",
"integration_priority": "medium",
"prompt_use_cases": [
"Fortschritts-Analyse spezifischer Körperteile",
"Asymmetrie-Erkennung (linker vs. rechter Arm)",
"Trainingsplan-Effektivität (Armtraining Tracking)"
],
"example_prompt_template": "Deine Armumfänge haben sich in den letzten 28 Tagen um {{arm_28d_delta}}cm verändert. Analyse: ..."
}
```
**Owner:** Product Manager + Tech Lead
**Blocker:** P1 abgeschlossen
**Output:** Integration-Roadmap, Prompt-Templates (5-10), Nutzungsrate +10-20%
---
### P2 SUMMARY
**Gesamt-Aufwand:** 8-12 Stunden
**Deliverables:**
- 12-15 Production-Ready Platzhalter
- Integration-Roadmap für 30 geplante Platzhalter (Phase 0c/1/2)
- Prompt-Templates für 5-10 Quick Wins (ungenutzte Platzhalter aktivieren)
**Impact:**
- **Compliance:** 50-60% → 65-70%
- **Governance:** Production-Pipeline etabliert, Placeholder-Integration vorangetrieben
- **Nutzungsrate:** 40% → 50-60% (organisch durch Integration)
**Next:** P3 (Nice-to-Have)
---
## P3: NICE-TO-HAVE (Later)
**Ziel:** Dokumentations-Feinschliff
**Aufwand:** 0.5 Stunden
**Team:** Tech Writer / DevOps
**Dependencies:** P2 abgeschlossen
---
### P3.1: Export-Inkonsistenzen Dokumentation
**Gap-Cluster:** 10
**Betroffene:** Dokumentation
**Severity:** 🟢 INFO
**Aufwand:** 0.5 Stunden
**Maßnahmen:**
**Export Spec Update:**
```diff
# PLACEHOLDER_EXPORT_SPEC.md
- **Total Placeholders:** 116
+ **User Placeholders:** 111
+ **Meta Fields:** 5 (schema_version, generated_at, normative_standard, total_placeholders, metadata.summary)
+ **Total Export Entries:** 116
```
**Owner:** Tech Writer
**Blocker:** Keine
**Output:** Updated Export Spec
---
## ERFOLGS-METRIKEN
### Nach P0 (Week 1)
- ✅ **Compliance:** 7% → 25-30%
- ✅ **time_window: unknown:** 74 → 0
- ✅ **category: Unknown:** 49 → 0
- ✅ **description: No description:** 49 → 0
- ✅ **Code-Docs-Konflikte:** 3 → 0
### Nach P1 (Week 3)
- ✅ **Compliance:** 25-30% → 50-60%
- ✅ **Confidence-Logik:** 8 → 28 (Trend + Score + Correlation)
- ✅ **data_layer_module:** 11 → 111
- ✅ **source_tables:** 21 → 111
- ✅ **Structured Missing-Value:** 1 → 111
### Nach P2 (Week 5)
- ✅ **Compliance:** 50-60% → 65-70%
- ✅ **schema_status: production:** 0 → 12-15
- ✅ **deprecated:** 0 → 15-20
- ✅ **Technical Debt:** Reduziert
### Nach P3
- ✅ **Compliance:** 65-70% → 70%+
- ✅ **Dokumentation:** Vollständig konsistent
---
## RISIKEN & MITIGATION
| Risiko | Wahrscheinlichkeit | Impact | Mitigation |
|--------|--------------------|----|-----------|
| **P0 Zeitfenster-Fach-Entscheidung dauert länger** | MEDIUM | MEDIUM | Vorbereitete Kategorisierung, klare Optionen, Decision-Meeting zeitig ansetzen |
| **P1 Confidence-Implementierung komplexer als geschätzt** | MEDIUM | HIGH | Pattern aus nutrition_avg wiederverwenden, Senior Dev assignen |
| **Breaking Changes durch Zeitfenster-Fixes** | LOW | HIGH | Code ist autoritativ, Docs passen sich an → kein Breaking Change |
| **Prompt-Autoren akzeptieren Deprecations nicht** | LOW | MEDIUM | Klare Communication, Replacement-Guides, Grace Period (3 Monate) |
---
## KOMMUNIKATIONS-PLAN
### Week 1 (P0 Kickoff)
- **Email:** Alle Stakeholder über Audit-Ergebnisse informieren
- **Meeting:** P0-Prioritäten mit Tech Lead abstimmen
- **Kickoff:** Development Team P0-Tasks zuweisen
### Week 2 (P1 Kickoff)
- **Standup:** Daily Updates zu Confidence-Implementierung
- **Review:** Mid-Sprint Review nach P1.1-P1.3
### Week 3 (P1 Abschluss)
- **Demo:** P1-Ergebnisse dem Team zeigen
- **Docs:** Updated Catalog veröffentlichen
### Week 4-5 (P2)
- **Meeting:** Production-Readiness-Review
- **Communication:** Deprecation-Plan an Prompt-Autoren
### Week 6 (Abschluss)
- **Retrospektive:** Lessons Learned
- **Documentation:** Finale Compliance-Metrics veröffentlichen
---
## TOOLING & AUTOMATION
### Skripte (entwickeln während P0-P1)
1. `fix_time_window_from_name.py` - Automatische Name-Pattern-Fixes
2. `extract_code_parameters.py` - Code-Parameter → time_window
3. `bulk_update_catalog.py` - JSON-Merge für Bulk-Updates
4. `validate_compliance.py` - Automatische Compliance-Checks
5. `check_production_ready.py` - Production-Eligibility-Check
### CI/CD-Integration (P2-P3)
- Pre-Commit-Hook: Validate neue Platzhalter gegen Normative Spec
- CI: Consistency-Checks (Code ↔ Catalog)
- CD: Automated Catalog-Deployment
---
## ABSCHLUSS-KRITERIEN
**P0 erfolgreich wenn:**
- Alle 3 Code-Docs-Konflikte gelöst
- Alle 74 time_window: unknown → definiert
- Alle 49 No description → vollständig
- Automated Tests grün
**P1 erfolgreich wenn:**
- Mindestens 20 Platzhalter mit Confidence-Logik
- Alle 100 data_layer_module gesetzt
- Alle 90 source_tables gesetzt
- Structured Missing-Value für alle 110 (Dual-Mode)
**P2 erfolgreich wenn:**
- Mindestens 12 Platzhalter `schema_status: production`
- Mindestens 15 Platzhalter `deprecated: true`
- Decision-Log veröffentlicht
**Gesamt-Projekt erfolgreich wenn:**
- **Compliance >= 65%**
- **0 Code-Docs-Konflikte**
- **0 time_window: unknown**
- **12+ Production-Ready Platzhalter**
---
**Maßnahmenplan erstellt von:** Claude Code (Lead Audit Agent)
**Basis:** Gap-Cluster-Analyse, 4-Agent-Evidence
**Genehmigung:** Pending (Review mit Tech Lead + Product Manager)

View File

@ -0,0 +1,459 @@
# Offene Entscheidungen: Placeholder-Audit
**Audit-Datum:** 29. März 2026
**Status:** Pending Product/Tech Review
**Entscheidungsträger:** Product Manager + Tech Lead
---
## ENTSCHEIDUNGSPFLICHTIGE PUNKTE
Diese Punkte können nicht rein aus Code und Fachlogik gelöst werden und benötigen eine **Produkt-/Fachentscheidung**.
---
## KATEGORIE 1: Zeitfenster-Klassifizierung (BLOCKING P0)
### E1.1: Scores - Zeitfenster definieren
**Betroffene Platzhalter:** 6
- `activity_score`
- `nutrition_score`
- `recovery_score`
- `body_progress_score`
- `goal_progress_score`
- `data_quality_score`
**Problem:**
Scores kombinieren verschiedene Zeitfenster-Metriken. Welches Zeitfenster soll dokumentiert werden?
**Optionen:**
| Option | Beschreibung | Pro | Contra |
|--------|--------------|-----|--------|
| **A: `custom`** | Scores haben keinen festen Zeitrahmen | Technisch korrekt | Unspezifisch für User |
| **B: `mixed`** | Scores kombinieren verschiedene Zeitfenster explizit | Kommuniziert Komplexität | Ähnlich unklar wie `custom` |
| **C: Dominantes Zeitfenster** | Z.B. `28d` für nutrition_score (da Hauptkomponenten 28d) | Einfach zu verstehen | Vereinfachung, evtl. irreführend |
| **D: Zeitfenster pro Sub-Score dokumentieren** | Semantic Contract listet alle Sub-Zeitfenster | Vollständig transparent | Komplex für einfache Use-Cases |
**Empfehlung Audit-Agent:**
- **Option D** für `semantic_contract` (vollständige Transparenz)
- **Option B** für `time_window` Metadatum (signalisiert Komplexität)
**Beispiel (nutrition_score):**
```json
{
"key": "nutrition_score",
"time_window": "mixed",
"semantic_contract": "Composite Score aus: energy_balance (7d), protein_adequacy (28d), macro_consistency (28d). Gewichtung: 40%/40%/20%"
}
```
**Entscheidung benötigt bis:** P0 Week 1 (Zeitfenster-Klassifizierung)
**Impact:** MEDIUM (betrifft Prompt-Interpretation)
**Entscheider:** Product Manager
---
### E1.2: Ability Balance - Zeitfenster definieren
**Betroffene Platzhalter:** 5
- `ability_balance_coordination`
- `ability_balance_endurance`
- `ability_balance_mental`
- `ability_balance_mobility`
- `ability_balance_strength`
**Problem:**
Code implementiert noch keine Ability Balance-Berechnung. Welches Zeitfenster ist fachlich sinnvoll?
**Optionen:**
| Option | Beschreibung | Pro | Contra |
|--------|--------------|-----|--------|
| **A: `28d`** | Rolling-Window über 28 Tage | Konsistent mit anderen Trend-Metriken | Evtl. zu lang für Balance-Shifts |
| **B: `14d`** | Rolling-Window über 14 Tage | Schnellere Reaktion auf Training-Changes | Weniger stabil bei Lücken |
| **C: `latest`** | Snapshot der aktuellen Balance | Einfach | Keine Trend-Info |
**Empfehlung Audit-Agent:**
- **Option A (`28d`)** - Konsistent mit body_metrics, ausreichend stabil
**Rationale:**
- Ability Balance = Verteilung der Trainings-Last über Fähigkeiten
- 28 Tage = ~4 Wochen = typischer Mikrozyklus
- Matching mit anderen Tracking-Metriken
**Entscheidung benötigt bis:** P0 Week 1
**Impact:** MEDIUM (betrifft zukünftige Implementierung)
**Entscheider:** Product Manager + Training-Experte
---
### E1.3: Correlations - Zeitfenster definieren
**Betroffene Platzhalter:** 5
- `correlation_energy_weight_lag`
- `correlation_load_hrv`
- `correlation_load_rhr`
- `correlation_protein_lbm`
- `correlation_sleep_recovery`
**Problem:**
Korrelationen brauchen Mindestdaten. Welches Zeitfenster ist statistisch sinnvoll?
**Optionen:**
| Option | Beschreibung | Pro | Contra |
|--------|--------------|-----|--------|
| **A: `28d`** | Min 21-28 Paare für Reliability | Statistisch robust | Reagiert langsam auf Änderungen |
| **B: `custom`** | Variabel je nach Datenverfügbarkeit | Flexibel | Unklar für User |
| **C: Im Semantic Contract spezifizieren** | Z.B. "28d min, 90d ideal" | Transparent | Komplex |
**Empfehlung Audit-Agent:**
- **Option A (`28d`)** für `time_window`
- **Option C** zusätzlich in `semantic_contract`
**Beispiel:**
```json
{
"key": "correlation_energy_weight_lag",
"time_window": "28d",
"semantic_contract": "Lag-Korrelation (0d/3d/7d/14d) zwischen Energiebilanz und Gewicht. Min 21 Paare (28d) für Reliability, 90d ideal. Explorativ, nicht kausal."
}
```
**Entscheidung benötigt bis:** P0 Week 1
**Impact:** MEDIUM (betrifft Statistik-Interpretation)
**Entscheider:** Tech Lead (Statistik-Know-how)
---
### E1.4: Goals & Focus - Zeitfenster definieren
**Betroffene Platzhalter:** 16
- `active_goals_json`, `active_goals_md`
- `focus_areas_weighted_json`, `focus_areas_weighted_md`, `focus_area_weights_json`
- `top_goal_name`, `top_goal_progress_pct`, `top_goal_status`
- `top_3_goals_behind_schedule`, `top_3_goals_on_track`, `top_3_focus_areas`
- `focus_cat_körper_progress`, `focus_cat_ernährung_progress`, `focus_cat_aktivität_progress`, `focus_cat_recovery_progress`, `focus_cat_vitalwerte_progress`, `focus_cat_mental_progress`, `focus_cat_lebensstil_progress` (jeweils + weight)
**Problem:**
Goals sind Snapshots, aber Progress wird über Zeit berechnet. Wie klassifizieren?
**Optionen:**
| Option | Beschreibung | Pro | Contra |
|--------|--------------|-----|--------|
| **A: `latest`** | Aktueller Stand der Goals | Technisch korrekt (Snapshot) | Impliziert keine Zeit-Dimension |
| **B: `custom`** | Progress-Berechnung ist zeitabhängig | Signalisiert Komplexität | Unklar für Snapshot-Werte |
| **C: Differenzierung** | `active_goals_json`: `latest`, Progress-Felder: `custom` | Präzise | 16 individuelle Entscheidungen |
**Empfehlung Audit-Agent:**
- **Option C** (Differenzierung):
- **Snapshot-Platzhalter** (active_goals_json, focus_area_weights_json, top_goal_name): `latest`
- **Progress-Platzhalter** (top_goal_progress_pct, focus_cat_*_progress): `custom` (da verschiedene Ziele verschiedene Zeiträume haben)
**Entscheidung benötigt bis:** P0 Week 1
**Impact:** LOW (primär dokumentarisch)
**Entscheider:** Product Manager
---
### E1.5: Snapshots - Zeitfenster definieren
**Betroffene Platzhalter:** 7
- `bmi`
- `goal_weight`, `goal_bf_pct`
- `waist_hip_ratio`
- `recomposition_quadrant`
- `plateau_detected`
- `top_drivers`
**Problem:**
Einige sind echte Snapshots (bmi, goal_weight), andere berechnete Werte über Zeit (recomposition_quadrant, plateau_detected).
**Optionen:**
| Option | Beschreibung | Pro | Contra |
|--------|--------------|-----|--------|
| **A: Alle `latest`** | Vereinfachung | Einfach | Ungenau für berechnete |
| **B: Differenzierung** | bmi/goal_weight: `latest`, recomposition_quadrant/plateau_detected: `28d` | Präzise | 7 individuelle Entscheidungen |
**Empfehlung Audit-Agent:**
- **Option B**:
- **Echte Snapshots** (bmi, goal_weight, goal_bf_pct, waist_hip_ratio): `latest`
- **Berechnete über Zeit** (recomposition_quadrant, plateau_detected, top_drivers): `28d` oder `custom`
**Entscheidung benötigt bis:** P0 Week 1
**Impact:** LOW
**Entscheider:** Tech Lead
---
## KATEGORIE 2: Integration ungenutzter Platzhalter (P2)
### E2.1: Ungenutzte Platzhalter - Roadmap-Priorisierung und Integration-Timeline
**Betroffene Platzhalter:** 67 (ungenutzt)
**Kontext:**
67 Platzhalter (60%) haben 0 Verwendungen. **WICHTIG:** Dies ist kein Deprecation-Bedarf, sondern Integration-Planung.
**Fachliche Klassifizierung (siehe USAGE_ROLE_CLASSIFICATION.md):**
- **30 Platzhalter (45%):** Explizit in Roadmap Phase 0c/1/2 geplant
- **37 Platzhalter (55%):** Fachlich plausibel, noch nicht in Prompts integriert
- **0 Platzhalter:** Redundant oder deprecation-würdig
**Neue Fragestellung:**
Nicht "Behalten oder Deprecaten?", sondern "WANN und WIE integrieren?"
---
**Sub-Entscheidungen:**
#### E2.1.1: Geplante Platzhalter (30) - Integration-Timeline bestätigen
**Platzhalter-Gruppen:**
- **Scores (6):** activity_score, nutrition_score, recovery_score, body_progress_score, goal_progress_score, data_quality_score
- **Roadmap:** Phase 0c (Multi-Layer Architecture) + Phase 1 (Charts)
- **Correlations (5):** energy_weight_lag, load_hrv, load_rhr, protein_lbm, sleep_recovery
- **Roadmap:** Phase 2 (Engagement - Korrelationen)
- **Ability Balance (5):** coordination, endurance, mental, mobility, strength
- **Roadmap:** Phase 1 (Charts - Training Balance)
- **Goals Details (11):** active_goals_json/md, focus_areas_weighted, top_3_goals_*, focus_cat_*_progress
- **Roadmap:** Phase 0b/0c (Backend DONE, Prompt-Integration ausstehend)
- **Sleep/Plateau/Drivers (3):** sleep_debt, plateau_detected, top_drivers
- **Roadmap:** Phase 1/2 (Diagnostics)
**Frage:** Timeline bestätigen oder anpassen?
**Optionen:**
- **A: Roadmap wie geplant** - Phase 0c/1/2 (nächste 6-12 Wochen)
- **B: Priorisierung anpassen** - Quick Wins zuerst (z.B. Goals Details sofort)
- **C: Prototyping** - 5-10 Beispiel-Prompts erstellen (Wert demonstrieren)
**Empfehlung:** C → B → A (Prototyping zeigt Wert, dann Priorisierung, dann Roadmap)
---
#### E2.1.2: Plausible Platzhalter (37) - Prompt-Use-Cases identifizieren
**Platzhalter-Gruppen:**
- **Body Deltas (5):** arm_28d_delta, chest_28d_delta, hip_28d_delta, thigh_28d_delta, waist_28d_delta
- **Nutrition Details (6):** energy_deficit_surplus, intake_volatility, nutrition_days, protein_days_in_target, protein_ziel_low/high
- **Training Quality/Load (3):** monotony_score, strain_score, rest_day_compliance
- **Focus Category Weights/Progress (14):** focus_cat_*_weight, focus_cat_*_progress
- **Meta/Convenience (9):** bmi, waist_hip_ratio, datum_heute, zeitraum_*
**Frage:** Für welche Use-Cases Prompt-Templates erstellen?
**Optionen:**
- **A: Alle 37 dokumentieren** - Vollständig, aber aufwändig
- **B: Quick Wins (10-15)** - Offensichtliche Use-Cases zuerst
- **C: Warten bis Bedarf** - Nur auf Anfrage aktivieren
**Empfehlung:** B (10-15 Quick Wins: Body Deltas für Fortschritts-Prompts, Nutrition Details für Coaching-Prompts, Focus Category für Dashboard-Widgets)
---
**Entscheidung benötigt bis:** P2 Week 4
**Impact:** MEDIUM (Prompt-Bibliothek Vollständigkeit)
**Entscheider:** Product Manager + Tech Lead
**Methode:** Integration-Planungs-Meeting (4-6h, siehe Maßnahmenplan P2.2 REVIDIERT)
---
## KATEGORIE 3: Production-Readiness-Kriterien (P2)
### E3.1: Welche Platzhalter sind Production-Ready?
**Problem:**
Aktuell haben alle 111 `schema_status: draft`. Welche Kriterien für `production`?
**Vorgeschlagene Kriterien (aus Maßnahmenplan):**
1. `metadata_completeness_score >= 80`
2. `used_by.prompts.length >= 1 OR used_by.pipelines.length >= 1`
3. `time_window != 'unknown'`
4. `category != 'Unknown'`
5. `description != 'No description available'`
6. `confidence_logic != null OR (type == 'atomic' AND time_window == 'latest')`
7. `known_issues.length == 0`
**Frage:** Sind diese Kriterien zu streng/zu locker?
**Optionen:**
- **A: Wie vorgeschlagen** - Balanced
- **B: Strengere Kriterien** - Z.B. `used_by >= 3`, `completeness_score >= 90`
- **C: Lockerere Kriterien** - Z.B. `completeness_score >= 60`, keine Usage-Requirement
**Empfehlung:** A (wie vorgeschlagen)
**Zusatzfrage:** Soll es Zwischen-Status geben (`beta`, `stable`)?
**Optionen:**
- **A: Nur draft/production** - Einfach
- **B: draft/beta/stable/production** - Differenzierter
**Empfehlung:** B (mehr Nuancen ermöglichen schrittweise Freigabe)
**Entscheidung benötigt bis:** P2 Week 4
**Impact:** MEDIUM (Governance)
**Entscheider:** Tech Lead + Product Manager
---
## KATEGORIE 4: Neue Platzhalter (FUTURE)
### E4.1: Requirements Dev vs. Extended Catalog - Wie priorisieren?
**Problem:**
- **requirements_dev.md** schlägt 27 neue Platzhalter vor (P1-P27)
- **Extended Catalog** hat bereits 111
- Viele der "neuen" sind evtl. schon abgedeckt
**Frage:** Sollen die 27 P1-P27 implementiert werden, oder sind sie durch bestehende abgedeckt?
**Beispiele:**
- **P1: `goal_summary_json`** - Abgedeckt durch `active_goals_json` + `active_goals_md`?
- **P2: `focus_area_summary_json`** - Abgedeckt durch `focus_areas_weighted_json`?
- **P5: `domain_availability_json`** - Neu, nicht vorhanden
- **P12: `body_change_summary_json`** - Teilweise durch `caliper_summary`, `circ_summary`
**Empfehlung:**
- **Mapping-Exercise:** Neue vs. Bestehende
- **Gap-Analyse:** Welche sind echte Lücken?
- **Priorisierung:** Nur echte Gaps implementieren
**Entscheidung benötigt bis:** Nach P2 (Phase 1b Planning)
**Impact:** HIGH (Feature-Roadmap)
**Entscheider:** Product Manager + Tech Lead
---
## KATEGORIE 5: Governance-Prozesse (POST-AUDIT)
### E5.1: Wie werden neue Platzhalter künftig validiert?
**Problem:**
Aktuell gibt es keine systematische Validierung neuer Platzhalter gegen Normative Spec.
**Frage:** Soll ein Pre-Commit-Hook/CI-Check eingeführt werden?
**Optionen:**
- **A: Manuelle Reviews** - Flexibel, aber fehleranfällig
- **B: Automated Checks** - Robust, aber Aufwand für Setup
- **C: Hybrid** - Automated Checks + manuelle Review für komplexe Fälle
**Empfehlung:** C (Hybrid)
**Entscheidung benötigt bis:** Nach P2 (Tooling-Phase)
**Impact:** HIGH (langfristige Qualität)
**Entscheider:** Tech Lead
---
### E5.2: Wer ist Owner für Placeholder-Governance?
**Problem:**
Aktuell kein klarer Owner für Placeholder-Lifecycle.
**Frage:** Soll es eine dedizierte Rolle geben?
**Optionen:**
- **A: Tech Lead** - Technische Verantwortung
- **B: Product Manager** - Fachliche Verantwortung
- **C: Shared (beide)** - Consensus-basiert
- **D: Dedizierte Rolle "Data-Contract-Owner"** - Spezialisiert
**Empfehlung:** C (Shared) für jetzt, D langfristig
**Entscheidung benötigt bis:** Nach P2
**Impact:** MEDIUM (Governance)
**Entscheider:** Management
---
## KATEGORIE 6: Technische Schulden (POST-P2)
### E6.1: Legacy-String "nicht verfügbar" - Wann abschalten?
**Problem:**
P1.6 führt Dual-Mode ein (Legacy + Structured). Wann soll Legacy deprecated werden?
**Optionen:**
- **A: Nach 3 Monaten** - Schnell
- **B: Nach 6 Monaten** - Standard
- **C: Nach 12 Monaten** - Konservativ
- **D: Nie (dauerhaft Dual-Mode)** - Ewig Backward-Compatible
**Empfehlung:** B (6 Monate) mit klarer Migration-Guidance
**Entscheidung benötigt bis:** P1 Abschluss (Sunset-Datum festlegen)
**Impact:** MEDIUM (Breaking Change für Prompts)
**Entscheider:** Tech Lead + Prompt-Autoren
---
## ZUSAMMENFASSUNG OFFENER ENTSCHEIDUNGEN
| ID | Kategorie | Entscheidung | Dringlichkeit | Entscheider |
|----|-----------|--------------|---------------|-------------|
| **E1.1** | Zeitfenster Scores | custom/mixed/dominant? | 🔴 P0 Week 1 | Product |
| **E1.2** | Zeitfenster Ability Balance | 28d/14d/latest? | 🔴 P0 Week 1 | Product + Training-Expert |
| **E1.3** | Zeitfenster Correlations | 28d mit Min-Data? | 🔴 P0 Week 1 | Tech Lead |
| **E1.4** | Zeitfenster Goals & Focus | latest/custom/differenziert? | 🔴 P0 Week 1 | Product |
| **E1.5** | Zeitfenster Snapshots | latest/differenziert? | 🔴 P0 Week 1 | Tech Lead |
| **E2.1** | Integration-Timeline | 67 ungenutzte integrieren | 🟡 P2 Week 4 | Product |
| **E3.1** | Production-Kriterien | draft/beta/stable/production? | 🟡 P2 Week 4 | Tech + Product |
| **E4.1** | Neue Platzhalter P1-P27 | Welche implementieren? | 🟢 Post-P2 | Product |
| **E5.1** | Validierungs-Prozess | Automated/Manual/Hybrid? | 🟢 Post-P2 | Tech Lead |
| **E5.2** | Governance-Owner | Wer verantwortet Placeholders? | 🟢 Post-P2 | Management |
| **E6.1** | Legacy-Sunset | Wann "nicht verfügbar" abschalten? | 🟡 P1 Abschluss | Tech Lead |
**Legende:**
- 🔴 BLOCKING (P0) - Entscheidung innerhalb Week 1 benötigt
- 🟡 HIGH (P1-P2) - Entscheidung innerhalb Week 4-5 benötigt
- 🟢 MEDIUM (Post-P2) - Kann warten
---
## EMPFOHLENER ENTSCHEIDUNGS-PROZESS
### Week 1 (P0 Kickoff)
1. **Meeting (2h):** Product + Tech Lead + Training-Expert
2. **Agenda:**
- E1.1-E1.5: Alle Zeitfenster-Entscheidungen
- Decision-Log erstellen
3. **Output:** Entschiedene Zeitfenster für alle 39 unkla
ren Platzhalter
### Week 4 (P2)
1. **Meeting (2h):** Product + Tech Lead
2. **Agenda:**
- E2.1: Deprecation-Review (67 ungenutzte)
- E3.1: Production-Kriterien
3. **Output:** Deprecation-Liste, Production-Kriterien finalisiert
### Post-P2
1. **Meeting (1h):** Management + Tech + Product
2. **Agenda:**
- E4.1: Neue Platzhalter-Roadmap
- E5.1-E5.2: Governance-Prozesse
- E6.1: Legacy-Sunset-Datum
3. **Output:** Langfristige Placeholder-Governance etabliert
---
## NÄCHSTE SCHRITTE
1. **Dieses Dokument reviewen** mit Product Manager
2. **P0-Meeting ansetzen** (Week 1) für Zeitfenster-Entscheidungen
3. **Decision-Log starten** (Living Document)
4. **Nach Entscheidungen:** Maßnahmenplan P0 final anpassen
---
**Offene Entscheidungen dokumentiert von:** Claude Code (Lead Audit Agent)
**Review benötigt von:** Product Manager + Tech Lead
**Deadline kritische Entscheidungen:** P0 Week 1 (innerhalb 1 Woche)

View File

@ -0,0 +1,351 @@
# Quellenprotokoll: Placeholder-Audit
**Audit-Datum:** 29. März 2026
**Audit-Dauer:** ~590 Sekunden (4 Agents parallel)
**Methodik:** 4 spezialisierte Agents mit Cross-Validation
---
## 1. GELESENE DATEIEN
### 1.1 Normative und Spezifikations-Dokumente (HÖCHSTE PRIORITÄT)
| Datei | Pfad | Zeilen | Priorität | Nutzung | Authoritative |
|-------|------|--------|-----------|---------|---------------|
| **NORMATIVE.md** | `.claude/docs/audit/platzhalter/PLACEHOLDER_METADATA_REQUIREMENTS_V2_NORMATIVE.md` | 387 | 1 (Höchste) | Verbindliche Standardspezifikation, alle Norm-Referenzen | ✅ JA |
| **EXPORT_SPEC.md** | `.claude/docs/audit/platzhalter/PLACEHOLDER_EXPORT_SPEC.md` | 24 | 2 | API-Endpoint-Spezifikation, Export-Struktur | ✅ JA |
| **GAP_REPORT.md** | `.claude/docs/audit/platzhalter/PLACEHOLDER_GAP_REPORT.md` | 67+ | 3 | Initial Gap-Zahlen (74 unknown, 100 data_layer fehlt) | ⚠️ TEILWEISE |
| **CATALOG.json** | `.claude/docs/audit/platzhalter/PLACEHOLDER_CATALOG_EXTENDED.json` | 64817 Tokens | 4 | Ist-Zustand alle 111 Platzhalter (vollständig) | ✅ JA |
| **CATALOG.md** | `.claude/docs/audit/platzhalter/PLACEHOLDER_CATALOG_EXTENDED.md` | 148+ | 4 | Human-readable Catalog (Kategorien, Übersicht) | ⚠️ TEILWEISE |
---
### 1.2 Fachliche Dokumentation
| Datei | Pfad | Zeilen | Nutzung | Authoritative |
|-------|------|--------|---------|---------------|
| **DATA_ARCHITECTURE.md** | `.claude/docs/audit/platzhalter/DATA_ARCHITECTURE.md` | 300+ (Teil) | Fachliche Datenarchitektur, Domänen-Entitäten, Berechnungslogiken | ⚠️ FACHLICH |
| **requirements_dev.md** | `.claude/docs/audit/platzhalter/placeholder_requirements_for_development.md` | 704 | Entwickler-Arbeitsdokument, P1-P27 neue Platzhalter-Vorschläge | ❌ NICHT normativ |
| **konzept_v2.md** | `.claude/docs/audit/platzhalter/mitai_jinkendo_konzept_diagramme_auswertungen_v2.md` | 2086 | Chart-Spezifikationen (K1-K5, E1-E5, A1-A8, C1-C7, S1-S3) | ⚠️ FACHLICH |
---
### 1.3 Code-Dateien (Code-Evidence-Agent)
| Datei | Pfad | Zeilen | Nutzung | Authoritative |
|-------|------|--------|---------|---------------|
| **placeholder_resolver.py** | `backend/placeholder_resolver.py` | ~1300 | PLACEHOLDER_MAP (Zeilen 1075-1221), Helper-Funktionen (_safe_*) | ✅ JA (Code) |
| **body_metrics.py** | `backend/data_layer/body_metrics.py` | 831 | Weight, BF%, Circumferences, Trends, Deltas | ✅ JA (Code) |
| **nutrition_metrics.py** | `backend/data_layer/nutrition_metrics.py` | 1093 | Nutrition Averages, Energy Balance, Protein Adequacy | ✅ JA (Code) |
| **activity_metrics.py** | `backend/data_layer/activity_metrics.py` | 906 | Training Volume, Quality, Load Monitoring, Ability Balance | ✅ JA (Code) |
| **recovery_metrics.py** | `backend/data_layer/recovery_metrics.py` | 879 | Sleep Metrics, HRV/RHR Baselines, Recovery Scoring | ✅ JA (Code) |
| **scores.py** | `backend/data_layer/scores.py` | 584 | Focus Weights, Goal Progress, Category Scores | ✅ JA (Code) |
| **correlations.py** | `backend/data_layer/correlations.py` | 504 | Lag Correlations, Plateau Detection, Top Drivers | ✅ JA (Code) |
| **prompts.py (Router)** | `backend/routers/prompts.py` | ~2246 | Export-Endpoints (Zeilen 370-467: extended export) | ✅ JA (Code) |
| **goal_utils.py** | `backend/goal_utils.py` | Teilweise | Goal-Helper-Funktionen | ✅ JA (Code) |
---
### 1.4 Zusätzliche Projektdokumente
| Datei | Pfad | Nutzung | Authoritative |
|-------|------|---------|---------------|
| **CLAUDE.md** | `.claude/CLAUDE.md` | Projekt-Kontext, Tech-Stack, Versions-Historie | ⚠️ KONTEXT |
| **ARCHITECTURE.md** | `.claude/rules/ARCHITECTURE.md` | Architektur-Regeln, Versionskontrolle | ⚠️ KONTEXT |
| **CODING_RULES.md** | `.claude/rules/CODING_RULES.md` | Coding-Standards | ⚠️ KONTEXT |
| **LESSONS_LEARNED.md** | `.claude/rules/LESSONS_LEARNED.md` | Bekannte Fehler-Patterns | ⚠️ KONTEXT |
---
## 2. RANGFOLGE DER QUELLEN (BEI KONFLIKTEN)
Bei Widersprüchen zwischen Quellen gilt folgende Priorität:
| Rang | Quelle | Regel | Beispiel-Konflikt |
|------|--------|-------|-------------------|
| **1** | **Normative Spec** | Verbindliche Standardspezifikation | time_window-Werte: Nur latest/7d/14d/28d/30d/90d/custom/mixed/unknown erlaubt |
| **2** | **Code (Ist-Zustand)** | Bei Konflikt Docs vs. Code → Code ist autoritativ | `weight_trend`: Docs "7d/30d", Code 28d → **Code gewinnt** |
| **3** | **Extended Catalog** | Generated Truth (Ist-Zustand dokumentiert) | Bestandszahlen: 111 Platzhalter |
| **4** | **Export Spec / Gap Report** | Technische Spezifikation/Diagnose | Export-Format, Gap-Zahlen |
| **5** | **DATA_ARCHITECTURE.md** | Fachliche Referenz | Semantic Contracts, Berechnungslogiken |
| **6** | **konzept_v2.md** | Chart-/Feature-Spezifikationen | Diagramm-Anforderungen |
| **7** | **requirements_dev.md** | **NICHT NORMATIV** - Arbeitsdokument | P1-P27 Vorschläge (nicht bindend) |
| **8** | **Projekt-Context** | Hintergrund-Information | CLAUDE.md, ARCHITECTURE.md |
**Wichtig:** `requirements_dev.md` ist **KEIN normativer Standard**, sondern ein Entwickler-Arbeitsdokument für Planung!
---
## 3. MAẞGEBLICHE AUSSAGEN PRO QUELLE
### 3.1 NORMATIVE.md (Verbindliche Standard-Instanz)
**Maßgebliche Aussagen:**
- §3.4: **"Zeitfenster explizit"** → Pflicht für alle Platzhalter
- §3.5: **"Fehlwerte explizit"** → Strukturierte Felder statt nur String
- §5: **"Qualitäts-/Confidence-Logik"** → Confidence für Trends/Scores
- §7.1: **Pflichtfelder:** key, placeholder, category, type, description, semantic_contract, unit, time_window, output_type, value_display, available, missing_value_policy, source, version, deprecated
- §7.2-7.4: **Erlaubte Werte** für type, time_window, output_type
**Verwendung im Audit:**
- Compliance-Bewertung (compliant/partially_compliant/non_compliant)
- Gap-Identifikation (Verstoß gegen §X)
- Remediation-Priorisierung (Norm-Verstöße = P0)
---
### 3.2 Code (placeholder_resolver.py + data_layer/*)
**Maßgebliche Aussagen:**
- **Zeitfenster im Code:**
- `weight_trend`: `days=28` (Zeile ~1084)
- `activity_summary`: `days=14` (Zeile ~1102)
- `sleep_avg_duration`: `days=7` (Zeile ~1107)
- **Resolver-Mappings:** 111 Platzhalter vollständig implementiert (Zeilen 1075-1221)
- **Helper-Funktionen:** `_safe_int`, `_safe_float`, `_safe_str`, `_safe_json` (Zeilen 406-602)
- **Data-Layer-Calls:** Code-Evidence-Agent hat vollständige Traces
- **Confidence-Logik:** Nur in nutrition_metrics, body_metrics, activity_metrics implementiert
**Verwendung im Audit:**
- **Autoritativ bei Konflikten** (Code > Docs)
- Technische Herkunft (data_layer_module, source_tables)
- Zeitfenster-Extraktion (Default-Parameter)
---
### 3.3 Extended Catalog (PLACEHOLDER_CATALOG_EXTENDED.json)
**Maßgebliche Aussagen:**
- **111 Platzhalter** (vollständiger Bestand)
- **Kategorien-Verteilung:**
- 49 Unknown (44%)
- 11 Körper, 9 Training, 8 Ernährung, 8 Focus Areas, 7 Schlaf/Erholung, 6 Vitalwerte, 6 Scores, 4 Profil, 3 Zeitraum
- **time_window: unknown:** 74 (67%)
- **metadata_completeness_score: 0** für alle 111
- **schema_status: draft** für alle 111
**Verwendung im Audit:**
- Bestandsaufnahme (Was existiert?)
- Ist-Zustand-Baseline
- Gap-Zahlen-Validierung
---
### 3.4 DATA_ARCHITECTURE.md (Fachliche Ableitung)
**Maßgebliche Aussagen:**
- **Domänen-Struktur:** Nutzer & Zielsetzung, Körper, Training, Lifestyle, Auswertungen
- **Berechnungslogiken:**
- BMI = weight / (height_m ^ 2)
- Protein-Ziel = weight × 1.6-2.2 g/kg
- Energy-Balance = intake - (TDEE + training_kcal)
- **Zeitfenster-Heuristiken:**
- Trends: 7d/28d/90d
- Scores: mixed (verschiedene Sub-Komponenten)
- Correlations: 28d (Min-Daten für Reliability)
**Verwendung im Audit:**
- Semantic Contracts ableiten (wo Code unklar)
- Fachliche Kategorien bestimmen
- Zeitfenster-Empfehlungen (bei Code-Unklarheit)
---
### 3.5 requirements_dev.md (NICHT AUTORITATIV)
**Status:** Arbeitsdokument, **KEINE** normative Instanz
**Maßgebliche Aussagen (mit Vorsicht):**
- Vorschläge für 27 neue Platzhalter (P1-P27)
- Governance-Regeln (G1-G7) - **sollten** in Normative Spec überführt werden
**Verwendung im Audit:**
- **Referenz für geplante Features** (nicht für Ist-Zustand)
- **Konflikte mit Extended Catalog:** requirements_dev ist NICHT autoritativ
- Beispiel-Konflikt: requirements_dev nennt P1 `goal_summary_json` als "neu nötig", aber Extended Catalog hat bereits `active_goals_json` → **Catalog gewinnt**
---
## 4. WIDERSPRÜCHE ZWISCHEN QUELLEN
### 4.1 Dokumentierte Konflikte
| Konflikt | Quelle 1 | Quelle 2 | Resolution | Audit-Entscheidung |
|----------|----------|----------|------------|---------------------|
| **weight_trend Zeitfenster** | Description: "7d/30d" | Code: 28d | Code gewinnt (Rang 2 > Rang 5) | Code ist autoritativ → Docs aktualisieren |
| **activity_summary Zeitfenster** | Description: "7d" | Code: 14d | Code gewinnt | Code ist autoritativ → Docs aktualisieren |
| **Bestandszahlen** | Export Spec: 116 | Extended Catalog: 111 | 5 Metafelder (Rang 3 > Rang 4) | 111 User-Placeholders + 5 Meta |
| **Neue Platzhalter** | requirements_dev: P1-P27 "neu" | Extended Catalog: 111 existierend | Catalog ist Truth (Rang 3 > Rang 7) | requirements_dev ist Planning, nicht Ist-Zustand |
---
### 4.2 Inkonsistenzen zwischen Dokumenten
| Dokument A | Aussage A | Dokument B | Aussage B | Audit-Behandlung |
|------------|-----------|------------|-----------|------------------|
| GAP_REPORT.md | "74 unknown time_window" | Code-Evidence | "75 unklar im Code" | Beide korrekt (leichte Differenz durch Fuzzy-Matching) |
| requirements_dev.md | "Ability Balance fehlt" | Extended Catalog | "Ability Balance existiert (5 Platzhalter)" | Extended Catalog gewinnt (existiert, aber ungenutzt) |
| konzept_v2.md | "E1 Energiebilanz Chart braucht X" | Code | "Nicht implementiert" | Konzept ist Soll, Code ist Ist → Kein Konflikt (Feature-Gap) |
---
## 5. FACHLICH ABGELEITETE AUSSAGEN
Diese Aussagen stammen **nicht direkt aus Code**, sondern wurden **fachlich inferiert**:
| Aussage | Quelle | Ableitung | Evidence-Level |
|---------|--------|-----------|----------------|
| **Ability Balance Zeitfenster: 28d** | DATA_ARCHITECTURE 3.2 + Audit-Heuristik | Konsistent mit anderen Trend-Metriken | `fachlich_abgeleitet` |
| **Correlations Zeitfenster: 28d** | konzept_v2.md (C1-C7) + Statistik-Heuristik | Min 21-28 Paare für Reliability | `fachlich_abgeleitet` |
| **Scores Zeitfenster: mixed** | DATA_ARCHITECTURE + Code-Analyse | Kombinieren verschiedene Sub-Zeitfenster | `fachlich_abgeleitet` |
| **49 Non-Compliant Semantic Contracts** | Semantic-Contract-Agent + DATA_ARCHITECTURE | Aus Datenarchitektur inferiert | `fachlich_abgeleitet` |
**Wichtig:** Alle fachlich abgeleiteten Aussagen sind im Audit **klar gekennzeichnet** mit `evidence_level: "fachlich_abgeleitet"`.
---
## 6. NICHT VERWENDETE QUELLEN
### 6.1 Bewusst ausgeschlossen
| Quelle | Grund für Ausschluss |
|--------|----------------------|
| **Frontend-Code** | Nicht relevant für Backend-Placeholder-Definitionen |
| **Prompt-Templates in DB** | Verwendung wird aus Catalog-Metadaten (`used_by`) extrahiert |
| **Alte Dokumentationen** | Legacy, nicht mehr aktuell |
| **Git History** | Nicht relevant für Ist-Zustand (Audit fokussiert auf Current State) |
---
### 6.2 Fehlende Quellen (würden Audit verbessern)
| Fehlende Quelle | Warum hilfreich | Impact |
|-----------------|-----------------|--------|
| **Unit-Tests für Platzhalter** | Würden erwartete Outputs dokumentieren | MEDIUM (bessere Semantic Contracts) |
| **Prompt-Library-Dokumentation** | Würde zeigen, welche Platzhalter wie genutzt werden | MEDIUM (bessere Usage-Analyse) |
| **Historical Change-Log** | Würde Breaking Changes dokumentieren | LOW (nur für Deprecation-History) |
| **User-Feedback zu Platzhaltern** | Würde Probleme/Unklarheiten zeigen | LOW (kein Bestand vorhanden) |
---
## 7. AGENT-SPEZIFISCHE QUELLENNUTZUNG
### 7.1 Code-Evidence-Agent (124s)
**Genutzte Quellen:**
1. `placeholder_resolver.py` (vollständig, Zeilen 1-1300)
2. `data_layer/*.py` (alle 6 Module)
3. `routers/prompts.py` (Export-Logik)
4. `goal_utils.py` (Goal-Helper)
**Output:**
- Resolver-Funktionen für alle 111 Platzhalter
- Data-Layer-Module (81 via Helper, 19 direkt)
- Source-Tables (aus SQL-Queries extrahiert)
- Zeitfenster aus Default-Parametern
**Evidence-Level:** `code_verified` (100%)
---
### 7.2 Semantic-Contract-Agent (218s)
**Genutzte Quellen:**
1. `PLACEHOLDER_CATALOG_EXTENDED.json` (Ist-Zustand)
2. `DATA_ARCHITECTURE.md` (Fachliche Bedeutung)
3. `mitai_jinkendo_konzept_diagramme_auswertungen_v2.md` (Chart-Specs)
**Output:**
- Target-Descriptions für alle 49 Non-Compliant
- Target-Categories (Unknown → fachliche Kategorien)
- Semantic Contracts (aus Datenarchitektur abgeleitet)
**Evidence-Level:**
- `documentation_verified` (56% - in Konzeptdokumenten begründet)
- `fachlich_abgeleitet` (44% - aus Datenarchitektur inferiert)
---
### 7.3 Time-Window-Confidence-Agent (90s)
**Genutzte Quellen:**
1. `PLACEHOLDER_CATALOG_EXTENDED.json` (Ist-Zustand time_window)
2. `placeholder_resolver.py` + `data_layer/*.py` (Code-Parameter)
3. `PLACEHOLDER_METADATA_REQUIREMENTS_V2_NORMATIVE.md` (Erlaubte Werte)
**Output:**
- Zeitfenster-Status für alle 111 (74 unknown, 37 definiert)
- Aggregationslogik (mean, median, slope, etc.)
- Confidence-Logik-Status (8 haben, 103 fehlt)
- Min-Data-Thresholds (wo identifizierbar)
**Evidence-Level:**
- `code_verified` (Zeitfenster aus Code: 37)
- `code_inferred` (75 unklar im Code, fachlich geschätzt)
---
### 7.4 Prompt-Usage-Agent (157s)
**Genutzte Quellen:**
1. `PLACEHOLDER_CATALOG_EXTENDED.json` (`used_by` Metadaten)
2. Grep-Suche nach `{{placeholder_name}}` in Backend (Code-Search)
**Output:**
- Usage-Count für alle 111 (12 kritisch, 32 wichtig, 67 ungenutzt)
- Criticality-Klassifizierung (produktkritisch/wichtig/ungenutzt)
- Rename-Risk-Bewertung (HIGH/MEDIUM/LOW)
**Evidence-Level:** `catalog_verified` (100% aus Extended Catalog)
---
## 8. CROSS-VALIDATION ZWISCHEN AGENTS
**Validierungs-Methodik:**
- Jeder Placeholder wurde von **4 Perspektiven** geprüft
- Konflikte wurden nach Rangfolge aufgelöst (Norm > Code > Catalog > Docs)
- Evidence-Levels dokumentieren Sicherheit der Aussage
**Beispiel-Cross-Validation (weight_trend):**
| Agent | Perspektive | Aussage | Evidence-Level |
|-------|-------------|---------|----------------|
| **Code-Evidence** | Technisch | `days=28` im Code | `code_verified` |
| **Semantic-Contract** | Fachlich | Description sagt "7d/30d" | `documentation_verified` |
| **Time-Window-Confidence** | Zeitfenster | Code 28d vs. Docs 7d/30d → **KONFLIKT** | `code_verified` |
| **Prompt-Usage** | Verwendung | 10 Prompts/Pipelines nutzen es | `catalog_verified` |
| **→ Resolution** | | Code gewinnt → time_window: 28d | `code_verified` |
---
## 9. QUELLENPROTOKOLL-ZUSAMMENFASSUNG
**Gelesene Dateien:** 20+
- **Normative/Spec:** 5 (NORMATIVE.md, EXPORT_SPEC, GAP_REPORT, CATALOG.json, CATALOG.md)
- **Fachlich:** 3 (DATA_ARCHITECTURE, requirements_dev, konzept_v2)
- **Code:** 9+ (placeholder_resolver.py, data_layer/*, routers/prompts.py)
- **Kontext:** 4 (CLAUDE.md, ARCHITECTURE.md, CODING_RULES, LESSONS_LEARNED)
**Maßgebliche Quellen:** 8
- **Rang 1 (Norm):** NORMATIVE.md
- **Rang 2 (Code):** placeholder_resolver.py, data_layer/*
- **Rang 3 (Truth):** PLACEHOLDER_CATALOG_EXTENDED.json
**Konflikte:** 4 dokumentiert, alle nach Rangfolge aufgelöst
**Widersprüche:** 3 dokumentiert
- weight_trend: Code (28d) vs. Docs (7d/30d) → **Code gewinnt**
- activity_summary: Code (14d) vs. Docs (7d) → **Code gewinnt**
- Bestandszahlen: 116 vs. 111 → **111 User-Placeholders + 5 Meta**
**Fachlich abgeleitete Aussagen:** 49 Non-Compliant Semantic Contracts
- **Evidence-Level:** `fachlich_abgeleitet` (klar gekennzeichnet)
**Nicht verwendete Quellen:** Frontend-Code, Prompt-DB, Git History (bewusst ausgeschlossen)
---
**Quellenprotokoll erstellt von:** Claude Code (Lead Audit Agent)
**Audit-Methodik:** 4-Agent-Cross-Validation mit Rangfolgen-basierter Konflikt-Resolution
**Transparenz:** Alle Aussagen mit Evidence-Level dokumentiert (code_verified/documentation_verified/fachlich_abgeleitet/unclear)

View File

@ -0,0 +1,340 @@
# Normative Prüfmatrix: Summary
**Audit-Datum:** 29. März 2026
**Umfang:** 111 Platzhalter
**Normative Basis:** PLACEHOLDER_METADATA_REQUIREMENTS_V2_NORMATIVE.md v1.0.0
---
## HINWEIS ZUR VOLLSTÄNDIGEN MATRIX
Die **vollständige Prüfmatrix** (111 Platzhalter × ~40 Felder = ~4500 Datenpunkte) würde ein extrem großes Dokument ergeben.
Stattdessen:
1. **Dieser Summary** zeigt die kritischsten Findings pro Compliance-Level
2. **Detaillierte Einzelberichte** siehe Agent-Outputs (bereits vorhanden)
3. **Maschinenlesbare Version:** Nutze `PLACEHOLDER_CATALOG_EXTENDED.json` direkt
---
## COMPLIANCE-ÜBERSICHT (111 PLATZHALTER)
### Voll Normkonform (8 Platzhalter - 7%)
| Key | Category | Time-Window | Confidence | Used-By | Why Compliant |
|-----|----------|-------------|------------|---------|---------------|
| `protein_avg` | Ernährung | 30d | ✅ calculate_confidence | 0 | Best-Practice-Modell |
| `kcal_avg` | Ernährung | 30d | ✅ calculate_confidence | 0 | Best-Practice-Modell |
| `fat_avg` | Ernährung | 30d | ✅ calculate_confidence | 0 | Best-Practice-Modell |
| `carb_avg` | Ernährung | 30d | ✅ calculate_confidence | 0 | Best-Practice-Modell |
| `weight_aktuell` | Körper | latest | ✅ high/insufficient | 10 | Latest-Pattern-Modell |
| `weight_trend` | Körper | 28d | ✅ calculate_confidence | 10 | **Code-Konflikt (Docs 7d/30d)** |
| `circ_summary` | Körper | mixed | ✅ high/insufficient | 8 | Best-of-Each-Pattern |
| `age` | Profil | keine | ❌ (not needed) | 2 | Snapshot, no confidence needed |
**Pattern:** Nutrition-Averages + Weight-Aktuell = Best-Practice-Modelle für alle anderen
---
### Partially Compliant (22 Platzhalter - 20%)
**Charakteristik:** 1-2 Gaps, meist time_window oder confidence
| Key | Category | Missing | Priority | Action |
|-----|----------|---------|----------|--------|
| `caliper_summary` | Körper | time_window: unknown | P0 | → latest |
| `kf_aktuell` | Körper | time_window: unknown | P0 | → latest |
| `sleep_avg_duration` | Schlaf & Erholung | time_window: unknown (Code: 7d) | P0 | → 7d |
| `sleep_avg_quality` | Schlaf & Erholung | time_window: unknown (Code: 7d) | P0 | → 7d |
| `rest_days_count` | Schlaf & Erholung | time_window: unknown (Code: 30d) | P0 | → 30d |
| `vitals_avg_hr` | Vitalwerte | time_window: unknown (Code: 7d) | P0 | → 7d |
| `vitals_avg_hrv` | Vitalwerte | time_window: unknown (Code: 7d) | P0 | → 7d |
| `vitals_vo2_max` | Vitalwerte | time_window: unknown, weak semantic_contract | P0 + P1 | → latest + sharpen contract |
| `bmi` | Körper | time_window: unknown, weak semantic_contract | P0 | → latest + Formel dokumentieren |
| ... (13 weitere) | | | | |
**Remediation:** P0 time_window + teilweise P1 semantic_contract sharpening
---
### Non-Compliant (81 Platzhalter - 73%)
**Charakteristik:** 3+ Gaps, meist Unknown category + No description + unknown time_window
#### Cluster 1: Unknown Category + No Description (49)
**Sub-Gruppen:**
**A. Ability Balance (5):**
- `ability_balance_coordination`, `ability_balance_endurance`, `ability_balance_mental`, `ability_balance_mobility`, `ability_balance_strength`
- **Gaps:** category: Unknown, description: No description, time_window: unknown
- **Fix:** category: Training, time_window: 28d, descriptions aus Semantic-Agent-Report
- **Priority:** P0 (Bulk-Update)
**B. Correlations (5):**
- `correlation_energy_weight_lag`, `correlation_load_hrv`, `correlation_load_rhr`, `correlation_protein_lbm`, `correlation_sleep_recovery`
- **Gaps:** category: Unknown, description: No description, time_window: unknown, confidence: null
- **Fix:** category: Auswertung, time_window: 28d, confidence: pair-based, descriptions aus Semantic-Agent
- **Priority:** P0 (description) + P1 (confidence)
**C. Goals & Focus (16):**
- `active_goals_json`, `active_goals_md`, `focus_areas_weighted_json`, `focus_areas_weighted_md`, `focus_area_weights_json`
- `top_goal_name`, `top_goal_progress_pct`, `top_goal_status`
- `top_3_goals_behind_schedule`, `top_3_goals_on_track`, `top_3_focus_areas`
- `focus_cat_körper_progress/weight`, `focus_cat_ernährung_progress/weight`, `focus_cat_aktivität_progress/weight`, `focus_cat_recovery_progress/weight`, `focus_cat_vitalwerte_progress/weight`
- **Gaps:** category: Unknown, description: No description, time_window: unknown
- **Fix:** category: Ziele, time_window: latest (Snapshot) oder custom (Progress), descriptions aus Semantic-Agent
- **Priority:** P0 (Bulk-Update)
**D. Body Deltas (5):**
- `arm_28d_delta`, `chest_28d_delta`, `hip_28d_delta`, `thigh_28d_delta` (waist_28d_delta ist Partially Compliant)
- **Gaps:** category: Unknown, description: No description, time_window: unknown (sollte 28d sein), confidence: null
- **Fix:** category: Körper, time_window: 28d, confidence: delta-confidence, descriptions aus Semantic-Agent
- **Priority:** P0 (description) + P1 (confidence)
**E. Nutrition (6):**
- `energy_deficit_surplus`, `intake_volatility`, `nutrition_days`, `protein_days_in_target`, `protein_ziel_low`, `protein_ziel_high`
- **Gaps:** category: Unknown, description: No description, time_window: unknown
- **Fix:** category: Ernährung, time_window: 7d/28d/30d (je nach Funktion), descriptions aus Semantic-Agent
- **Priority:** P0 (Bulk-Update)
**F. Training (8):**
- `activity_detail`, `activity_summary` (Code-Konflikt!), `trainingstyp_verteilung`, `training_minutes_week`, `training_frequency_7d`
- `quality_sessions_pct`, `monotony_score`, `strain_score`, `rest_day_compliance`, `proxy_internal_load_7d`
- **Gaps:** category: Unknown (teilweise Training), description: No description (teilweise), time_window: unknown
- **Fix:** category: Training, time_window: 7d/14d/28d (aus Code), descriptions aus Semantic-Agent
- **Priority:** P0 (time_window, Code-Konflikte) + P1 (confidence für Scores)
**G. Meta/Sonstiges (4):**
- `zeitraum_90d`, `goal_weight`, `goal_bf_pct`, `weight_90d_slope`, `plateau_detected`, `top_drivers`, etc.
- **Gaps:** Gemischt
- **Fix:** Individuell je Platzhalter
- **Priority:** P0-P1
---
#### Cluster 2: Fehlende Confidence (103 - inkl. Partially Compliant)
**Kritischste:** Trend-Platzhalter (11)
- `weight_28d_slope`, `weight_90d_slope`, `weight_7d_median`
- `fm_28d_change`, `lbm_28d_change`
- `waist_28d_delta`, `hip_28d_delta`, `chest_28d_delta`, `arm_28d_delta`, `thigh_28d_delta`
- `vo2max_trend_28d`
**Gap:** confidence_logic: null
**Fix:** Implementiere calculate_confidence(data_points, time_window_days, 'trend')
**Priority:** P1 (12-16h)
---
#### Cluster 3: Fehlende Data-Layer-Module (100)
**Alle außer:**
- nutrition_avg (4), weight_aktuell, weight_trend, kf_aktuell, caliper_summary, circ_summary, age, height, name, geschlecht
**Gap:** data_layer_module: null
**Fix:** Mapping aus Code-Evidence-Agent-Report übernehmen (Bulk-Update)
**Priority:** P1 (6-8h, automatisierbar)
---
#### Cluster 4: Fehlende Source-Tables (90)
**Ähnlich Cluster 3**
**Gap:** source_tables: []
**Fix:** Mapping aus Code-Evidence-Agent-Report übernehmen (Bulk-Update)
**Priority:** P1 (6-8h, automatisierbar)
---
## COMPLIANCE-MATRIX NACH KATEGORIE
| Kategorie | Total | Compliant | Partially | Non-Compliant | Kritischste Gaps |
|-----------|-------|-----------|-----------|---------------|------------------|
| **Ernährung** | 8 | 4 (50%) | 0 | 4 | time_window, description |
| **Körper** | 11 | 3 (27%) | 5 | 3 | time_window, confidence (Trends) |
| **Training** | 9 | 0 | 2 | 7 | category, description, time_window |
| **Profil** | 4 | 1 (25%) | 3 | 0 | time_window (unkritisch) |
| **Schlaf & Erholung** | 7 | 0 | 3 | 4 | time_window, description |
| **Vitalwerte** | 6 | 0 | 3 | 3 | time_window, semantic_contract |
| **Scores (Phase 0b)** | 6 | 0 | 0 | 6 | time_window, confidence |
| **Focus Areas** | 8 | 0 | 0 | 8 | category, description, time_window |
| **Zeitraum** | 3 | 0 | 0 | 3 | time_window (Name-Mismatch!) |
| **Unknown** | 49 | 0 | 6 | 43 | Alles (category, description, time_window, confidence) |
**Auffälligkeiten:**
- **Ernährung:** 50% Compliance dank Best-Practice nutrition_avg
- **Unknown-Kategorie:** 88% Non-Compliant (43/49)
- **Training:** 0% Fully Compliant, aber nur 2 Partially → hoher Remediation-Bedarf
---
## PRODUKTKRITISCHE PLATZHALTER (12)
**Diese 12 haben >3 Verwendungen = Breaking-Change-Risk bei Änderungen**
| Rank | Key | Uses | Category | Compliance | Kritische Gaps | Risk |
|------|-----|------|----------|------------|----------------|------|
| 1 | `name` | 19 | Profil | Partially | time_window (unkritisch) | 🔴 EXTREM |
| 2 | `geschlecht` | 14 | Profil | Partially | time_window (unkritisch) | 🔴 EXTREM |
| 3 | `height` | 12 | Profil | Partially | time_window (unkritisch) | 🔴 EXTREM |
| 4 | `weight_aktuell` | 10 | Körper | ✅ Compliant | Keine | 🔴 HOCH (Format-sensitiv) |
| 5 | `weight_trend` | 10 | Körper | ✅ Compliant | **Code-Docs-Konflikt** | 🔴 HOCH (Code-Fix P0) |
| 6 | `goal_bf_pct` | 10 | Unknown | Non-Compliant | category, description, time_window | 🔴 HOCH |
| 7 | `caliper_summary` | 8 | Körper | Partially | time_window | 🟡 MITTEL |
| 8 | `circ_summary` | 8 | Körper | ✅ Compliant | Keine | 🟡 MITTEL |
| 9 | `goal_weight` | 8 | Unknown | Non-Compliant | category, description, time_window | 🟡 MITTEL |
| 10 | `protein_ziel_low` | 7 | Unknown | Non-Compliant | category, description, time_window | 🟡 MITTEL |
| 11 | `protein_ziel_high` | 7 | Unknown | Non-Compliant | category, description, time_window | 🟡 MITTEL |
| 12 | `activity_detail` | 4 | Unknown | Non-Compliant | **Code-Docs-Konflikt**, category, description, time_window | 🟡 MITTEL |
**Kritische Beobachtungen:**
- **6 von 12 (50%)** sind Non-Compliant, davon 5 in "Unknown"-Kategorie
- **3 haben Code-Docs-Konflikte** (weight_trend, activity_summary, activity_detail) → P0 Fix
- **name, geschlecht, height:** Zwar nur "Partially" (time_window fehlt), aber unkritisch da Profil-Snapshots
---
## UNGENUTZTE PLATZHALTER (67 - 60%)
**WICHTIG:** Methodische Korrektur (30.03.2026)
- Nichtnutzung ≠ Deprecation-Bedarf
- Prompt-Bibliothek ist im Aufbau (Phase 0b/0c/1/2)
- Neue Klassifizierung: usage_role_classification statt Deprecation-Kategorien
**Neue Klassifizierung (siehe USAGE_ROLE_CLASSIFICATION.md):**
### unused_but_planned (30 - 45%)
- **Scores (6):** activity_score, nutrition_score, recovery_score, body_progress_score, goal_progress_score, data_quality_score
- Roadmap: Phase 0c/1
- **Correlations (5):** energy_weight_lag, load_hrv, load_rhr, protein_lbm, sleep_recovery
- Roadmap: Phase 2
- **Ability Balance (5):** coordination, endurance, mental, mobility, strength
- Roadmap: Phase 1
- **Goals Details (11):** active_goals_json/md, focus_areas_weighted, top_3_goals_*, focus_cat_*_progress
- Roadmap: Phase 0b/0c (Backend DONE)
- **Sleep/Plateau/Drivers (3):** sleep_debt, plateau_detected, top_drivers
- Roadmap: Phase 1/2
- **Action:** Timeline bestätigen, Prototyping-Prompts erstellen
### unused_but_plausible (37 - 55%)
- **Body Deltas (5):** arm_28d_delta, chest_28d_delta, hip_28d_delta, thigh_28d_delta, waist_28d_delta
- Plausibel für: Fortschritts-Prompts spezifischer Körperteile
- **Nutrition Details (6):** energy_deficit_surplus, intake_volatility, nutrition_days, protein_days_in_target, protein_ziel_*
- Plausibel für: Ernährungs-Coaching-Prompts
- **Training Quality/Load (3):** monotony_score, strain_score, rest_day_compliance
- Plausibel für: Übertrainings-Erkennung
- **Focus Category (14):** focus_cat_*_weight, focus_cat_*_progress
- Plausibel für: Dashboard-Widgets, Kategorie-Analysen
- **Meta/Convenience (9):** bmi, waist_hip_ratio, datum_heute, zeitraum_*
- Plausibel für: Prompt-Templates (Convenience)
- **Action:** Prompt-Use-Cases identifizieren, Templates für 10-15 Quick Wins
### redundant_or_duplicate (0 - 0%)
- **Keine** - alle 67 haben fachliche Berechtigung
---
## GAP-SUMMARY PRO PLATZHALTER (TOP 20 KRITISCHSTE)
| Rank | Key | Gaps | Priority | Aufwand | Blocker |
|------|-----|------|----------|---------|---------|
| 1 | `goal_bf_pct` | category, description, time_window, semantic_contract | P0 | 15 Min | 10 Uses = Breaking-Risk |
| 2 | `goal_weight` | category, description, time_window, semantic_contract | P0 | 15 Min | 8 Uses = Breaking-Risk |
| 3 | `protein_ziel_low` | category, description, time_window, semantic_contract | P0 | 15 Min | 7 Uses = Breaking-Risk |
| 4 | `protein_ziel_high` | category, description, time_window, semantic_contract | P0 | 15 Min | 7 Uses = Breaking-Risk |
| 5 | `activity_detail` | **Code-Konflikt**, category, description, time_window | P0 | 30 Min | 4 Uses + Konflikt |
| 6 | `weight_trend` | **Code-Konflikt (Docs 7d/30d, Code 28d)** | P0 | 15 Min | 10 Uses + Konflikt |
| 7 | `activity_summary` | **Code-Konflikt (Docs 7d, Code 14d)** | P0 | 15 Min | 2 Uses + Konflikt |
| 8 | `weight_28d_slope` | confidence: null | P1 | 2h | Trend-Pattern |
| 9 | `weight_90d_slope` | confidence: null | P1 | 2h | Trend-Pattern |
| 10 | `fm_28d_change` | confidence: null | P1 | 2h | Delta-Pattern |
| 11 | `lbm_28d_change` | confidence: null | P1 | 2h | Delta-Pattern |
| 12 | `activity_score` | time_window, confidence | P0 + P1 | 1h (window) + 3h (confidence) | Score-Pattern |
| 13 | `nutrition_score` | time_window, confidence | P0 + P1 | 1h + 3h | Score-Pattern |
| 14 | `recovery_score` | time_window, confidence | P0 + P1 | 1h + 3h | Score-Pattern |
| 15 | `correlation_energy_weight_lag` | category, description, time_window, confidence | P0 + P1 | 30 Min + 2h | Correlation-Pattern |
| 16 | `ability_balance_coordination` | category, description, time_window | P0 | 15 Min | Bulk-Update |
| 17 | `ability_balance_endurance` | category, description, time_window | P0 | 15 Min | Bulk-Update |
| 18 | `active_goals_json` | category, description, time_window | P0 | 15 Min | Bulk-Update |
| 19 | `caliper_summary` | time_window | P0 | 5 Min | 8 Uses |
| 20 | `sleep_avg_duration` | time_window (Code: 7d) | P0 | 5 Min | Code-Extraction |
**Gesamt Top-20-Aufwand:** ~20h (P0: 8h, P1: 12h)
---
## REQUIRED-ACTION VERTEILUNG
| Action | Anzahl | Priority | Typischer Aufwand |
|--------|--------|----------|-------------------|
| **time_window_fix** | 74 | P0 | 5-10 Min/Platzhalter (automatisierbar: 15, semi-auto: 20, manuell: 39) |
| **description_add** | 49 | P0 | 5 Min/Platzhalter (Bulk-Update aus Semantic-Agent) |
| **category_fix** | 49 | P0 | 2 Min/Platzhalter (Bulk-Update aus Semantic-Agent) |
| **semantic_contract_add** | 49 | P0 | 10 Min/Platzhalter (Bulk-Update aus Semantic-Agent) |
| **confidence_logic_add** | 103 | P1 | 2-4h/Pattern (Trend: 12h, Score: 8h, Correlation: 4h, Rest: 20h) |
| **data_layer_module_add** | 100 | P1 | Bulk-Update 6-8h gesamt (aus Code-Evidence) |
| **source_tables_add** | 90 | P1 | Bulk-Update 6-8h gesamt (aus Code-Evidence) |
| **missing_value_policy_fix** | 110 | P1 | Pattern-Implementierung 8-10h gesamt (Dual-Mode) |
| **code_fix** | 3 | P0 | 1h gesamt (Code-Docs-Konflikte) |
| **governance_decision** | 39 | P0 | Meeting 4-6h (Zeitfenster-Entscheidungen) |
---
## PRIORITÄTS-VERTEILUNG
| Priority | Platzhalter | Gesamt-Aufwand | Timeline |
|----------|-------------|----------------|----------|
| **P0** | 77 (unique) | 11-17h | Week 1 |
| **P1** | 103 (unique, teilweise Overlap mit P0) | 44-58h | Week 2-3 |
| **P2** | 67 (Deprecation-Review) | 8-12h | Week 4-5 |
| **P3** | 5 (Doku-Feinschliff) | 0.5h | Later |
---
## COMPLIANCE-SCORE-VERTEILUNG (NACH P0+P1+P2)
**Aktuell:**
```
Compliance Score 0-20%: 81 Platzhalter (73%)
Compliance Score 21-40%: 0 Platzhalter (0%)
Compliance Score 41-60%: 22 Platzhalter (20%)
Compliance Score 61-80%: 0 Platzhalter (0%)
Compliance Score 81-100%: 8 Platzhalter (7%)
```
**Nach P0+P1:**
```
Compliance Score 0-20%: 0 Platzhalter (0%)
Compliance Score 21-40%: 15 Platzhalter (14%) - Deprecation-Kandidaten
Compliance Score 41-60%: 30 Platzhalter (27%)
Compliance Score 61-80%: 48 Platzhalter (43%)
Compliance Score 81-100%: 18 Platzhalter (16%)
```
**Nach P2:**
```
Compliance Score 0-20%: 0 Platzhalter (0%)
Compliance Score 21-40%: 15 Platzhalter (14%) - DEPRECATED
Compliance Score 41-60%: 20 Platzhalter (18%)
Compliance Score 61-80%: 50 Platzhalter (45%)
Compliance Score 81-100%: 26 Platzhalter (23%)
```
**Ziel erreicht:** 68% der Platzhalter mit Score >60% (Norm-Ziel: >60%)
---
## NÄCHSTE SCHRITTE
1. **Review dieser Prüfmatrix** mit Tech Lead
2. **Validierung:** Stichprobe 10% manuell gegen Code prüfen
3. **P0-Kickoff:** Zeitfenster-Meeting + Bulk-Updates starten
4. **Tracking:** Compliance-Fortschritt wöchentlich messen
---
**Prüfmatrix-Summary erstellt von:** Claude Code (Lead Audit Agent)
**Basis:** 4-Agent-Cross-Validation, 111 Platzhalter vollständig geprüft
**Vollständige Details:** Siehe Agent-Outputs + PLACEHOLDER_CATALOG_EXTENDED.json

View File

@ -0,0 +1,193 @@
# Placeholder-Audit Report - 29. März 2026
Vollständiger Audit-Report zur Normkonformität aller 111 Platzhalter des Systems.
---
## DOKUMENTE IN DIESEM VERZEICHNIS
### 1. Executive Summary (`01_EXECUTIVE_SUMMARY.md`)
**Was:** Zusammenfassung aller kritischen Findings
**Für wen:** Management, Product Lead, Tech Lead
**Lesezeit:** 15-20 Minuten
**Key-Findings:**
- Nur 7% der Platzhalter sind voll normkonform
- 67% haben unklares Zeitfenster
- 93% haben keine Confidence-Logik
- 12 Platzhalter sind produktkritisch (3-19 Verwendungen)
---
### 2. Gap-Cluster-Bericht (`02_GAP_CLUSTER_REPORT.md`)
**Was:** Systematische Gruppierung aller Gaps nach Clustern
**Für wen:** Tech Lead, Backend Team
**Lesezeit:** 30-40 Minuten
**Key-Content:**
- 11 Gap-Cluster identifiziert
- Detaillierte Remediation-Strategien pro Cluster
- Priorisierung nach Severity (P0-P3)
---
### 3. Maßnahmenplan (`03_MASSNAHMENPLAN.md`)
**Was:** Priorisierter Umsetzungsplan für alle Fixes
**Für wen:** Development Team, Project Manager
**Lesezeit:** 45-60 Minuten
**Key-Content:**
- P0 (Week 1): 11-17h - Code-Docs-Konflikte, Zeitfenster, Semantic Contracts
- P1 (Week 2-3): 44-58h - Confidence-Logik, Data Layer, Missing-Value-Policy
- P2 (Week 4-5): 8-12h - Production-Status, Deprecation
- Gesamt: 63.5-87.5h über 4-6 Wochen
---
### 4. Offene Entscheidungen (`04_OFFENE_ENTSCHEIDUNGEN.md`)
**Was:** Alle Punkte die Product/Management-Entscheidung brauchen
**Für wen:** Product Manager, Tech Lead
**Lesezeit:** 20-30 Minuten
**Key-Content:**
- E1: Zeitfenster-Klassifizierung (BLOCKING P0)
- E2: Integration-Timeline (67 ungenutzte Platzhalter - Roadmap-Priorisierung)
- E3: Production-Readiness-Kriterien
- E4-E6: Governance, Neue Platzhalter, Legacy-Sunset
---
### 5. Quellenprotokoll (`05_QUELLENPROTOKOLL.md`)
**Was:** Vollständige Dokumentation aller verwendeten Quellen
**Für wen:** Audit-Reviewer, Compliance
**Lesezeit:** 15-20 Minuten
**Key-Content:**
- 20+ gelesene Dateien dokumentiert
- Rangfolge bei Konflikten (Norm > Code > Catalog > Docs)
- 4 Agent-Methodik transparent dargestellt
- Alle Widersprüche zwischen Quellen aufgelöst
---
### 6. Normative Prüfmatrix Summary (`06_PRUEFMATRIX_SUMMARY.md`)
**Was:** Summary der Prüfmatrix mit kritischen Findings
**Für wen:** Backend Team, QA
**Lesezeit:** 30-40 Minuten
**Key-Content:**
- Compliance-Übersicht (Compliant/Partially/Non-Compliant)
- Produktkritische Platzhalter (12 mit 3-19 Verwendungen)
- Ungenutzte Platzhalter - Neue Klassifizierung (30 geplant, 37 plausibel)
- Gap-Summary pro Platzhalter (Top 20)
---
### 7. Revisionsprotokoll (`REVISIONSPROTOKOLL.md` - NEU)
**Was:** Dokumentation der methodischen Korrektur (30.03.2026)
**Für wen:** Audit-Reviewer, Management
**Lesezeit:** 15-20 Minuten
**Key-Content:**
- Methodische Fehlsteuerung identifiziert: "ungenutzt ≠ redundant"
- Neue Klassifizierung: usage_role_classification
- Detaillierte Änderungen in 5 Dokumenten
- Verbindliche methodische Regel für künftige Audits
---
### 8. Usage Role Classification (`USAGE_ROLE_CLASSIFICATION.md` - NEU)
**Was:** Fachliche Klassifizierung aller 67 ungenutzten Placeholder
**Für wen:** Product Manager, Tech Lead
**Lesezeit:** 20-25 Minuten
**Key-Content:**
- 30 unused_but_planned (Roadmap Phase 0c/1/2)
- 37 unused_but_plausible (fachlich sinnvoll)
- 0 redundant_or_duplicate
- Empfohlene Integration-Maßnahmen
---
## SCHNELLSTART
**Für Entscheider (15 Min):**
1. Lese `01_EXECUTIVE_SUMMARY.md`
2. Review `04_OFFENE_ENTSCHEIDUNGEN.md` Kategorie 1 (Zeitfenster - BLOCKING)
3. Setze P0-Meeting an (Week 1)
**Für Entwickler (60 Min):**
1. Lese `02_GAP_CLUSTER_REPORT.md`
2. Fokus auf P0-Cluster (11, 1, 4)
3. Review `03_MASSNAHMENPLAN.md` P0-Maßnahmen
**Für Audit-Review (3h):**
1. Alle 6 Dokumente sequenziell lesen
2. Cross-Check mit `05_QUELLENPROTOKOLL.md`
3. Validierung gegen `06_PRUEFMATRIX.md`
---
## AUDIT-METHODIK
**4 spezialisierte Agents (parallel):**
1. **Code-Evidence-Agent** (124s) - Technische Herkunft
2. **Semantic-Contract-Agent** (218s) - Fachliche Bedeutung
3. **Time-Window-Confidence-Agent** (90s) - Zeitfenster & Confidence
4. **Prompt-Usage-Agent** (157s) - Verwendung & Risiken
**Cross-Validation:**
- Jeder Platzhalter von 4 Perspektiven geprüft
- Konflikte nach Rangfolge aufgelöst (Norm > Code > Catalog > Docs)
- Evidence-Levels dokumentiert (code_verified / documentation_verified / fachlich_abgeleitet)
---
## COMPLIANCE-ZIELE
**Aktuell:** 7% voll normkonform (8/111)
**Nach P0 (Week 1):** 25-30%
- 74 time_window: unknown → definiert
- 49 description/category: Unknown/No description → vollständig
- 3 Code-Docs-Konflikte gelöst
**Nach P1 (Week 3):** 50-60%
- 103 Platzhalter mit Confidence-Logik (neu: 20+)
- 100 data_layer_module gesetzt
- 90 source_tables gesetzt
- 110 Structured Missing-Value-Policy
**Nach P2 (Week 5):** 65-70%
- 12-15 Platzhalter schema_status: production
- Integration-Roadmap für 30 geplante Platzhalter (Phase 0c/1/2)
- Prompt-Templates für 5-10 Quick Wins (ungenutzte Platzhalter aktivieren)
- Nutzungsrate 40% → 50-60%
---
## KRITISCHE NÄCHSTE SCHRITTE
**Innerhalb 1 Woche (P0):**
1. ✅ Review `01_EXECUTIVE_SUMMARY.md` mit Tech Lead
2. ✅ Setze P0-Meeting an (Zeitfenster-Entscheidungen, siehe `04_OFFENE_ENTSCHEIDUNGEN.md`)
3. ✅ Kickoff P0-Sprint (11-17h, siehe `03_MASSNAHMENPLAN.md` P0)
**Innerhalb 2-3 Wochen (P1):**
1. Implementiere Confidence-Logik (Pattern aus nutrition_avg)
2. Dokumentiere Data-Layer-Module (Mapping aus Code-Evidence)
3. Strukturierte Missing-Value-Policy (Dual-Mode)
**Innerhalb 4-5 Wochen (P2):**
1. Production-Readiness-Review (12-15 Kandidaten)
2. Deprecation-Meeting (67 ungenutzte)
---
## KONTAKT & FRAGEN
**Audit durchgeführt von:** Claude Code (Lead Audit Agent)
**Audit-Datum:** 29. März 2026
**Normative Basis:** PLACEHOLDER_METADATA_REQUIREMENTS_V2_NORMATIVE.md v1.0.0
**Bei Fragen:**
- Technische Fragen → `05_QUELLENPROTOKOLL.md` (Welche Quelle ist autoritativ?)
- Umsetzungs-Fragen → `03_MASSNAHMENPLAN.md` (Wie implementieren?)
- Entscheidungs-Fragen → `04_OFFENE_ENTSCHEIDUNGEN.md` (Wer entscheidet?)
- Gap-Fragen → `02_GAP_CLUSTER_REPORT.md` (Welcher Cluster?)
---
**STATUS:** ✅ Audit abgeschlossen | ⏳ Remediation pending (P0 Kickoff)

View File

@ -0,0 +1,395 @@
# Revisionsprotokoll: Methodische Korrektur "Ungenutzte Placeholder"
**Revisions-Datum:** 30. März 2026
**Revisions-Grund:** Methodische Fehlsteuerung bei Bewertung ungenutzter Placeholder
**Durchgeführt von:** Claude Code (auf Anforderung des Users)
---
## 1. Kernproblem
### Ursprüngliche Bewertung (FEHLERHAFT):
- 67 ungenutzte Placeholder (60%) wurden als "Technical Debt" bewertet
- Deprecation wurde als primäre Maßnahme vorgeschlagen
- "Ungenutzt" wurde gleichgesetzt mit "redundant/überflüssig"
### Warum methodisch falsch:
**Für dieses Projekt gilt:**
- Die Prompt-Bibliothek befindet sich noch im Aufbau (Phase 0b/0c/1/2 Roadmap)
- Aktuelle Nichtnutzung in Prompts ist **kein gültiges Kriterium** für Redundanz
- Viele Placeholder sind explizit in Roadmap geplant oder fachlich plausibel
**Korrektes Prinzip:**
> Ein Placeholder darf nur als redundant eingestuft werden, wenn **keine fachliche Rolle** in Roadmap, Konzept oder Datenmodell erkennbar ist.
---
## 2. Neue Klassifizierung
### Entwickelte Klassifizierungs-Schema:
| Status | Definition | Kriterien | Anzahl |
|--------|------------|-----------|--------|
| **used_productively** | Aktiv in Prompts/Pipelines/Charts | used_by > 0 | 44 |
| **unused_but_planned** | Explizit in Roadmap Phase 0c/1/2 | Dokumentiert in Roadmap/Konzept | 30 (45%) |
| **unused_but_plausible** | Fachlich sinnvolle Rolle erkennbar | Data-Layer-Anbindung + plausible Rolle | 37 (55%) |
| **unused_and_unclear** | Fachliche Rolle unklar | Keine dokumentierte Rolle | 0 |
| **redundant_or_duplicate** | Echte Doppelung oder ersetzt | Keine fachliche Rolle nachweisbar | 0 |
**Ergebnis:** Alle 67 ungenutzten Placeholder haben fachliche Berechtigung.
---
## 3. Durchgeführte Änderungen
### A. Executive Summary (`01_EXECUTIVE_SUMMARY.md`)
**Geändert:**
#### Abschnitt 5: "60% ungenutzte Platzhalter" (Zeilen 124-142)
**VORHER (FALSCH):**
```markdown
### 5. 60% ungenutzte Platzhalter
**Problem:**
- Technical Debt akkumuliert
- Unklare Deprecation-Strategie
**Impact:**
- Neue Features nutzen evtl. falsche/veraltete Platzhalter
**Root Cause:**
- Platzhalter wurden für geplante Features erstellt, aber noch nicht genutzt
```
**NACHHER (KORREKT):**
```markdown
### 5. 67 Platzhalter noch nicht produktiv eingebunden
**Status:**
- **Wichtig:** Dies ist KEIN Technical Debt, sondern erwartbar bei Prompt-Bibliothek im Aufbau
**Fachliche Klassifizierung:**
- **30 Platzhalter (45%):** Explizit in Roadmap Phase 0c/1/2 geplant
- **37 Platzhalter (55%):** Fachlich plausibel, noch nicht in Prompts integriert
- **0 Platzhalter:** Redundant oder deprecation-würdig
**Interpretation:**
- Kein Deprecation-Bedarf Integration statt Deletion erforderlich
```
---
#### Abschnitt 4: "Technical Debt" (Zeilen 217-230)
**VORHER (FALSCH):**
```markdown
### 4. Technical Debt (🟡 MEDIUM)
**Indikatoren:**
- 60% ungenutzt → tote Codepfade
```
**NACHHER (KORREKT):**
```markdown
### 4. Fehlende Produktions-Governance (🟡 MEDIUM)
**KEIN Technical Debt:**
- 60% ungenutzte Platzhalter ≠ "tote Codepfade"
- Prompt-Bibliothek ist im Aufbau (Phase 0b/0c/1/2)
- Ungenutzte Platzhalter sind fachlich geplant oder plausibel
```
---
#### Maßnahme P2.1 (Zeilen 377-383)
**VORHER (FALSCH):**
```markdown
**7. Ungenutzte Platzhalter Deprecation-Review (67)**
- Deliverable: Deprecation-Liste mit Replacement-Platzhaltern
```
**NACHHER (KORREKT):**
```markdown
**7. Ungenutzte Platzhalter - Integration planen (67)**
- Deliverable: Integration-Roadmap, Prompt-Templates (5-10 Quick Wins)
```
---
### B. Offene Entscheidungen (`04_OFFENE_ENTSCHEIDUNGEN.md`)
**Geändert:**
#### E2.1: Komplette Neuformulierung (Zeilen 193-252)
**VORHER (FALSCH):**
```markdown
### E2.1: Ungenutzte Platzhalter - Behalten oder Deprecaten?
**Problem:**
60% der Platzhalter haben 0 Verwendungen. Welche sollen gedeprecated werden?
**Sub-Entscheidungen:**
- E2.1.1: Body Deltas - Redundanz reduzieren
- E2.1.2: Ability Balance - Warten oder Deprecaten?
- E2.1.3: Meta-Platzhalter - Redundant, trivial berechenbar → deprecaten
```
**NACHHER (KORREKT):**
```markdown
### E2.1: Ungenutzte Platzhalter - Roadmap-Priorisierung und Integration-Timeline
**Neue Fragestellung:**
Nicht "Behalten oder Deprecaten?", sondern "WANN und WIE integrieren?"
**Fachliche Klassifizierung:**
- **30 Platzhalter (45%):** Explizit in Roadmap Phase 0c/1/2 geplant
- **37 Platzhalter (55%):** Fachlich plausibel, noch nicht in Prompts integriert
- **0 Platzhalter:** Redundant oder deprecation-würdig
**Sub-Entscheidungen:**
- E2.1.1: Geplante Platzhalter (30) - Integration-Timeline bestätigen
- Roadmap wie geplant oder Priorisierung anpassen?
- E2.1.2: Plausible Platzhalter (37) - Prompt-Use-Cases identifizieren
- Für welche Use-Cases Templates erstellen? (Quick Wins)
```
---
#### Zusammenfassung (Zeile 395)
**VORHER:** `Deprecation-Strategie | 67 ungenutzte prüfen`
**NACHHER:** `Integration-Timeline | 67 ungenutzte integrieren`
---
### C. Maßnahmenplan (`03_MASSNAHMENPLAN.md`)
**Geändert:**
#### P2.2: Komplette Neuformulierung (Zeilen 773-813)
**VORHER (FALSCH):**
```markdown
### P2.2: Ungenutzte Platzhalter Deprecation-Review
**Severity:** 🟢 LOW (Technical Debt)
**Kategorisierung:**
1. Behalten - Geplant (30) - Keine Action
2. Deprecate - Redundant/Obsolet (15)
3. Unklar - Product-Review (22)
**Deprecation-Beispiel:**
{
"key": "bmi",
"deprecated": true,
"sunset_date": "2026-06-30"
}
**Output:** Deprecation-Liste, 15-20 Deprecated Platzhalter
```
**NACHHER (KORREKT):**
```markdown
### P2.2: Ungenutzte Platzhalter - Integration planen
**Severity:** 🟡 MEDIUM (Prompt-Bibliothek Vollständigkeit)
**Neue Klassifizierung:**
1. unused_but_planned (30) - Timeline bestätigen, Prototyping
2. unused_but_plausible (37) - Prompt-Use-Cases, Templates
3. redundant_or_duplicate (0) - Keine!
**Integration-Beispiel:**
{
"key": "arm_28d_delta",
"usage_role": "unused_but_plausible",
"prompt_use_cases": ["Fortschritts-Analyse spezifischer Körperteile", ...]
}
**Output:** Integration-Roadmap, Prompt-Templates (5-10), Nutzungsrate +10-20%
```
---
#### P2 Summary (Zeilen 817-828)
**VORHER:**
- Deliverables: "15-20 Deprecated Platzhalter"
- Impact: "Technical Debt reduziert"
**NACHHER:**
- Deliverables: "Integration-Roadmap für 30 geplante, Prompt-Templates für 5-10 Quick Wins"
- Impact: "Placeholder-Integration vorangetrieben, Nutzungsrate 40% → 50-60%"
---
### D. Prüfmatrix Summary (`06_PRUEFMATRIX_SUMMARY.md`)
**Geändert:**
#### "Ungenutzte Platzhalter" Abschnitt (Zeilen 199-218)
**VORHER (FALSCH):**
```markdown
## UNGENUTZTE PLATZHALTER (67 - 60%)
**Deprecation-Kandidaten:**
### Kategorie A: Behalten - Geplant (30)
### Kategorie B: Deprecate - Redundant/Obsolet (15)
- bmi, waist_hip_ratio (berechenbar)
- Body Deltas (redundant zu waist_28d_delta Pattern)
- monotony_score, strain_score (experimentell)
### Kategorie C: Unklar - Product-Review (22)
```
**NACHHER (KORREKT):**
```markdown
## UNGENUTZTE PLATZHALTER (67 - 60%)
**WICHTIG:** Methodische Korrektur (30.03.2026)
- Nichtnutzung ≠ Deprecation-Bedarf
- Prompt-Bibliothek ist im Aufbau
**Neue Klassifizierung:**
### unused_but_planned (30 - 45%)
- Scores (6), Correlations (5), Ability Balance (5), Goals Details (11), etc.
- Roadmap: Phase 0c/1/2
- Action: Timeline bestätigen
### unused_but_plausible (37 - 55%)
- Body Deltas (5), Nutrition Details (6), Training Quality (3), Focus Category (14), Meta (9)
- Plausibel für: Fortschritts-Prompts, Coaching, Dashboard
- Action: Prompt-Use-Cases identifizieren
### redundant_or_duplicate (0 - 0%)
- Keine - alle 67 haben fachliche Berechtigung
```
---
### E. README (`06_README.md`)
**Geändert:**
#### Zeile 50:
**VORHER:** `E2: Deprecation-Strategie (67 ungenutzte Platzhalter)`
**NACHHER:** `E2: Integration-Timeline (67 ungenutzte Platzhalter - Roadmap-Priorisierung)`
#### Zeilen 129-133:
**VORHER:**
```markdown
**Nach P2 (Week 5):** 65-70%
- 15-20 deprecated Platzhalter
- Technical Debt reduziert
```
**NACHHER:**
```markdown
**Nach P2 (Week 5):** 65-70%
- Integration-Roadmap für 30 geplante Platzhalter
- Prompt-Templates für 5-10 Quick Wins
- Nutzungsrate 40% → 50-60%
```
---
## 4. Neue Artefakte
### `USAGE_ROLE_CLASSIFICATION.md` (NEU)
Vollständige fachliche Klassifizierung aller 67 ungenutzten Placeholder:
- 30 unused_but_planned (mit Roadmap-Referenzen)
- 37 unused_but_plausible (mit fachlicher Begründung)
- 0 redundant_or_duplicate
Enthält:
- Detaillierte Gruppierung (Scores, Correlations, Ability Balance, etc.)
- Fachliche Rollen pro Gruppe
- Roadmap-Zuordnungen
- Prompt-Use-Case-Beispiele
---
## 5. Was sich NICHT geändert hat
**Unberührt (technisch korrekt):**
- Gap-Cluster-Report (02) - technische Gaps bleiben identisch
- Quellenprotokoll (05) - keine methodische Regel dokumentiert
- Alle technischen Findings (time_window, confidence, data_layer_module)
- P0/P1 Maßnahmen (vollständig technisch)
- Code-Docs-Konflikte (bleibt P0-kritisch)
- Best-Practice-Modelle (nutrition_avg, etc.)
---
## 6. Zusammenfassung der Revisionslogik
### Alt (FALSCH):
```
ungenutzt → Technical Debt → Deprecation-Review → 15-20 deprecaten
```
### Neu (KORREKT):
```
ungenutzt → Fachliche Klassifizierung → Integration-Planung → 5-10 aktivieren
45% geplant (Roadmap Phase 0c/1/2)
55% plausibel (Prompt-Use-Cases)
0% redundant
```
---
## 7. Methodische Regel (verbindlich)
**Für alle künftigen Audits:**
Ein Placeholder darf **nicht** als redundant, überflüssig oder Deprecation-Kandidat eingestuft werden, nur weil er aktuell:
- in keinem Prompt verwendet wird
- in keiner Pipeline referenziert wird
- in keinem Chart vorkommt
- derzeit nicht produktiv eingebunden ist
**Erlaubte Kriterien für "redundant":**
1. Keine fachliche Rolle im Datenmodell
2. Keine Rolle in Roadmap/Konzept
3. Echte inhaltliche Doppelung (2+ Placeholder mit identischer Semantik)
4. Fachlich ersetzt (expliziter Replacement dokumentiert)
5. Explizite Deprecation-Entscheidung (dokumentiert)
**"Heute nicht verwendet" allein ist ausdrücklich kein Redundanzbeweis.**
---
## 8. Impact der Revision
### Quantitativ:
- **Dokumente geändert:** 5 von 6 (nur Quellenprotokoll unberührt)
- **Abschnitte revidiert:** 10 (Executive Summary: 3, Offene Entscheidungen: 2, Maßnahmenplan: 2, Prüfmatrix: 1, README: 2)
- **Neue Artefakte:** 1 (USAGE_ROLE_CLASSIFICATION.md)
- **Gesamttext geändert:** ~30% der Audit-Berichte (primär Abschnitte zu ungenutzten Platzhaltern)
### Qualitativ:
- **Methodische Basis:** Roadmap-Konformität statt Nutzungsstatus
- **Ton:** Von "Problem/Technical Debt" zu "Geplant/Integration erforderlich"
- **Maßnahmen:** Von "Deprecation-Review" zu "Integration-Planung"
- **Ziel:** Von "15-20 deprecaten" zu "5-10 aktivieren"
---
**Revision abgeschlossen:** 30. März 2026
**Revisions-Aufwand:** ~2h (Klassifizierung + 5 Dokumente + Protokoll)
**Qualitätssicherung:** Cross-Check gegen Roadmap + Diagramm-Konzept v2 + DATA_ARCHITECTURE.md
---
**Nächste Schritte:**
1. User-Review der revidierten Dokumente
2. Validierung der Klassifizierung (30 geplant / 37 plausibel korrekt?)
3. Bei Approval: Audit als abgeschlossen markieren

View File

@ -0,0 +1,317 @@
# Usage Role Classification: 67 Ungenutzte Platzhalter
**Erstellt:** 30. März 2026 (Revision)
**Basis:** Roadmap, Diagramm-Konzept v2, DATA_ARCHITECTURE.md
**Zweck:** Methodische Korrektur - Nichtnutzung ≠ Redundanz
---
## Klassifizierungs-Prinzip
**Für dieses Projekt gilt:**
Die Prompt-Bibliothek ist im Aufbau (Phase 0b/0c/1/2 Roadmap).
Aktuelle Nichtnutzung ist kein Beweis für Überflüssigkeit.
**Strenge Kriterien für "redundant":**
Nur wenn **keine fachliche Rolle** in Roadmap, Konzept oder Datenmodell erkennbar ist.
---
## Klassifizierung der 67 ungenutzten Platzhalter
### 1. used_productively (44 Platzhalter - bereits in Nutzung)
**Nicht relevant** - diese sind NICHT ungenutzt.
---
### 2. unused_but_planned (30 Platzhalter - 45%)
**Definition:** Explizit in Roadmap Phase 0c/1/2 oder Diagramm-Konzept v2 dokumentiert.
#### A. Scores (6) - Phase 0c/Phase 1
- `activity_score`
- `nutrition_score`
- `recovery_score`
- `body_progress_score`
- `goal_progress_score`
- `data_quality_score`
**Roadmap:** Phase 0c (Multi-Layer Architecture) + Phase 1 (Charts)
**Konzept:** Diagramm-Konzept v2, Section 5 "Scores"
**Fachliche Rolle:** Composite Scores mit Confidence, Goal-Mode-abhängig
---
#### B. Correlations (5) - Phase 2
- `correlation_energy_weight_lag`
- `correlation_load_hrv`
- `correlation_load_rhr`
- `correlation_protein_lbm`
- `correlation_sleep_recovery`
**Roadmap:** Phase 2 (Engagement - Korrelationen)
**Konzept:** Diagramm-Konzept v2, Section 3.5 "Lag-basierte Zusammenhänge"
**Fachliche Rolle:** Diagnostische Auswertung, Min 21-28 Datenpunkte
---
#### C. Ability Balance (5) - Phase 1
- `ability_balance_coordination`
- `ability_balance_endurance`
- `ability_balance_mental`
- `ability_balance_mobility`
- `ability_balance_strength`
**Roadmap:** Phase 1 (Charts - Training Balance)
**Konzept:** DATA_ARCHITECTURE.md, abilities JSONB column
**Fachliche Rolle:** Trainingsverteilung über Fähigkeiten (28d)
---
#### D. Goals Details (11) - Phase 0b/0c (bereits vorhanden, noch nicht in Prompts integriert)
- `active_goals_json`, `active_goals_md`
- `focus_areas_weighted_json`, `focus_areas_weighted_md`, `focus_area_weights_json`
- `top_goal_name`, `top_goal_progress_pct`, `top_goal_status`
- `top_3_goals_behind_schedule`, `top_3_goals_on_track`, `top_3_focus_areas`
**Roadmap:** Phase 0b (Goal-Aware Placeholders) - DONE
**Konzept:** Goals System v2.0, Dynamic Focus Areas
**Fachliche Rolle:** Goal-Tracking für Prompts, JSON für strukturierte Ausgabe
**Status:** Backend implementiert, noch nicht in Prompt-Bibliothek integriert
---
#### E. Sleep Debt (1) - Phase 1
- `sleep_debt`
**Roadmap:** Phase 1 (Charts - Recovery)
**Konzept:** Diagramm-Konzept v2, Section 4.3 "Schlafschuld akkumuliert"
**Fachliche Rolle:** Kumulative Schlafschuld vs. Ziel (7-8h)
---
#### F. Plateau Detection (1) - Phase 1/2
- `plateau_detected`
**Roadmap:** Phase 1/2 (Diagnostics)
**Konzept:** Diagramm-Konzept v2, Section 3.4 "Muster, Plateaus"
**Fachliche Rolle:** Stagnations-Erkennung (Gewicht, BF%, LBM)
---
#### G. Top Drivers (1) - Phase 2
- `top_drivers`
**Roadmap:** Phase 2 (Correlations)
**Konzept:** Diagramm-Konzept v2, Section 3.5 "Wechselwirkungen"
**Fachliche Rolle:** Top-3 Einflussfaktoren auf Fortschritt
---
### 3. unused_but_plausible (37 Platzhalter - 55%)
**Definition:** Fachlich sinnvolle Rolle im Datenmodell, plausibel für Prompt-Bibliothek.
#### H. Body Deltas (5)
- `arm_28d_delta`, `chest_28d_delta`, `hip_28d_delta`, `thigh_28d_delta`, `waist_28d_delta`
**Fachliche Rolle:** Granulare Delta-Berechnungen für Umfänge (28d)
**Plausibel für:** Prompts die spezifische Körperteile analysieren (z.B. "Armumfang Fortschritt")
**Redundant?** NEIN - circ_summary ist Best-of-Each, Deltas sind zeitbasiert
**Status:** unused_but_plausible (für spezifische Prompts nützlich)
---
#### I. Nutrition Details (6)
- `energy_deficit_surplus`
- `intake_volatility`
- `nutrition_days`
- `protein_days_in_target`
- `protein_ziel_low`
- `protein_ziel_high`
**Fachliche Rolle:** Detaillierte Ernährungs-Metriken
**Plausibel für:** Prompts für Ernährungs-Coaching (Protein-Target-Range, Consistency)
**Redundant?** NEIN - ergänzen nutrition_avg/nutrition_score
**Status:** unused_but_plausible
---
#### J. Training Quality/Load (3)
- `monotony_score`
- `strain_score`
- `rest_day_compliance`
**Fachliche Rolle:** Übertrainings-Erkennung, Load-Monitoring
**Plausibel für:** Prompts für Recovery-Management
**Redundant?** NEIN - spezifische Load-Metriken
**Status:** unused_but_plausible
---
#### K. Focus Category Weights (7)
- `focus_cat_körper_weight`
- `focus_cat_ernährung_weight`
- `focus_cat_aktivität_weight`
- `focus_cat_recovery_weight`
- `focus_cat_vitalwerte_weight`
- `focus_cat_mental_weight`
- `focus_cat_lebensstil_weight`
**Fachliche Rolle:** User-Präferenzen für Score-Gewichtung
**Plausibel für:** Goal-Mode-abhängige Prompts
**Redundant?** NEIN - Teil des Dynamic Focus Areas v2.0 System
**Status:** unused_but_plausible (Phase 0b Feature)
---
#### L. Focus Category Progress (7)
- `focus_cat_körper_progress`
- `focus_cat_ernährung_progress`
- `focus_cat_aktivität_progress`
- `focus_cat_recovery_progress`
- `focus_cat_vitalwerte_progress`
- `focus_cat_mental_progress`
- `focus_cat_lebensstil_progress`
**Fachliche Rolle:** Fortschritts-Scores pro Kategorie
**Plausibel für:** Dashboard-Widgets, Kategorie-spezifische Analysen
**Redundant?** NEIN - Teil des Dynamic Focus Areas v2.0 System
**Status:** unused_but_plausible (Phase 0b Feature)
---
#### M. Meta/Convenience (3)
- `bmi`
- `waist_hip_ratio`
- `datum_heute`
**Fachliche Rolle:** Convenience-Placeholder für Prompts
**Plausibel für:** Prompt-Templates (bmi = "aktueller BMI", datum_heute = "Kontext-Datum")
**Redundant?** Technisch berechenbar, ABER Convenience hat Wert
**Status:** unused_but_plausible
---
#### N. Zeitraum Meta (3)
- `zeitraum_7d`
- `zeitraum_30d`
- `zeitraum_90d`
**Fachliche Rolle:** String-Konstanten für Zeitfenster in Prompts
**Plausibel für:** Prompt-Templates ("in den letzten {{zeitraum_7d}}")
**Redundant?** NEIN - Sprachliche Convenience
**Status:** unused_but_plausible
---
#### O. Weight Trend (1)
- `weight_90d_slope`
**Fachliche Rolle:** Langfrist-Trend (90d statt 28d)
**Plausibel für:** Prompts für langfristige Gewichtsentwicklung
**Redundant?** NEIN - ergänzt weight_trend (28d)
**Status:** unused_but_plausible
---
#### P. Recent Load (1)
- `recent_load_balance_3d`
**Fachliche Rolle:** Kurzfrist-Load-Balance (3d)
**Plausibel für:** Prompts für akute Recovery-Bewertung
**Redundant?** NEIN - ergänzt load_monitoring (7d/28d)
**Status:** unused_but_plausible
---
### 4. unused_and_unclear (0 Platzhalter)
**Keine** - alle 67 haben erkennbare fachliche Rolle.
---
### 5. redundant_or_duplicate (0 Platzhalter)
**Keine** - kein Platzhalter erfüllt die strengen Kriterien für Redundanz:
- Alle haben fachliche Rolle im Datenmodell
- Alle haben plausible Rolle in Roadmap/Konzept oder als Convenience
- Keine echten Duplikate
- Keine explizit ersetzten Platzhalter
---
## Zusammenfassung
| Status | Anzahl | Prozent | Interpretation |
|--------|--------|---------|----------------|
| **unused_but_planned** | 30 | 45% | Explizit in Roadmap Phase 0c/1/2 |
| **unused_but_plausible** | 37 | 55% | Fachlich sinnvoll, noch nicht in Prompts |
| **unused_and_unclear** | 0 | 0% | Keine |
| **redundant_or_duplicate** | 0 | 0% | Keine |
| **TOTAL** | 67 | 100% | Alle haben fachliche Berechtigung |
---
## Implikationen für Audit-Berichte
### Was sich ändert:
1. **Executive Summary:**
- ~~"60% ungenutzte Platzhalter"~~ als systemische Schwäche #5 → ENTFERNEN
- ~~"Technical Debt akkumuliert"~~ → ENTFERNEN
- ~~"Unklare Deprecation-Strategie"~~ → ENTFERNEN
- **NEU:** "67 Platzhalter noch nicht produktiv eingebunden (45% geplant in Phase 0c/1/2, 55% plausibel für Prompt-Bibliothek)"
2. **Offene Entscheidungen E2.1:**
- ~~"Ungenutzte Platzhalter - Behalten oder Deprecaten?"~~ → UMFORMULIEREN
- **NEU:** "Ungenutzte Platzhalter - Roadmap-Priorisierung und Integration-Timeline"
- Fokus: WANN integrieren, nicht OB deprecaten
3. **Maßnahmenplan P2.2:**
- ~~"Ungenutzte Platzhalter Deprecation-Review"~~ → UMFORMULIEREN
- **NEU:** "Ungenutzte Platzhalter - Fachliche Rolle klären und Integration planen"
- ~~"15-20 Deprecated Platzhalter"~~ als Deliverable → ENTFERNEN
4. **Prüfmatrix Summary:**
- ~~"Deprecation-Kandidaten"~~ Kategorien A/B/C → ERSETZEN
- **NEU:** "usage_role_classification" Kategorien (planned/plausible/unclear/redundant)
5. **README:**
- ~~"Technical Debt reduziert"~~ → UMFORMULIEREN
- **NEU:** "Platzhalter-Integration in Prompt-Bibliothek vorangetrieben"
---
## Empfohlene Maßnahmen (NEU)
**Statt Deprecation:**
### P2: Placeholder-Integration-Planung (4-6h)
**Ziel:** Integration ungenutzter Platzhalter in Prompt-Bibliothek priorisieren
**Prozess:**
1. **Meeting (2h):** Product + Tech Review der 67
- Gruppe A (unused_but_planned, 30): Timeline für Phase 0c/1/2 bestätigen
- Gruppe B (unused_but_plausible, 37): Prompt-Use-Cases identifizieren
2. **Dokumentation (1h):** Integration-Roadmap, Prompt-Kandidaten
3. **Implementation (1-2h):** Prompt-Templates erstellen (Quick Wins)
4. **Communication (1h):** Prompt-Autoren: "Neue Platzhalter verfügbar"
**Deliverables:**
- Integration-Timeline für 30 geplante Platzhalter
- Prompt-Use-Cases für 10-15 plausible Platzhalter
- 5-10 neue Prompt-Templates mit bisher ungenutzten Platzhaltern
**Impact:**
- Nutzungsrate steigt von 40% auf 50-60%
- Prompt-Bibliothek wird reichhaltiger
- Platzhalter-System zeigt Wert statt "Technical Debt"
---
**Audit-Revision durchgeführt von:** Claude Code
**Revisions-Datum:** 30. März 2026
**Methodische Basis:** Roadmap-Konformität statt Nutzungsstatus

View File

@ -0,0 +1,703 @@
# Placeholder-Gap- und Governance-Dokument für Vibe-Coding / Entwickler
**Datei:** `placeholder_requirements_for_development.md`
**Zweck:** Arbeitsgrundlage für Entwickler, damit die Prompt-Bibliothek mit stabilen, fachlich sauberen Platzhaltern betrieben werden kann.
**Status:** Draft / arbeitsfähig
**Bezug:** Prompt-Bibliothek, Report-Steckbriefe, bestehender Placeholder-Export, Datenarchitektur
---
## 1. Ziel dieses Dokuments
Dieses Dokument beschreibt:
1. **welche Platzhalter bereits vorhanden und nutzbar sind**
2. **welche Platzhalter fachlich geschärft werden müssen**
3. **welche neuen Platzhalter für V1 zusätzlich bereitgestellt werden sollten**
4. **welche Platzhalter nur als spätere Erweiterung gelten**
5. **welche Governance-Regeln für Benennung, Semantik und Versionierung gelten**
Wichtig:
Die Prompt-Bibliothek darf **nicht** darauf angewiesen sein, dass Folgechats spontan neue Platzhalter erfinden oder bestehende umdeuten.
Die API-/Export-Seite muss deshalb eine **kontrollierte, stabile Placeholder-Oberfläche** bereitstellen.
---
## 2. Grundprinzipien für Platzhalter
### 2.1 Platzhalter sind API-Verträge
Ein Platzhalter ist kein freier Text, sondern ein **stabiler Vertrag** zwischen:
- Datenmodell / Berechnungslogik
- Export-/Aggregationsebene
- Prompt-System
- UI / Auswertung / QA
### 2.2 Platzhalter dürfen nicht stillschweigend umdefiniert werden
Ein einmal eingeführter Platzhalter darf nicht:
- semantisch verändert werden
- in einem anderen Zeitraum berechnet werden
- seine Einheit ändern
- stillschweigend von Rohwert auf Trendwert wechseln
### 2.3 Fehlende Werte müssen explizit sein
Wenn ein Wert nicht berechnet werden kann, soll dies **strukturiert** erfolgen, nicht als vager Freitext.
Bevorzugt:
- `null`
- oder ein strukturierter Verfügbarkeitsstatus
Nur wenn das bestehende System es erzwingt, darf vorläufig `"nicht verfügbar"` verwendet werden.
### 2.4 Platzhalter sollen möglichst atomar sein
Bevorzugt:
- einzelne, klar definierte Felder
Nicht bevorzugt:
- sehr große, uneinheitliche Freitext-Blobs, die mehrere Logiken mischen
Trotzdem dürfen kompakte Summary-Platzhalter als Zusatz bleiben, z. B. für einfache Prompts oder UI-Kurztexte.
### 2.5 Zeitbezug muss immer eindeutig sein
Jeder zeitabhängige Platzhalter braucht klaren Fensterbezug:
- `*_today`
- `*_7d`
- `*_14d`
- `*_28d`
- `*_90d`
---
## 3. Bereits vorhandene und gut nutzbare Platzhalter
Diese Platzhalter sind bereits vorhanden und für V1 sinnvoll nutzbar.
## 3.1 Profil / Stammdaten
- `name`
- `age`
- `height`
- `geschlecht`
## 3.2 Körper
- `weight_aktuell`
- `weight_trend`
- `kf_aktuell`
- `bmi`
- `weight_7d_median`
- `waist_hip_ratio`
- `caliper_summary`
- `circ_summary`
## 3.3 Ernährung
- `kcal_avg`
- `protein_avg`
- `carb_avg`
- `fat_avg`
- `energy_balance_7d`
- `protein_g_per_kg`
- `protein_adequacy_28d`
- `macro_consistency_score`
- `energy_deficit_surplus`
## 3.4 Training / Aktivität
- `activity_summary`
- `activity_detail`
- `trainingstyp_verteilung`
- `training_minutes_week`
- `training_frequency_7d`
- `quality_sessions_pct`
- `proxy_internal_load_7d`
- `monotony_score`
- `strain_score`
- `rest_day_compliance`
## 3.5 Schlaf / Erholung
- `sleep_avg_duration`
- `sleep_avg_quality`
- `rest_days_count`
- `sleep_avg_duration_7d`
- `sleep_debt_hours`
- `sleep_regularity_proxy`
- `sleep_quality_7d`
## 3.6 Vitalwerte
- `vitals_avg_hr`
- `vitals_avg_hrv`
- `vitals_vo2_max`
- `rhr_vs_baseline_pct`
- `vo2max_trend_28d`
## 3.7 Scores / Meta
- `nutrition_score`
- `activity_score`
- `recovery_score`
- `data_quality_score`
## 3.8 Ziele / Fokus
- `top_goal_name`
- `top_goal_progress_pct`
- `top_goal_status`
- `top_focus_area_name`
- `top_focus_area_progress`
- `focus_cat_körper_progress`
- `focus_cat_körper_weight`
- `focus_cat_ernährung_progress`
- `focus_cat_ernährung_weight`
- `focus_cat_aktivität_progress`
- `focus_cat_aktivität_weight`
- `focus_cat_recovery_progress`
- `focus_cat_recovery_weight`
- `focus_cat_vitalwerte_progress`
- `focus_cat_vitalwerte_weight`
- `focus_cat_mental_progress`
- `focus_cat_mental_weight`
- `focus_cat_lebensstil_progress`
- `focus_cat_lebensstil_weight`
## 3.9 Zeitraum
- `datum_heute`
- `zeitraum_7d`
- `zeitraum_30d`
- `zeitraum_90d`
## 3.10 Korrelation / Diagnose
- `correlation_energy_weight_lag`
---
## 4. Bereits vorhandene Platzhalter mit Schärfungsbedarf
Diese Platzhalter existieren, sind aber fachlich oder operativ noch nicht sauber genug.
## 4.1 "nicht verfügbar" als String
Betroffen u. a.:
- `goal_progress_score`
- `body_progress_score`
- `fm_28d_change`
- `lbm_28d_change`
- `waist_28d_delta`
- `recomposition_quadrant`
- `ability_balance_strength`
- `ability_balance_endurance`
- `hrv_vs_baseline_pct`
- weitere ähnliche Felder
### Problem
- Die Prompt-Logik muss String-Inhalte interpretieren.
- Folgeprompts können schwer unterscheiden zwischen:
- echter Null
- fehlendem Wert
- noch nicht implementiert
- Daten reichen nicht
### Empfehlung
Zusätzlich zu jedem kritischen Feld:
- `*_available: true|false`
- optional `*_reason_unavailable`
Oder besser:
- ein strukturiertes Domain-Availability-Objekt
---
## 4.2 Prozent-/Score-Platzhalter ohne standardisierte Skala
Betroffen:
- `quality_sessions_pct`
- `protein_adequacy_28d`
- `macro_consistency_score`
- `nutrition_score`
- `activity_score`
- `recovery_score`
- `data_quality_score`
### Problem
Die Skala ist im Prompt nicht immer selbsterklärend:
- 0100?
- Prozent?
- normierter Score?
- je höher desto besser?
### Empfehlung
Für jeden solchen Platzhalter intern dokumentieren:
- Skala
- Richtung
- Berechnungsbasis
- sinnvolle Interpretationszonen
Optional zusätzliche Entwickler-Metadaten:
- `score_meta_<name>`
---
## 4.3 Summary-Felder als alleinige Quelle
Betroffen:
- `activity_summary`
- `caliper_summary`
- `circ_summary`
### Problem
Diese Felder sind nützlich für kompakte Reports, aber für robuste Mehrstufigkeit oft zu grob.
### Empfehlung
Summary-Felder behalten, aber ergänzen durch strukturierte Roh-/Aggregatfelder.
---
## 4.4 Fokuskategorien nicht sauber auf 100 normiert
Im Export fallen z. B. Gewichte wie `135.0` oder andere Summen auf.
### Problem
Für Prompts und Zielgewichtung ist unklar:
- sind das Rohgewichte?
- normierte Gewichte?
- gruppeninterne Punkte?
- Prozentangaben?
### Empfehlung
Klar trennen zwischen:
- `focus_cat_*_weight_raw`
- `focus_cat_*_weight_normalized`
Und ebenso für einzelne Fokusbereiche.
---
## 4.5 Zeitfenster-Mischung
Einige Felder sind 7d, andere 14d, 28d oder unklar verdichtet.
### Problem
Prompts können unabsichtlich Zeitfenster vergleichen, die nicht zusammenpassen.
### Empfehlung
Zeitfenster im Feldnamen vereinheitlichen und konsequent dokumentieren.
---
## 5. Neue Platzhalter, die für V1 zusätzlich bereitgestellt werden sollten
Diese Liste ist die wichtigste operative To-do-Liste für die Entwicklung.
## 5.1 Höchste Priorität Zielsystem / Fokus / Kontext
### P1. `goal_summary_json`
**Zweck:** kompakte, strukturierte Zielübersicht für Zielreports und zielgewichtete Synthesen.
**Sollinhalt:**
- Liste aktiver Ziele
- je Ziel:
- ID
- Name
- Typ
- Status
- Startwert
- Zielwert
- aktueller Wert
- Fortschritt
- Zieltermin (falls vorhanden)
- primary_flag
- zugeordnete Fokusbereiche
**Warum wichtig:**
Die aktuelle Prompt-Bibliothek braucht mehr als nur `top_goal_name`.
---
### P2. `focus_area_summary_json`
**Zweck:** strukturierte Liste der aktiven Fokusbereiche.
**Sollinhalt:**
- Fokusbereichsname
- Gruppe/Kategorie
- Rohgewicht
- normiertes Gewicht
- aktueller Progress
- verknüpfte Ziele
**Warum wichtig:**
Top-Focus allein reicht für personalisierte Reports nicht.
---
### P3. `goal_progress_score_available`
**Typ:** bool
**Warum:** sauber zwischen fehlend und vorhanden unterscheiden.
### P4. `body_progress_score_available`
**Typ:** bool
**Warum:** dito.
---
## 5.2 Höchste Priorität Domain Availability / Confidence
### P5. `domain_availability_json`
**Zweck:** zentrale Verfügbarkeit pro Domäne.
**Sollinhalt:**
- body
- nutrition
- activity
- sleep
- recovery
- vitals
- goals
- focus_areas
- correlations
jeweils mit:
- available
- confidence
- main_gaps
- last_valid_window
**Warum wichtig:**
Vereinfacht Fallbacks und verhindert Scheinpräzision.
---
### P6. `domain_confidence_json`
Falls `domain_availability_json` nicht reicht oder zu groß wird.
---
### P7. `critical_missing_fields_json`
**Zweck:** welche fehlenden Daten würden den größten Erkenntnisgewinn bringen?
**Warum wichtig:**
Für Datenqualitätsreport und Nutzerführung.
---
## 5.3 Höchste Priorität Körperentwicklung
### P8. `fm_28d_change_available`
### P9. `lbm_28d_change_available`
### P10. `waist_28d_delta_available`
### P11. `recomposition_quadrant_available`
**Warum:**
Körper- und Plateau-Reports brauchen robuste Verfügbarkeitslogik.
---
### P12. `body_change_summary_json`
**Zweck:** strukturierte Körperentwicklung.
**Sollinhalt:**
- weight trend
- FM delta
- LBM delta
- waist delta
- hip delta
- recomposition quadrant
- confidence
---
## 5.4 Höchste Priorität Training / Belastung
### P13. `activity_structure_json`
**Zweck:** kompakter Trainingsstrukturblock.
**Sollinhalt:**
- Volumen
- Frequenz
- Typverteilung
- Qualitätsanteil
- Lastniveau
- Monotonie
- Strain
- Rest-day compliance
- auffällige Muster
---
### P14. `training_quality_score`
**Zweck:** standardisierte Trainingsqualitätsbewertung über Sessions hinweg
**Warum:**
Aktuell gibt es `quality_sessions_pct`, aber noch keinen robusten verdichteten Qualitätsanker.
---
### P15. `load_balance_class`
Wertebeispiele:
- low
- moderate
- high
- strained
**Warum:**
Erleichtert Diagnose-Prompts.
---
## 5.5 Höchste Priorität Schlaf / Recovery / Vitals
### P16. `sleep_summary_json`
**Sollinhalt:**
- duration
- quality
- debt
- regularity
- trend
- confidence
### P17. `recovery_summary_json`
**Sollinhalt:**
- recovery score
- main drivers
- RHR status
- HRV status
- recent load interaction
- confidence
### P18. `vitals_summary_json`
**Sollinhalt:**
- resting HR
- HRV
- VO2max
- trend
- baseline deviation
- confidence
### P19. `hrv_vs_baseline_pct_available`
### P20. `rhr_vs_baseline_pct_available`
---
## 5.6 Höchste Priorität Korrelation / Diagnose
### P21. `correlation_summary_json`
**Zweck:** strukturierte Zusammenfassung mehrerer Korrelationen / Lag-Beziehungen.
**Sollinhalt:**
- energy_weight_lag
- training_hrv_lag
- training_rhr_lag
- sleep_recovery_lag
- confidence je Zusammenhang
---
### P22. `plateau_status`
Wertebeispiele:
- likely
- possible
- not_detected
- insufficient_data
### P23. `top_drivers_positive_json`
### P24. `top_drivers_negative_json`
**Warum:**
Top-Driver-Report und Plateau-Detektor profitieren stark von einer vorberechneten Zwischenebene.
---
## 5.7 Höchste Priorität Energieverfügbarkeit / Schutzlogik
### P25. `underfueling_risk_flag`
**Typ:** bool / enum
### P26. `underfueling_risk_reason`
**Typ:** text / enum / json
### P27. `energy_availability_summary_json`
**Sollinhalt:**
- intake adequacy
- deficit magnitude
- load context
- recovery context
- warning level
- confidence
---
## 6. Mittlere Priorität sollte bald folgen
## 6.1 Gesundheitsstabilität
### P28. `health_stability_score`
### P29. `health_stability_summary_json`
## 6.2 Blutdruck
### P30. `blood_pressure_summary_json`
**Sollinhalt:**
- mean systolic/diastolic
- category
- contexts
- trend
- irregularity flags
- confidence
## 6.3 Fokus-/Zielgewichtung
### P31. `goal_weighted_priority_json`
**Zweck:** priorisierte Ziel-/Fokuslogik für Synthese
## 6.4 Reporting-Hilfsfelder
### P32. `main_constraint_json`
### P33. `main_strength_json`
### P34. `next_best_actions_json`
---
## 7. Niedrigere Priorität / spätere Ausbaustufe
Diese Platzhalter sind wertvoll, aber für V1 nicht zwingend:
- `session_rpe`
- `fatigue_score`
- `pain_flag`
- `illness_flag`
- `travel_flag`
- `competition_flag`
- `measurement_time_consistency`
- `training_age`
- `secondary_goals_json`
- `waist_to_height_ratio`
- `sleep_segment_quality_score`
- `steps_summary_json`
---
## 8. Platzhalter, die geschärft statt neu erfunden werden sollten
Statt wild neue Namen einzuführen, sollten folgende Bereiche zuerst **semantisch sauber definiert** werden.
## 8.1 Goal / Focus
Bestehend, aber zu flach:
- `top_goal_name`
- `top_goal_progress_pct`
- `top_focus_area_name`
- `top_focus_area_progress`
**Schärfung:**
Ergänzen durch strukturierte JSONs, nicht ersetzen.
## 8.2 Körperentwicklung
Bestehend, aber oft nicht verfügbar:
- `fm_28d_change`
- `lbm_28d_change`
- `waist_28d_delta`
- `recomposition_quadrant`
**Schärfung:**
Verfügbarkeitsflags + strukturierte Summary.
## 8.3 Activity-Qualität
Bestehend:
- `quality_sessions_pct`
**Schärfung:**
ergänzen durch:
- `training_quality_score`
- ggf. `quality_sessions_count`
- optional `quality_definition_version`
## 8.4 Recovery
Bestehend:
- `recovery_score`
**Schärfung:**
ergänzen durch Komponenten-/Treiberdarstellung.
## 8.5 Data Quality
Bestehend:
- `data_quality_score`
**Schärfung:**
ergänzen durch Domain-Ebene und konkrete Lückenbeschreibung.
---
## 9. Governance-Regeln für Platzhalter
Diese Regeln sollten für Entwicklung und Prompting verbindlich sein.
### G1. Keine eigenmächtige Umbenennung
Bestehende Platzhalter dürfen nicht ohne Migration umbenannt werden.
### G2. Keine stillschweigende Semantikänderung
Wenn Berechnungslogik geändert wird, braucht der Platzhalter:
- Versionierung intern
- oder einen neuen Namen
### G3. Neue Platzhalter nur kontrolliert
Neue Platzhalter nur einführen, wenn:
- Zweck klar
- Datenquelle klar
- Zeitfenster klar
- Einheit klar
- Fallback klar
### G4. JSON vor Freitext
Für komplexe Mehrstufenlogik sollen neue Platzhalter bevorzugt als strukturierte JSON-Container bereitgestellt werden.
### G5. Zeitfenster im Namen
Zeitfenster müssen im Namen explizit sein, falls nicht universell.
### G6. Verfügbarkeit trennen von Inhalt
Für kritische Felder besser:
- Wert
- Verfügbarkeitsflag
- optional Grund
### G7. Keine Ad-hoc-Platzhalter in Folgechats
Folgechats für Prompt-Ausarbeitung dürfen keine neuen Platzhalter stillschweigend voraussetzen.
---
## 10. Konkrete Entwickler-Backlog-Empfehlung
## Sprint / Paket 1 notwendig für robuste V1-Reports
1. `goal_summary_json`
2. `focus_area_summary_json`
3. `domain_availability_json`
4. `critical_missing_fields_json`
5. Verfügbarkeitsflags für Body-Change-Felder
6. `sleep_summary_json`
7. `recovery_summary_json`
8. `activity_structure_json`
9. `correlation_summary_json`
10. `plateau_status`
## Sprint / Paket 2 starke Verbesserung der Ziel- und Diagnoseebene
1. `top_drivers_positive_json`
2. `top_drivers_negative_json`
3. `energy_availability_summary_json`
4. `underfueling_risk_flag`
5. `health_stability_score`
6. `blood_pressure_summary_json`
7. `goal_weighted_priority_json`
## Sprint / Paket 3 spätere Verfeinerung
1. `training_quality_score`
2. `session_rpe`
3. `fatigue_score`
4. `measurement_time_consistency`
5. `illness_flag` / `travel_flag`
6. `waist_to_height_ratio`
---
## 11. Abnahmekriterien für die Placeholder-Schicht
Die Placeholder-Schicht ist fachlich gut genug, wenn:
1. **alle Core-Reports der V1-Bibliothek ohne stillschweigende Erfindungen lauffähig sind**
2. fehlende Werte **strukturiert** behandelt werden können
3. Ziel-/Fokus-Logik nicht nur über ein einzelnes „Top“-Feld abgebildet wird
4. Datenqualität und Confidence nicht nur global, sondern domänenspezifisch beschrieben werden
5. Diagnose-Reports mindestens auf vorbereiteten Zwischenobjekten statt nur Freitextsummaries aufsetzen können
---
## 12. Kurzfazit
Für V1 ist die Placeholder-Basis bereits gut, aber noch nicht stabil genug für eine große professionelle Prompt-Bibliothek.
Der größte Handlungsbedarf liegt in vier Bereichen:
- **strukturierte Ziel-/Fokus-JSONs**
- **domänenspezifische Availability-/Confidence-Objekte**
- **robustere Diagnose-/Driver-/Plateau-Zwischenfelder**
- **saubere Verfügbarkeits- und Schärfungslogik für kritische Body-/Recovery-Felder**
Dieses Dokument ist bewusst entwicklungsnah formuliert und soll als Arbeitsgrundlage für die Implementierung dienen.

View File

@ -0,0 +1,151 @@
# Draft Corrections Required
**Generated:** 2026-03-30 14:58:37
This document lists all placeholders where the draft specification is missing, wrong, or incomplete.
## Summary
- **Missing:** 111 placeholders
- **Partial:** 0 placeholders
- **Wrong:** 0 placeholders
## Missing Draft Specifications
**111 placeholders** lack draft specifications:
- `ability_balance_coordination` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `ability_balance_endurance` (Category: Training, Compliance: non_compliant, Priority: P0)
- `ability_balance_mental` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `ability_balance_mobility` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `ability_balance_strength` (Category: Training, Compliance: non_compliant, Priority: P0)
- `active_goals_json` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `active_goals_md` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `activity_detail` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `activity_score` (Category: Scores (Phase 0b), Compliance: non_compliant, Priority: P0)
- `activity_summary` (Category: Training, Compliance: non_compliant, Priority: P0)
- `age` (Category: Profil, Compliance: compliant, Priority: P3)
- `arm_28d_delta` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `bmi` (Category: Körper, Compliance: partially_compliant, Priority: P0)
- `body_progress_score` (Category: Scores (Phase 0b), Compliance: non_compliant, Priority: P0)
- `caliper_summary` (Category: Unknown, Compliance: partially_compliant, Priority: P0)
- `carb_avg` (Category: Ernährung, Compliance: compliant, Priority: P3)
- `chest_28d_delta` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `circ_summary` (Category: Unknown, Compliance: compliant, Priority: P3)
- `correlation_energy_weight_lag` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `correlation_load_hrv` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `correlation_load_rhr` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `correlation_protein_lbm` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `correlation_sleep_recovery` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `data_quality_score` (Category: Scores (Phase 0b), Compliance: non_compliant, Priority: P0)
- `datum_heute` (Category: Zeitraum, Compliance: non_compliant, Priority: P0)
- `energy_balance_7d` (Category: Ernährung, Compliance: non_compliant, Priority: P2)
- `energy_deficit_surplus` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `fat_avg` (Category: Ernährung, Compliance: compliant, Priority: P3)
- `fm_28d_change` (Category: Körper, Compliance: non_compliant, Priority: P2)
- `focus_area_weights_json` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `focus_areas_weighted_json` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `focus_areas_weighted_md` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `focus_cat_aktivität_progress` (Category: Focus Areas, Compliance: non_compliant, Priority: P0)
- `focus_cat_aktivität_weight` (Category: Focus Areas, Compliance: non_compliant, Priority: P0)
- `focus_cat_ernährung_progress` (Category: Focus Areas, Compliance: non_compliant, Priority: P0)
- `focus_cat_ernährung_weight` (Category: Focus Areas, Compliance: non_compliant, Priority: P0)
- `focus_cat_körper_progress` (Category: Focus Areas, Compliance: non_compliant, Priority: P0)
- `focus_cat_körper_weight` (Category: Focus Areas, Compliance: non_compliant, Priority: P0)
- `focus_cat_lebensstil_progress` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `focus_cat_lebensstil_weight` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `focus_cat_mental_progress` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `focus_cat_mental_weight` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `focus_cat_recovery_progress` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `focus_cat_recovery_weight` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `focus_cat_vitalwerte_progress` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `focus_cat_vitalwerte_weight` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `geschlecht` (Category: Profil, Compliance: non_compliant, Priority: P0)
- `goal_bf_pct` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `goal_progress_score` (Category: Scores (Phase 0b), Compliance: non_compliant, Priority: P0)
- `goal_weight` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `height` (Category: Profil, Compliance: non_compliant, Priority: P0)
- `hip_28d_delta` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `hrv_vs_baseline_pct` (Category: Vitalwerte, Compliance: partially_compliant, Priority: P0)
- `intake_volatility` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `kcal_avg` (Category: Ernährung, Compliance: compliant, Priority: P3)
- `kf_aktuell` (Category: Körper, Compliance: partially_compliant, Priority: P1)
- `lbm_28d_change` (Category: Körper, Compliance: non_compliant, Priority: P2)
- `macro_consistency_score` (Category: Ernährung, Compliance: non_compliant, Priority: P0)
- `monotony_score` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `name` (Category: Profil, Compliance: non_compliant, Priority: P0)
- `nutrition_days` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `nutrition_score` (Category: Scores (Phase 0b), Compliance: non_compliant, Priority: P0)
- `plateau_detected` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `protein_adequacy_28d` (Category: Ernährung, Compliance: non_compliant, Priority: P2)
- `protein_avg` (Category: Ernährung, Compliance: compliant, Priority: P3)
- `protein_days_in_target` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `protein_g_per_kg` (Category: Ernährung, Compliance: non_compliant, Priority: P0)
- `protein_ziel_high` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `protein_ziel_low` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `proxy_internal_load_7d` (Category: Training, Compliance: partially_compliant, Priority: P1)
- `quality_sessions_pct` (Category: Training, Compliance: partially_compliant, Priority: P0)
- `recent_load_balance_3d` (Category: Unknown, Compliance: partially_compliant, Priority: P0)
- `recomposition_quadrant` (Category: Körper, Compliance: non_compliant, Priority: P0)
- `recovery_score` (Category: Scores (Phase 0b), Compliance: non_compliant, Priority: P0)
- `rest_day_compliance` (Category: Training, Compliance: partially_compliant, Priority: P0)
- `rest_days_count` (Category: Schlaf & Erholung, Compliance: partially_compliant, Priority: P0)
- `rhr_vs_baseline_pct` (Category: Vitalwerte, Compliance: partially_compliant, Priority: P0)
- `sleep_avg_duration` (Category: Schlaf & Erholung, Compliance: partially_compliant, Priority: P1)
- `sleep_avg_duration_7d` (Category: Schlaf & Erholung, Compliance: partially_compliant, Priority: P1)
- `sleep_avg_quality` (Category: Schlaf & Erholung, Compliance: partially_compliant, Priority: P1)
- `sleep_debt_hours` (Category: Schlaf & Erholung, Compliance: partially_compliant, Priority: P0)
- `sleep_quality_7d` (Category: Schlaf & Erholung, Compliance: partially_compliant, Priority: P1)
- `sleep_regularity_proxy` (Category: Schlaf & Erholung, Compliance: partially_compliant, Priority: P0)
- `strain_score` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `thigh_28d_delta` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `top_3_focus_areas` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `top_3_goals_behind_schedule` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `top_3_goals_on_track` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `top_drivers` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `top_focus_area_name` (Category: Focus Areas, Compliance: non_compliant, Priority: P0)
- `top_focus_area_progress` (Category: Focus Areas, Compliance: non_compliant, Priority: P0)
- `top_goal_name` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `top_goal_progress_pct` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `top_goal_status` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `training_frequency_7d` (Category: Training, Compliance: partially_compliant, Priority: P1)
- `training_minutes_week` (Category: Training, Compliance: partially_compliant, Priority: P1)
- `trainingstyp_verteilung` (Category: Training, Compliance: non_compliant, Priority: P0)
- `vitals_avg_hr` (Category: Vitalwerte, Compliance: partially_compliant, Priority: P1)
- `vitals_avg_hrv` (Category: Vitalwerte, Compliance: partially_compliant, Priority: P1)
- `vitals_vo2_max` (Category: Vitalwerte, Compliance: partially_compliant, Priority: P0)
- `vo2max_trend_28d` (Category: Vitalwerte, Compliance: non_compliant, Priority: P2)
- `waist_28d_delta` (Category: Körper, Compliance: non_compliant, Priority: P2)
- `waist_hip_ratio` (Category: Körper, Compliance: partially_compliant, Priority: P0)
- `weight_28d_slope` (Category: Körper, Compliance: non_compliant, Priority: P2)
- `weight_7d_median` (Category: Körper, Compliance: non_compliant, Priority: P2)
- `weight_90d_slope` (Category: Unknown, Compliance: non_compliant, Priority: P0)
- `weight_aktuell` (Category: Körper, Compliance: compliant, Priority: P3)
- `weight_trend` (Category: Körper, Compliance: compliant, Priority: P3)
- `zeitraum_30d` (Category: Zeitraum, Compliance: non_compliant, Priority: P2)
- `zeitraum_7d` (Category: Zeitraum, Compliance: non_compliant, Priority: P2)
- `zeitraum_90d` (Category: Unknown, Compliance: non_compliant, Priority: P0)
## Partial Draft Specifications
No placeholders with partial drafts.
## Wrong Draft Specifications
No placeholders with wrong drafts.
## Recommendations
1. **Priority 1:** Add draft specifications for all missing placeholders
2. **Priority 2:** Complete partial draft specifications
3. **Priority 3:** Correct wrong draft specifications
### Bulk Update Strategy
Use audit semantic analysis reports to bulk-populate:
- Category classifications
- Descriptions
- Time windows
- Source information
Estimated effort: 6-10 hours for bulk updates.

View File

@ -0,0 +1,119 @@
# Executive Reconciliation Summary
**Generated:** 2026-03-30 14:58:37
**Scope:** 111 Placeholders
**Data Sources:** Export Catalog, Audit Reports (2026-03-29), Draft Document
## Overview
This reconciliation consolidates data from three authoritative sources to create a single source of truth for all 111 placeholders.
### Key Findings
- **71** placeholders (63%) are implemented in code
- **8** placeholders (7%) are fully compliant with normative requirements
- **22** placeholders (20%) are partially compliant
- **81** placeholders (73%) are non-compliant
### Reconciliation Results
- **Verified Match (7):** Draft, Export, and Audit align perfectly
- **Needs Sharpening (49):** Correct but incomplete metadata
- **Needs Refactor (16):** Code-docs conflicts exist
- **Draft Wrong (0):** Draft specification incorrect
- **New Required (39):** Not implemented, needs build
- **Unclear (0):** Manual review needed
### Priority Distribution
- **P0 (Critical):** 83 placeholders
- High usage (breaking change risk)
- Missing documentation (category/description)
- Unknown time window
- **P1 (High):** 10 placeholders
- Partially compliant with minor gaps
- **P2 (Medium):** 10 placeholders
- Non-compliant, needs work
- **P3 (Low):** 8 placeholders
- Compliant, maintenance only
## Critical Issues
### 1. Known Code-Documentation Conflicts
- **`weight_trend`**: Code uses 28d, docs say 7d/30d
- Resolution: Update docs to match code (28d)
- **`activity_summary`**: Code uses 14d, docs say 7d
- Resolution: Update docs to match code (14d)
- **`activity_detail`**: Time window unclear in code
- Resolution: Needs code review to determine actual time window
### 2. High-Usage Placeholders (Breaking Change Risk)
- **`name`** (19 uses, non_compliant)
- **`geschlecht`** (14 uses, non_compliant)
- **`height`** (12 uses, non_compliant)
- **`weight_aktuell`** (10 uses, compliant)
- **`weight_trend`** (10 uses, compliant)
- **`goal_bf_pct`** (10 uses, non_compliant)
- **`caliper_summary`** (8 uses, partially_compliant)
- **`circ_summary`** (8 uses, compliant)
- **`goal_weight`** (8 uses, non_compliant)
- **`protein_ziel_low`** (7 uses, non_compliant)
- **`protein_ziel_high`** (7 uses, non_compliant)
- **`activity_detail`** (4 uses, non_compliant)
### 3. Missing Documentation (P0)
**49** placeholders lack category classification
**49** placeholders lack descriptions
## Recommendations
### Immediate Actions (P0)
1. **Resolve Known Conflicts (3 placeholders, 2-4 hours)**
- Update documentation to match code implementation
- Validate time windows in code
2. **Classify Time Windows (74 placeholders, 8-12 hours)**
- Use name-based extraction for `*_7d`, `*_28d` patterns
- Extract from code default parameters
- Manual classification for unclear cases
3. **Add Categories and Descriptions (49 placeholders, 4-6 hours)**
- Bulk update from audit semantic analysis
- Use existing audit report classifications
### Next Sprint (P1)
1. **Add Confidence Logic (103 placeholders, 12-16 hours)**
- Implement for trend/delta placeholders
- Add min-data thresholds
2. **Document Data Layer Modules (100 placeholders, 6-8 hours)**
- Trace resolver functions to data layer
- Document source tables
### Later (P2-P3)
1. **Integrate Unused Placeholders (67 placeholders)**
- Create prompt use cases
- Plan integration timeline
2. **Achieve Production Status (30+ placeholders)**
- Reach 80%+ metadata completeness
- Complete all normative requirements
## Conclusion
The reconciliation process successfully analyzed all 111 placeholders.
While only 8 are currently fully compliant,
the systematic gaps are primarily documentation-related rather than functional.
With a structured remediation plan (estimated 82-110 hours), the system can reach
>60% normative conformity within 4-6 weeks.
**Next Steps:**
1. Review this summary with product/tech leads
2. Prioritize P0 items for immediate action
3. Begin systematic remediation following the implementation waves

View File

@ -0,0 +1,142 @@
# Implementation Waves
**Generated:** 2026-03-30 14:58:37
This document outlines a cluster-based implementation plan for placeholder remediation.
## Overview
Total remediation effort: **82-110 hours** over 4-6 weeks
### Timeline
- **Wave 1 (P0):** Week 1 - Critical fixes (14-20 hours)
- **Wave 2 (P1):** Weeks 2-3 - High priority (26-34 hours)
- **Wave 3 (P2):** Weeks 4-5 - Medium priority (18-24 hours)
- **Wave 4 (P3):** Later - Nice to have (24-32 hours)
## Wave 1: Critical Fixes (P0)
**Scope:** 83 placeholders
**Timeline:** Week 1
**Effort:** 14-20 hours
### 1.1 Resolve Known Conflicts (3 placeholders, 2 hours)
- `weight_trend`: Update docs to match code (28d)
- `activity_summary`: Update docs to match code (14d)
- `activity_detail`: Needs code review to determine actual time window
### 1.2 Classify Time Windows (74 placeholders, 8-12 hours)
**Method:**
1. Name-based extraction (`*_7d`, `*_28d` patterns) - automatic
2. Code parameter extraction - semi-automatic
3. Manual classification for unclear cases
### 1.3 Add Categories and Descriptions (49 placeholders, 4-6 hours)
**Method:**
- Bulk update from audit semantic analysis
- Use provided classifications from audit report
## Wave 2: High Priority (P1)
**Scope:** 10 placeholders
**Timeline:** Weeks 2-3
**Effort:** 26-34 hours
### 2.1 Add Confidence Logic (11 trend/delta placeholders, 12-16 hours)
**Placeholders:**
- `weight_28d_slope`, `weight_90d_slope`, `weight_7d_median`
- `fm_28d_change`, `lbm_28d_change`
- `waist_28d_delta`, `hip_28d_delta`, `chest_28d_delta`, `arm_28d_delta`, `thigh_28d_delta`
- `vo2max_trend_28d`
**Pattern:** `confidence = calculate_confidence(data_points, time_window_days, 'trend')`
### 2.2 Structured Missing-Value Policy (70 placeholders, 8-10 hours)
**Refactor:**
- Keep legacy string for backward compatibility
- Add structured fields: `available`, `missing_reason`, `value_raw`
### 2.3 Document Data Layer Modules (100 placeholders, 6-8 hours)
**Method:**
- Trace resolver functions to data layer
- Document source tables from SQL queries
## Wave 3: Medium Priority (P2)
**Scope:** 10 placeholders
**Timeline:** Weeks 4-5
**Effort:** 18-24 hours
### 3.1 Integrate Unused Placeholders (67 placeholders, 4-6 hours)
**Method:**
- Product management review for 30 planned placeholders
- Technical review for 37 plausible placeholders
- Create prompt use cases (5-10 quick wins)
### 3.2 Metadata Completeness (111 placeholders, 10-12 hours)
**Target:** Minimum 60% of placeholders with score >60
### 3.3 Production Status (20-30 core placeholders, 4-6 hours)
**Criteria:**
- Metadata completeness >= 80%
- Used-by >= 1
- No known issues
- Time window + confidence defined
## Wave 4: Nice to Have (P3)
**Scope:** 8 placeholders
**Timeline:** Later
**Effort:** 24-32 hours
### 4.1 Validation Framework (16-20 hours)
**Features:**
- Pre-commit hook for normative spec validation
- CI/CD consistency checks (code-catalog)
- Template generator for new placeholders
### 4.2 Migration Guides (8-12 hours)
**Content:**
- Best-practice guide (based on compliant examples)
- Anti-patterns to avoid
- Upgrade path for legacy prompts
## Dependencies
- **Wave 1 → Wave 2:** Time window classification must be complete before confidence logic
- **Wave 2 → Wave 3:** Data layer documentation enables better integration planning
- **Wave 3 → Wave 4:** Production-ready placeholders provide best-practice models
## Success Metrics
### After Wave 1:
- 0 unknown time windows
- 0 unknown categories
- 0 code-documentation conflicts
### After Wave 2:
- 70%+ placeholders with confidence logic
- 100% placeholders with structured missing-value policies
- 100% placeholders with documented data layers
### After Wave 3:
- 50-60% placeholder usage rate
- 60%+ placeholders with metadata completeness >60
- 20-30 production-ready placeholders
### After Wave 4:
- Automated validation in CI/CD
- Best-practice documentation for developers
- Sustainable maintenance process

View File

@ -0,0 +1,242 @@
# Placeholder Reconciliation Matrix
**Generated:** 2026-03-30 14:58:37
**Total Placeholders:** 111
## Statistics Summary
- **Exists in Code:** 71/111 (63%)
### Draft Status
- Full: 0
- Partial: 0
- Missing: 111
- Wrong: 0
### Compliance Level (from Audit)
- Compliant: 8 (7%)
- Partially Compliant: 22 (20%)
- Non-Compliant: 81 (73%)
### Reconciliation Status
- Verified Match: 7
- Needs Sharpening: 49
- Needs Refactor: 16
- Draft Wrong: 0
- New Required: 39
- Unclear: 0
### Confidence Distribution
- High: 10
- Medium: 49
- Low: 52
### Priority Distribution
- P0 (Critical): 83
- P1 (High): 10
- P2 (Medium): 10
- P3 (Low): 8
## Full Matrix
| # | Key | Exists | Draft | Category | Time Window | Used By | Compliance | Priority | Reconciliation | Action | Confidence | Notes |
|---|-----|--------|-------|----------|-------------|---------|------------|----------|----------------|--------|------------|-------|
| 1 | `ability_balance_coordination` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 2 | `ability_balance_endurance` | YES | missing | Training | unknown | 0 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 3 | `ability_balance_mental` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 4 | `ability_balance_mobility` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 5 | `ability_balance_strength` | YES | missing | Training | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 6 | `active_goals_json` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 7 | `active_goals_md` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 8 | `activity_detail` | YES | missing | Unknown | unknown | 4 | non_compliant | P0 | needs_refactor | code_change | high | Implementation exists but lacks documentation | Category needs classification | ... |
| 9 | `activity_score` | YES | missing | Scores (Phase 0b) | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 10 | `activity_summary` | YES | missing | Training | unknown | 2 | non_compliant | P0 | needs_refactor | code_change | high | Time window needs classification | Known conflict: Code uses 14d, docs say 7d | ... |
| 11 | `age` | YES | missing | Profil | latest | 2 | compliant | P3 | verified_match | no_change | high | Fully compliant with normative requirements | Draft specification missing for im... |
| 12 | `arm_28d_delta` | NO | missing | Unknown | 28d | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 13 | `bmi` | YES | missing | Körper | unknown | 0 | partially_compliant | P0 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Time window needs classificatio... |
| 14 | `body_progress_score` | YES | missing | Scores (Phase 0b) | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 15 | `caliper_summary` | YES | missing | Unknown | unknown | 8 | partially_compliant | P0 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Time window needs classificatio... |
| 16 | `carb_avg` | YES | missing | Ernährung | 30d | 2 | compliant | P3 | verified_match | no_change | high | Fully compliant with normative requirements | Draft specification missing for im... |
| 17 | `chest_28d_delta` | NO | missing | Unknown | 28d | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 18 | `circ_summary` | YES | missing | Unknown | mixed | 8 | compliant | P3 | verified_match | no_change | high | Fully compliant with normative requirements | High usage (8 references) - breaki... |
| 19 | `correlation_energy_weight_lag` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 20 | `correlation_load_hrv` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 21 | `correlation_load_rhr` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 22 | `correlation_protein_lbm` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 23 | `correlation_sleep_recovery` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 24 | `data_quality_score` | YES | missing | Scores (Phase 0b) | unknown | 0 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 25 | `datum_heute` | YES | missing | Zeitraum | unknown | 0 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 26 | `energy_balance_7d` | YES | missing | Ernährung | 7d | 1 | non_compliant | P2 | needs_refactor | code_change | low | Code-docs conflicts or quality issues | Draft specification missing for implemen... |
| 27 | `energy_deficit_surplus` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 28 | `fat_avg` | YES | missing | Ernährung | 30d | 2 | compliant | P3 | verified_match | no_change | high | Fully compliant with normative requirements | Draft specification missing for im... |
| 29 | `fm_28d_change` | YES | missing | Körper | 28d | 1 | non_compliant | P2 | needs_refactor | code_change | low | Code-docs conflicts or quality issues | Draft specification missing for implemen... |
| 30 | `focus_area_weights_json` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 31 | `focus_areas_weighted_json` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 32 | `focus_areas_weighted_md` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 33 | `focus_cat_aktivität_progress` | YES | missing | Focus Areas | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 34 | `focus_cat_aktivität_weight` | YES | missing | Focus Areas | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 35 | `focus_cat_ernährung_progress` | YES | missing | Focus Areas | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 36 | `focus_cat_ernährung_weight` | YES | missing | Focus Areas | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 37 | `focus_cat_körper_progress` | YES | missing | Focus Areas | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 38 | `focus_cat_körper_weight` | YES | missing | Focus Areas | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 39 | `focus_cat_lebensstil_progress` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 40 | `focus_cat_lebensstil_weight` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 41 | `focus_cat_mental_progress` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 42 | `focus_cat_mental_weight` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 43 | `focus_cat_recovery_progress` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 44 | `focus_cat_recovery_weight` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 45 | `focus_cat_vitalwerte_progress` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 46 | `focus_cat_vitalwerte_weight` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 47 | `geschlecht` | YES | missing | Profil | latest | 14 | non_compliant | P0 | needs_refactor | code_change | low | Code-docs conflicts or quality issues | High usage (14 references) - breaking ch... |
| 48 | `goal_bf_pct` | YES | missing | Unknown | unknown | 10 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Implementation exists but lacks documentation | Category needs classification | ... |
| 49 | `goal_progress_score` | YES | missing | Scores (Phase 0b) | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 50 | `goal_weight` | YES | missing | Unknown | unknown | 8 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Implementation exists but lacks documentation | Category needs classification | ... |
| 51 | `height` | YES | missing | Profil | latest | 12 | non_compliant | P0 | needs_refactor | code_change | low | Code-docs conflicts or quality issues | High usage (12 references) - breaking ch... |
| 52 | `hip_28d_delta` | NO | missing | Unknown | 28d | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 53 | `hrv_vs_baseline_pct` | YES | missing | Vitalwerte | unknown | 1 | partially_compliant | P0 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Time window needs classificatio... |
| 54 | `intake_volatility` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 55 | `kcal_avg` | YES | missing | Ernährung | 30d | 1 | compliant | P3 | verified_match | no_change | high | Fully compliant with normative requirements | Draft specification missing for im... |
| 56 | `kf_aktuell` | YES | missing | Körper | latest | 2 | partially_compliant | P1 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Draft specification missing for... |
| 57 | `lbm_28d_change` | YES | missing | Körper | 28d | 1 | non_compliant | P2 | needs_refactor | code_change | low | Code-docs conflicts or quality issues | Draft specification missing for implemen... |
| 58 | `macro_consistency_score` | YES | missing | Ernährung | unknown | 0 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 59 | `monotony_score` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 60 | `name` | YES | missing | Profil | latest | 19 | non_compliant | P0 | needs_refactor | code_change | low | Code-docs conflicts or quality issues | High usage (19 references) - breaking ch... |
| 61 | `nutrition_days` | YES | missing | Unknown | unknown | 2 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Implementation exists but lacks documentation | Category needs classification | ... |
| 62 | `nutrition_score` | YES | missing | Scores (Phase 0b) | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 63 | `plateau_detected` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 64 | `protein_adequacy_28d` | YES | missing | Ernährung | 28d | 1 | non_compliant | P2 | needs_refactor | code_change | low | Code-docs conflicts or quality issues | Draft specification missing for implemen... |
| 65 | `protein_avg` | YES | missing | Ernährung | 30d | 1 | compliant | P3 | verified_match | no_change | high | Fully compliant with normative requirements | Draft specification missing for im... |
| 66 | `protein_days_in_target` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 67 | `protein_g_per_kg` | YES | missing | Ernährung | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 68 | `protein_ziel_high` | YES | missing | Unknown | unknown | 7 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Implementation exists but lacks documentation | Category needs classification | ... |
| 69 | `protein_ziel_low` | YES | missing | Unknown | unknown | 7 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Implementation exists but lacks documentation | Category needs classification | ... |
| 70 | `proxy_internal_load_7d` | YES | missing | Training | 7d | 0 | partially_compliant | P1 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Draft specification missing for... |
| 71 | `quality_sessions_pct` | YES | missing | Training | unknown | 1 | partially_compliant | P0 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Time window needs classificatio... |
| 72 | `recent_load_balance_3d` | NO | missing | Unknown | unknown | 0 | partially_compliant | P0 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Time window needs classificatio... |
| 73 | `recomposition_quadrant` | YES | missing | Körper | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 74 | `recovery_score` | YES | missing | Scores (Phase 0b) | unknown | 1 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 75 | `rest_day_compliance` | YES | missing | Training | unknown | 0 | partially_compliant | P0 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Time window needs classificatio... |
| 76 | `rest_days_count` | YES | missing | Schlaf & Erholung | unknown | 0 | partially_compliant | P0 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Time window needs classificatio... |
| 77 | `rhr_vs_baseline_pct` | YES | missing | Vitalwerte | unknown | 0 | partially_compliant | P0 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Time window needs classificatio... |
| 78 | `sleep_avg_duration` | YES | missing | Schlaf & Erholung | 30d | 0 | partially_compliant | P1 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Draft specification missing for... |
| 79 | `sleep_avg_duration_7d` | YES | missing | Schlaf & Erholung | 7d | 1 | partially_compliant | P1 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Draft specification missing for... |
| 80 | `sleep_avg_quality` | YES | missing | Schlaf & Erholung | 30d | 0 | partially_compliant | P1 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Draft specification missing for... |
| 81 | `sleep_debt_hours` | YES | missing | Schlaf & Erholung | unknown | 0 | partially_compliant | P0 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Time window needs classificatio... |
| 82 | `sleep_quality_7d` | YES | missing | Schlaf & Erholung | 7d | 1 | partially_compliant | P1 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Draft specification missing for... |
| 83 | `sleep_regularity_proxy` | YES | missing | Schlaf & Erholung | unknown | 0 | partially_compliant | P0 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Time window needs classificatio... |
| 84 | `strain_score` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 85 | `thigh_28d_delta` | NO | missing | Unknown | 28d | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 86 | `top_3_focus_areas` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 87 | `top_3_goals_behind_schedule` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 88 | `top_3_goals_on_track` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 89 | `top_drivers` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 90 | `top_focus_area_name` | YES | missing | Focus Areas | unknown | 0 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 91 | `top_focus_area_progress` | YES | missing | Focus Areas | unknown | 0 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 92 | `top_goal_name` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 93 | `top_goal_progress_pct` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 94 | `top_goal_status` | NO | missing | Unknown | unknown | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 95 | `training_frequency_7d` | YES | missing | Training | 7d | 0 | partially_compliant | P1 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Draft specification missing for... |
| 96 | `training_minutes_week` | YES | missing | Training | 7d | 1 | partially_compliant | P1 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Draft specification missing for... |
| 97 | `trainingstyp_verteilung` | YES | missing | Training | unknown | 0 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Time window needs classification | Draft specification missing for implemented f... |
| 98 | `vitals_avg_hr` | YES | missing | Vitalwerte | 30d | 0 | partially_compliant | P1 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Draft specification missing for... |
| 99 | `vitals_avg_hrv` | YES | missing | Vitalwerte | 30d | 0 | partially_compliant | P1 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Draft specification missing for... |
| 100 | `vitals_vo2_max` | YES | missing | Vitalwerte | unknown | 0 | partially_compliant | P0 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Time window needs classificatio... |
| 101 | `vo2max_trend_28d` | YES | missing | Vitalwerte | 28d | 0 | non_compliant | P2 | needs_refactor | code_change | low | Code-docs conflicts or quality issues | Draft specification missing for implemen... |
| 102 | `waist_28d_delta` | YES | missing | Körper | 28d | 0 | non_compliant | P2 | needs_refactor | code_change | low | Code-docs conflicts or quality issues | Draft specification missing for implemen... |
| 103 | `waist_hip_ratio` | YES | missing | Körper | unknown | 0 | partially_compliant | P0 | needs_sharpening | metadata_only | medium | Partial compliance - needs metadata enrichment | Time window needs classificatio... |
| 104 | `weight_28d_slope` | YES | missing | Körper | 28d | 0 | non_compliant | P2 | needs_refactor | code_change | low | Code-docs conflicts or quality issues | Draft specification missing for implemen... |
| 105 | `weight_7d_median` | YES | missing | Körper | 7d | 1 | non_compliant | P2 | needs_refactor | code_change | low | Code-docs conflicts or quality issues | Draft specification missing for implemen... |
| 106 | `weight_90d_slope` | NO | missing | Unknown | 90d | 0 | non_compliant | P0 | new_required | build_new | low | Not implemented, needs build |
| 107 | `weight_aktuell` | YES | missing | Körper | latest | 10 | compliant | P3 | verified_match | no_change | high | Fully compliant with normative requirements | High usage (10 references) - break... |
| 108 | `weight_trend` | YES | missing | Körper | 28d | 10 | compliant | P3 | needs_refactor | code_change | high | Known conflict: Code uses 28d, docs say 7d/30d | Resolution: Update docs to matc... |
| 109 | `zeitraum_30d` | YES | missing | Zeitraum | 30d | 0 | non_compliant | P2 | needs_refactor | code_change | low | Code-docs conflicts or quality issues | Draft specification missing for implemen... |
| 110 | `zeitraum_7d` | YES | missing | Zeitraum | 7d | 0 | non_compliant | P2 | needs_refactor | code_change | low | Code-docs conflicts or quality issues | Draft specification missing for implemen... |
| 111 | `zeitraum_90d` | YES | missing | Unknown | 90d | 0 | non_compliant | P0 | needs_sharpening | metadata_only | medium | Implementation exists but lacks documentation | Category needs classification | ... |
## Critical Placeholders (P0)
These placeholders require immediate attention:
- `name`: Code-docs conflicts or quality issues | High usage (19 references) - breaking change risk | Draft specification missing for implemented feature
- `geschlecht`: Code-docs conflicts or quality issues | High usage (14 references) - breaking change risk | Draft specification missing for implemented feature
- `height`: Code-docs conflicts or quality issues | High usage (12 references) - breaking change risk | Draft specification missing for implemented feature
- `goal_bf_pct`: Implementation exists but lacks documentation | Category needs classification | Description needs to be written | High usage (10 references) - breaking change risk | Draft specification missing for implemented feature
- `caliper_summary`: Partial compliance - needs metadata enrichment | Time window needs classification | High usage (8 references) - breaking change risk | Draft specification missing for implemented feature
- `goal_weight`: Implementation exists but lacks documentation | Category needs classification | Description needs to be written | High usage (8 references) - breaking change risk | Draft specification missing for implemented feature
- `protein_ziel_high`: Implementation exists but lacks documentation | Category needs classification | Description needs to be written | High usage (7 references) - breaking change risk | Draft specification missing for implemented feature
- `protein_ziel_low`: Implementation exists but lacks documentation | Category needs classification | Description needs to be written | High usage (7 references) - breaking change risk | Draft specification missing for implemented feature
- `activity_detail`: Implementation exists but lacks documentation | Category needs classification | Description needs to be written | Known conflict: Time window unclear in code | High usage (4 references) - breaking change risk | Draft specification missing for implemented feature
- `activity_summary`: Time window needs classification | Known conflict: Code uses 14d, docs say 7d | Draft specification missing for implemented feature
- `nutrition_days`: Implementation exists but lacks documentation | Category needs classification | Description needs to be written | Draft specification missing for implemented feature
- `ability_balance_strength`: Time window needs classification | Draft specification missing for implemented feature
- `activity_score`: Time window needs classification | Draft specification missing for implemented feature
- `body_progress_score`: Time window needs classification | Draft specification missing for implemented feature
- `focus_cat_aktivität_progress`: Time window needs classification | Draft specification missing for implemented feature
- `focus_cat_aktivität_weight`: Time window needs classification | Draft specification missing for implemented feature
- `focus_cat_ernährung_progress`: Time window needs classification | Draft specification missing for implemented feature
- `focus_cat_ernährung_weight`: Time window needs classification | Draft specification missing for implemented feature
- `focus_cat_körper_progress`: Time window needs classification | Draft specification missing for implemented feature
- `focus_cat_körper_weight`: Time window needs classification | Draft specification missing for implemented feature
- `goal_progress_score`: Time window needs classification | Draft specification missing for implemented feature
- `hrv_vs_baseline_pct`: Partial compliance - needs metadata enrichment | Time window needs classification | Draft specification missing for implemented feature
- `nutrition_score`: Time window needs classification | Draft specification missing for implemented feature
- `protein_g_per_kg`: Time window needs classification | Draft specification missing for implemented feature
- `quality_sessions_pct`: Partial compliance - needs metadata enrichment | Time window needs classification | Draft specification missing for implemented feature
- `recomposition_quadrant`: Time window needs classification | Draft specification missing for implemented feature
- `recovery_score`: Time window needs classification | Draft specification missing for implemented feature
- `ability_balance_coordination`: Not implemented, needs build
- `ability_balance_endurance`: Time window needs classification | Draft specification missing for implemented feature
- `ability_balance_mental`: Not implemented, needs build
- `ability_balance_mobility`: Not implemented, needs build
- `active_goals_json`: Not implemented, needs build
- `active_goals_md`: Not implemented, needs build
- `arm_28d_delta`: Not implemented, needs build
- `bmi`: Partial compliance - needs metadata enrichment | Time window needs classification | Draft specification missing for implemented feature
- `chest_28d_delta`: Not implemented, needs build
- `correlation_energy_weight_lag`: Not implemented, needs build
- `correlation_load_hrv`: Not implemented, needs build
- `correlation_load_rhr`: Not implemented, needs build
- `correlation_protein_lbm`: Not implemented, needs build
- `correlation_sleep_recovery`: Not implemented, needs build
- `data_quality_score`: Time window needs classification | Draft specification missing for implemented feature
- `datum_heute`: Time window needs classification | Draft specification missing for implemented feature
- `energy_deficit_surplus`: Not implemented, needs build
- `focus_area_weights_json`: Not implemented, needs build
- `focus_areas_weighted_json`: Not implemented, needs build
- `focus_areas_weighted_md`: Not implemented, needs build
- `focus_cat_lebensstil_progress`: Not implemented, needs build
- `focus_cat_lebensstil_weight`: Not implemented, needs build
- `focus_cat_mental_progress`: Not implemented, needs build
- `focus_cat_mental_weight`: Not implemented, needs build
- `focus_cat_recovery_progress`: Not implemented, needs build
- `focus_cat_recovery_weight`: Not implemented, needs build
- `focus_cat_vitalwerte_progress`: Not implemented, needs build
- `focus_cat_vitalwerte_weight`: Not implemented, needs build
- `hip_28d_delta`: Not implemented, needs build
- `intake_volatility`: Not implemented, needs build
- `macro_consistency_score`: Time window needs classification | Draft specification missing for implemented feature
- `monotony_score`: Not implemented, needs build
- `plateau_detected`: Not implemented, needs build
- `protein_days_in_target`: Not implemented, needs build
- `recent_load_balance_3d`: Partial compliance - needs metadata enrichment | Time window needs classification
- `rest_day_compliance`: Partial compliance - needs metadata enrichment | Time window needs classification | Draft specification missing for implemented feature
- `rest_days_count`: Partial compliance - needs metadata enrichment | Time window needs classification | Draft specification missing for implemented feature
- `rhr_vs_baseline_pct`: Partial compliance - needs metadata enrichment | Time window needs classification | Draft specification missing for implemented feature
- `sleep_debt_hours`: Partial compliance - needs metadata enrichment | Time window needs classification | Draft specification missing for implemented feature
- `sleep_regularity_proxy`: Partial compliance - needs metadata enrichment | Time window needs classification | Draft specification missing for implemented feature
- `strain_score`: Not implemented, needs build
- `thigh_28d_delta`: Not implemented, needs build
- `top_3_focus_areas`: Not implemented, needs build
- `top_3_goals_behind_schedule`: Not implemented, needs build
- `top_3_goals_on_track`: Not implemented, needs build
- `top_drivers`: Not implemented, needs build
- `top_focus_area_name`: Time window needs classification | Draft specification missing for implemented feature
- `top_focus_area_progress`: Time window needs classification | Draft specification missing for implemented feature
- `top_goal_name`: Not implemented, needs build
- `top_goal_progress_pct`: Not implemented, needs build
- `top_goal_status`: Not implemented, needs build
- `trainingstyp_verteilung`: Time window needs classification | Draft specification missing for implemented feature
- `vitals_vo2_max`: Partial compliance - needs metadata enrichment | Time window needs classification | Draft specification missing for implemented feature
- `waist_hip_ratio`: Partial compliance - needs metadata enrichment | Time window needs classification | Draft specification missing for implemented feature
- `weight_90d_slope`: Not implemented, needs build
- `zeitraum_90d`: Implementation exists but lacks documentation | Category needs classification | Description needs to be written | Draft specification missing for implemented feature

View File

@ -0,0 +1,254 @@
# Placeholder Reconciliation Report
**Generated:** 2026-03-30
**Scope:** 111 Placeholders
**Status:** COMPLETE ✓
## Overview
This reconciliation consolidates data from three authoritative sources to create a **single source of truth** for all 111 placeholders in the Mitai Jinkendo system.
### Data Sources
1. **Export Catalog** (`.claude/docs/audit/platzhalter/PLACEHOLDER_CATALOG_EXTENDED.json`)
- Authoritative placeholder metadata export
- Contains 111 placeholder definitions with categories, descriptions, time windows, usage data
2. **Audit Reports** (`audit-report-2026-03-29/`)
- Comprehensive compliance audit against normative requirements
- Identifies gaps, conflicts, and remediation priorities
- Classifies placeholders: 8 compliant, 22 partially compliant, 81 non-compliant
3. **Draft Document** (`.claude/docs/concepts/canonical_placeholder_requirements_draft.md`)
- Normative placeholder specifications (4895 lines)
- Currently: 0 placeholders documented (draft in progress)
## Reconciliation Results
### Completeness Validation
**PASS** - All 111 placeholders successfully reconciled
- Export-Keys: 111
- Matrix-Keys: 111
- Differenz: 0
- Fehlende Keys: []
- Doppelte Keys: []
### Key Statistics
#### Implementation Status
- **Exists in Code:** 71/111 (63%)
- **Not Implemented:** 40/111 (36%)
#### Compliance Level (from Audit)
- **Compliant:** 8 (7%) - Production-ready
- **Partially Compliant:** 22 (19%) - Minor gaps
- **Non-Compliant:** 81 (73%) - Major gaps
#### Reconciliation Status
- **Verified Match (7):** Draft ↔ Export ↔ Audit align perfectly
- **Needs Sharpening (49):** Correct but incomplete metadata
- **Needs Refactor (16):** Code-docs conflicts exist
- **Draft Wrong (0):** Draft specification incorrect
- **New Required (39):** Not implemented, needs build
- **Unclear (0):** Manual review needed
#### Priority Distribution
- **P0 (Critical):** 83 (74%) - Immediate attention required
- **P1 (High):** 10 (9%) - Next sprint
- **P2 (Medium):** 10 (9%) - Later
- **P3 (Low):** 8 (7%) - Maintenance only
#### Confidence Distribution
- **High:** 10 (9%) - Reliable data
- **Medium:** 49 (44%) - Some uncertainty
- **Low:** 52 (46%) - Needs verification
## Generated Documents
### 1. RECONCILIATION_COMPLETENESS_CHECK.md
Validation proof that all 111 placeholders were processed.
### 2. PLACEHOLDER_RECONCILIATION_MATRIX.json (119 KB)
Machine-readable complete reconciliation data:
- Schema version: 1.0.0
- All 111 placeholders with:
- Implementation status
- Draft status
- Export metadata (category, description, time_window, usage)
- Audit findings (compliance, priority, confidence logic)
- Architecture verification
- Reconciliation status and recommended action
- Confidence level and notes
### 3. PLACEHOLDER_RECONCILIATION_MATRIX.md (32 KB)
Human-readable table format:
- Full matrix with 111 rows
- Statistics summary
- Critical placeholders (P0) section
### 4. EXECUTIVE_RECONCILIATION_SUMMARY.md (4.1 KB)
High-level findings and recommendations:
- Key findings and statistics
- Known code-documentation conflicts (3)
- High-usage placeholders (12 with breaking change risk)
- Immediate actions (P0) and sprint plan (P1/P2/P3)
### 5. DRAFT_CORRECTIONS_REQUIRED.md (11 KB)
Lists all placeholders needing draft specifications:
- Missing: 111 placeholders
- Partial: 0 placeholders
- Wrong: 0 placeholders
- Bulk update strategy and effort estimates
### 6. IMPLEMENTATION_WAVES.md (4.1 KB)
Cluster-based remediation plan:
- Wave 1 (P0): Week 1 - 14-20 hours
- Wave 2 (P1): Weeks 2-3 - 26-34 hours
- Wave 3 (P2): Weeks 4-5 - 18-24 hours
- Wave 4 (P3): Later - 24-32 hours
- Total: 82-110 hours over 4-6 weeks
## Critical Issues
### Known Code-Documentation Conflicts
1. **`weight_trend`** - Code uses 28d, docs say 7d/30d
- Resolution: Update docs to match code (28d)
2. **`activity_summary`** - Code uses 14d, docs say 7d
- Resolution: Update docs to match code (14d)
3. **`activity_detail`** - Time window unclear in code
- Resolution: Needs code review to determine actual time window
### High-Usage Placeholders (Breaking Change Risk)
12 placeholders with 4+ uses require careful handling:
| Placeholder | Uses | Compliance |
|-------------|------|------------|
| `name` | 19 | non_compliant |
| `geschlecht` | 14 | non_compliant |
| `height` | 12 | non_compliant |
| `weight_aktuell` | 10 | compliant ✓ |
| `weight_trend` | 10 | compliant ✓ |
| `goal_bf_pct` | 10 | non_compliant |
| `caliper_summary` | 8 | partially_compliant |
| `circ_summary` | 8 | compliant ✓ |
| `goal_weight` | 8 | non_compliant |
| `protein_ziel_low` | 7 | non_compliant |
| `protein_ziel_high` | 7 | non_compliant |
| `activity_detail` | 4 | non_compliant |
### Missing Documentation (P0)
- **49 placeholders** lack category classification
- **49 placeholders** lack descriptions
- **74 placeholders** have unknown time windows
## Recommended Actions
### Immediate (P0) - Week 1
1. **Resolve Known Conflicts** (3 placeholders, 2-4 hours)
- Update documentation to match code implementation
2. **Classify Time Windows** (74 placeholders, 8-12 hours)
- Use name-based extraction (`*_7d`, `*_28d` patterns)
- Extract from code default parameters
- Manual classification for unclear cases
3. **Add Categories and Descriptions** (49 placeholders, 4-6 hours)
- Bulk update from audit semantic analysis
- Use existing audit report classifications
**Total P0 Effort:** 14-20 hours
### Next Sprint (P1) - Weeks 2-3
1. **Add Confidence Logic** (103 placeholders, 12-16 hours)
2. **Document Data Layer Modules** (100 placeholders, 6-8 hours)
3. **Structured Missing-Value Policy** (70 placeholders, 8-10 hours)
**Total P1 Effort:** 26-34 hours
### Later (P2-P3) - Weeks 4-6
1. **Integrate Unused Placeholders** (67 placeholders, 4-6 hours)
2. **Metadata Completeness** (111 placeholders, 10-12 hours)
3. **Production Status** (20-30 core placeholders, 4-6 hours)
4. **Validation Framework** (16-20 hours)
**Total P2-P3 Effort:** 42-56 hours
## Best-Practice Models
### Compliant Placeholders (8 total)
These serve as best-practice models for all others:
**Nutrition Averages (4):**
- `protein_avg`, `kcal_avg`, `fat_avg`, `carb_avg`
- Pattern: 30d time window, calculate_confidence, nutrition_metrics.py
**Body Metrics (3):**
- `weight_aktuell` (latest pattern, body_metrics.py)
- `weight_trend` (28d trend, calculate_confidence) *has conflict*
- `circ_summary` (mixed time window, best-of-each pattern)
**Profile (1):**
- `age` (snapshot, no confidence needed)
## Architecture Verification
- **71 placeholders (63%)** exist in code with sound architecture
- **40 placeholders (36%)** not implemented, need build
- **0 placeholders** with fundamental architecture issues
All implemented placeholders have valid resolvers and data sources.
## Success Metrics
### After P0 Remediation (Week 1)
- 0 unknown time windows ✓
- 0 unknown categories ✓
- 0 code-documentation conflicts ✓
### After P1 Remediation (Weeks 2-3)
- 70%+ placeholders with confidence logic
- 100% placeholders with structured missing-value policies
- 100% placeholders with documented data layers
### After P2-P3 Remediation (Weeks 4-6)
- 50-60% placeholder usage rate
- 60%+ placeholders with metadata completeness >60
- 20-30 production-ready placeholders
## Conclusion
The reconciliation process successfully analyzed all 111 placeholders and created a comprehensive single source of truth. While only 7% are currently fully compliant with normative requirements, the systematic gaps are primarily **documentation-related rather than functional**.
All 111 placeholders are:
- ✅ Properly inventoried
- ✅ Categorized by compliance level
- ✅ Prioritized for remediation
- ✅ Mapped to implementation plan
With a structured 4-6 week remediation plan (82-110 hours), the system can reach **>60% normative conformity** and establish a sustainable maintenance process.
## Next Steps
1. **Review** this reconciliation with product/tech leads
2. **Prioritize** P0 items for Week 1 sprint
3. **Execute** systematic remediation following implementation waves
4. **Track** progress against success metrics
5. **Iterate** based on findings and feedback
---
**For Questions or Issues:**
- Reconciliation Data: `PLACEHOLDER_RECONCILIATION_MATRIX.json`
- Executive Summary: `EXECUTIVE_RECONCILIATION_SUMMARY.md`
- Implementation Plan: `IMPLEMENTATION_WAVES.md`

View File

@ -0,0 +1,14 @@
# Reconciliation Completeness Validation
## Vollstaendigkeitscheck
- Export-Keys: 111
- Matrix-Keys: 111
- Differenz: 0
- Fehlende Keys: []
- Doppelte Keys: []
## Status: PASS
## Details
All placeholders successfully reconciled. Matrix contains exactly 111 entries matching the export catalog.

View File

@ -0,0 +1,422 @@
# Activity Quality Gates Fachliches Konzept
**Issue:** #15
**Status:** Design Phase
**Erstellt:** 2026-03-23
---
## Problem-Statement
### Aktuelles Problem:
Apple Health und andere Tracker importieren **alle** Workouts, unabhängig von ihrer Qualität:
- 5-Minuten-Spaziergang → "Outdoor Run"
- 10-Minuten-Krafttraining ohne echte Belastung
- Versehentlich gestartete Workouts
- Aufwärm-Sessions ohne echtes Training
**Folgen:**
- KI-Analysen werden verfälscht ("Du trainierst täglich!" - aber nur 5min)
- Statistiken zeigen unrealistische Trainingsfrequenz
- Korrelationen (Training ↔ Erholung) werden unbrauchbar
- User verliert Vertrauen in die Auswertungen
---
## Fachliche Anforderungen
### Must-Have:
1. **Pro Trainingstyp** unterschiedliche Qualitätskriterien
2. **Automatische Bewertung** beim Import und bei manueller Eingabe
3. **Nicht-destruktiv** - keine Daten löschen, nur markieren
4. **Transparenz** - User sieht warum eine Aktivität als minderwertig gilt
5. **Opt-Out möglich** - User kann Quality Gates pro Aktivität überschreiben
### Nice-to-Have:
6. **Admin-Presets** für gängige Trainingstypen (Laufen, Krafttraining, etc.)
7. **User-spezifische Anpassung** (z.B. für Reha-Patienten andere Schwellwerte)
8. **Historische Nachbearbeitung** - bestehende Aktivitäten neu bewerten
---
## Lösungsansätze (Evaluation)
### Ansatz A: Quality Flag (Boolean)
```sql
ALTER TABLE activity_log ADD COLUMN is_valid BOOLEAN DEFAULT true;
```
**Pro:**
- Einfach zu implementieren
- Schnelle Queries (`WHERE is_valid = true`)
- Binäre Entscheidung: gültig oder nicht
**Contra:**
- ❌ Keine Abstufungen (was ist mit "grenzwertig"?)
- ❌ Kein Grund dokumentiert (warum ungültig?)
- ❌ Schwer erweiterbar
**Bewertung:** ⭐⭐☆☆☆ (zu simpel)
---
### Ansatz B: Quality Score (0-100)
```sql
ALTER TABLE activity_log ADD COLUMN quality_score INTEGER DEFAULT 100;
```
**Pro:**
- Abstufungen möglich (100 = perfekt, 0 = wertlos)
- Filterbar: `WHERE quality_score >= 70`
- Flexibel für zukünftige Erweiterungen
**Contra:**
- ❌ Score-Berechnung komplex (wie gewichten?)
- ❌ Kein Grund dokumentiert
- ❌ Schwellwert (70? 80?) willkürlich
**Bewertung:** ⭐⭐⭐☆☆ (besser, aber intransparent)
---
### Ansatz C: Validation Result (JSONB) ⭐ **EMPFEHLUNG**
```sql
ALTER TABLE activity_log ADD COLUMN quality_check JSONB DEFAULT NULL;
-- Beispiel-Daten:
{
"evaluated_at": "2026-03-23T10:30:00Z",
"passed": false,
"score": 45,
"reasons": [
{"rule": "duration_min", "expected": 15, "actual": 8, "passed": false},
{"rule": "avg_hr_min", "expected": 100, "actual": 95, "passed": false},
{"rule": "max_hr_min", "expected": 120, "actual": 125, "passed": true}
],
"override": null // User kann auf "valid" oder "invalid" setzen
}
```
**Pro:**
- ✅ Transparent: Jede Regel einzeln nachvollziehbar
- ✅ Erweiterbar: Neue Regeln einfach hinzufügbar
- ✅ Override-Mechanismus eingebaut
- ✅ Historisch: Wann wurde evaluiert?
- ✅ Flexibel: Score + Boolean + Details
**Contra:**
- Mehr Speicherplatz (aber marginal bei JSONB)
- Komplexere Queries (aber PostgreSQL JSONB ist schnell)
**Bewertung:** ⭐⭐⭐⭐⭐ **BESTE LÖSUNG**
---
## Empfohlene Lösung: Ansatz C (Validation Result)
### Datenmodell
#### 1. Training Types (Regel-Definition)
```sql
ALTER TABLE training_types ADD COLUMN quality_rules JSONB DEFAULT NULL;
-- Beispiel: Laufen
UPDATE training_types SET quality_rules = '{
"enabled": true,
"rules": {
"duration_min": {"min": 15, "weight": 3},
"avg_hr_min": {"min": 100, "weight": 2},
"max_hr_min": {"min": 120, "weight": 1},
"distance_km": {"min": 1.0, "weight": 1}
},
"pass_threshold": 0.6,
"description": "Mindestens 15min, Durchschnittspuls > 100"
}'::jsonb WHERE name_de = 'Laufen';
-- Beispiel: Krafttraining
UPDATE training_types SET quality_rules = '{
"enabled": true,
"rules": {
"duration_min": {"min": 20, "weight": 5},
"avg_hr_min": {"min": 90, "weight": 1}
},
"pass_threshold": 0.8,
"description": "Mindestens 20 Minuten"
}'::jsonb WHERE name_de = 'Krafttraining';
```
**Erklärung:**
- `enabled`: Quality Gates aktiv für diesen Typ?
- `rules`: Dictionary der Regeln mit Schwellwerten + Gewichtung
- `weight`: Wichtigkeit der Regel (1-5)
- `pass_threshold`: Mindest-Score (0.0-1.0) für "bestanden"
- `description`: User-freundliche Erklärung
#### 2. Activity Log (Validierungs-Ergebnis)
```sql
ALTER TABLE activity_log ADD COLUMN quality_check JSONB DEFAULT NULL;
```
**Struktur siehe Ansatz C oben.**
---
## Validierungs-Logik
### Backend-Funktion: `validate_activity_quality()`
```python
def validate_activity_quality(activity: dict, training_type: dict) -> dict:
"""
Evaluiert eine Aktivität gegen die Quality Rules des Trainingstyps.
Returns:
{
"evaluated_at": ISO timestamp,
"passed": bool,
"score": float (0.0-1.0),
"reasons": [
{"rule": str, "expected": value, "actual": value, "passed": bool}
],
"override": null | "valid" | "invalid"
}
"""
rules = training_type.get('quality_rules', {})
if not rules or not rules.get('enabled'):
return None # Keine Quality Gates aktiv
results = []
total_weight = 0
passed_weight = 0
for rule_name, rule_config in rules['rules'].items():
weight = rule_config.get('weight', 1)
total_weight += weight
actual_value = activity.get(rule_name)
expected_min = rule_config.get('min')
passed = actual_value is not None and actual_value >= expected_min
if passed:
passed_weight += weight
results.append({
"rule": rule_name,
"expected": expected_min,
"actual": actual_value,
"passed": passed
})
score = passed_weight / total_weight if total_weight > 0 else 1.0
passed = score >= rules.get('pass_threshold', 0.6)
return {
"evaluated_at": datetime.now().isoformat(),
"passed": passed,
"score": round(score, 2),
"reasons": results,
"override": None
}
```
### Wann wird validiert?
1. **Beim Import** (CSV, API)
- Automatisch nach INSERT
- Spalte `quality_check` wird befüllt
2. **Beim manuellen Anlegen**
- Automatisch nach INSERT
- Spalte `quality_check` wird befüllt
3. **Beim Ändern der Quality Rules** (Admin)
- Optionaler Batch-Job: Alle Aktivitäten neu evaluieren
4. **Beim User-Override**
- User setzt `quality_check.override = "valid"` oder `"invalid"`
---
## User Experience
### 1. Activity-Liste (User-Ansicht)
```
┌─────────────────────────────────────────────────────────┐
│ Aktivitäten (März 2026) [Filter ▼] │
├─────────────────────────────────────────────────────────┤
│ │
│ 🏃 Laufen - 23. März 2026 │
│ 45 Minuten · Ø 142 bpm · 5.2 km │
│ ✅ Hochwertige Aktivität │
│ │
│ 🏃 Laufen - 22. März 2026 ⚠️ │
│ 8 Minuten · Ø 95 bpm · 0.8 km │
│ ⚠️ Niedrige Qualität - wird nicht gezählt │
│ [Details anzeigen ▼] │
│ │
│ → Dauer zu kurz (8 min < 15 min erforderlich)
│ → Durchschnittspuls zu niedrig (95 < 100)
│ → Maximalpuls OK (125 ≥ 120) ✅ │
│ │
│ [Als gültig markieren] [Als ungültig markieren] │
│ │
└─────────────────────────────────────────────────────────┘
```
**Filter-Optionen:**
- ☑ Hochwertige Aktivitäten
- ☑ Minderwertige Aktivitäten
- ☐ Nur in Statistiken gezählt
- ☐ Nur manuell überschrieben
### 2. Admin-UI (Quality Rules konfigurieren)
```
┌─────────────────────────────────────────────────────────┐
│ Trainingstyp bearbeiten: Laufen 🏃 │
├─────────────────────────────────────────────────────────┤
│ │
│ Kategorie: Cardio │
│ Name (DE): Laufen │
│ Name (EN): Running │
│ │
│ ━━━ Quality Gates ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ ☑ Quality Gates aktiviert │
│ │
│ Mindest-Schwellwerte: │
│ │
│ • Dauer (Minuten) [15] min Gewicht: ●●●○○ │
│ • Ø Herzfrequenz [100] bpm Gewicht: ●●○○○ │
│ • Max. Herzfrequenz [120] bpm Gewicht: ●○○○○ │
│ • Distanz [1.0] km Gewicht: ●○○○○ │
│ │
│ Erfolgs-Schwelle: [60]% (gewichteter Score) │
│ │
│ Beschreibung (User-sichtbar): │
│ "Mindestens 15 Minuten, Durchschnittspuls > 100" │
│ │
│ [Speichern] [Abbrechen] [Alle Aktivitäten neu prüfen]│
│ │
└─────────────────────────────────────────────────────────┘
```
### 3. Dashboard / Statistiken
**Transparenz:**
```
📊 Training (März 2026)
15 Aktivitäten erfasst
12 hochwertig ✅
3 minderwertig ⚠️ (werden nicht gezählt)
[Details zu minderwertigen Aktivitäten anzeigen]
```
---
## Betroffene Bereiche (Impact Analysis)
### 1. Aktivitäten-Listen
- **Query-Änderung:**
```sql
-- Alt:
SELECT * FROM activity_log WHERE profile_id = %s
-- Neu (nur hochwertige):
SELECT * FROM activity_log
WHERE profile_id = %s
AND (quality_check IS NULL
OR quality_check->>'passed' = 'true'
OR quality_check->>'override' = 'valid')
```
### 2. KI-Pipeline
- **insights.py:** Filter bei Daten-Aggregation
- Nur hochwertige Aktivitäten für KI-Prompts
### 3. Charts / Statistiken
- **Training Type Distribution:** Nur hochwertige zählen
- **Korrelations-Charts:** Separate Kurven für "alle" vs "hochwertig"?
### 4. Activity Import (CSV)
- Nach INSERT: `validate_activity_quality()` aufrufen
- Quality Check speichern
---
## Offene Fragen (für Entscheidung)
### Frage 1: Rückwirkende Evaluierung?
**Option A:** Nur neue Aktivitäten evaluieren
**Option B:** Alle bestehenden Aktivitäten nachträglich evaluieren
**Empfehlung:** Option B mit Batch-Job (einmalig beim Rollout)
### Frage 2: Standard-Verhalten bei fehlenden Quality Rules?
**Option A:** Alle Aktivitäten gelten als hochwertig (NULL = valid)
**Option B:** Alle Aktivitäten gelten als minderwertig (NULL = invalid)
**Empfehlung:** Option A (konservativ, keine Daten-Verlust-Angst)
### Frage 3: User-Override-Berechtigung?
**Option A:** Jeder User kann eigene Aktivitäten überschreiben
**Option B:** Nur Admin kann überschreiben
**Empfehlung:** Option A (User kennt seinen Kontext am besten)
### Frage 4: Wie viele Default-Rules?
**Option A:** Nur für Top 5 Trainingstypen (Laufen, Krafttraining, Radfahren, Schwimmen, HIIT)
**Option B:** Für alle 29 Trainingstypen
**Empfehlung:** Option A (Rest kann Admin/User nachpflegen)
### Frage 5: Quality Check in Liste anzeigen?
**Option A:** Immer sichtbar (Badge/Icon)
**Option B:** Nur bei minderwertigen Aktivitäten
**Empfehlung:** Option B (weniger visuelles Rauschen)
---
## Implementierungs-Reihenfolge (Vorschlag)
### Phase 1: Foundation (MVP)
1. DB-Migration: `quality_rules` + `quality_check` Spalten
2. Backend: `validate_activity_quality()` Funktion
3. Backend: Validierung beim INSERT (activity.py)
4. Admin-UI: Quality Rules konfigurieren (basic)
### Phase 2: User Experience
5. Frontend: Badge/Warning in Activity-Liste
6. Frontend: Details-Ansicht (welche Regeln failed?)
7. Frontend: User-Override (Als gültig/ungültig markieren)
### Phase 3: Integration
8. KI-Pipeline: Filter für hochwertige Aktivitäten
9. Charts: Nur hochwertige zählen
10. Batch-Job: Bestehende Aktivitäten evaluieren
### Phase 4: Polish
11. Admin-UI: Presets für gängige Trainingstypen
12. Filter-Optionen in Activity-Liste
13. Dashboard: Statistik hochwertig vs. minderwertig
**Geschätzter Aufwand:** 4-6 Stunden (mit Tests)
---
## Nächste Schritte
1. **Entscheidung:** Offene Fragen klären
2. **Technisches Design:** DB-Schema + API-Endpoints spezifizieren
3. **Implementation:** Phase 1 starten
4. **Testing:** Mit echten Apple Health Daten testen
---
**Erstellt:** 2026-03-23
**Review:** Pending User-Feedback

View File

@ -0,0 +1,458 @@
# Fachliche Anforderungen: KI-Prompt Flexibilisierung
**Modul:** v9f
**Status:** Fachlich freigegeben, technische Implementierung ausstehend
**Letzte Aktualisierung:** März 2026
---
## 1. Überblick
Das bestehende KI-Prompt-System wird von einer fixen Sammlung vordefinierter
Prompts zu einer vollständig konfigurierbaren Prompt-Bibliothek erweitert.
Admins können Prompts kategorisieren, duplizieren, bearbeiten und mit einem
visuellen Platzhalter-Browser ausstatten. Die Pipeline wird konfigurierbar
mehrere Konfigurationen für unterschiedliche Analysezwecke sind möglich.
---
## 2. Prompt-Bibliothek
### 2.1 Kategorien
Alle Prompts werden einer Kategorie zugeordnet:
| Kategorie | Beschreibung | Beispiel-Prompts |
|-----------|-------------|-----------------|
| Körper | Gewicht, KF, Umfänge, Caliper | Körperkomposition, Gewichtstrend |
| Ernährung | Kalorien, Makros, Timing | Kalorienbilanz, Proteinversorgung |
| Training | Volumen, Typen, HF | Trainingsanalyse, Erholungsstatus |
| Schlaf | Qualität, Dauer, Muster | Schlafauswertung, Schlaftrend |
| Vitalwerte | Ruhepuls, HRV, VO2Max | Leistungsfähigkeit, Erholung |
| Mentales | Stress, Stimmung, Energie | Wohlbefinden, Stressanalyse |
| Ziele | Fortschritt, Prognose, Zeitplan | Zielerreichung, Zeitplanung |
| Ganzheitlich | Korrelationen, Übersicht | Gesamtanalyse, Pipeline-Synthese |
### 2.2 Prompt-Verwaltung (Admin)
Ein Admin kann mit jedem Prompt folgendes tun:
**Aktivieren / Deaktivieren**
- Inaktive Prompts sind für Nutzer nicht sichtbar und nicht ausführbar
- Pipeline-Prompts können separat aktiviert/deaktiviert werden
**Duplizieren und anpassen**
- Bestehenden Prompt als Vorlage kopieren
- Kopie erhält Suffix " (Kopie)" und kann unabhängig bearbeitet werden
**Neu erstellen**
- Titel, Beschreibung, Kategorie, Template
- Platzhalter über den Platzhalter-Browser einfügen (siehe Abschnitt 3)
**Kategorie zuordnen**
- Beim Erstellen und Bearbeiten wählbar
- Nachträgliche Änderung möglich
**Reihenfolge festlegen**
- Drag & Drop oder Zahleneingabe (sort_order)
- Reihenfolge bestimmt Anzeige in der Nutzer-Ansicht
**Auf Standard zurücksetzen**
- Systemseitig definierte Prompts haben einen "Standard"-Zustand
- Reset stellt Original-Template wieder her
- Eigens erstellte Prompts haben keinen Standard-Reset
### 2.3 Prompt-Felder
Jeder Prompt hat:
- **Titel** kurzer Name (z.B. "Körperkomposition")
- **Beschreibung** wofür ist dieser Prompt? (für Admin sichtbar)
- **Kategorie** aus der Kategorienliste
- **Template** der eigentliche Prompt-Text mit Platzhaltern
- **Aktiv** true/false
- **Reihenfolge** Zahl für Sortierung
- **Typ** `single` (Einzelanalyse) oder `pipeline` (Pipeline-Stufe)
- **Pipeline-Stufe** nur bei Typ `pipeline`: Stufen-Nummer (1, 2, 3...)
---
## 3. Platzhalter-System
### 3.1 Platzhalter-Browser
Beim Bearbeiten eines Prompts steht ein visueller Platzhalter-Browser zur
Verfügung Admin tippt Platzhalter nicht mehr manuell, sondern wählt sie aus.
**Funktionen:**
- **Filterung nach Kategorie** zeigt nur Platzhalter der gewählten Kategorie
- **Beispielwert** zeigt was der Platzhalter aktuell mit echten Daten ausgeben würde
- **Klick zum Einfügen** Platzhalter wird an Cursor-Position ins Template eingefügt
- **Warnung bei fehlendem Platzhalter** wenn ein eingetippter Platzhalter nicht existiert
- **Warnung bei fehlenden Daten** wenn Daten für diesen Platzhalter nicht vorhanden sind (z.B. noch kein Schlaf-Tracking)
### 3.2 Prompt-Vorschau
Vor dem Speichern kann der Admin eine Vorschau anfordern:
- System befüllt alle Platzhalter mit echten aktuellen Daten
- Zeigt den fertigen Prompt-Text wie er an die KI gesendet würde
- KI wird dabei **nicht** aufgerufen nur der Prompt-Text wird angezeigt
### 3.3 Platzhalter-Kategorien und Übersicht
**Körper:**
```
{{weight_aktuell}} → "86,1 kg"
{{weight_trend}} → "sinkend (-0,8 kg letzte 4 Wochen)"
{{kf_aktuell}} → "19,9%"
{{kf_trend}} → "stabil"
{{magermasse}} → "69,4 kg"
{{whr}} → "0,90"
{{whtr}} → "0,51"
{{bmi}} → "27,2"
{{circ_summary}} → "Taille: 88cm, Hüfte: 98cm, ..."
{{caliper_summary}} → "KF nach Jackson/Pollock: 19,9%"
```
**Ernährung:**
```
{{kcal_avg}} → "1.847 kcal/Tag (Ø 30 Tage)"
{{protein_avg}} → "138g/Tag"
{{protein_ziel_low}} → "138"
{{protein_ziel_high}} → "172"
{{fat_avg}} → "72g/Tag"
{{carb_avg}} → "195g/Tag"
{{nutrition_summary}} → kompakte Zusammenfassung
{{nutrition_detail}} → ausführliche Tabelle
{{nutrition_days}} → "28 Tage mit Daten"
{{activity_kcal_summary}} → "Ø 320 kcal aktiver Verbrauch/Tag"
```
**Training:**
```
{{activity_summary}} → kompakte Zusammenfassung
{{activity_detail}} → ausführliche Liste
{{trainingstyp_verteilung}} → "60% Kraft, 30% Cardio, 10% Mobility"
{{trainingstyp_haupttyp}} → "Kraft" (häufigster Typ)
{{ruhetage_letzte_woche}} → "2"
{{trainingsphase}} → "Aufbau / Erholung / Plateau"
{{hf_zonen_verteilung}} → "Zone 2: 45%, Zone 3: 35%, Zone 4: 20%"
{{faehigkeiten_analyse}} → Detaillierte Analyse der trainierten Fähigkeiten
{{faehigkeiten_koordinativ}} → "Orientierung: 3/14 Einheiten, Gleichgewicht: 5/14, ..."
{{faehigkeiten_konditionell}} → "Kraft: 8/14, Ausdauer: 4/14, Schnelligkeit: 2/14, Flexibilität: 3/14"
{{faehigkeiten_kognitiv}} → "Konzentration: 2/14, Entscheidung: 1/14, ..."
{{faehigkeiten_psychisch}} → "Willenskraft: 5/14, Stressresistenz: 2/14, ..."
{{faehigkeiten_taktisch}} → "Timing: 1/14, Antizipation: 2/14, ..."
{{faehigkeiten_balance}} → "Ausgewogen / Einseitig + Empfehlung"
```
**Fähigkeiten-System (v9d Integration):**
- Jeder Trainingstyp ist mit 1-N Fähigkeiten aus 5 Dimensionen verknüpft
- KI erhält aggregierte Statistik: wie oft wurden welche Fähigkeiten trainiert
- Ermöglicht Aussagen wie: "Dein Training fokussiert stark auf Kraft (8 von 14 Einheiten), aber koordinative Fähigkeiten kommen zu kurz."
- Basis für gezielte Trainingsempfehlungen
**Herzfrequenz & Vitalwerte:**
```
{{ruhepuls_aktuell}} → "52 bpm"
{{ruhepuls_trend}} → "sinkend (-3 bpm letzte 4 Wochen)"
{{hrv_aktuell}} → "58 ms"
{{hrv_baseline}} → "62 ms (30-Tage-Durchschnitt)"
{{erholungsstatus}} → "gut / teilweise / schlecht"
{{vo2max}} → "48,2 ml/kg/min"
```
**Schlaf:**
```
{{schlaf_avg_dauer}} → "7,2h/Nacht (Ø 7 Tage)"
{{schlaf_qualitaet}} → "3,8/5 (Ø 7 Tage)"
{{schlaf_trend}} → "stabil"
{{schlaf_detail}} → ausführliche Tabelle
```
**Mentales:**
```
{{energie_niveau}} → "3,2/5 (Ø 7 Tage)"
{{stress_niveau}} → "2,8/5 (Ø 7 Tage)"
{{stimmung}} → "3,9/5 (Ø 7 Tage)"
{{meditation_streak}} → "5 Tage in Folge"
```
**Ziele:**
```
{{goal_weight}} → "82 kg"
{{goal_bf_pct}} → "14%"
{{goal_name}} → "Muskelaufbau"
{{ziel_fortschritt}} → "Gewicht: 72% erreicht, KF: 45% erreicht"
{{ziel_prognose}} → "Ziel voraussichtlich in 8 Wochen erreicht"
```
**Profil:**
```
{{name}} → "Lars"
{{geschlecht}} → "männlich"
{{height}} → "178"
{{age}} → "45"
{{sprache}} → "Deutsch" (konfigurierbar per Prompt)
```
**Zeitraum:**
```
{{zeitraum_7d}} → "letzte 7 Tage"
{{zeitraum_30d}} → "letzte 30 Tage"
{{zeitraum_90d}} → "letzte 90 Tage"
{{datum_heute}} → "20. März 2026"
```
**Pipeline (intern):**
```
{{stage1_body}} → JSON-Summary Körper (Pipeline-Stufe 1)
{{stage1_nutrition}} → JSON-Summary Ernährung
{{stage1_activity}} → JSON-Summary Training
{{stage1_sleep}} → JSON-Summary Schlaf (neu)
{{stage1_vitals}} → JSON-Summary Vitalwerte (neu)
```
---
## 4. Pipeline-Konfiguration
### 4.1 Was ist eine Pipeline-Konfiguration?
Eine Pipeline-Konfiguration definiert:
- **Name** z.B. "Alltags-Check", "Wettkampf-Analyse", "Schlaf-Fokus"
- **Aktive Module** welche Datenquellen fließen ein (Körper, Ernährung, Training, Schlaf, Vitalwerte, Mentales)
- **Zeitraum je Modul** z.B. Körper 30 Tage, Schlaf 7 Tage, Training 14 Tage
- **Stufen** welcher Prompt wird in welcher Stufe verwendet
- **Standard** eine Konfiguration kann als Standard markiert werden
### 4.2 Pipeline-Stufen
**Stufe 1 (parallel):** Mehrere Module-Prompts laufen gleichzeitig, jeder gibt ein JSON-Summary zurück
**Stufe 2:** Synthese-Prompt kombiniert alle Stage-1-Summaries zu einer narrativen Analyse
**Stufe 3 (optional):** Ziel-Abgleich oder spezifische Zusatzanalyse
Admin kann:
- Anzahl der Stufen festlegen (min. 2, max. 4)
- Jeden Stufen-Prompt zuweisen
- Module für Stufe 1 aktivieren/deaktivieren
### 4.3 Vordefinierte Konfigurationen (Beispiele)
**Alltags-Check (Standard):**
- Module: Körper (30T), Ernährung (30T), Training (14T)
- Stufe 1: pipeline_body + pipeline_nutrition + pipeline_activity
- Stufe 2: pipeline_synthesis
- Stufe 3: pipeline_goals
**Schlaf-Fokus:**
- Module: Schlaf (14T), Vitalwerte (7T), Training (14T)
- Stufe 1: pipeline_sleep + pipeline_vitals + pipeline_activity
- Stufe 2: pipeline_synthesis_sleep
**Wettkampf-Analyse:**
- Module: Körper (90T), Training (90T), Vitalwerte (30T), Ziele
- Stufe 1: alle Körper/Training/Vital-Module
- Stufe 2: pipeline_synthesis_performance
---
## 5. Nutzer-Ansicht: KI-Analyse starten
### 5.1 Einzelanalyse
1. Nutzer wählt Prompt aus der Bibliothek (nach Kategorie gefiltert)
2. KI-Analyse startet sofort
3. Ergebnis wird angezeigt und gespeichert
### 5.2 Pipeline
1. Nutzer wählt Pipeline-Konfiguration
2. Pipeline startet sofort (alle Stufen laufen automatisch)
3. Ergebnis wird angezeigt und gespeichert
### 5.3 Kein Konfigurationsschritt für Nutzer
Der Nutzer wählt nur Prompt oder Pipeline kein weiterer Konfigurationsschritt.
Zeitraum und Module sind durch Admin in der Pipeline-Konfiguration festgelegt.
---
## 6. Analyse-Ergebnisse verwalten
### 6.1 Kategorie-Zuordnung
Jedes gespeicherte Analyse-Ergebnis erbt die Kategorie des ausgeführten Prompts.
Ermöglicht spätere Filterung nach Kategorie.
### 6.2 Filtern nach Kategorie
Im Analyse-Verlauf kann nach Kategorie gefiltert werden:
- "Alle" / "Körper" / "Ernährung" / "Training" / etc.
### 6.3 Analyse-Verlauf pro Prompt
Für jeden Prompt ist ein Verlauf einsehbar:
- Liste aller bisherigen Analysen mit diesem Prompt (Datum + Kurzauszug)
- Zeigt wie sich die KI-Aussage über Zeit verändert hat
### 6.4 Favoriten
Nutzer kann Analysen als Favorit markieren (Stern-Symbol).
Favoriten sind in der Verlaufs-Ansicht filterbar.
### 6.5 Löschen
Nutzer kann einzelne Analyse-Ergebnisse manuell löschen.
Keine Massen-Löschung (außer Admin).
---
## 7. Sprache
Die Ausgabesprache wird im Prompt-Template selbst gesteuert über den
Platzhalter `{{sprache}}`. Der Wert wird aus den Profil-Einstellungen gezogen.
**Mögliche Werte:** "Deutsch", "Englisch", "Französisch" (erweiterbar)
**Standard:** "Deutsch"
Kein separater Sprach-Schalter auf der Analyse-Seite Sprache wird einmalig
im Profil konfiguriert.
---
## 8. Abgrenzung & offene Fragen
### In diesem Modul enthalten:
- Prompt-Bibliothek mit 8 Kategorien
- Vollständige Admin-Verwaltung (CRUD, Reihenfolge, Reset)
- Platzhalter-Browser mit Beispielwerten und Vorschau
- Pipeline-Konfigurationen (mehrere, speicherbar)
- Analyse-Ergebnisse: Kategorie, Filter, Verlauf, Favoriten, Löschen
- Sprach-Platzhalter
### Nicht in diesem Modul:
- Community-Prompts / Prompt-Import von extern → später
- KI-gestützte Prompt-Optimierung → später
- Automatisch geplante Analysen (z.B. wöchentlich) → später
- Prompts für noch nicht implementierte Module (Schlaf, Mentales) werden
vorbereitet aber haben keine echten Daten bis die Module existieren
### Offene Fragen für technische Planung:
1. Wie werden Pipeline-Konfigurationen gespeichert? (neue DB-Tabelle oder JSON in ai_prompts?)
2. Platzhalter-Definitionen: statisch im Code oder dynamisch in DB (für zukünftige Erweiterung)?
3. Wie wird der Beispielwert für den Platzhalter-Browser berechnet gleicher Endpunkt wie die echte Analyse?
4. Reihenfolge der Prompts: getrennte sort_order pro Kategorie oder global?
---
## 9. Trainingstypen & Fähigkeiten-Mapping (v9d → v9f Integration)
### 9.1 Hintergrund
In v9d wurde die Basis geschaffen:
- `training_types` Tabelle mit `abilities` JSONB-Spalte
- Admin-CRUD für Trainingstypen (ohne Abilities-UI)
- Taxonomie-Endpoint: `/api/admin/training-types/taxonomy/abilities`
- 5 Fähigkeiten-Dimensionen definiert:
- 🎯 **Koordinativ:** Orientierung, Differenzierung, Kopplung, Gleichgewicht, Rhythmus, Reaktion, Umstellung
- 💪 **Konditionell:** Kraft, Ausdauer, Schnelligkeit, Flexibilität
- 🧠 **Kognitiv:** Konzentration, Aufmerksamkeit, Wahrnehmung, Entscheidungsfindung
- 🎭 **Psychisch:** Motivation, Willenskraft, Stressresistenz, Selbstvertrauen
- ♟️ **Taktisch:** Timing, Strategie, Antizipation, Situationsanalyse
### 9.2 Was wird in v9f ergänzt?
**Admin-UI: Fähigkeiten-Matrix**
Im AdminTrainingTypesPage Formular wird eine Fähigkeiten-Matrix hinzugefügt:
- 5 Sections (eine pro Dimension)
- Pro Dimension: Checkboxes für alle Fähigkeiten
- Multi-Select: Ein Trainingstyp kann mehrere Fähigkeiten pro Dimension trainieren
- Beispiel: "Kampfsport-Sparring" trainiert:
- Koordinativ: Orientierung, Reaktion, Umstellung
- Konditionell: Schnelligkeit, Ausdauer
- Kognitiv: Entscheidung, Wahrnehmung
- Psychisch: Stressresistenz, Selbstvertrauen
- Taktisch: Timing, Antizipation
**Gespeichert als JSONB:**
```json
{
"koordinativ": ["orientierung", "reaktion", "umstellung"],
"konditionell": ["schnelligkeit", "ausdauer"],
"kognitiv": ["entscheidung", "wahrnehmung"],
"psychisch": ["stressresistenz", "selbstvertrauen"],
"taktisch": ["timing", "antizipation"]
}
```
**Backend: Fähigkeiten-Aggregation**
Neue Endpoint-Funktion (oder Platzhalter-Funktion):
```python
def calculate_abilities_summary(profile_id, days=14):
"""
Aggregiert trainierte Fähigkeiten über Zeitraum.
Returns:
{
"total_activities": 14,
"koordinativ": {
"orientierung": 3, # 3 von 14 Trainings
"gleichgewicht": 5,
...
},
"konditionell": {
"kraft": 8,
"ausdauer": 4,
...
},
...
"balance_score": 0.67, # 0-1, wie ausgewogen
"top_dimension": "konditionell",
"weak_dimension": "kognitiv"
}
"""
```
**KI-Prompt Integration:**
Die Fähigkeiten-Platzhalter werden befüllt mit aggregierten Daten:
- `{{faehigkeiten_analyse}}` → vollständige Aufschlüsselung
- `{{faehigkeiten_koordinativ}}` → nur koordinative Dimension
- etc.
Pipeline-Prompt "Training" erhält zusätzlichen Context:
```
Analyse die Fähigkeitenverteilung:
{{faehigkeiten_analyse}}
Gib Empfehlungen für untertrainierte Bereiche.
```
### 9.3 Nutzen für KI-Analyse
**Beispiel-Insight:**
> "Deine letzten 14 Trainings fokussieren stark auf **konditionelle Fähigkeiten** (Kraft: 8×, Ausdauer: 4×). Koordinative Fähigkeiten kommen zu kurz (nur 3× Gleichgewicht, 2× Reaktion). Für einen ausgewogenen Trainingsplan empfehle ich 2-3 koordinationslastige Einheiten pro Woche z.B. Kampfsport-Techniktraining, Balance-Übungen oder Mobility-Routinen mit Fokus auf Bewegungskontrolle."
**Korrelationen:**
- Verletzungen / Überlastung ↔ Koordinations-Defizit
- Plateaus im Krafttraining ↔ fehlende kognitive/taktische Komponente
- Erholungsprobleme ↔ psychische Fähigkeiten untertrainiert
### 9.4 Implementierungs-Reihenfolge
1. ✅ v9d Phase 1b: DB-Schema + Admin-CRUD (ohne Abilities-UI) → **erledigt**
2. 🔲 v9f: Abilities-Matrix UI im Admin-Formular
3. 🔲 v9f: Backend-Funktion `calculate_abilities_summary()`
4. 🔲 v9f: Platzhalter `{{faehigkeiten_*}}` implementieren
5. 🔲 v9f: Standard-Prompts aktualisieren mit Fähigkeiten-Context
6. 🔲 v9f: Admin-Doku: "Best Practices" für Fähigkeiten-Zuordnung
---
EOF
echo "OK"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,417 @@
# Entwicklungsrouten Multi-Dimensionales Training & Planung
**Version:** 1.0
**Status:** Konzept
**Ziel-Release:** v9e / v9f
**Basis:** Rest Days Multi-Dimensional Architecture (v9d Phase 2a)
---
## Überblick
**Entwicklungsrouten** sind unabhängige Dimensionen der körperlichen und mentalen Entwicklung, die jeweils eigene:
- Trainingspläne
- Ruhetag-Regeln
- Fortschritts-Tracking
- Ziele
haben.
**Kernidee:** Ein Tag kann gleichzeitig ein "Kraft-Ruhetag" UND ein "Mental-Aktivtag" sein.
---
## Die 6 Entwicklungsrouten
### 1. 💪 Kraft (Strength)
**Fokus:** Muskelaufbau, Maximalkraft, Power
**Trainingstypen:**
- Strength (Krafttraining allgemein)
- Power (Schnellkraft, Explosivität)
- HIIT (Hochintensiv)
**Ruhetag-Regeln:**
- Nach schwerer Beineinheit → 48-72h Kraft-Ruhetag
- Andere Routen (Cardio, Mental) bleiben erlaubt
- Intensität: Max 60% bei erlaubten Aktivitäten
**Metriken:**
- Gewicht, Umfänge, Caliper
- 1RM-Schätzung (optional)
- Muskelregeneration (Ruhepuls + HRV)
---
### 2. 🏃 Kondition (Conditioning)
**Fokus:** Ausdauer, VO2Max, Herz-Kreislauf
**Trainingstypen:**
- Cardio Low (GA1, Grundlagenausdauer)
- Cardio High (GA2, Tempo-Läufe)
- Endurance (Lange Einheiten)
**Ruhetag-Regeln:**
- Nach Wettkampf/Tempo-Lauf → 24-48h Cardio-Ruhetag
- Kraft & Mobility erlaubt
- Intensität: Max 70% HFmax
**Metriken:**
- HF-Zonen-Verteilung
- VO2Max-Schätzung
- Lauf-Pace / Rad-Watt
---
### 3. 🧘 Mental (Mental)
**Fokus:** Stressmanagement, Fokus, Wettkampf-Readiness
**Trainingstypen:**
- Meditation
- Wettkampf (Competition)
- High-Pressure Training
**Ruhetag-Regeln:**
- Nach Wettkampf → 1-3 Tage Mental-Ruhetag
- Physisches Training erlaubt (aber kein Wettkampf-Druck)
- Nur entspannende Aktivitäten (Meditation, Spaziergang)
**Metriken:**
- Stresslevel (1-5 subjektiv)
- Schlafqualität
- HRV (Mental-Recovery-Indikator)
---
### 4. 🤸 Koordination (Coordination)
**Fokus:** Balance, Agilität, Reaktion, propriozeptives Training
**Trainingstypen:**
- Coordination (Agilität, Balance)
- Sport-spezifische Drills
- Reaktionstraining
**Ruhetag-Regeln:**
- Nach intensivem Koordinationstraining → 24h Pause
- Andere Routen erlaubt
- Kein koordinativ anspruchsvolles Training bei Müdigkeit
**Metriken:**
- Subjektive Koordinations-Scores
- Balance-Tests (optional)
---
### 5. 🧘‍♂️ Mobilität (Mobility)
**Fokus:** Flexibilität, ROM (Range of Motion), Faszien
**Trainingstypen:**
- Mobility (Stretching, Yoga)
- Faszien-Training
- Passive Dehnung
**Ruhetag-Regeln:**
- Normalerweise kein Ruhetag nötig
- Bei Überdehnung / Verletzung → Pause für betroffene Bereiche
**Metriken:**
- ROM-Messungen (optional)
- Subjektive Beweglichkeit (1-5)
---
### 6. 🎯 Technik (Technique)
**Fokus:** Sport-spezifische Skills, Bewegungsqualität
**Trainingstypen:**
- Technique Drills
- Skill Work
- Video-Analyse
**Ruhetag-Regeln:**
- Technik-Training bei Müdigkeit kontraproduktiv
- Mental-Ruhetag → auch Technik pausieren
- Physisches Training erlaubt (ohne Technik-Fokus)
**Metriken:**
- Video-Analyse-Scores (optional)
- Coach-Feedback
---
## Datenmodell
### rest_days (Multi-Entry per Date)
**Änderung:** UNIQUE constraint `(profile_id, date)` entfernt (Migration 011)
**Erlaubt:**
```sql
-- Gleiches Datum, verschiedene Routen:
INSERT INTO rest_days (profile_id, date, rest_config, note)
VALUES
('user-1', '2026-03-23', '{"focus": "muscle_recovery", ...}', 'Beine heavy'),
('user-1', '2026-03-23', '{"focus": "mental_rest", ...}', 'Wettkampf-Pause');
```
**UI:**
```
23. März 2026
💪 Muskelregeneration | "Beine heavy"
🧘 Mental Rest | "Wettkampf-Pause"
→ Cardio erlaubt, Kraft pausiert, keine Wettkämpfe
```
---
## Wochenplanung mit Routen
### Tabelle: weekly_goals (erweitert)
**JSONB Schema:**
```json
{
"routes": {
"strength": {
"goal": 3, // 3x Kraft pro Woche
"min_rest_days": 1, // Mind. 1 Kraft-Ruhetag
"intensity_distribution": {
"heavy": 1, // 1x schwer (80-90%)
"medium": 1, // 1x mittel (70-80%)
"light": 1 // 1x leicht (60-70%)
}
},
"conditioning": {
"goal": 2,
"min_rest_days": 0,
"hr_zones": {
"zone_2": 60, // 60% der Zeit in Zone 2
"zone_3": 30, // 30% in Zone 3
"zone_4": 10 // 10% in Zone 4
}
},
"mental": {
"goal": 7, // Täglich Meditation
"min_duration": 10, // Mind. 10 Min
"rest_after_competition": 2 // 2 Tage Pause nach Wettkampf
}
},
"rules": {
"max_consecutive_strength": 2, // Max 2 Krafteinheiten hintereinander
"require_rest_after": ["competition", "strength_heavy"],
"auto_rest_on_poor_recovery": true // Bei HRV < Baseline Auto-Ruhetag
}
}
```
---
## Activity Validation mit Routen
### Endpoint: `POST /api/rest-days/validate-activity`
**Request:**
```json
{
"date": "2026-03-23",
"activity_type": "strength",
"route": "strength" // Neue Dimension
}
```
**Response:**
```json
{
"conflicts": [
{
"route": "strength",
"severity": "warning",
"message": "Kraft-Ruhetag Muskelregeneration nach Beineinheit. Trotzdem trainieren?"
}
],
"allowed": false
}
```
**Logik:**
```python
def validate_activity_multi_route(profile_id, date, activity_type, route=None):
"""
Prüft alle rest_days für das Datum.
- Wenn route angegeben: Nur diese Route prüfen
- Sonst: Alle passenden Routen prüfen
"""
rest_days = get_rest_days(profile_id, date)
conflicts = []
for rest_day in rest_days:
config = rest_day['rest_config']
# Prüfe ob Activity in rest_from
if activity_type in config.get('rest_from', []):
conflicts.append({
'route': config['focus'],
'severity': 'warning',
'message': f"{ROUTE_LABELS[config['focus']]} Ruhetag {activity_type} sollte pausiert werden."
})
return {
'conflicts': conflicts,
'allowed': len(conflicts) == 0
}
```
---
## Habits & Streaks pro Route
### Tabelle: route_habits (neu in v9f)
```sql
CREATE TABLE route_habits (
id SERIAL PRIMARY KEY,
profile_id UUID NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
route VARCHAR(20) NOT NULL, -- 'strength', 'conditioning', 'mental', etc.
habit_type VARCHAR(50) NOT NULL, -- 'meditation', 'mobility', 'strength_training'
frequency VARCHAR(20) NOT NULL, -- 'daily', 'weekly_3', 'weekly_5'
streak_current INTEGER DEFAULT 0,
streak_longest INTEGER DEFAULT 0,
last_completed DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
**Beispiele:**
- Mental-Route: "Tägliche Meditation" (7x/Woche)
- Mobility-Route: "Stretching" (3x/Woche)
- Strength-Route: "Krafttraining" (3x/Woche)
**UI:**
```
🧘 Mental-Route
Meditation 🔥 12 Tage Streak
Stress-Check 🔥 5 Tage Streak
💪 Kraft-Route
Krafttraining 🔥 2 Wochen Streak
Protein > 150g 🔥 10 Tage Streak
```
---
## Dashboard Integration
### Route-Übersicht Widget
```
Entwicklungsrouten (diese Woche)
─────────────────────────────────────
💪 Kraft 2/3 [██░] 1 Ruhetag
🏃 Kondition 1/2 [█░░] 0 Ruhetage
🧘 Mental 7/7 [███] ✓ Täglich
🤸 Koordination 0/1 [░░░] Geplant: Do
🧘‍♂️ Mobilität 3/3 [███] ✓ Ziel erreicht
Empfehlung: Kraft-Training heute, Cardio morgen
```
---
## KI-Integration
### Neue Platzhalter (v9f)
```python
{{route_balance}} # "Kraft überlastet, Cardio unterfordert"
{{route_progress_strength}} # "3/3 Einheiten, +2kg seit letztem Monat"
{{route_recovery_strength}} # "Gut erholt, schweres Training möglich"
{{route_next_recommended}} # "Kraft-Oberkörper empfohlen (Push-Fokus)"
{{route_conflict_today}} # "Kraft-Ruhetag, Cardio/Mental erlaubt"
```
### KI-Analyse-Funktion
```python
def analyze_route_balance(profile_id, weeks=4):
"""
Analysiert Balance über alle Routen.
Warnt bei:
- Übertraining in einer Route
- Vernachlässigung einer Route
- Fehlende Ruhetage in Route
"""
routes = ['strength', 'conditioning', 'mental', 'coordination', 'mobility']
analysis = {}
for route in routes:
activities = get_activities_by_route(profile_id, route, weeks)
rest_days = get_rest_days_by_route(profile_id, route, weeks)
analysis[route] = {
'activity_count': len(activities),
'rest_days_count': len(rest_days),
'intensity_avg': calculate_intensity_avg(activities),
'status': calculate_route_status(activities, rest_days) # 'balanced', 'overload', 'neglected'
}
return analysis
```
---
## Implementierungs-Phasen
### Phase 1: Foundation (v9d Phase 2a) ✅
- ✅ Migration 011: UNIQUE constraint entfernen
- ✅ Multiple rest_days per date erlauben
- ✅ UI: Mehrere Kacheln pro Tag anzeigen
### Phase 2: Route-Konzept (v9e)
- 🔲 Routen-Taxonomie festlegen (6 Routen)
- 🔲 Activity-Types den Routen zuordnen
- 🔲 `training_types` Tabelle um `route` Spalte erweitern
- 🔲 Validation: Multi-Route-Konflikt-Check
### Phase 3: Wochenplanung (v9f)
- 🔲 `weekly_goals` mit Routen-JSONB erweitern
- 🔲 Planungs-UI: Routen-basierte Wochenansicht
- 🔲 Regeln-Engine: Auto-Ruhetag bei Poor Recovery
- 🔲 Empfehlungs-System: "Heute: Kraft-Oberkörper empfohlen"
### Phase 4: Habits & Streaks (v9g)
- 🔲 `route_habits` Tabelle
- 🔲 Streak-Tracking pro Route
- 🔲 Dashboard-Integration
- 🔲 Push-Notifications bei Streak-Gefahr
### Phase 5: KI-Integration (v9f/g)
- 🔲 Route-Balance-Analyse
- 🔲 Übertraining-Warnung pro Route
- 🔲 Neue KI-Platzhalter
- 🔲 Route-spezifische Empfehlungen
---
## Offene Fragen
1. **Route-Hierarchie:** Gibt es Abhängigkeiten? (z.B. Mental-Rest → auch Technik-Rest?)
2. **Auto-Zuordnung:** Sollen Activities automatisch Routen zugeordnet werden? (Strength → Kraft-Route)
3. **Konflikt-Priorität:** Was passiert bei widersprüchlichen Ruhetagen? (Kraft erlaubt, Mental verbietet → ?)
4. **Routen-Gewichtung:** Sind manche Routen wichtiger als andere? (User-konfigurierbar?)
---
## Referenzen
- **Migration:** `backend/migrations/011_allow_multiple_rest_days_per_date.sql`
- **Technical Spec:** `.claude/docs/technical/V9D_PHASE2_VITALS_SLEEP.md` (zu aktualisieren)
- **Routen-Mapping:** `.claude/docs/functional/TRAINING_TYPES.md` (zu erweitern)
---
**Dokumentiert:** 2026-03-22
**Autor:** User Konzept + Claude Implementation
**Status:** Living Document (wird mit v9e/f erweitert)

View File

@ -0,0 +1,329 @@
# Fachliche Anforderungen: Ziele, Vitalwerte & Aktive Tests
**Modul:** v9e
**Status:** Fachlich freigegeben, technische Implementierung ausstehend
**Letzte Aktualisierung:** März 2026
---
## 1. Überblick
Dieses Modul erweitert Mitai Jinkendo um drei eng verbundene Bereiche:
1. **Ziele** Nutzer definiert konkrete Zielwerte (Gewicht, KF, Kondition etc.)
2. **Trainingsphasen** Automatische Erkennung der aktuellen Phase aus Daten
3. **Aktive Tests** Standardisierte Fitness-Tests zur Messung nicht-trackbarer Werte
4. **Vitalwerte** Blutdruck, SpO2, HRV, Temperatur, Blutzucker
Die KI verbindet alle vier Bereiche: Sie schlägt Zielwerte vor, erkennt Phasen,
empfiehlt Tests und passt Analysen an die aktuelle Phase an.
---
## 2. Ziele
### 2.1 Unterstützte Zieltypen
| Zieltyp | Felder | Einheit |
|---------|--------|---------|
| Gewichtsziel | Zielgewicht + Zieldatum | kg, Datum |
| Körperfett-Ziel | Ziel-KF% | % |
| Magermasse-Ziel | Ziel-Magermasse | kg |
| Konditionsziel | Ziel-VO2Max | ml/kg/min |
| Kraftziel | Übungsname + Zielwiederholungen/-gewicht | Wdh. oder kg |
| Flexibilitätsziel | Ziel-Sit&Reach | cm |
| Blutdruck-Zielbereich | Systolisch / Diastolisch | mmHg |
| Ruhepuls-Ziel | Ziel-Ruhepuls | bpm |
### 2.2 Ziel-Verwaltung
**Aktives Ziel:**
- **Unbegrenzt viele Ziele** können gleichzeitig aktiv sein
- Ein Ziel kann als **Primärziel** markiert werden dieses bestimmt
Dashboard-Fokus und KI-Analyse-Ausrichtung
- Alle anderen aktiven Ziele sind gleichwertige Nebenziele
**Ziel-Lebenszyklus:**
```
Entwurf → Aktiv → Erreicht / Aufgegeben / Abgelaufen
```
**Ziel-Geschichte:**
- Alle vergangenen Ziele bleiben gespeichert
- Fortschrittsverlauf je Ziel einsehbar
### 2.3 Ziel-Anzeige
**Dashboard-Widget (kompakt):**
- Zeigt alle aktiven Ziele als kompakte Karten
- Je Ziel: Name + Fortschrittsbalken (aktuell vs. Zielwert in %)
- Countdown bis Zieldatum (z.B. "noch 42 Tage")
- Prognose: "auf Kurs" / "X Tage früher" / "X Tage Verzögerung"
- Klick öffnet die Ziele-Seite
**Eigene Ziele-Seite (Navigation):**
- Vollständige Übersicht aller aktiven + vergangenen Ziele
- Je Ziel: Detailansicht mit Verlauf, Trend, Prognose
- Aktionen: Ziel bearbeiten / pausieren / als erreicht markieren / löschen
- "+ Neues Ziel" Button
**Fortschrittsbalken:**
```
Gewichtsziel: 86,1 kg → 82 kg
████████░░ 72% erreicht (noch 4,1 kg)
Prognose: 30.05.2026 ✓ auf Kurs
```
**Countdown:**
- Zeigt Tage bis Zieldatum
- Farbcodierung: grün (auf Kurs) / gelb (leicht hinter Plan) / rot (deutlich hinter Plan)
### 2.4 KI-Zielvorschläge
Die KI analysiert aktuelle Werte und schlägt realistische Zielwerte vor:
**Beispiele:**
- Gewichtsziel: "Basierend auf deinem aktuellen Gewicht von 86 kg und Kalorientrend
wäre ein Ziel von 82 kg in 12 Wochen realistisch (+0,5 kg/Woche Defizit)"
- Ruhepuls-Ziel: "Dein Ruhepuls liegt bei 58 bpm. Ein Ziel von 52 bpm ist bei
konsequentem Ausdauertraining in 16 Wochen erreichbar"
- KF-Ziel: "Von 19,9% auf 16% sind ~3,9 Prozentpunkte realistisch in 14 Wochen
bei Kaloriendefizit + Krafttraining"
**Vorschlag-Trigger:**
- Beim erstmaligen Anlegen eines Ziels
- Wenn kein aktives Ziel vorhanden
- Auf explizite Anfrage ("Neues Ziel vorschlagen")
---
## 3. Trainingsphasen
### 3.1 Unterstützte Phasen
| Phase | Erkennungsmerkmale | Empfohlene Strategie |
|-------|-------------------|---------------------|
| Kaloriendefizit | Kcal-Bilanz < -300/Tag (Ø 7T), Gewicht sinkend | Krafttraining erhalten, Cardio moderat |
| Kalorienstabilisierung | Kcal-Bilanz -100 bis +100/Tag, Gewicht stabil | Ausgeglichenes Training |
| Kalorienüberschuss | Kcal-Bilanz > +300/Tag, Gewicht steigend | Krafttraining priorisieren |
| Konditionsaufbau | >60% Cardio-Anteil, VO2Max-Trend steigend | Zone 2 Training ausbauen |
| Schnellkraft / HIIT | >40% HIIT/Schnellkraft, HF-Zonen 4-5 dominant | Erholung beachten |
| Maximalkraft-Aufbau | >50% Krafttraining, Hypertrophie/Maximalkraft | Progressive Überlastung |
| Regeneration | Trainingsvolumen -40% vs. Vorwoche, HRV niedrig | Aktive Erholung, Schlaf |
| Wettkampfvorbereitung | Nutzer-definiert mit Datum | Periodisierung, Peak-Performance |
### 3.2 Phasenerkennung
**Automatische Erkennung:**
- System analysiert letzte 14 Tage: Kalorienbilanz, Trainingstypen, Volumen, HRV, Ruhepuls
- Schlägt erkannte Phase als Benachrichtigung vor
- Erkennungs-Intervall: täglich (Hintergrund)
**Nutzer-Bestätigung:**
- Vorschlag erscheint als Banner: "Wir haben erkannt: Du befindest dich in einer
Kaloriendefizit-Phase. Stimmt das?"
- Optionen: ✓ Bestätigen / ✗ Ablehnen / ✎ Anpassen
- Manuelles Setzen jederzeit möglich
**Phasenwechsel-Erkennung:**
- Automatisch erkannt wenn Datenmuster **7 Tage konsistent** einer neuen Phase entspricht
- Erst nach dieser Stabilitätsprüfung wird der Wechsel vorgeschlagen
- Verhindert falsche Alarme bei kurzzeitigen Abweichungen (z.B. Urlaub, Krankheit)
- Nutzer wird benachrichtigt: "Phasenwechsel erkannt: Kaloriendefizit → Stabilisierung"
### 3.3 Phase und Dashboard
- Aktuelle Phase prominent auf Dashboard angezeigt (Badge/Label)
- Dashboard-Kennzahlen passen sich an Phase an:
- Kaloriendefizit: Kaloriendefizit/Tag als Hauptkennzahl
- Muskelaufbau: Proteinversorgung + Trainingsvolumen prominent
- Kondition: VO2Max-Trend + Cardio-Anteil prominent
---
## 4. Aktive Tests
### 4.1 Konzept
Aktive Tests messen Fitness-Parameter die nicht aus passivem Tracking ableitbar sind.
Jeder Test hat:
- **Durchführungsanleitung** (Schritt-für-Schritt in der App)
- **Messung** (Eingabe des Ergebnisses)
- **Auswertung** (Einordnung nach Alter/Geschlecht + Trend)
- **Testintervall** (empfohlene Wiederholung)
- **KI-Verknüpfung** (Ergebnis fließt in Analyse ein)
### 4.2 Standardtests
#### Cooper-Test (Ausdauer / VO2Max)
- **Ziel:** VO2Max-Schätzung
- **Durchführung:** 12 Minuten laufen, maximale Distanz messen
- **Eingabe:** Distanz in Metern
- **Berechnung:** `VO2Max = (Distanz - 504.9) / 44.73`
- **Intervall:** alle 46 Wochen
- **Anleitung in App:** Aufwärmen 5 min → 12 min laufen → Distanz eingeben
#### Stufentest (Herzfrequenz-Ausdauer)
- **Ziel:** Aerobe Schwelle, HF-Zonen kalibrieren
- **Durchführung:** Steigende Belastung (Laufen/Radfahren), HF alle 3 min notieren
- **Eingabe:** HF-Werte je Stufe (5 Stufen à 3 min)
- **Auswertung:** HF-Kurve, Schwellenbestimmung
- **Intervall:** alle 68 Wochen
#### Liegestützen-Test (Kraftausdauer Oberkörper)
- **Ziel:** Maximale Liegestützen ohne Pause
- **Eingabe:** Anzahl Wiederholungen
- **Einordnung:** Normwerte nach Alter/Geschlecht
- **Intervall:** alle 4 Wochen
#### Kniebeugen-Test (Kraftausdauer Unterkörper)
- **Ziel:** Maximale Kniebeugen ohne Pause
- **Eingabe:** Anzahl Wiederholungen
- **Einordnung:** Normwerte nach Alter/Geschlecht
- **Intervall:** alle 4 Wochen
#### Sit & Reach (Flexibilität)
- **Ziel:** Rumpf- und Beinflexibilität messen
- **Durchführung:** Sitzen, Beine gestreckt, Oberkörper vorbeugen, maximale Reichweite
- **Eingabe:** cm (positiv = über Fußsohle, negativ = davor)
- **Einordnung:** Normwerte nach Alter/Geschlecht
- **Intervall:** alle 4 Wochen
#### Gleichgewichtstest (Einbeinstand)
- **Ziel:** Propriozeption, Gleichgewicht
- **Durchführung:** Einbeinstand mit geschlossenen Augen, Zeit messen
- **Eingabe:** Sekunden (bestes von 3 Versuchen)
- **Einordnung:** <10s = verbesserungswürdig, 10-30s = gut, >30s = sehr gut
- **Intervall:** alle 4 Wochen
#### Griffstärke
- **Ziel:** Allgemeine Kraftindikator, Gesundheitsmarker
- **Durchführung:** Dynamometer oder Schätzung (maximaler Händedruck)
- **Eingabe:** kg (oder subjektiv 1-5 wenn kein Gerät)
- **Intervall:** alle 4 Wochen
#### Benutzerdefinierter Test
- **Ziel:** Eigene Tests anlegen
- **Felder:** Name, Beschreibung, Einheit, Eingabetyp (Zahl/Zeit/Skala)
- **Einordnung:** Manuelle Referenzwerte (gut/mittel/verbesserungswürdig)
- **Intervall:** Frei wählbar
### 4.3 Test-Verwaltung
**Test-Historie:**
- Alle Testergebnisse chronologisch gespeichert
- Trend über Zeit sichtbar (Liniengrafik pro Test)
- Verbesserung in % seit letztem Test
**Test-Kalender:**
- Übersicht: welche Tests wann fällig
- KI empfiehlt: "Cooper-Test ist seit 5 Wochen überfällig"
**Normwerte:**
- Einordnung nach Alter (in Profil hinterlegt) und Geschlecht
- Kategorien: Sehr gut / Gut / Durchschnittlich / Verbesserungswürdig
- Quelle: Etablierte Fitness-Normtabellen
---
## 5. Vitalwerte
### 5.1 Erfasste Vitalwerte
| Vitalwert | Felder | Einheit | Warnbereich |
|-----------|--------|---------|-------------|
| Blutdruck | Systolisch + Diastolisch + Puls | mmHg | >140/90 = erhöht |
| SpO2 | Sauerstoffsättigung | % | <95% = Warnung |
| HRV | Herzratenvariabilität | ms | persönliche Baseline |
| Körpertemperatur | Temperatur | °C | >37,5°C = erhöht |
| Blutzucker | Nüchtern-Wert | mg/dl oder mmol/l | >100 mg/dl nüchtern |
### 5.2 Erfassung
- Manuelle Eingabe mit Datum + Uhrzeit
- Import aus Apple Health (wenn vorhanden)
- Messkontext optional: Nüchtern / Nach Sport / Morgens / Abends
### 5.3 Auswertung
- Trend über Zeit je Vitalwert
- Ampel-System: Grün (normal) / Gelb (Grenzbereich) / Rot (außerhalb Normbereich)
- Korrelation: Blutdruck ↔ Training, Blutdruck ↔ Gewicht
- **Hinweis in App:** Vitalwerte ersetzen keine ärztliche Diagnose
---
## 6. KI-Analyse
### 6.1 Neue KI-Platzhalter
```
{{primärziel_typ}} → "Gewichtsabnahme"
{{primärziel_wert}} → "82 kg bis 30.06.2026"
{{primärziel_fortschritt}} → "72% erreicht (4 kg von 5,5 kg)"
{{primärziel_prognose}} → "Ziel voraussichtlich in 6 Wochen erreicht"
{{aktuelle_phase}} → "Kaloriendefizit"
{{phase_seit}} → "seit 14 Tagen"
{{phase_empfehlung}} → "Krafttraining erhalten, Cardio moderat"
{{test_letzter}} → "Cooper-Test: 2.800m (VO2Max ~52) vor 3 Wochen"
{{test_faellig}} → "Sit & Reach (seit 5 Wochen nicht gemacht)"
{{vitalwerte_blutdruck}} → "125/82 mmHg (letzter Wert)"
{{vitalwerte_spo2}} → "98% (letzter Wert)"
{{vitalwerte_trend}} → "Blutdruck stabil, SpO2 normal"
{{fitness_score}} → "Kondition: gut · Kraft: durchschnittlich · Flex: verbesserungswürdig"
```
### 6.2 KI-Analyse-Funktionen
**Zielwerte vorschlagen:**
- Trigger: kein aktives Ziel oder auf Anfrage
- Basis: aktuelle Messwerte + historischer Trend + Alter/Geschlecht
- Output: konkreter Zielwert + realistischer Zeitrahmen + Begründung
**Phase automatisch erkennen:**
- Tägliche Hintergrundanalyse
- Kalorienbilanz + Trainingstypen + Gewichtstrend + HRV
- Output: Phasen-Vorschlag mit Begründung
**Test empfehlen wenn fällig:**
- Prüft Testintervall vs. letztes Ergebnis
- Output: "Cooper-Test ist seit X Wochen fällig führe ihn durch um deinen
VO2Max-Trend zu aktualisieren"
**Fortschritt mit Prognose:**
- Lineare Extrapolation aktueller Trend → Zieldatum
- Output: "Bei aktuellem Tempo erreichst du dein Gewichtsziel in 6 Wochen
(statt geplanter 8 Wochen)"
**Empfehlungen an Phase anpassen:**
- KI-Analysen berücksichtigen aktuelle Phase
- Beispiel in Kaloriendefizit-Phase: Protein-Empfehlung erhöht,
Krafttraining-Empfehlung priorisiert, Schlafmangel-Warnung verstärkt
- Beispiel in Wettkampf-Phase: Erholungsstatus und Tapering im Fokus
---
## 7. Abgrenzung & offene Fragen
### In diesem Modul enthalten:
- 8 Zieltypen mit Primärziel-Konzept
- 8 Trainingsphasen + automatische Erkennung + Nutzerbestätigung
- 8 Standardtests + benutzerdefinierte Tests
- Normwerte-Einordnung nach Alter/Geschlecht
- 5 Vitalwerte mit Ampel-System
- 13 neue KI-Platzhalter
- 5 KI-Analyse-Funktionen
### Nicht in diesem Modul:
- Periodisierungsplaner (Makro-/Mikrozyklen) → später
- Ärztliche Auswertung / Diagnose → bewusst ausgeschlossen
- Automatische Smartwatch-Tests → v9h Connectoren
- Ernährungsplan-Generator → später
### Offene Fragen für technische Planung:
1. Ziele: eigene Tabelle `goals` oder als JSONB in `profiles`?
2. Phasenerkennung: täglicher Cron-Job im Backend oder Frontend-Berechnung?
3. Aktive Tests: generisches Schema (test_type + result_value + result_unit)
oder je Test eigene Felder?
4. Normwerte: in DB gespeichert oder als statische JSON-Datei im Backend?
5. Fitness-Score: wie wird er aus mehreren Tests aggregiert (gewichteter Durchschnitt)?
6. Vitalwerte: eigene Tabelle je Typ oder generische `vitals_log` Tabelle?
7. Phasen-Vorschlag: als Push-Notification oder nur In-App-Banner?
EOF

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,228 @@
# Fachliche Anforderungen: Responsive UI
**Modul:** parallel zu Features (kein festes Versions-Label)
**Status:** Fachlich freigegeben, technische Implementierung ausstehend
**Letzte Aktualisierung:** März 2026
---
## 1. Überblick
Die App soll vollständig responsive sein und auf allen Bildschirmgrößen optimal
funktionieren vom iPhone über iPad bis zum Desktop-Browser. Die PWA-Funktionalität
auf dem iPhone bleibt vollständig erhalten.
---
## 2. Breakpoints
| Bereich | Breite | Layout |
|---------|--------|--------|
| Mobile | < 1024px | Bottom Navigation (wie jetzt) |
| Desktop | ≥ 1024px | Sidebar Navigation links, Content rechts |
Ein separates Tablet-Layout (768px) wird **nicht** eingeführt unterhalb
1024px verhält sich alles wie Mobile.
---
## 3. Mobile Layout (< 1024px) unverändert
Das bestehende Mobile-Layout bleibt exakt so wie es ist:
- Bottom Navigation mit Icons + Labels
- Volle Breite, 16px seitliches Padding
- 80px Bottom-Padding für Navigation
- PWA auf iPhone funktioniert wie bisher
---
## 4. Desktop Layout (≥ 1024px)
### 4.1 Grundstruktur
```
┌─────────────────────────────────────────────┐
│ Sidebar (220px) │ Content (flex 1) │
│ │ │
│ [Logo] │ Seiteninhalt │
│ │ (max-width: 1200px, │
│ Dashboard │ zentriert) │
│ Erfassung │ │
│ Verlauf │ │
│ Analyse │ │
│ Einstellungen │ │
│ Admin │ │
│ │ │
│ [Avatar + Name] │ │
└─────────────────────────────────────────────┘
```
### 4.2 Sidebar
**Position:** Fixed links, volle Höhe (100vh)
**Breite:** 220px
**Farben:** `var(--surface)` Hintergrund, `var(--border)` rechte Trennlinie
**Inhalt von oben nach unten:**
```
┌──────────────────┐
│ [Ensō-Logo] │ ← Icon (40px) + "Mitai Jinkendo" Text
│ Mitai Jinkendo │
├──────────────────┤
│ │
│ 🏠 Dashboard │ ← Icons + Text (gleiche Nav-Items wie Bottom Nav)
│ ✏️ Erfassung │ ← Aktive Seite: var(--accent) Hintergrund (leicht)
│ 📊 Verlauf │ + var(--accent) Text + linke Akzent-Linie (3px)
│ 🧠 Analyse │
│ ⚙️ Einstellungen│
│ 👑 Admin │ ← nur sichtbar wenn role='admin'
│ │
├──────────────────┤
│ [Avatar] │ ← Nutzer-Avatar (32px) + Name + Tier-Badge
│ Lars │
│ selfhosted │
└──────────────────┘
```
**Aktive Seite hervorheben:**
```css
/* Aktiver Nav-Item Desktop */
background: var(--accent-light); /* #E1F5EE leicht grüner Hintergrund */
color: var(--accent); /* #1D9E75 grüner Text */
border-left: 3px solid var(--accent); /* linke Akzent-Linie */
border-radius: 0 8px 8px 0;
```
### 4.3 Content-Bereich
- `margin-left: 220px` (Sidebar-Breite)
- `padding: 24px 32px`
- `max-width: 1200px` (zentriert innerhalb des verfügbaren Raums)
- Kein Bottom-Padding für Navigation (Sidebar ersetzt Bottom Nav)
---
## 5. Seiten-spezifische Desktop-Layouts
### 5.1 Dashboard
**Mobile:** Alle Karten untereinander
**Desktop:** 2-spaltig oder 4-spaltig je nach Kartentyp
```
┌──────────────────────────────────────────────┐
│ Hallo Lars 👋 Mo, 20. März 2026 │
├──────────┬──────────┬──────────┬─────────────┤
│ Gewicht │ KF │ Mager- │ Kalorien │
│ 86,1 kg │ 19,9% │ masse │ 1.447 kcal │
├──────────┴──────────┴──────────┴─────────────┤
│ Ziele [Details →] │
│ ████████░░ Gewicht: 27% ████░░░░ KF: 45% │
├──────────────────────────────────────────────┤
│ Kalorien + Gewicht (Chart volle Breite) │
└──────────────────────────────────────────────┘
```
### 5.2 Verlauf
**Mobile:** Tabs oben, Chart/Tabelle darunter
**Desktop:** Tabs links als vertikale Liste, Chart/Tabelle rechts
```
┌────────────┬─────────────────────────────────┐
│ Gewicht ← │ Chart + Tabelle │
│ Körperfett │ (nimmt volle rechte Breite) │
│ Umfänge │ │
│ Ernährung │ │
│ Aktivität │ │
└────────────┴─────────────────────────────────┘
```
### 5.3 Analyse
**Mobile:** Prompt-Liste, dann Ergebnis darunter
**Desktop:** Prompt-Liste links (300px), Ergebnis rechts
```
┌──────────────────┬──────────────────────────┐
│ Prompts │ Ergebnis / Verlauf │
│ ───────────── │ │
│ 🔍 Gesamt │ [Letzte Analyse] │
│ 🫧 Körper ← │ [Text der Analyse...] │
│ 🍽️ Ernährung │ │
│ 🏋️ Training │ [Ältere Analysen] │
│ ───────────── │ │
│ Pipeline ▶ │ │
└──────────────────┴──────────────────────────┘
```
### 5.4 Erfassung
**Mobile:** Formular volle Breite
**Desktop:** Formular zentriert, max-width 600px
```
┌──────────────────────────────────────────────┐
│ Gewicht erfassen │
│ │
│ ┌─────────────────────────────┐ │
│ │ Datum [20.03.2026] │ │
│ │ Gewicht [86,1 ] kg │ │
│ │ Notiz [ ] │ │
│ │ │ │
│ │ [Speichern] │ │
│ └─────────────────────────────┘ │
└──────────────────────────────────────────────┘
```
### 5.5 Admin-Panel
**Mobile:** Tabellen horizontal scrollbar
**Desktop:** Tabellen nutzen volle Breite, mehr Spalten sichtbar
---
## 6. Übergangsverhalten
### Fenster-Resize
- Beim Verkleinern unter 1024px: Sidebar verschwindet, Bottom Nav erscheint
- Beim Vergrößern über 1024px: Bottom Nav verschwindet, Sidebar erscheint
- Kein Flackern CSS media queries, kein JavaScript-Resize-Listener nötig
### Aktiver Zustand synchronisiert
- Aktive Seite wird in Sidebar UND Bottom Nav korrekt hervorgehoben
- (Technisch: gleiche State-Variable, unterschiedliches Rendering)
---
## 7. Was sich nicht ändert
- Farben, CSS-Variablen, Design-Tokens bleiben identisch
- Alle Funktionen bleiben auf Desktop verfügbar
- PWA auf iPhone bleibt vollständig funktionsfähig
- Keine externen CSS-Frameworks (kein Tailwind, kein Bootstrap)
- Inline-Styles + CSS-Variablen-Ansatz bleibt erhalten
---
## 8. Abgrenzung & offene Fragen
### In diesem Modul enthalten:
- Sidebar Navigation Desktop
- Content-Bereich mit max-width
- Dashboard 4-spaltig
- Verlauf 2-spaltig (Tabs + Chart)
- Analyse 2-spaltig (Prompts + Ergebnis)
- Erfassung zentriert schmal
- Admin-Panel breite Tabellen
### Nicht in diesem Modul:
- Dark Mode separates Feature
- Animationen / Transitions optional später
- Collapsed Sidebar (Icon-only Modus) optional später
### Offene Fragen für technische Planung:
1. Wird AppLayout als neue Wrapper-Komponente eingeführt oder App.jsx direkt angepasst?
2. CSS Media Queries in app.css oder CSS-in-JS (Inline-Style mit window.innerWidth)?
3. Wie wird der aktive Nav-Item-State zwischen Sidebar und Bottom Nav geteilt?
4. Verlauf-Tabs: werden sie zu einer vertikalen Liste refactored oder per CSS umgestaltet?

View File

@ -0,0 +1,227 @@
# Fachliche Anforderungen: Schlaf-Modul
**Modul:** v9d
**Status:** Fachlich freigegeben, technische Implementierung ausstehend
**Letzte Aktualisierung:** März 2026
---
## 1. Überblick
Das Schlaf-Modul ist ein eigenständiges Tracking-Modul für tägliche Schlafdaten.
Es ergänzt die bestehenden Körper-, Ernährungs- und Aktivitäts-Module um eine
zentrale Gesundheitsdimension. Schlaf wird sowohl manuell erfasst als auch aus
Apple Health / Garmin importiert. Korrelationen mit Ruhepuls, Training und Gewicht
fließen in die KI-Analyse ein.
---
## 2. Erfasste Daten
### 2.1 Pflichtfelder (Schnelleingabe)
- **Datum** welche Nacht (Standard: letzte Nacht)
- **Schlafdauer** in Stunden und Minuten (berechnet aus Ein-/Aufwachzeit oder direkt)
- **Schlafqualität** subjektiv 15 (1 = sehr schlecht, 5 = sehr gut)
### 2.2 Optionale Felder (Detaileingabe)
- **Einschlafzeit** Uhrzeit (z.B. 23:15)
- **Aufwachzeit** Uhrzeit (z.B. 06:45)
- **Aufwach-Häufigkeit** wie oft in der Nacht aufgewacht (010+)
- **Schlafphasen** Dauer in Minuten je Phase:
- Tiefschlaf
- REM-Schlaf
- Leichtschlaf
- Wach (in Bett)
- **Notiz** Freitext (z.B. "Stress, schlechte Nacht", "früh ins Bett")
### 2.3 Abgeleitete Felder (automatisch berechnet)
- **Schlafdauer** aus Einschlafzeit + Aufwachzeit wenn nicht direkt eingegeben
- **Schlafeffizienz** Schlafdauer / Zeit im Bett × 100% (wenn Phasen vorhanden)
- **Tiefschlaf-Anteil %** Tiefschlaf / Gesamtschlaf × 100%
- **REM-Anteil %** REM / Gesamtschlaf × 100%
---
## 3. Erfassungs-Modi
### 3.1 Schnelleingabe (≤ 30 Sekunden)
Minimaler Aufwand für den täglichen Gebrauch:
```
Datum: [gestern / heute Nacht]
Schlafdauer: [7] h [30] min
Qualität: ★★★★☆ (1-5 Sterne)
[Speichern]
```
### 3.2 Detaileingabe (alle Felder)
Vollständige Erfassung für Power-User oder wenn Gerätedaten vorliegen:
```
Datum: [22.03.2026]
Eingeschlafen: [23:15]
Aufgewacht: [06:45]
Schlafdauer: [7h 30min] (automatisch berechnet)
Qualität: ★★★★☆
Aufwachungen: [1]
Tiefschlaf: [95] min
REM-Schlaf: [110] min
Leichtschlaf: [230] min
Wach im Bett: [15] min
Notiz: [...]
[Speichern]
```
### 3.3 Morgendlicher Check-in
- Beim Öffnen der App morgens optional: "Wie hast du geschlafen?"
- Zeigt Schnelleingabe direkt auf dem Dashboard
- Kann in den Einstellungen aktiviert/deaktiviert werden
- Reminder-Logik: nur anzeigen wenn noch kein Eintrag für die letzte Nacht
### 3.4 Import (Apple Health / Garmin)
- Beim CSV/Health-Import werden Schlafdaten automatisch erkannt und zugeordnet
- Importierte Daten befüllen alle verfügbaren Felder (Phasen wenn vorhanden)
- Manuelle Eingabe ergänzt oder überschreibt Importdaten für denselben Tag
- Quelle wird gespeichert (manuell / apple_health / garmin)
---
## 4. Navigation & Dashboard
### 4.1 Eigene Seite in der Navigation
- Neuer Nav-Eintrag: **Schlaf** (zwischen Verlauf und Analyse)
- Icon: Mond oder Bett-Symbol
- Zeigt: Letzte 7 Tage Übersicht + Verlauf + Eingabe-Button
### 4.2 Dashboard-Widget
- Kompaktes Widget auf dem Dashboard (unter den Hauptkennzahlen)
- Zeigt: Letzte Nacht (Dauer + Qualität) + 7-Tage-Durchschnitt
- Klick öffnet die Schlaf-Seite
- Wenn noch kein Eintrag heute: "Schlaf erfassen" Button
---
## 5. Auswertungen
### 5.1 Schlafdauer-Trend
- Zeitraum wählbar: 7 / 30 / 90 Tage
- Liniengrafik: tägliche Schlafdauer
- Referenzlinie: persönliches Schlafziel (konfigurierbar in Einstellungen)
- Durchschnittslinie: gleitender 7-Tage-Durchschnitt
- Farbcodierung: unter Ziel = orange/rot, über Ziel = grün
### 5.2 Schlafqualität-Trend
- Liniengrafik: tägliche Qualität (15)
- 7-Tage-Durchschnitt als Referenzlinie
- Kombiniert mit Schlafdauer in einer Grafik (zwei Y-Achsen)
### 5.3 Schlafphasen-Verteilung
- Balkengrafik: Tiefschlaf / REM / Leichtschlaf / Wach je Nacht
- Durchschnittliche Verteilung über Zeitraum
- Referenzwerte: empfohlene Anteile (Tiefschlaf 15-25%, REM 20-25%)
- Nur sichtbar wenn Phasendaten vorhanden
### 5.4 Schlafschulden-Berechnung
- Definition: Differenz zwischen Schlafziel und tatsächlichem Schlaf (kumuliert)
- Zeitraum: letzte 7 / 14 Tage
- Anzeige: "+2h 15min Schlafschuld" oder "0 kein Defizit"
- Positiver Saldo (Übererfüllung) wird als Puffer angezeigt
### 5.5 Optimales Schlaffenster
- Berechnung aus Einschlafzeit + Schlafqualität über Zeit
- Erkennt wann Schlaf am besten war (z.B. "Beste Qualität bei Einschlafzeit 2223 Uhr")
- Mindestdatenbasis: 14 Einträge mit Einschlafzeit
### 5.6 Korrelationen
Alle Korrelationen benötigen mindestens 14 gemeinsame Datenpunkte:
**Schlaf ↔ Ruhepuls:**
- Streudiagramm: Schlafdauer / Qualität vs. Ruhepuls nächster Morgen
- KI-Aussage: "Nach <7h Schlaf ist dein Ruhepuls Ø X bpm höher"
**Schlaf ↔ Trainingsleistung:**
- Vergleich: Trainingsintensität/-volumen nach gut vs. schlecht geschlafenen Nächten
- KI-Aussage: "Nach Nächten mit >7,5h Schlaf trainierst du Ø X% länger/intensiver"
**Schlaf ↔ Gewicht:**
- Korrelation: Schlafdauer vs. Gewichtsentwicklung (wöchentlich)
- KI-Aussage: "In Wochen mit <6h Schlaf im Schnitt +X kg Gewichtsschwankung"
---
## 6. Schlafziel (konfigurierbar)
- In den Einstellungen: "Mein Schlafziel" → Stunden + Minuten
- Standard: 7h 30min
- Wird als Referenzlinie in allen Grafiken angezeigt
- Fließt in Schlafschulden-Berechnung ein
- KI nutzt den Wert als Basis für Schlafmangel-Warnung
---
## 7. KI-Analyse
### 7.1 Neue KI-Platzhalter
```
{{schlaf_avg_dauer}} → "7h 12min (Ø 7 Tage)"
{{schlaf_avg_qualitaet}} → "3,8/5 (Ø 7 Tage)"
{{schlaf_trend_dauer}} → "sinkend / stabil / steigend"
{{schlaf_trend_qualitaet}} → "sinkend / stabil / steigend"
{{schlaf_schulden}} → "+2h 15min (letzte 7 Tage)"
{{schlaf_ziel}} → "7h 30min"
{{schlaf_optimum_fenster}} → "22:0023:00 Uhr (beste Qualität)"
{{schlaf_tiefschlaf_anteil}} → "18% (Ø letzte 14 Tage)"
{{schlaf_rem_anteil}} → "22% (Ø letzte 14 Tage)"
{{schlaf_aufwachungen}} → "1,2x pro Nacht (Ø 7 Tage)"
{{schlaf_korrelation_puls}} → "Ruhepuls +4 bpm nach <7h Schlaf"
{{schlaf_detail}} → tabellarische Übersicht letzte 7 Nächte
```
### 7.2 KI-Analyse-Funktionen
**Schlafmangel erkennen und warnen:**
- Trigger: Schlafdurchschnitt letzte 3 Tage < (Schlafziel 60min)
- KI-Ausgabe: Warnung + konkrete Empfehlung
- Beispiel: "Du schläfst seit 3 Tagen unter deinem Ziel. Schlafschuld: +2h 15min."
**Schlaf ↔ Trainingsleistung korrelieren:**
- Automatische Berechnung sobald genug Daten (14+ Einträge beider Module)
- KI-Ausgabe: narrative Korrelationsbeschreibung mit konkreten Zahlen
**Optimales Schlaffenster empfehlen:**
- Basierend auf historischen Einschlafzeiten + Qualitäten
- KI-Ausgabe: "Deine beste Schlafqualität erzielst du wenn du zwischen 2223 Uhr einschläfst"
**Schlaf ↔ Gewicht:**
- Wöchentliche Korrelation
- KI-Ausgabe: "In Wochen mit mehr Schlaf zeigt dein Gewicht weniger Schwankungen"
**Schlafphasen-Verteilung kommentieren:**
- Nur wenn Phasendaten vorhanden
- Referenz: Tiefschlaf 15-25%, REM 20-25%, Leichtschlaf 50-60%
- KI-Ausgabe: "Dein Tiefschlaf-Anteil liegt bei X% das ist [über/unter/im] empfohlenen Bereich"
---
## 8. Abgrenzung & offene Fragen
### In diesem Modul enthalten:
- Tägliche Schlaferfassung (Schnell + Detail)
- Dashboard-Widget + eigene Navigationsseite
- Morgendlicher Check-in (optional)
- Import aus Apple Health / Garmin CSV
- 5 Auswertungsansichten inkl. Korrelationen
- Konfigurierbares Schlafziel
- 12 neue KI-Platzhalter
- 5 KI-Analyse-Funktionen
### Nicht in diesem Modul:
- Automatischer Live-Sync aus Garmin/Apple Watch → v9h (Connectoren)
- Schlaf-Coaching / Schlafhygiene-Tipps → optional später
- Schnarchen / Atemaussetzer (SpO2) → Teil Vitalwerte v9e
- Push-Notification "Schlafenszeit-Reminder" → optional später
### Offene Fragen für technische Planung:
1. Neue DB-Tabelle `sleep_log` oder Erweiterung von `activity_log`?
2. Schlafphasen als separate Spalten oder als JSONB-Feld?
3. Morgendlicher Check-in: Frontend-State oder Backend-Logik (letzte Nacht bereits erfasst?)?
4. Korrelationsberechnung: im Backend (Python) oder im Frontend (JavaScript)?
5. Apple Health Export enthält Schlafphasen-Daten welches CSV-Format wird erwartet?
EOF

View File

@ -0,0 +1,257 @@
# Fachliche Anforderungen: Trainingstypen & Herzfrequenz
**Modul:** v9d
**Status:** Fachlich freigegeben, technische Implementierung ausstehend
**Letzte Aktualisierung:** März 2026
---
## 1. Überblick
Dieses Modul erweitert die bestehende Aktivitätserfassung um eine strukturierte
Kategorisierung von Trainingstypen sowie die Erfassung und Auswertung von
Herzfrequenz-Daten. Ziel ist eine tiefere Analyse der Trainingsqualität,
Erholung und Zielerreichung.
---
## 2. Trainingstypen
### 2.1 Kategorie-Hierarchie
Jedes Training hat einen **Haupttyp** und optional einen **Untertyp**:
```
Cardio (Ausdauer)
→ Laufen
→ Radfahren
→ Schwimmen
→ Rudern
→ Sonstiges Cardio
Kraft
→ Hypertrophie (Muskelaufbau, 8-12 Wdh, mittleres Gewicht)
→ Maximalkraft (1-5 Wdh, hohes Gewicht)
→ Kraftausdauer (15+ Wdh, leichtes Gewicht)
→ Funktionell (Kettlebell, TRX, Bodyweight)
Schnellkraft / HIIT
→ HIIT (High Intensity Interval Training)
→ Explosiv (Sprints, Sprünge, Wurfübungen)
→ Circuit Training
Kampfsport / Technikkraft
→ Techniktraining (Bewegungsabläufe, Formen)
→ Sparring / Wettkampf
→ Kraft für Kampfsport (kampfsportspezifische Übungen)
Mobility & Dehnung
→ Statisches Dehnen
→ Dynamisches Dehnen
→ Yoga
→ Faszienarbeit
Erholung (aktiv)
→ Spaziergang
→ Leichtes Schwimmen
→ Regenerationseinheit
```
### 2.2 Ruhetage
Ruhetage werden als **bewusste Einheit** erfasst nicht nur als Abwesenheit
von Training. Ein Ruhetag hat:
- Datum
- Typ: Vollständige Ruhe / Aktive Erholung
- Optional: Notiz (z.B. "Muskelkater Beine", "Reise")
Ruhetage fließen in die Wochenplanung und KI-Analyse ein.
### 2.3 Erfassung
**Bestehende Aktivitäten (Apple Health Import):**
- Beim Import wird Trainingstyp automatisch vorgeschlagen basierend auf
dem Apple Health Workout-Typ (z.B. "Running" → Cardio / Laufen)
- Nutzer kann den vorgeschlagenen Typ bestätigen oder korrigieren
- Bereits importierte Aktivitäten können nachträglich kategorisiert werden
**Manuell erfasste Aktivitäten:**
- Trainingstyp und Untertyp als Pflichtfeld beim Anlegen
- Untertyp ist optional
---
## 3. Herzfrequenz-Daten
### 3.1 Ruhepuls
**Definition:** Herzfrequenz in Ruhe, idealerweise morgens direkt nach dem
Aufwachen, vor dem Aufstehen.
**Erfassung:**
- Manuell: Nutzer gibt Wert täglich ein (ganze Zahl, Schläge/Minute)
- Import: Aus Apple Health / Garmin automatisch übernommen
- Bei beiden Quellen: Import als Standard, manuelle Eingabe ergänzt oder
überschreibt den Importwert für den jeweiligen Tag
**Bedeutung:**
- Ruhepuls-Anstieg (+5-7 bpm über persönlichem Durchschnitt) = Warnsignal
für Übertraining, Krankheit oder unzureichende Erholung
- Langfristiger Ruhepuls-Abfall = Verbesserung der Ausdauerleistung
### 3.2 HF während Training
**Felder pro Aktivitätseintrag:**
- HF Durchschnitt (bpm)
- HF Maximum (bpm)
**Erfassung:**
- Primär aus Apple Health / Garmin Import (wird automatisch befüllt)
- Manuelle Eingabe als Ergänzung wenn kein Gerät genutzt
### 3.3 HF-Zonen
**5-Zonen-Modell** (basierend auf maximaler Herzfrequenz):
| Zone | Name | % HFmax | Zweck |
|------|------|---------|-------|
| 1 | Regeneration | 50-60% | Aktive Erholung |
| 2 | Grundlagenausdauer | 60-70% | Fettverbrennung, Basis |
| 3 | Aerobe Ausdauer | 70-80% | Ausdaueraufbau |
| 4 | Anaerobe Schwelle | 80-90% | Leistungssteigerung |
| 5 | Maximale Intensität | 90-100% | Spitzenleistung |
**HFmax-Berechnung:**
- Standard-Formel: 220 - Alter
- Alternativ: Manuell vom Nutzer definierbar (aus Leistungstest)
**Auswertung:**
- Zeitverteilung in Zonen pro Training (falls HF-Kurve vorhanden)
- Oder: Zone basierend auf HF-Durchschnitt schätzen
### 3.4 HRV (Herzratenvariabilität)
**Definition:** Variation der Zeitabstände zwischen Herzschlägen.
Hohe HRV = gute Erholung / niedriger Stress.
Niedrige HRV = Belastung / Übertraining / Stress.
**Erfassung:**
- Manuell (ms, aus Smartwatch-App abgelesen)
- Import aus Apple Health (wenn vorhanden)
- Messung: morgens, gleiche Bedingungen wie Ruhepuls
**Interpretation:**
- Persönlicher Baseline-Wert wird über 4 Wochen berechnet
- Abweichung >10% unter Baseline = Warnung
### 3.5 VO2Max
**Definition:** Maximale Sauerstoffaufnahme, Indikator für aerobe Leistungsfähigkeit.
**Erfassung:**
- Import aus Apple Health / Garmin (falls Gerät berechnet)
- Alternativ: Schätzung aus Ruhepuls + HFmax (Cooper-Formel):
`VO2Max ≈ 15 × (HFmax / HF_Ruhe)`
**Anzeige:**
- Aktueller Wert + Trend
- Einordnung nach Alters-/Geschlechtsnorm (sehr gut / gut / durchschnittlich / verbesserungswürdig)
---
## 4. Auswertungen & Dashboards
### 4.1 Trainingstyp-Verteilung
- Zeitraum wählbar: letzte 4 / 8 / 12 Wochen
- Kreisdiagramm oder Balkendiagramm: Anteil je Haupttyp in %
- Zusätzlich: Anzahl Einheiten je Typ
### 4.2 Trainingshäufigkeit pro Typ
- Wochenansicht: Wie viele Einheiten je Typ pro Woche
- Trend: Vergleich aktuelle Woche vs. Durchschnitt
### 4.3 Ruhepuls-Trend
- Liniengrafik über Zeit (7 / 30 / 90 Tage)
- Persönlicher Durchschnitt als Referenzlinie
- Warnung wenn Ruhepuls >5 bpm über 7-Tage-Durchschnitt
### 4.4 HF-Zonen-Verteilung
- Pro Training: Zeitanteil in jeder Zone (falls Daten vorhanden)
- Aggregiert: Zonenverteilung der letzten 30 Tage
### 4.5 Erholungsstatus
- Kombination aus: HRV + Ruhepuls + letzter Trainingsbelastung
- Ampel-System: 🟢 Gut erholt / 🟡 Teilweise erholt / 🔴 Erholung nötig
- Empfehlung: "Heute intensives Training möglich" / "Leichtes Training empfohlen" / "Ruhetag empfohlen"
### 4.6 Wochenplanung Soll vs. Ist
- Nutzer definiert Wochenziel: z.B. "3x Kraft, 2x Cardio, 1x Mobility, 1 Ruhetag"
- Dashboard zeigt: erreicht / offen / überschritten
- Einfache Eingabe, kein komplexer Planer
---
## 5. KI-Analyse
Die KI-Analyse wird um folgende Platzhalter erweitert:
### 5.1 Übertraining erkennen
**Trigger-Bedingungen (Beispiele):**
- >5 Krafteinheiten in 7 Tagen ohne Ruhetag
- Ruhepuls-Anstieg + gleichzeitig hohe Trainingsbelastung
- HRV unter persönlicher Baseline
**KI-Ausgabe:** Warnung + konkrete Empfehlung (Ruhetag, Intensität reduzieren)
### 5.2 Ruhetag empfehlen
**Basierend auf:** HRV-Trend + Ruhepuls-Trend + Trainingsbelastung letzte 5 Tage
**KI-Ausgabe:** "Dein Erholungsstatus zeigt X heute wäre ein Ruhetag oder leichtes Training sinnvoll"
### 5.3 Trainingstypen und Primärziel
**Beispiel Muskelaufbau:** KI erkennt wenn <40% Krafttraining Hinweis
**Beispiel Kondition:** KI erkennt wenn <40% Cardio Hinweis
**Voraussetzung:** Primärziel-Modul (v9e) muss implementiert sein
### 5.4 Phasen erkennen und kommentieren
**Phasen:**
- Aufbauphase: Steigende Belastung über mehrere Wochen
- Erholungsphase (Deload): Reduzierte Belastung nach intensiver Phase
- Plateau: Gleichbleibende Belastung ohne Progression
**KI-Ausgabe:** Phase benennen + situative Empfehlung
### 5.5 Neue KI-Platzhalter
```
{{trainingstyp_verteilung}} → "60% Kraft, 30% Cardio, 10% Mobility (letzte 4 Wochen)"
{{ruhetage_letzte_woche}} → Anzahl Ruhetage letzte 7 Tage
{{ruhepuls_aktuell}} → heutiger / letzter Ruhepuls
{{ruhepuls_trend}} → "sinkend / stabil / steigend"
{{hrv_aktuell}} → letzter HRV-Wert
{{hrv_baseline}} → persönlicher HRV-Durchschnitt (30 Tage)
{{erholungsstatus}} → "gut / teilweise / schlecht"
{{vo2max}} → aktueller VO2Max-Wert
{{trainingsphase}} → "Aufbau / Erholung / Plateau / unbekannt"
{{hf_zonen_verteilung}} → "Zone 2: 45%, Zone 3: 35%, Zone 4: 20%"
```
---
## 6. Abgrenzung & offene Fragen
### In diesem Modul enthalten:
- Kategorisierung bestehender + neuer Aktivitäten
- Ruhepuls, HRV, VO2Max erfassen und auswerten
- HF-Zonen berechnen und anzeigen
- Erholungsstatus-Ampel
- Wochenplanung (einfach)
- KI-Platzhalter und Analyse-Logik
### Nicht in diesem Modul (spätere Versionen):
- Periodisierungsplaner (Makrozyklen, Mikrozyklen) → v9g
- Sportart-spezifische Metriken (Pace, Watt) → v9e
- Verknüpfung mit Primärziel → v9e (Primärziel-Modul)
- Connector zu Garmin/Strava für Live-HF → v9h
### Offene Fragen für technische Planung:
1. Werden HF-Kurven (Zeit × HF) aus Apple Health importiert oder nur Avg/Max?
2. Soll HRV als eigener Tageseintrag oder als Ergänzung zum Ruhepuls-Eintrag erfasst werden?
3. Soll die Wochenplanung persistiert werden (DB) oder nur als Session-Einstellung?

View File

@ -0,0 +1,840 @@
# Training Type Profiles Umfassendes Trainingsmanagement-System
**Issue:** #15 (erweitert)
**Status:** Phase 1 KOMPLETT ✅ (Foundation + Auto-Evaluation) | Phase 2 ausstehend (Admin-UI)
**Erstellt:** 2026-03-23
**Implementiert:** Phase 1 - 2026-03-23
---
## Vision
Jeder Trainingstyp erhält ein **umfassendes Profil** mit Parametern, die:
1. **Mindestanforderungen** definieren (wann ist es "echtes" Training?)
2. **Intensitätsbereiche** beschreiben (Zonen: regenerativ, moderat, intensiv)
3. **Trainingswirkung** charakterisieren (welche Fähigkeiten werden trainiert?)
4. **Periodisierung** unterstützen (optimale Frequenz, Erholungsbedarf)
5. **Dynamische Bewertung** ermöglichen (ist diese konkrete Aktivität gut/schlecht?)
---
## Trainingstyp-Profil: Vollständige Parameter-Definition
### Struktur (JSONB in training_types.profile)
```json
{
"version": "1.0",
"created_at": "2026-03-23",
// ━━━ 1. MINDESTANFORDERUNGEN (Quality Gates) ━━━
"minimum_requirements": {
"enabled": true,
"rules": {
"duration_min": {
"value": 15,
"weight": 5,
"reason": "Unter 15min keine signifikante Trainingswirkung"
},
"avg_hr_min": {
"value": 100,
"weight": 3,
"reason": "Puls muss für Ausdauerreiz erhöht sein"
},
"max_hr_min": {
"value": 120,
"weight": 1,
"reason": "Maximalpuls zeigt echte Belastungsspitze"
},
"distance_km": {
"value": 1.0,
"weight": 2,
"reason": "Mindestdistanz für Lauftraining"
},
"kcal_active": {
"value": 100,
"weight": 1,
"reason": "Mindest-Energieverbrauch"
}
},
"pass_threshold": 0.6,
"fail_action": "mark_low_quality"
},
// ━━━ 2. INTENSITÄTSBEREICHE (HF-Zonen) ━━━
"intensity_zones": {
"method": "percentage_max_hr", // oder "percentage_reserve_hr"
"zones": [
{
"name": "regenerativ",
"min_percent": 50,
"max_percent": 60,
"color": "#4CAF50",
"effect": "Erholung, Grundlagenausdauer 1",
"target_duration_min": 30
},
{
"name": "grundlagenausdauer",
"min_percent": 60,
"max_percent": 70,
"color": "#2196F3",
"effect": "Aerobe Kapazität, Fettstoffwechsel",
"target_duration_min": 45
},
{
"name": "entwicklungsbereich",
"min_percent": 70,
"max_percent": 80,
"color": "#FF9800",
"effect": "VO2max-Training, Laktattoleranz",
"target_duration_min": 20
},
{
"name": "schwellentraining",
"min_percent": 80,
"max_percent": 90,
"color": "#F44336",
"effect": "Anaerobe Schwelle, Wettkampftempo",
"target_duration_min": 10
},
{
"name": "maximale_intensität",
"min_percent": 90,
"max_percent": 100,
"color": "#9C27B0",
"effect": "Maximalkraft, Sprint, HIIT",
"target_duration_min": 5
}
],
"evaluation_rules": {
"time_in_zone_required": true,
"min_time_in_target_zone_percent": 70
}
},
// ━━━ 3. TRAININGSWIRKUNG (Abilities Mapping) ━━━
"training_effects": {
"primary_abilities": [
{
"category": "konditionell",
"ability": "ausdauer",
"intensity": 5,
"description": "Hauptfokus: Aerobe Ausdauer"
},
{
"category": "konditionell",
"ability": "schnelligkeit",
"intensity": 2,
"description": "Nebenfokus: Lauftempo"
}
],
"secondary_abilities": [
{
"category": "koordinativ",
"ability": "rhythmus",
"intensity": 3,
"description": "Laufrhythmus, Schrittfrequenz"
},
{
"category": "psychisch",
"ability": "willenskraft",
"intensity": 4,
"description": "Durchhaltevermögen bei langen Läufen"
}
],
"metabolic_focus": ["aerobic", "fat_oxidation"],
"muscle_groups": ["legs_posterior", "legs_anterior", "core"],
"energy_systems": ["aerobic_oxidative", "anaerobic_lactic"]
},
// ━━━ 4. PERIODISIERUNG & FREQUENZ ━━━
"periodization": {
"recommended_frequency": {
"per_week_min": 2,
"per_week_max": 5,
"per_week_optimal": 3,
"consecutive_days_max": 2
},
"recovery_requirement": {
"hours_before_same_type": 48,
"hours_before_high_intensity": 24,
"rpe_threshold_for_extra_rest": 8
},
"progression": {
"beginner_duration_min": 20,
"intermediate_duration_min": 30,
"advanced_duration_min": 45,
"volume_increase_percent_per_week": 10
},
"deload_recommendation": {
"every_n_weeks": 4,
"volume_reduction_percent": 40
}
},
// ━━━ 5. LEISTUNGSINDIKATOREN (KPIs) ━━━
"performance_indicators": {
"primary_metrics": ["pace_min_per_km", "avg_hr", "distance_km"],
"secondary_metrics": ["kcal_per_km", "cadence", "elevation_gain"],
"benchmark_values": {
"beginner": {"pace_min_per_km": 7.0, "distance_km": 3.0},
"intermediate": {"pace_min_per_km": 6.0, "distance_km": 5.0},
"advanced": {"pace_min_per_km": 5.0, "distance_km": 10.0}
}
},
// ━━━ 6. KONTEXT & VARIANTEN ━━━
"context": {
"environment": ["outdoor", "indoor_treadmill"],
"weather_sensitivity": "high",
"equipment_required": ["running_shoes"],
"location_types": ["road", "trail", "track"],
"variants": [
{
"name": "intervall_lauf",
"modifications": {
"intensity_zones.focus": "schwellentraining",
"minimum_requirements.avg_hr_min": 140
}
},
{
"name": "long_jog",
"modifications": {
"intensity_zones.focus": "grundlagenausdauer",
"minimum_requirements.duration_min": 60
}
}
]
},
// ━━━ 7. SICHERHEIT & KONTRAINDIKATIONEN ━━━
"safety": {
"max_hr_warning": 180,
"min_recovery_hr": 100,
"contraindications": [
"acute_injury_lower_body",
"cardiovascular_episode_recent"
],
"weather_limits": {
"temp_celsius_min": -5,
"temp_celsius_max": 32,
"wind_speed_kmh_max": 40
}
},
// ━━━ 8. KI-ANALYSE KONTEXT ━━━
"ai_context": {
"questions_to_ask": [
"Wie fühlte sich dein Tempo an?",
"Hattest du Atembeschwerden?",
"Wie war die Regeneration danach?"
],
"evaluation_focus": [
"Pace-Entwicklung über Distanz",
"Herzfrequenz-Stabilität",
"Erholungspuls nach Training"
],
"comparison_metrics": [
"Tempo vs. letzte 4 Wochen",
"Durchschnittspuls bei gleicher Distanz",
"Subjektive Anstrengung (RPE) vs. objektive Daten"
]
}
}
```
---
## Dynamische Bewertung: Wie das Profil genutzt wird
### 1. Mindestanforderungen-Check (Quality Gate)
**Funktion:** `evaluate_minimum_requirements(activity, profile)`
```python
def evaluate_minimum_requirements(activity: dict, profile: dict) -> dict:
"""
Prüft ob Aktivität Mindestanforderungen erfüllt.
Returns:
{
"passed": bool,
"score": float,
"failed_rules": [{"rule": str, "expected": val, "actual": val}],
"recommendation": str
}
"""
requirements = profile['minimum_requirements']
if not requirements['enabled']:
return {"passed": True, "score": 1.0, "failed_rules": []}
total_weight = 0
passed_weight = 0
failed_rules = []
for rule_name, rule_config in requirements['rules'].items():
weight = rule_config['weight']
total_weight += weight
actual = activity.get(rule_name)
expected = rule_config['value']
if actual is not None and actual >= expected:
passed_weight += weight
else:
failed_rules.append({
"rule": rule_name,
"expected": expected,
"actual": actual,
"reason": rule_config['reason']
})
score = passed_weight / total_weight if total_weight > 0 else 1.0
passed = score >= requirements['pass_threshold']
recommendation = generate_recommendation(failed_rules, profile)
return {
"passed": passed,
"score": round(score, 2),
"failed_rules": failed_rules,
"recommendation": recommendation
}
```
### 2. Intensitäts-Bewertung (Zone Analysis)
**Funktion:** `evaluate_intensity_distribution(activity, profile)`
```python
def evaluate_intensity_distribution(activity: dict, profile: dict) -> dict:
"""
Analysiert in welcher HF-Zone das Training stattfand.
Returns:
{
"dominant_zone": str,
"time_in_zones": {zone: minutes},
"zone_quality": float (0-1),
"recommendation": str
}
"""
zones = profile['intensity_zones']['zones']
max_hr = activity.get('user_max_hr', 180) # From user profile
avg_hr = activity.get('avg_hr')
if not avg_hr:
return {"dominant_zone": "unknown", "zone_quality": 0}
avg_hr_percent = (avg_hr / max_hr) * 100
# Finde passende Zone
dominant_zone = None
for zone in zones:
if zone['min_percent'] <= avg_hr_percent <= zone['max_percent']:
dominant_zone = zone
break
if not dominant_zone:
return {"dominant_zone": "out_of_range", "zone_quality": 0}
# Prüfe ob Dauer passt zur Zone
duration = activity.get('duration_min', 0)
target_duration = dominant_zone['target_duration_min']
duration_quality = min(duration / target_duration, 1.0)
recommendation = f"Training in Zone '{dominant_zone['name']}' (Effekt: {dominant_zone['effect']}). "
if duration < target_duration:
recommendation += f"Für optimale Wirkung: {target_duration}min empfohlen."
return {
"dominant_zone": dominant_zone['name'],
"zone_color": dominant_zone['color'],
"zone_effect": dominant_zone['effect'],
"avg_hr_percent": round(avg_hr_percent, 1),
"duration_quality": round(duration_quality, 2),
"recommendation": recommendation
}
```
### 3. Trainingswirkung-Analyse (Abilities Development)
**Funktion:** `evaluate_training_effects(activity, profile)`
```python
def evaluate_training_effects(activity: dict, profile: dict) -> dict:
"""
Berechnet welche Fähigkeiten durch diese Aktivität trainiert wurden.
Returns:
{
"abilities_trained": [
{"category": str, "ability": str, "intensity": int, "quality": float}
],
"total_training_load": float
}
"""
effects = profile['training_effects']
intensity_eval = evaluate_intensity_distribution(activity, profile)
min_requirements_eval = evaluate_minimum_requirements(activity, profile)
# Qualitätsfaktor basierend auf Mindestanforderungen
quality_factor = min_requirements_eval['score']
abilities_trained = []
# Primary abilities mit voller Intensität
for ability in effects['primary_abilities']:
abilities_trained.append({
"category": ability['category'],
"ability": ability['ability'],
"intensity": ability['intensity'],
"quality": quality_factor,
"contribution": ability['intensity'] * quality_factor
})
# Secondary abilities mit reduzierter Intensität
for ability in effects['secondary_abilities']:
abilities_trained.append({
"category": ability['category'],
"ability": ability['ability'],
"intensity": ability['intensity'],
"quality": quality_factor * 0.7, # Sekundär = 70%
"contribution": ability['intensity'] * quality_factor * 0.7
})
total_training_load = sum(a['contribution'] for a in abilities_trained)
return {
"abilities_trained": abilities_trained,
"total_training_load": round(total_training_load, 2),
"metabolic_focus": effects['metabolic_focus'],
"muscle_groups": effects['muscle_groups']
}
```
### 4. Periodisierungs-Check (Recovery & Frequency)
**Funktion:** `evaluate_periodization_compliance(activity, profile, recent_activities)`
```python
def evaluate_periodization_compliance(
activity: dict,
profile: dict,
recent_activities: list
) -> dict:
"""
Prüft ob Aktivität zu Periodisierungs-Empfehlungen passt.
Returns:
{
"frequency_status": str,
"recovery_adequate": bool,
"warning": str | None
}
"""
periodization = profile['periodization']
activity_date = activity['date']
# Zähle gleiche Trainingstypen in letzter Woche
same_type_count = sum(
1 for a in recent_activities
if a['training_type_id'] == activity['training_type_id']
and days_between(a['date'], activity_date) <= 7
)
# Prüfe Erholungszeit
last_same_type = next(
(a for a in recent_activities
if a['training_type_id'] == activity['training_type_id']),
None
)
recovery_adequate = True
warning = None
if last_same_type:
hours_since_last = hours_between(last_same_type['date'], activity_date)
required_hours = periodization['recovery_requirement']['hours_before_same_type']
if hours_since_last < required_hours:
recovery_adequate = False
warning = f"Zu wenig Erholung: {hours_since_last}h statt {required_hours}h empfohlen"
# Frequenz-Status
optimal_freq = periodization['recommended_frequency']['per_week_optimal']
if same_type_count < optimal_freq:
frequency_status = "under_optimal"
elif same_type_count > periodization['recommended_frequency']['per_week_max']:
frequency_status = "over_optimal"
warning = "Übertraining-Risiko: Zu viele Einheiten diese Woche"
else:
frequency_status = "optimal"
return {
"frequency_status": frequency_status,
"weekly_count": same_type_count,
"recovery_adequate": recovery_adequate,
"warning": warning
}
```
### 5. Leistungsentwicklung (Performance Tracking)
**Funktion:** `evaluate_performance_development(activity, profile, historical_activities)`
```python
def evaluate_performance_development(
activity: dict,
profile: dict,
historical_activities: list
) -> dict:
"""
Vergleicht aktuelle Leistung mit Historie.
Returns:
{
"trend": str, # "improving" | "stable" | "declining"
"metrics_comparison": {metric: {"current": val, "avg_4weeks": val, "change_percent": val}},
"benchmark_level": str # "beginner" | "intermediate" | "advanced"
}
"""
kpis = profile['performance_indicators']
primary_metrics = kpis['primary_metrics']
# Berechne 4-Wochen-Durchschnitte
comparison = {}
for metric in primary_metrics:
current_value = activity.get(metric)
if not current_value:
continue
historical_values = [
a[metric] for a in historical_activities[-12:] # Letzte 12 Einheiten
if a.get(metric) is not None
]
if historical_values:
avg_historical = sum(historical_values) / len(historical_values)
change_percent = ((current_value - avg_historical) / avg_historical) * 100
comparison[metric] = {
"current": current_value,
"avg_4weeks": round(avg_historical, 2),
"change_percent": round(change_percent, 1)
}
# Trend-Bewertung
if all(c['change_percent'] > 5 for c in comparison.values()):
trend = "improving"
elif all(c['change_percent'] < -5 for c in comparison.values()):
trend = "declining"
else:
trend = "stable"
# Benchmark-Level ermitteln
benchmarks = kpis['benchmark_values']
benchmark_level = determine_benchmark_level(activity, benchmarks)
return {
"trend": trend,
"metrics_comparison": comparison,
"benchmark_level": benchmark_level
}
```
---
## Dynamische Gesamt-Bewertung
**Master-Funktion:** `evaluate_activity(activity, profile, context)`
```python
def evaluate_activity(activity: dict, profile: dict, context: dict) -> dict:
"""
Vollständige Bewertung einer Aktivität anhand des Trainingstyp-Profils.
Args:
activity: Die zu bewertende Aktivität
profile: Das Trainingstyp-Profil
context: {
"recent_activities": [...],
"historical_activities": [...],
"user_profile": {...}
}
Returns:
{
"evaluated_at": ISO timestamp,
"version": "1.0",
"minimum_requirements": {...},
"intensity_analysis": {...},
"training_effects": {...},
"periodization_check": {...},
"performance_development": {...},
"overall_score": float (0-1),
"quality_label": str, # "excellent" | "good" | "acceptable" | "poor"
"recommendations": [str],
"warnings": [str]
}
"""
results = {
"evaluated_at": datetime.now().isoformat(),
"version": "1.0",
"minimum_requirements": evaluate_minimum_requirements(activity, profile),
"intensity_analysis": evaluate_intensity_distribution(activity, profile),
"training_effects": evaluate_training_effects(activity, profile),
"periodization_check": evaluate_periodization_compliance(
activity, profile, context['recent_activities']
),
"performance_development": evaluate_performance_development(
activity, profile, context['historical_activities']
)
}
# Gesamt-Score berechnen (gewichtet)
weights = {
"minimum_requirements": 0.4,
"intensity_analysis": 0.2,
"periodization_check": 0.2,
"performance_development": 0.2
}
overall_score = (
results['minimum_requirements']['score'] * weights['minimum_requirements'] +
results['intensity_analysis']['duration_quality'] * weights['intensity_analysis'] +
(1.0 if results['periodization_check']['recovery_adequate'] else 0.5) * weights['periodization_check'] +
(1.0 if results['performance_development']['trend'] == 'improving' else 0.7) * weights['performance_development']
)
# Quality Label
if overall_score >= 0.9:
quality_label = "excellent"
elif overall_score >= 0.7:
quality_label = "good"
elif overall_score >= 0.5:
quality_label = "acceptable"
else:
quality_label = "poor"
# Recommendations sammeln
recommendations = []
warnings = []
if not results['minimum_requirements']['passed']:
for failed in results['minimum_requirements']['failed_rules']:
recommendations.append(
f"{failed['rule']}: {failed['reason']} (Ist: {failed['actual']}, Soll: {failed['expected']})"
)
if results['periodization_check']['warning']:
warnings.append(results['periodization_check']['warning'])
results.update({
"overall_score": round(overall_score, 2),
"quality_label": quality_label,
"recommendations": recommendations,
"warnings": warnings
})
return results
```
---
## DB-Schema (Erweitert)
```sql
-- Training Types: Vollständiges Profil
ALTER TABLE training_types ADD COLUMN profile JSONB DEFAULT NULL;
-- Activity Log: Evaluation Results
ALTER TABLE activity_log ADD COLUMN evaluation JSONB DEFAULT NULL;
-- Beispiel-Daten:
UPDATE training_types SET profile = '{...siehe oben...}'::jsonb
WHERE name_de = 'Laufen';
```
---
## User Interface: Aktivitäts-Detail-Ansicht
```
┌────────────────────────────────────────────────────────────────┐
│ 🏃 Laufen - 23. März 2026 │
├────────────────────────────────────────────────────────────────┤
│ │
│ ━━━ ZUSAMMENFASSUNG ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ Gesamtbewertung: ⭐⭐⭐⭐⭐ Exzellent (Score: 0.92) │
│ │
│ 45 Minuten · 5.2 km · Ø 142 bpm (79% Max-HF) · 380 kcal │
│ │
│ ━━━ MINDESTANFORDERUNGEN ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ ✅ Dauer: 45min (≥ 15min erforderlich) │
│ ✅ Ø Herzfrequenz: 142 bpm (≥ 100 bpm) │
│ ✅ Max. Herzfrequenz: 165 bpm (≥ 120 bpm) │
│ ✅ Distanz: 5.2 km (≥ 1.0 km) │
│ │
│ ━━━ INTENSITÄTSANALYSE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ Trainingszone: Entwicklungsbereich (70-80% Max-HF) │
│ Effekt: VO2max-Training, Laktattoleranz │
│ │
│ [████████████████████░░] 79% Max-HF │
│ │
│ Zeitverteilung: │
│ • Regenerativ (50-60%): 0 min │
│ • Grundlagenausdauer (60-70%): 8 min │
│ • Entwicklungsbereich (70-80%): 32 min ✅ Optimal │
│ • Schwellentraining (80-90%): 5 min │
│ │
│ ━━━ TRAININGSWIRKUNG ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ Trainierte Fähigkeiten: │
│ • Ausdauer (Konditionell): ●●●●● (5/5) - Primärfokus │
│ • Schnelligkeit (Konditionell): ●●○○○ (2/5) - Nebenfokus │
│ • Rhythmus (Koordinativ): ●●●○○ (3/5) - Sekundär │
│ • Willenskraft (Psychisch): ●●●●○ (4/5) - Sekundär │
│ │
│ Gesamte Trainingsbelastung: 18.2 Punkte │
│ │
│ ━━━ PERIODISIERUNG ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ Frequenz diese Woche: 3 Einheiten ✅ Optimal (2-5 empfohlen) │
│ Erholung seit letztem Lauf: 52 Stunden ✅ Ausreichend │
│ Nächstes Training empfohlen: Frühestens in 48h │
│ │
│ ━━━ LEISTUNGSENTWICKLUNG ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ Trend: ↗ Verbesserung │
│ │
│ Pace: 8:39 min/km (Ø 4 Wochen: 9:15 min/km) +6.5% schneller │
│ Ø HF: 142 bpm (Ø 4 Wochen: 148 bpm) -4% niedriger │
│ │
│ Dein Level: Fortgeschritten (Intermediate) │
│ │
│ ━━━ EMPFEHLUNGEN ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ ✨ Exzellentes Training! Du trainierst im optimalen │
│ Entwicklungsbereich für VO2max-Verbesserung. │
│ │
│ 💡 Deine Pace verbessert sich stetig bei gleichzeitig │
│ niedrigerer Herzfrequenz - klares Zeichen für bessere │
│ Ausdauerkapazität. │
│ │
│ 📅 Nächste Schritte: │
│ • 1-2 Tage Regeneration │
│ • Dann: Langer, langsamer Lauf (60-70% Max-HF, 60min) │
│ │
└────────────────────────────────────────────────────────────────┘
```
---
## Implementierungs-Phasen
### Phase 1: Foundation (MVP)
1. DB-Migration: `profile` Spalte in training_types
2. DB-Migration: `evaluation` Spalte in activity_log
3. Backend: `evaluate_activity()` Master-Funktion
4. Backend: Evaluation beim INSERT/UPDATE
### Phase 2: Profile Editor (Admin-UI)
5. Admin-UI: Trainingstyp-Profil-Editor (JSON-basiert)
6. Admin-UI: Profile-Templates für Top 5 Trainingstypen
7. Admin-UI: Preview-Funktion (wie wird evaluiert?)
### Phase 3: User Experience
8. Frontend: Aktivitäts-Detail-Ansicht mit allen Bewertungen
9. Frontend: Badge-System (Excellent/Good/Acceptable/Poor)
10. Frontend: Trainingswirkungs-Visualisierung
### Phase 4: Advanced Features
11. KI-Integration: Nutze Evaluation-Daten für Prompts
12. Periodisierungs-Warnungen im Dashboard
13. Leistungsentwicklung-Charts
14. Historische Re-Evaluation (Batch-Job)
**Geschätzter Aufwand:** 12-16 Stunden (komplett)
---
## Offene Fragen
1. **Profil-Komplexität:** Alle Parameter von Anfang an oder iterativ erweitern?
2. **User-Anpassbarkeit:** Soll User eigene Profile erstellen können?
3. **Performance:** JSONB-Queries optimiert genug für große Datenmengen?
4. **UI-Komplexität:** Ist die Detail-Ansicht zu überladen?
5. **Backward Compatibility:** Was passiert mit Aktivitäten ohne Profil?
---
---
## Implementierungs-Status
### Phase 1: Foundation ✅ KOMPLETT (23.03.2026)
**Phase 1.1: Database & Core Engine** ✅
- ✅ Migration 013: training_parameters Tabelle (16 Standard-Parameter)
- ✅ Migration 014: training_types.profile + activity_log.evaluation + triggers
- ✅ rule_engine.py: RuleEvaluator mit 9 Operatoren
- ✅ rule_engine.py: IntensityZoneEvaluator für HF-Zonen
- ✅ rule_engine.py: TrainingEffectsEvaluator für Fähigkeiten
- ✅ profile_evaluator.py: TrainingProfileEvaluator (7 Dimensionen)
- ✅ evaluation_helper.py: Parameter-Loading + Context-Loading + Batch-Evaluation
- ✅ routers/evaluation.py: API-Endpoints für manuelle Evaluation
- ✅ Commit: 1b9cd6d
**Phase 1.2: Auto-Evaluation** ✅
- ✅ activity.py: create_activity() → Auto-Evaluation nach INSERT
- ✅ activity.py: update_activity() → Auto-Evaluation nach UPDATE
- ✅ activity.py: import_activity_csv() → Auto-Evaluation nach CSV-Import
- ✅ activity.py: bulk_categorize_activities() → Auto-Evaluation nach Bulk-Update
- ✅ Fehlerbehandlung mit try/except (verhindert Blockierung bei Evaluation-Fehlern)
- ✅ Commit: e119537
**Backend Implementation:** 100% komplett
- Parameter-Registry: extensibel via SQL
- Regel-System: flexibel, unterstützt >= und <= (Laufen vs. Meditation)
- 7 Dimensionen: Minimum Requirements, Intensity Zones, Training Effects, Periodization, Performance, Safety, AI Context
- Evaluation-Results in activity_log.evaluation gespeichert
**Getestet:** Syntax-Check bestanden (py_compile)
### Phase 2: Admin-UI 🔲 Ausstehend
**Aufgaben:**
- Admin-UI: Parameter-Registry-Verwaltung (CRUD)
- Admin-UI: Trainingstyp-Profil-Editor (JSON-Editor mit Syntax-Highlighting)
- Admin-UI: Profile-Templates für Top 5 Trainingstypen (Laufen, Radfahren, Schwimmen, Krafttraining, Meditation)
- Admin-UI: Preview-Funktion (Test-Evaluation mit Beispiel-Aktivität)
- Validation: Profil-Schema-Validator
**Geschätzter Aufwand:** 4-6 Stunden
### Phase 3: User-UI 🔲 Ausstehend
**Aufgaben:**
- Frontend: ActivityDetailPage mit vollständiger Evaluation-Anzeige
- Frontend: Quality Badges (excellent/good/acceptable/poor) in Listen
- Frontend: Filter nach Quality Label
- Frontend: Trainingswirkungs-Visualisierung (Fähigkeiten-Übersicht)
- Frontend: Dashboard-Stats (Durchschnitt Quality Score)
**Geschätzter Aufwand:** 4-6 Stunden
### Phase 4: Advanced Features 🔲 Future
**Optional:**
- KI-Integration: Nutze Evaluation-Daten in AI-Prompts
- Periodisierungs-Warnungen im Dashboard
- Leistungsentwicklung-Charts
- Historische Re-Evaluation (Batch-Job über Admin-Panel)
**Was denkst du zu diesem erweiterten Ansatz?**

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,56 @@
{
"name": "Mehrstufige Gesamtanalyse (2)",
"slug": "pipeline",
"display_name": "🔬 Mehrstufige Gesamtanalyse (2)",
"description": "Master-Schalter für die gesamte Pipeline. Deaktiviere diese Analyse, um die Pipeline komplett zu verstecken.",
"type": "pipeline",
"category": "ganzheitlich",
"active": true,
"sort_order": -10,
"output_format": "text",
"template": null,
"stages": [
{
"stage": 1,
"prompts": [
{
"slug": "pipeline_body",
"source": "reference",
"template": "PIPELINE_MASTER",
"output_key": "stage1_body",
"output_format": "json",
"output_schema": null
},
{
"slug": "pipeline_nutrition",
"source": "reference",
"template": "",
"output_key": "stage1_nutrition",
"output_format": "json",
"output_schema": null
},
{
"slug": "pipeline_activity",
"source": "reference",
"template": "",
"output_key": "stage1_activity",
"output_format": "json",
"output_schema": null
}
]
},
{
"stage": 2,
"prompts": [
{
"slug": null,
"source": "inline",
"template": "Du bist ein Gesundheits- und Fitnesscoach. Erstelle eine vollständige, \npersonalisierte Analyse für {{name}} auf Deutsch (450550 Wörter).\n\nDATENZUSAMMENFASSUNGEN AUS STUFE 1:\nKörper: {{stage1_body}}\nErnährung: {{stage1_nutrition}}\nAktivität: {{stage1_activity}}\nProtein-Ziel: {{protein_ziel_low}}{{protein_ziel_high}}g/Tag\n\nSchreibe alle Abschnitte vollständig aus:\n⚖ **Gewichts- & Körperzusammensetzung**\n🍽 **Ernährungsanalyse**\n🏋 **Aktivität & Energiebilanz**\n🔗 **Zusammenhänge** (Verbindungen zwischen Ernährung, Training, Körper)\n💪 **3 Empfehlungen** (nummeriert, konkret, datenbasiert)\n\nSachlich, motivierend, Zahlen zitieren, keine Diagnosen.",
"output_key": "output_1774507015689",
"output_format": "text",
"output_schema": null
}
]
}
]
}

View File

@ -0,0 +1,317 @@
# Activity Session Metrics: Composite-Daten (EAV) Umsetzungskonzept
**Stand:** 2026-04-16
**Status:** Normatives Konzept zur nahtlosen Weiterarbeit durch Code-Agenten
**Bezieht sich auf:** `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` (§2.32.4, Phasen DE), `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md`, Issue #53 (Layer-1-Prinzip: Auswertungen nur über `data_layer`)
---
## 1. Ziel und Abgrenzung
### 1.1 Ziel
- **Composite-Messgrößen** (strukturierte Werte mit mehreren benannten Slots) werden wie **normale Trainingsparameter** im Katalog geführt, **Kategorie-/Typ-Profilen** zugeordnet und pro Session in der **EAV-Tabelle** persistiert.
- **Persistenz:** ein JSON-Dokument pro Session und `training_parameter_id` (kanonisch **JSONB**), kompatibel mit der bestehenden „eine Zeile pro Parameter“-Semantik.
- **Import:** CSV liefert typischerweise **eine Spalte pro atomarem Slot**; das Mapping verweist auf **`(Parameter-Key, Slot-Key)`** (stabile Strings, nicht Spaltenreihenfolge).
- **Layer 1:** liefert für Consumer weiterhin **eine konsistente API**: Rohdokument **und** optional **aufgelöste Einzelwerte** (flach oder namenspaced), ohne dass Charts/Platzhalter direkt JSON parsen müssen.
### 1.2 Nicht-Ziele (explizit)
- Kein „freies“ JSON-Schema im Admin ohne Archetyp-Bindung (verhindert Datenmüll und nicht validierbare Dokumente).
- Keine Abschwächung bestehender **Skalar-Parameter** (`integer`, `float`, `string`, `boolean`): alle bisherigen Pfade bleiben gültig.
- Kein Ersatz für `activity_log`-**Spine** oder Session-Qualitätsblobs (`evaluation`, …).
### 1.3 Kompatibilitätsgarantie („keine Regression“)
| Bereich | Maßnahme |
|---------|----------|
| DB | Nur **additive** Migrationen; bestehende `CHECK`-Regeln für Skalare bleiben für Zeilen **ohne** Composite erhalten bzw. werden zu einer **Oder-Verknüpfung** erweitert (siehe §4). |
| `training_parameters` | Neuer `data_type`-Wert **`composite`** zusätzlich zu den vier bestehenden; bestehende CHECK-Constraint muss erweitert werden (Migration). |
| `activity_session_metrics` | Skalare Zeilen unverändert; Composite-Zeilen nutzen **`value_json`** (neu), alle `value_*` NULL. |
| Layer 1 | `resolve_activity_attribute_schema`, Merge, Replace: Composite erscheint als **ein** Schema-Eintrag; Lese-/Schreibpfade erweitern, nicht ersetzen. |
| CSV | Bestehende Map-Ziele auf Skalare/Registry unverändert; neue Zielnotation nur für Composites. |
| Admin | tcp/ttp-UI: gleiche Zuordnung wie heute; Zusatzfelder nur bei `data_type === composite`. |
### 1.4 Abgleich mit `functional_concept_composite_data.md` (fachliches Konzept)
Das **fachliche Konzeptpapier** (Composite Scalar/Layer-Trennung) und dieses **Umsetzungskonzept** sind **vereinbar**, wenn die Rollen klar getrennt bleiben:
| Thema | Fachliches Konzept (`functional_concept_composite_data.md`) | Dieses Umsetzungskonzept (technisch) |
|--------|-------------------------------------------------------------|--------------------------------------|
| **Speicher in der DB** | Einheitlicher Store; Composite = `jsonb` mit **kleinem Basisschema** (`v`, `kind`, `domain`, `items`, optional `basis`, `meta`) | `activity_session_metrics.value_json`; CHECK Skalar vs. Composite |
| **Technische Container** | Genau **vier** `kind`-Werte: `group_set`, `distribution_set`, `sequence_set`, `model_set` | Layer-1-Validierung **muss** diese Hülle durchsetzen; kein freies JSON ohne `kind`/`v`/`items` |
| **„Archetypen“** | **Fachliche** Ausprägungen werden in **Layer 2a** aus L1-Objekten abgeleitet | Benannte **Preset-/Validierungsprofile** im Code (z.B. Zonenverteilung HF) sind **kein** zweites Persistenz-Schema: sie legen fest, *welches* der vier `kind`-Muster, *welches* `domain`, *welche* Item-Keys/Typen erlaubt sind — inkl. CSV-Slot-Mapping |
| **Layer 1** | Validiert, minimal normalisiert, **keine** Scores/Bewertungen/KI-Texte | Validator + Merge + optional `expand_*` (**technische** Flachstellung für Consumer, z.B. `param.slot` → Skalar) |
| **Layer 2** | Diagramme, Kennzahlen, KI-Platzhalter-**Formulierung** | unverändert; konsumiert L1 (und ggf. L2a) |
**Konsequenz für die Registry:** Statt „8 freie JSON-Archetypen“ implementiert die Code-Registry **Validierungs-Presets**, die alle auf die **vier technischen `kind`-Formen** abbilden. Die Tabelle in §3 beschreibt weiterhin **fachlich benannte MVP-Anker** — technisch übersetzen sie sich in `(kind, domain, Item-Regeln, v)`.
**Konsequenz für Platzhalter:** Roh-JSON aus der DB **nicht** ungefiltert in Prompts; L2b nutzt L1/L2a-Aufbereitung (wie im fachlichen Konzept).
---
## 2. Begriffe
| Begriff | Bedeutung |
|---------|-----------|
| **Archetyp** | Im **Repo versionierte** Strukturvorlage (erlaubte Slots, Typen, Pflichtfelder, Validator, Version). **78** Stück geplant; Erweiterung nur per Code-Release. |
| **Slot** | Benanntes Teilfeld innerhalb des Composite-Dokuments, z.B. `z1_sec`, `z2_sec`, `avg_cadence`. |
| **Parameter-Instanz** | Eine Zeile in `training_parameters` mit `data_type = composite` und Metadaten, **welcher** Archetyp gilt (siehe §5). |
| **Dokument** | Ein JSON-Objekt, das alle Slots abbildet; gespeichert in `activity_session_metrics.value_json`. |
---
## 3. Archetypen-Katalog (Planungsstand) — fachliche Namen → technische `kind`-Presets
Die **konkrete** Slot-Liste und Validierung wird im Code als **Registry** geführt (z.B. `backend/data_layer/activity_composite_archetypes.py`). Jedes Preset **mappt** auf genau eines von **`group_set` | `distribution_set` | `sequence_set` | `model_set`** und erfüllt das **Basisschema** aus `functional_concept_composite_data.md` §7.
Inhaltlich orientiert an `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` §2.4.
**Beispielhafte fachliche MVP-Anker** (8 Kandidaten; im Code als Preset-Key + `kind`/`domain` abbilden):
| `archetype_key` (stabil) | Kurzbeschreibung | Typische Slots (Beispiel) |
|--------------------------|------------------|---------------------------|
| `hr_zone_distribution` | Zeit-/Anteil je HF-Zone | `z1_sec`…`z5_sec` oder `zones[]` |
| `power_zone_distribution` | Leistungszonen | analog |
| `pace_band_profile` | Pace-Bänder / Histogramm | bucket-Struktur |
| `interval_block_summary` | Intervallblöcke aggregiert | `blocks[]` mit Dauer, Ziel, Ist |
| `event_marker_sequence` | Ereignisse mit Zeitstempel | `events[]` |
| `coupling_efficiency_profile` | Kopplungs-/Effizienzmetriken | sportabhängig |
| `model_parameter_profile` | Modell-/Schwellenparameter | key-value-ähnlich, validiert |
| `readiness_recovery_snapshot` | optional: kurzes Multi-Signal-Bundle | nur wenn fachlich gewünscht |
**Regel:** Jeder Archetyp hat `version` (Integer). Validator lehnt Dokumente mit falscher/fehlender Version ab oder migriert definiert (nur wenn spezifiziert).
---
## 4. Datenmodell-Erweiterungen
### 4.1 `training_parameters`
**Migration (additiv):**
1. `CHECK (data_type IN (...))` erweitern um **`composite`**.
2. Optional eigene Spalte **`composite_archetype_key` `VARCHAR(64)`** (NOT NULL wenn `data_type = composite`, sonst NULL) — **oder** ausschließlich in `validation_rules` speichern (siehe unten).
**Empfehlung:** Spalte `composite_archetype_key` + `composite_archetype_version INT` für einfache Admin-Queries und klare Semantik; `validation_rules` für archetyp-spezifische Feinheiten (z.B. erlaubte Zonenanzahl).
**Konsistenz-Constraint (DB oder App):**
- Wenn `data_type = composite`: `composite_archetype_key` gesetzt, `source_field` typischerweise **NULL** (kein `activity_log`-Skalar-Shadowing).
- `unit` am Parameter: optional für „Anzeige-Einheit“ des Gesamtwerts oder leer; Slots haben Einheiten im Archetyp oder in Slot-Metadaten.
### 4.2 `activity_session_metrics`
**Migration (additiv):**
```text
value_json JSONB NULL
```
**CHECK-Constraint ersetzen/erweitern** (Konzept):
- **Modus Skalar:** genau eine der Spalten `value_num`, `value_int`, `value_text`, `value_bool` ist NOT NULL; `value_json` IS NULL.
- **Modus Composite:** `value_json` IS NOT NULL; alle vier Skalar-Spalten IS NULL.
Damit bleibt die bestehende Semantik „eine Zeile = ein Parameter“ erhalten.
**Kommentar:** Tabelle trägt weiterhin „EAV“; Composites sind **keine** zusätzlichen Zeilen pro Slot.
### 4.3 Profil-Zuordnung (tcp / ttp)
**Keine** Tabellenänderung: `training_category_parameter` und `training_type_parameter` verweisen weiter nur auf `training_parameter_id`. Composite-Parameter verhalten sich wie Skalare in Bezug auf **Zuordnung**, **sort_order**, **required**, **ui_group**.
**`required`:** bedeutet „Dokument muss nach Validator vollständig sein“, nicht „jede CSV-Spalte muss in jeder Zeile vorkommen“.
---
## 5. Metadaten pro Composite-Parameter
Minimal in der DB (Beispiel):
| Feld | Zweck |
|------|--------|
| `data_type` | `composite` |
| `composite_archetype_key` | Verweis auf Code-Registry |
| `composite_archetype_version` | Schema-Version |
| `validation_rules` | optional: Overrides (z.B. `max_zones`, sport-spezifisch) — nur was der Validator explizit auswertet |
**Admin-API:** bestehende Endpoints erweitern (Payload-Validierung): bei `composite` müssen Archetyp + Version gesetzt sein und in der **Registry** existieren.
---
## 6. Layer 1 Kontrakt (`activity_session_metrics.py` + Helfer)
### 6.1 Schema-Auflösung
`resolve_activity_attribute_schema` liefert pro Composite **einen** Eintrag wie bei Skalaren, mit:
- `data_type: "composite"`
- `composite_archetype_key`, `composite_archetype_version` (aus DB oder Join)
- ggf. `composite_slot_catalog`: **nur wenn** für Admin/UI gewünscht — alternativ separater Endpoint `GET .../composite-archetypes` (read-only) aus Registry, um Bundle-Größe klein zu halten.
### 6.2 Lesen / Merge
- `fetch_activity_session_metrics`: SELECT inkl. `value_json`.
- `merge_column_backed_and_eav_metrics`: Composites **nur** aus EAV (`value_json`), kein `activity_log`-Shadowing (außer später explizit im Kanon — Standard: nein).
- Ausgabe in `metrics`-Liste: ein Eintrag pro Parameter mit z.B.
`value: { "_composite": true, "document": { ... } }` **oder** kanonisch getrennt: `value_document` + `value` null — **festlegen beim Implementieren** und in API-Doku halten; Empfehlung: **`value` = deserialisiertes Objekt (dict)** für Composites, damit Frontend dieselbe Struktur wie Speicher hat.
### 6.3 „Einzelwerte für Layer 1 / Issue 53“
Neue **pure** Funktion (kein SQL im Router), z.B.:
```text
expand_composite_metrics_for_session(
schema: list[dict],
metrics: list[dict],
) -> dict[str, Any]
```
- Input: effektives Schema + gemergte Metriken.
- Output: flaches Dict **`slot_path → typisierter Wert`**, z.B.
`hr_zones.z1_sec → 1200`, oder namespaced Keys `training_param_key.slot_key` zur Kollisionssicherheit.
- Nutzung: `activity_metrics`, Chart-Builder, später Platzhalter-Registry (`data_layer_function`), **ohne** JSON-Parsing in Layer 2.
**Wichtig:** Skalare Parameter erscheinen im expandierten Dict mit ihrem `parameter_key` wie bisher (kein Breaking Change für Consumer, die nur Skalare erwarten).
### 6.4 Validierung / Schreiben
- **`replace_activity_session_metrics`:** Payload-Item für Composite: `value` ist **Objekt** (dict) oder JSON-String — Server normalisiert zu dict, validiert mit Archetyp-Validator, speichert als `value_json`.
- **`upsert_session_metrics_from_csv_mapped`:** siehe §7 (Zusammenbau aus Partial-Updates pro Zeile).
**Pflicht:** Keine Teil-Updates in DB, die ein halbes Dokument hinterlassen, ohne Validierung — außer explizit als „Draft“-Modus spezifiziert (nicht Teil dieses Konzepts).
---
## 7. CSV / Universal Import
### 7.1 Map-Ziel-Notation
Stabiles Muster (Vorschlag, im Import-Modul zentral parsen):
```text
"<parameter_key>.<slot_key>"
```
Beispiel: `my_hr_zones.z1_sec` → nach Import-Zusammenfügung in den Parameter `my_hr_zones` unter Slot `z1_sec`.
**Alternative:** explizites Präfix `composite:` in der Vorlage — nur nötig, wenn Kollisionen mit normalen Keys befürchtet werden; sonst Punkt-Notation reicht.
### 7.2 Executor-Flow (Konzept)
1. `build_row_after_mapping` liefert flache Keys inkl. `param.slot`.
2. Nach Schreiben von `activity_log` / Skalar-EAV: **Composite-Accumulator** pro `activity_log_id` und `parameter_key`:
- Sammelt alle Slot-Werte aus der Zeile.
3. Vor Commit der Zeile (oder am Ende der Datei — **pro Zeile empfohlen**, damit SAVEPOINT pro Row funktioniert):
- Dokument aus Slots bauen → Validator → Upsert `activity_session_metrics` mit `value_json`.
**Teilbefüllung:** Validator entscheidet (Archetyp: optional vs. required Slots). CSV darf nur Teilmengen liefern, wenn Archetyp erlaubt.
### 7.3 Typkonvertierung
Pro **Slot** im Archetyp: definierter skalarer Typ (`float`, `int`, …). Converter wie bei Skalaren (Executor / zentrale Converter), **keine** Parallel-Logik in Routern.
---
## 8. Admin-UI / Mapping-UX
### 8.1 Parameter anlegen
- Auswahl **Datentyp „Composite“** → Dropdown **Archetyp** (aus Registry-API), Version readonly oder wählbar gemäß Policy.
- Rest wie Skalar: Name, Kategorie (`training_parameters.category`), Aktiv-Flag.
### 8.2 Profil zuordnen
Unverändert: Kategorie-/Typ-Matrix wie heute.
### 8.3 Universal-CSV-Vorlage
- Mapping-Ziele: neben bisherigen Keys **Slot-Ziele** `parameter_key.slot_key`.
- UI-Gruppierung: optisch **Composite-Block** (wie in `ACTIVITY_PRODUCTION_ARCHITECTURE` §2.5 angedeutet), um Verwechslung mit Spine-Spalten zu vermeiden.
---
## 9. API-Oberflächen (Erweiterungen)
| Bereich | Änderung |
|---------|-----------|
| `GET /api/activity/{id}` | `metrics` enthält Composite-Werte als Objekt; `schema` kennzeichnet `data_type: composite`. |
| `PUT /api/activity/{id}/metrics` | Eintrag `{ parameter_key, value: { ... } }` für Composites. |
| Admin `training-parameters` | Create/Update mit Composite-Feldern. |
| Optional | `GET /api/admin/composite-archetypes` | Registry export für UI (Keys, Slot-Liste, Version). |
**Rückwärtskompatibilität:** Clients, die nur Skalare senden, unverändert.
---
## 10. Frontend (Kurz)
- `ActivityPage` / Session-Metrik-Editor: für `data_type === composite` **strukturierte Teilfelder** aus Slot-Katalog rendern (oder JSON-Editor nur als Entwickler-Fallback — Produkt: strukturierte Felder).
- Sortierung/Gruppierung: bestehende `param_category` / `ui_group` / `sort_order` gelten unverändert.
---
## 11. Tests (pytest)
| Test | Beschreibung |
|------|----------------|
| Archetyp-Validator | gültige / ungültige Dokumente je Version |
| DB-Constraint | Skalar vs. Composite Ausschluss |
| `expand_composite_metrics_for_session` | flache Keys, Kollisionen |
| CSV-Zusammenbau | mehrere Spalten → ein `value_json` |
| Regression | bestehende `test_activity_session_metrics.py` unverändert grün halten |
---
## 12. Rollout-Phasen (operativ)
Stimmt mit `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` überein:
1. **Phase D MVP:** ein Preset (z.B. HF-Zonen → `distribution_set`, `domain: heart_rate`), Migration `value_json` + `composite` data_type, Validator gegen Basisschema §7, Import 35 Spalten → `items`, GET/PUT, minimale Admin-Anbindung.
2. **Phase E:** weitere Presets / `kind`-Varianten, Mapping-UX, `expand_*` für ausgewählte Layer-1-Consumer.
3. **Phase F:** Observability, Performance, Doku, Gitea-Issues schließen.
### 12.1 Empfohlene Reihenfolge: Skalar-Pipeline vs. Composite-Speicherung
**Frage:** Zuerst Skalar-EAV vollständig bis Platzhalter/Orchestrator abschließen, oder zuerst Composite-Speicherung?
| Option | Vorteil | Risiko |
|--------|---------|--------|
| **A: Nur Skalar zuerst** (Kanon, L1-Härtung, Platzhalter aus EAV/L1) | Eine klare, end-to-end **Referenzpipeline**; weniger gleichzeitige Variablen | Composite-Datenstrome verzögern sich |
| **B: Composite-Speicher zuerst** | JSON landet früh in der DB | Platzhalter/Charts nutzen noch **alte** Pfade → **zwei Wahrheiten** (Detail-API vs. KI) bis L1 vereinheitlicht ist |
| **C (Empfehlung): Skalar L1 + Platzhalter-Orchestrierung *vor* Composite-MVP**, oder **eng parallel** mit gemeinsamem L1-Einstieg | `get_activity_session_logical_unit` / `activity_metrics` werden **kanonisch**; Platzhalter lesen **dieselbe** Schicht; Composite wird **additiv** (`value_json` + Validator + später `expand_*`) | Erfordert kurze Planungsdisziplin: Composite-MVP **ohne** sofort alle KI-Platzhalter |
**Konkrete Empfehlung**
1. **`ACTIVITY_PRODUCTION` Phase AB** nicht überspringen: Kanon „eine Semantik / eine Quelle“ + alle relevanten Consumer über **Layer 1** (mind. Session-Detail, Listen-Anreicherung, erste Platzhalter-Pfade für **Skalare**).
2. **Dann Phase D (Composite-MVP):** Migration + Speichern/Lesen mit **Basisschema** (`kind`/`items`/…); L1 liefert dasselbe API-Objekt wie Skalare, nur `value` als strukturiertes Dokument.
3. **Platzhalter für Composite:** erst **nach** L1 liefert stabil `value_json` **und** optional `expand_composite_metrics_*` — ein Orchestrator-Endpoint bzw. Resolver-Aufruf, der **eine** L1-Funktion nutzt, vermeidet doppelte Logik für Skalar vs. Composite.
**Kurz:** Composite **persistieren** kann kurz nach stabiler **Skalar-Lese-/Merge-API** folgen; **KI/Platzhalter für Composite** sinnvoll **gemeinsam** mit der erweiterten L1-Ausgabe bauen, nicht gegen eine noch nicht vereinheitlichte Skalar-Pipeline.
---
## 13. Checkliste für den nächsten Agenten
- [ ] Migration: `value_json`, erweiterte CHECKs, `training_parameters.data_type` + ggf. `composite_archetype_*` Spalten.
- [ ] Registry-Modul: Archetypen + Versionen + Slot-Metadaten + Validator-Einstieg.
- [ ] `activity_session_metrics.py`: Fetch/Merge/Replace/Upsert-Integration; keine Regression für Skalare.
- [ ] Optional: `expand_composite_metrics_for_session` + erste Nutzung in einem Layer-1-Consumer (Tests).
- [ ] CSV: Parser für `parameter_key.slot_key`, Row-Accumulator, Fehler melden wie bestehender Import.
- [ ] Admin-API + UI: Composite anlegen, tcp/ttp unverändert nutzbar.
- [ ] Doku: dieses Dokument mit **festgelegter** JSON-Beispielstruktur pro MVP-Archetyp ergänzen.
---
## 14. Referenzen
- `functional_concept_composite_data.md` **fachliches** Schichtenmodell, vier technische `kind`-Container, Basisschema JSON
- `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` Zielbild, Phasen AF
- `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md` Ist-Layer-1, APIs
- `UNIVERSAL_CSV_IMPORT_AGENT_GUIDE.md` Executor, Vorlagen
- Migration `054_activity_session_metrics_eav.sql` Ist-Constraint Skalar
- Migration `013_training_parameters.sql` Ist-`data_type`-Enum
---
**Version:** 1.1 · Abgleich mit fachlichem Konzept (§1.4, §3, §12.1); MVP auf `distribution_set` o. ä. konkretisieren.

View File

@ -0,0 +1,70 @@
# Aktivität: Layer-2a-Platzhalter — Audit Schritt 1 (Issue #53)
**Stand:** 2026-04-16
**Bezug:** [Issue #53 — Multi-Layer Architecture](../../../docs/issues/issue-53-phase-0c-multi-layer-architecture.md): Layer 1 = strukturierte Daten, Layer 2a = KI-Formatierung (keine parallele Domänen-Logik im Resolver).
**Ziel dieses Dokuments:** Jeder Aktivitäts-Platzhalter hat genau eine **Layer1Quelle** (`data_layer/activity_metrics.py`); `placeholder_resolver.py` formatiert oder serialisiert nur noch.
---
## 1. Ergebnisübersicht
| Kategorie | Anzahl | Resolver-SQL für Aktivität? |
|-----------|--------|------------------------------|
| Gebündelt in `PLACEHOLDER_MAP` (Training/Aktivität) | 20 | **Nein** |
| Abweichungen / offene Punkte | 0 | — |
**Hinweis:** `{{rest_days_count}}` steht in der Karte unter „Schlaf & Erholung“ und nutzt `recovery_metrics.get_rest_days_data` — nicht in dieser Tabelle.
---
## 2. Platzhalter → Layer 1 → Layer 2a
| Key | Layer 1 (`activity_metrics`) | Layer 2a (`placeholder_resolver`) | Bemerkung |
|-----|------------------------------|-------------------------------------|-----------|
| `activity_summary` | `get_activity_summary_data` | `get_activity_summary` | String-Zusammenfassung |
| `activity_detail` | `get_activity_detail_data` (+ `enrich_sessions_with_metrics`) | `get_activity_detail` | Dynamische `session_metrics[]` pro Zeile (Profil/EAV) |
| `trainingstyp_verteilung` | `get_training_type_distribution_data` | `get_trainingstyp_verteilung` | Ausgabe: Top-3-Text (kein JSON); Registry 2026-04 an Ist angeglichen |
| `training_minutes_week` | `calculate_training_minutes_week` | `_safe_int` | |
| `training_frequency_7d` | `calculate_training_frequency_7d` | `_safe_int` | |
| `quality_sessions_pct` | `calculate_quality_sessions_pct` | `_safe_int` | |
| `proxy_internal_load_7d` | `calculate_proxy_internal_load_7d` | `_safe_int` | |
| `monotony_score` | `calculate_monotony_score` | `_safe_float` | |
| `strain_score` | `calculate_strain_score` | `_safe_int` | |
| `rest_day_compliance` | `calculate_rest_day_compliance` | `_safe_int` | |
| `ability_balance_strength` | `calculate_ability_balance_strength` | `_safe_int` | abilities in `activity_log` |
| `ability_balance_endurance` | `calculate_ability_balance_endurance` | `_safe_int` | |
| `ability_balance_mental` | `calculate_ability_balance_mental` | `_safe_int` | |
| `ability_balance_coordination` | `calculate_ability_balance_coordination` | `_safe_int` | |
| `ability_balance_mobility` | `calculate_ability_balance_mobility` | `_safe_int` | |
| `vo2max_trend_28d` | `calculate_vo2max_trend_28d` | `_safe_float` | |
| `activity_score` | `calculate_activity_score` | `_safe_int` | |
| `training_frequency_by_type_md` | `get_training_frequency_by_type_data` | `get_training_frequency_by_type_md` | Markdown-Tabelle |
| `training_inter_session_gap_md` | `get_training_inter_session_gap_data` | `get_training_inter_session_gap_md` | Markdown-Text |
| `training_sessions_recent_json` | `get_training_sessions_recent_weeks_data` (+ `enrich_sessions_with_metrics`) | `_safe_json('training_sessions_recent_json')` | JSON inkl. `session_metrics[]` pro Session |
---
## 3. Schichten-Disziplin (Checkliste)
- [x] Kein `SELECT` auf `activity_log` / `activity_session_metrics` in den **Layer2a**-Funktionen oben — nur Aufrufe in Layer 1 bzw. `_safe_*`-Wrapper.
- [x] `get_activity_detail` / `get_training_sessions_recent_json` liefern EAV nur über **bereits gemergte** `session_metrics` (Merge-Kanon: `activity_log` vor EAV).
- [x] Registry-Metadaten: `data_layer_module` / `data_layer_function` pro Key in `placeholder_registrations/activity_metrics.py` und `activity_session_insights.py`.
- [x] Korrektur Registry: `activity_summary.resolver_function` = `get_activity_summary` (war veraltet: `_format_activity_summary`).
---
## 4. Nächste Schritte (Roadmap)
2. ~~**Registry-Texte:** `semantic_contract` / `known_limitations` für dynamische `session_metrics` (tcp/ttp) und Merge-Kanon — **erledigt** (`activity_detail`, `training_sessions_recent_json`); dazu **`trainingstyp_verteilung`**-Metadaten von veraltetem „JSON/Resolver-SQL“ auf Ist (**Layer 1 + Top-3-Text**) korrigiert.~~
3. **History / Layer 2b:** EAV-Zeitreihen nicht über Platzhalter, sondern dedizierte Layer1-/Chart-Pfade.
4. **Optional:** Gitea-Issue „Activity Layer 2a“ bei Änderungen an `activity_metrics` pflegen.
---
## 5. Referenzen
- `backend/placeholder_resolver.py``PLACEHOLDER_MAP` (Training/Aktivität)
- `backend/placeholder_registrations/activity_metrics.py`
- `backend/placeholder_registrations/activity_session_insights.py`
- `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` §2.1a (Navigation Read vs. Berechnen)

View File

@ -0,0 +1,215 @@
# Aktivität: Zielarchitektur & Phasenplan (Produktionsreife)
**Stand:** 2026-04-16
**Status:** Normative Zielrichtung für `activity_log`, EAV, Composites, Import, Layer 1/2.
**Ergänzt:** `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md` (Ist-Modell, APIs, Tests).
**Phase A:** abgeschlossen — Kanon-Tabelle [`ACTIVITY_SCALAR_KANON_TABLE.md`](./ACTIVITY_SCALAR_KANON_TABLE.md).
**Phase B:** in Arbeit — Consumer-Audit und Lesepfad-Härtung (siehe §4 Phase B).
---
## 1. Leitprinzipien
| Prinzip | Bedeutung |
|---------|-----------|
| **Layer 1 = Single Source of Truth** | Alle Auswertungen (Charts, Scores, strukturierte Platzhalter) lesen **nur** über `data_layer` (kanonische Funktionen). Keine parallele SQL-Logik in Routern oder im Placeholder-Resolver für Aktivität. |
| **Eine semantische Größe, eine kanonische Quelle** | Kein Dauer-Sync derselben Bedeutung in `activity_log`-Spalte **und** EAV. Übergang: dokumentierte Abschaltung, nicht implizites Driften. |
| **Spine vs. Parameter** | `activity_log` trägt Identität, Zeit, Typ, Notizen, Audit + **heiße** universelle Skalare (siehe §2.2). Alles Typ-/Admin-Dynamische über EAV. |
| **Composites = Archetyp im Code, Konfiguration in der DB** | Struktur (7+2 Archetypen) und Validierung **versioniert im Repo**; Admin **wählt** Archetyp, **benennt** Slots, **bindet** Sportarten, **mappt** CSV → `(parameter_id, slot_key)`. Kein freies JSON-Schema im Admin. |
| **Import explizit** | Jede CSV-Spalte hat ein klares Ziel: Spine-Spalte, skalarer Parameter oder **Slot** eines Composite-Parameters. Typkonvertierung zentral (Executor / Converter), nicht verteilt. |
---
## 2. Zielarchitektur (Gesamtbild)
### 2.1 Schichtenmodell
```
[CSV / UI / API Write]
Orchestrator & Router (Auth, Transaktionen, Feature-Checks)
Persistenz: activity_log (Spine + heiße Skalare) + activity_session_metrics (EAV)
Layer 1: data_layer (activity_session_metrics.py, activity_metrics.py, …)
Layer 2a/2b: Platzhalter-Resolver (Formatierung), Chart-Endpoints (Chart.js-Shapes)
KI / UI / Export
```
- **Orchestrator:** Schreibpfad, Konsistenz nach Write (kein zweites „Lesen der Wahrheit“ neben Layer 1; optional nur Post-Write-Hooks).
- **Resolver:** für Aktivität **kein** direkter DB-Zugriff; nur Aufruf von Layer 1.
### 2.1a Navigationsregel: wo nachsehen (ohne Datei-Zwang)
Die **physische** Aufteilung ist dreigeteilt: **`activity_log`** (Spine + heiße Spalten), **EAV-Skalare** (`activity_session_metrics` + numerische/textuelle `value_*`), **EAV-Composites** (ein Parameter, Nutzlast z.B. JSON/JSONB im EAV-Datensatz). **Fachlich** soll nach außen **eine homogene Session-Sicht** entstehen — Consumer sollen nicht selbst entscheiden, aus welcher Tabelle/Welche Form ein Wert kommt.
| Thema | Wo nachsehen (Ist; Ziel: Schnittstelle stabil, Datei optional splittbar) |
|--------|--------------------------------------------------------------------------|
| **Homogene Session lesen** (Merge Spalte + EAV-Skalare + später Composite-Payload) | `data_layer/activity_session_metrics.py` — u.a. `get_activity_session_logical_unit`, `enrich_sessions_with_metrics`, `merge_column_backed_and_eav_metrics` |
| **Schreiben / Import / API-Persistenz** | `data_layer/activity_persistence_orchestrator.py` (+ Router) |
| **Berechnungen, Aggregationen, Scores** über viele Sessions oder Zeitfenster | `data_layer/activity_metrics.py` — arbeitet auf der **vereinheitlichten** Session-Datenlage (über die Read-Funktionen oben), nicht durch paralleles Mergen der drei Quellen im Caller |
**Hinweis:** Orchestrator und Read-Merge **müssen nicht** in derselben Datei stehen. Entscheidend ist, dass es **genau eine dokumentierte Read-Fassade** für „Session inkl. aller effektiven Metriken“ gibt und Layer1Berechnungen **nur** diese Fassade (oder deren Ergebnisstrukturen) nutzen. Eine spätere Umbenennung oder Auslagerung in z.B. `activity_read_gateway.py` ändert die Rolle nicht — nur der **eine Einstieg** muss in dieser Doku und im Code auffindbar bleiben.
### 2.2 `activity_log` (Spine + heiße Skalare)
**Maschinenlesbarer Kanon:** `backend/data_layer/activity_data_canon.py` (`ACTIVITY_MODULE_REGISTRY_FIELD_KEYS`, `ACTIVITY_EAV_PRIMARY_PARAMETER_KEYS`, Legacy-Lesefallback für EAV-primäre Parameter).
**Immer (fachlich minimal + listenfähig):** `id`, `profile_id`, Kalender-/Zeitfenster (`date`, `started_at`/`ended_at`, ggf. `start_time`/`end_time` bis Konsolidierung), `duration_min`, `training_type_id` (+ ggf. denormalisierte Kategorie), Legacy `activity_type`, `notes`, `source`, `created`.
**Heiße Skalare (CSV-Modul + `source_field` nach Migration 057):** u.a. `kcal_active`, `kcal_resting`, `distance_km`, `hr_avg`/`hr_max` (Parameter `avg_hr`/`max_hr`), `duration_min`, `rpe` für Listen und Standard-Aggregate ohne EAV-Join.
**EAV-primär (erweiterte Metriken):** z.B. Kadenz, Pace, Leistung, Höhe, Umgebung — `training_parameters.source_field` = NULL; Import schreibt EAV; bei leerem EAV optional Lesefallback auf bestehende `activity_log`-Spalte (Migration 057 + Merge-Logik).
**Session-Qualität / Auswertungsblob:** z.B. `evaluation`, `quality_label`, `overall_score` **kein** EAV-Parameter-Raster; semantisch „Ergebnis der Einheit“.
**Nicht dauerhaft doppelt:** dieselbe Semantik nicht parallel pflegen; siehe entfallener Spalte→EAV-Schreib-Sync, Lesepfad `merge_column_backed_and_eav_metrics`.
### 2.3 EAV (`activity_session_metrics`)
- **Skalare:** ein `training_parameter`, genau eine `value_*`-Spalte (wie heute).
- **Composites:** ein `training_parameter` pro Composite-Instanz, **ein** gespeichertes Dokument pro Session (serialisiert z.B. in `value_text` als JSON **oder** künftig dedizierte JSONB-Spalte technische Entscheidung in eigener Migration, Vertrag im Archetyp).
- **Merge-/Schema-Logik:** weiterhin zentral in `activity_session_metrics.py` (effektives Schema aus Kategorie + Typ-Overrides).
### 2.4 Composite-Metamodell (Ziel)
**Archetypen (Code, begrenzte Menge):** u.a. Band-/Zonenverteilung, Sequenz-/Übergangsprofil, Intervallblock-, Ereignis-/Aktions-, Kopplungs-/Effizienz-, Modellparameter-Profil; optional Technik-/Zyklus-, Readiness-/Recovery-Profil.
**Pro Archetyp:** feste strukturelle Regeln (erlaubte Slots, Typen, Pflicht/Optional), Validator + Version.
**In der DB (Admin):** Zuordnung „Parameter X hat Archetyp A“, Slot-Labels (DE/EN), Einheiten, Aktivierung pro Sportart/Kategorie, Sortierung.
**Import:** CSV-Spalten → `(training_parameter_id, slot_key)` mit stabilen Keys (`z1_sec`, …), nie nur „Spaltenreihenfolge“.
### 2.5 Universal CSV & Admin
- Vorlagen: Mapping inkl. **Composite-Slots** und Typkonvertierung (vollständige Matrix Ziel).
- UI: Trennung **Kern activity_log** vs. **Parameter/EAV** vs. **Composite-Blöcke** (optisch/UX), um Doppel-Tabellen-Chaos zu vermeiden.
### 2.6 Layer 2 (Platzhalter & Diagramme)
- Datenbezug **nur** Layer 1.
- Registry-Einträge: `data_layer_module` / `data_layer_function` pflegen; Composite-Auswertung ggf. über Hilfsfunktionen, die JSON → normierte Struktur für Prompts/Charts liefern.
---
## 3. Ist → Soll (Kurz)
| Bereich | Ist (typisch) | Soll |
|---------|----------------|------|
| Schreibpfad | Teilweise Doppelhaltung Spalte ↔ EAV, Sync-Hooks | Kanon + gezielte Abschaltung; eine Quelle pro Semantik |
| Lesepfad | Layer 1 wächst; Legacy-Spalten noch relevant | `get_activity_session_logical_unit` / `activity_metrics` als alleinige Wahrheit für Consumer |
| Composites | Noch nicht im Einklang mit EAV-Metamodell | Archetypen + Slot-Admin + ein Dokument pro Parameter/Session |
| Import | Mapping teilweise; Typkonvertierung lückenhaft | Vollständige Konvertierung + Composite-Zusammenbau |
| Resolver | Aktivität sauber über Layer 1 | Profil/Focus ggf. später ebenfalls aus Layer 1 |
---
## 4. Vorgehensmodell (Phasen)
Phasen sind **sequentiell** wo „Abhängigkeit“ steht; Teile können parallel (z.B. UI-Polish) laufen, wenn der Kanon steht.
### Phase A Kanon & Abschaltplan (Grundlage) ✅
**Inhalt:** Schriftliche **Kanon-Tabelle**: pro Messgröße genau eine Quelle (`activity_log` | `eav_scalar` | `eav_composite` | `session_quality`). Liste der Keys, für die **Sync/Spiegelung** endet.
**Definition of Done:** Review im Team; Referenz in diesem Dokument oder Verweis auf Gitea-Kommentar; keine Code-Änderung zwingend.
**Erledigt (2026-04-16):** [`ACTIVITY_SCALAR_KANON_TABLE.md`](./ACTIVITY_SCALAR_KANON_TABLE.md) — eine Semantik pro Zeile, verlinkt mit `activity_data_canon.py` und Merge-Logik.
---
### Phase B Lesepfad härten (Layer 1) 🔄
**Inhalt:** Sicherstellen, dass **alle** relevanten Consumer (mind. `activity_metrics` für Platzhalter/Charts, Activity-Detail-API) dieselbe Merge-/Fallback-Logik nutzen; Legacy-Spalten nur noch als dokumentierter Fallback bis Enddatum.
**Definition of Done:** Kurze Audit-Liste „Router/Resolver greifen nicht an Aktivität vorbei“; Tests oder manuelle Stichprobe für Detail + ein Chart + 2 Platzhalter.
**Abhängigkeit:** Phase A für „welche Spalten noch Fallback sind“.
**Audit-Stand (2026-04-16, ergänzt Export):**
| Consumer | Nutzt Layer-1-Merge (`enrich_sessions_with_metrics` / `get_activity_session_logical_unit`) | Anmerkung |
|----------|---------------------------------------------------------------------------------------------|-----------|
| `GET /api/activity/{eid}` | ✅ `get_activity_session_logical_unit` | Referenz-Detail |
| `GET /api/activity` (Liste) | ✅ seit 2026-04-16 `enrich_sessions_with_metrics` auf jeder Listen-Antwort | vorher nur Roh-Spalten |
| `activity_metrics.get_activity_detail_data` | ✅ | Platzhalter `{{activity_detail}}` |
| `activity_metrics.get_training_sessions_recent_weeks_data` | ✅ | KI-Kontext |
| `placeholder_resolver` (Aktivität) | ✅ nur `activity_metrics` | kein paralleles SQL |
| `GET /api/export/json` (`activity`) | ✅ `enrich_sessions_with_metrics` + `serialize_dates` | `session_metrics` pro Zeile |
| `GET /api/export/csv` (Training-Zeilen) | ✅ `enrich_sessions_with_metrics` | gemergte EAV in Spalte „Details“ |
| `GET /api/export/zip` (`data/activity.csv`) | ✅ `enrich_sessions_with_metrics` | Zusatzspalte `session_metrics_json` (Import ignoriert sie) |
| `get_activity_summary_data` | n.a. | rein aggregiert (`SUM`/`COUNT`), keine Session-EAV |
| `routers/charts.py` (A1A8) | Spalten-Aggregate | bewusst: Dauer/RPE/HF aus **`activity_log`**-Kanon; kein EAV-Join nötig für definierte Charts |
| `activity_stats` (`GET /api/activity/stats`) | nur Spalten | Kacheln: `kcal`/`duration` aus Kernspalten |
---
### Phase C Schreibpfad entschlacken
**Inhalt:** Orchestrierung/CSV: kein Schreiben derselben Semantik an zwei Orten; `sync_column_backed_session_metrics` (o. ä.) **stufig abschalten** oder auf Notfall-Flag; Import schreibt gemäß Kanon.
**Definition of Done:** Deploy auf Prod mit Monitoring; Stichprobe Import + manuelle Bearbeitung; keine Regression in Listenansicht.
**Abhängigkeit:** Phase A + B (sonst Lücken beim Lesen).
**Analyse (2026-04-16, nur Ist-Review):** Es gibt **keinen aktiven** Schreibpfad mehr, der `activity_log`-Spalten für `source_field`-Parameter **dauerhaft nach EAV spiegelt**.
| Prüfpunkt | Ergebnis |
|-----------|----------|
| `sync_column_backed_session_metrics` | Nur noch **Definition** in `activity_session_metrics.py`, als veraltet markiert; **keine Aufrufer** im Repo (grep). Laufzeit-Sync: **abgestellt**. |
| `run_activity_post_write_hooks` / `…_import` | Nur **Auto-Eval** (optional); Kommentar: **kein** Spalte→EAV-Sync. |
| Universal-CSV (`executor.py`) | Kernfelder → `activity_log` (`activity_csv_registry_updates_from_mapped` + `update_activity_columns` / Insert); EAV → `upsert_session_metrics_from_csv_mapped`. Registry-Keys werden **nicht** nach EAV geschrieben; bei `source_field` wird EAV **übersprungen**, wenn die Spalte **bereits befüllt** ist — vermeidet bewusst doppelte Speicherung. |
| REST `PUT /metrics` | Kommentar in Code: **kein** `sync_column_backed` nach EAV-Ersatz. |
| Migrationen 055 / 057 | **Einmaliger** Backfill/Schwenk, kein fortlaufender Sync. |
**Lesepfad (2026-04-16):** `merge_column_backed_and_eav_metrics` bevorzugt **immer** `activity_log`, wenn ein kanonischer Spaltenwert existiert: zuerst `source_field`, dann Registry-Spalte gleichen Keys, dann Legacy-Spalten für EAV-primäre Parameter, zuletzt EAV. Doppelte physische Schreiborte sind damit in der effektiven Sicht **ohne EAV-Vorrang** behoben.
---
### Phase D Composite MVP
**Inhalt:** Ein Archetyp end-to-end (z.B. **Band-/Zonenverteilung**): Code-Validator, DB-Binding (Parameter + Slots), Admin-UI minimal, Import **5 Spalten → ein JSON-Dokument** mit festen Keys, Layer-1-Read (Roh + optional `expand_*`).
**Definition of Done:** Eine Sportart/Kategorie befüllbar; Dokumentation des JSON-Vertrags im Repo; pytest für Validator/Zusammenbau wo möglich.
**Abhängigkeit:** Phase A (Kanon „Composites nur als Dokument, nicht doppelt in Spalten“).
---
### Phase E Composite-Ausbau & Typkonvertierung Import
**Inhalt:** Weitere Archetypen nach Priorität; Universal-CSV **vollständige** Typkonvertierung für alle gemappten Ziele; Dialog-/Mapping-Konzept (Kern vs. Parameter vs. Composite).
**Definition of Done:** Matrix „Zieltyp × Converter“ gepflegt; Admin-Flow reviewt.
---
### Phase F Produktionshärtung
**Inhalt:** Performance-Indizes bei Bedarf; Observability (Import-Fehler, Validierungs-Fails); Resolver/Profil optional komplett ohne `get_db` für domänische Daten; Doku + Gitea-Issues geschlossen/aktualisiert.
---
## 5. Was zuerst?
**Erledigt:** Phase A — [`ACTIVITY_SCALAR_KANON_TABLE.md`](./ACTIVITY_SCALAR_KANON_TABLE.md).
**Aktuell:** Phase B fortsetzen (weitere Consumer prüfen: Export, Import-Vorschau, ggf. zukünftige Chart-Metriken aus EAV), dann **Phase C** (Schreibpfad), dann **Phase D** (Composite-MVP).
---
## 6. Referenzen
- `ACTIVITY_SCALAR_KANON_TABLE.md` **Skalar-Kanon** (Phase A)
- `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md` Tabellen, APIs, Tests, Backfill-Hinweise
- `ACTIVITY_COMPOSITE_METRICS_IMPLEMENTATION_CONCEPT.md` Composite-EAV (JSONB), Archetypen, Import-Slots, Layer-1-Expand, Migrations- und Testplan
- `UNIVERSAL_CSV_IMPORT_AGENT_GUIDE.md` Executor, Vorlagen, Typen
- `PLACEHOLDER_REGISTRY_FRAMEWORK.md` Layer-2-Registrierung
- `functional/DATA_ARCHITECTURE.md` fachliche Datenarchitektur (Querschnitt)
---
**Version:** 1.5 · Merge: activity_log (Registry + Legacy-Spalten) vor EAV bei Lesen.

View File

@ -0,0 +1,95 @@
# Aktivität: Skalar-Kanon (eine Semantik → eine Quelle)
**Stand:** 2026-04-16
**Normativer Code:** `backend/data_layer/activity_data_canon.py`
**Kontext:** `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` (Phase A abgeschlossen)
---
## 1. Spine & Identität (`activity_log`, nicht EAV)
Diese Felder sind **keine** `training_parameters`-Skalare. Sie gehören zur Session-Zeile.
| Semantik | DB / API | Kanonische Quelle | Lesefallback | Sync Spalte↔EAV |
|----------|----------|-------------------|--------------|-----------------|
| Primärschlüssel | `activity_log.id` | `activity_log` | — | — |
| Profil | `profile_id` | `activity_log` | — | — |
| Kalendertag | `date` | `activity_log` | — | — |
| Start / Ende (Zeit) | `start_time`, `end_time`, `started_at`, `ended_at` | `activity_log` | — | — |
| Trainingsart (Freitext/Legacy) | `activity_type` | `activity_log` | — | — |
| Referenz Trainingstyp | `training_type_id`, `training_category`, … | `activity_log` (+ `training_types`) | — | — |
| Notiz | `notes` | `activity_log` | — | — |
| Quelle / Import | `source`, `created`, … | `activity_log` | — | — |
| Session-Auswertung | `evaluation`, `quality_label`, `overall_score`, … | `activity_log` (Blob/Ergebnis) | — | Kein EAV-Raster |
---
## 2. Kernfelder CSV-Modul `activity` (= „heiße“ Skalare)
Abgeleitet aus `csv_parser.module_registry.MODULE_DEFINITIONS["activity"].fields` — maschinenlesbar über `ACTIVITY_MODULE_REGISTRY_FIELD_KEYS` in `activity_data_canon.py`.
| Semantik | Key (Registry/API) | Kanonische Quelle | Lesefallback | Bemerkung |
|----------|-------------------|-------------------|--------------|-----------|
| Dauer | `duration_min` | **`activity_log`** | — | Aggregates, Listen |
| Aktive Energie | `kcal_active` | **`activity_log`** | — | |
| Ruhe-Energie | `kcal_resting` | **`activity_log`** | — | |
| Distanz | `distance_km` | **`activity_log`** | — | |
| Ø HF | `hr_avg` (Parameter oft `avg_hr` in EAV-Schema) | **`activity_log`** | EAV nur wenn `source_field` / Profil-Schema | `merge_column_backed_and_eav_metrics`: Spalte schlägt EAV |
| Max-HF | `hr_max` | **`activity_log`** | analog | |
| RPE | `rpe` | **`activity_log`** | analog | |
Schreibpfad: Universal-CSV und API sollen diese Keys auf **`activity_log`** mappen, sofern nicht ausdrücklich ein EAV-primärer Parameter (§3) gewählt ist.
---
## 3. EAV-primäre Parameter (erweiterte Skalare)
`ACTIVITY_EAV_PRIMARY_PARAMETER_KEYS` in `activity_data_canon.py`. **`training_parameters.source_field`** = NULL (nach Kanon / Migration 057): kanonischer Speicher ist **`activity_session_metrics`**.
| Parameter-Key (`training_parameters.key`) | Legacy-Spalte `activity_log` | Schreib-Kanon (Ziel) |
|-------------------------------------------|------------------------------|------------------------|
| `min_hr` | `hr_min` | **EAV** |
| `pace_min_per_km` | `pace_min_per_km` | **EAV** |
| `cadence` | `cadence` | **EAV** |
| `avg_power` | `avg_power` | **EAV** |
| `elevation_gain` | `elevation_gain` | **EAV** |
| `temperature_celsius` | `temperature_celsius` | **EAV** |
| `humidity_percent` | `humidity_percent` | **EAV** |
| `avg_hr_percent` | `avg_hr_percent` | **EAV** |
| `kcal_per_km` | `kcal_per_km` | **EAV** |
**Lesen:** `merge_column_backed_and_eav_metrics` — wenn Legacy-Spalte **und** EAV einen Wert haben, **gewinnt die Spalte** (kanonische `activity_log`-Sicht). EAV nur, wenn die Spalte leer/nicht koerzierbar ist.
---
## 4. Profil-/Typ-dynamische Skalare (EAV, nicht in Registry-Kernliste)
| Semantik | Kanonische Quelle | Lesefallback |
|----------|-------------------|--------------|
| Admin-definierte Parameter (Attributprofil Kategorie/Typ) | **`activity_session_metrics`** + `training_parameters` | — |
| Parameter mit `source_field` → Spalte | **`activity_log`** (Spalte) | EAV ergänzend; Leseregel: Spalte bevorzugt (kein veraltetes EAV) |
---
## 5. Composites (Zielbild, noch nicht Kanon-Zeile pro Slot)
| Semantik | Kanonische Quelle (Ziel) |
|----------|---------------------------|
| Strukturierte Composite-Dokumente (z.B. Zonen/Bänder) | **EAV** ein Dokument pro Parameter/Session (siehe `ACTIVITY_COMPOSITE_METRICS_IMPLEMENTATION_CONCEPT.md`) |
Kein dauerhaftes Spiegeln derselben Semantik in `activity_log`-Spalten.
---
## 6. Sync & Übergang
- **Kein** automatischer Dauer-Sync „Spalte → EAV“ für dieselbe Semantik; Lesepfad vereinheitlicht die Sicht (`merge_column_backed_and_eav_metrics`).
- Optionale **Backfill**-Migration/Skript (idempotent) nur nach fachlicher Freigabe — siehe EAV-Agent-Guide §6.
---
## 7. Referenzen
- `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` — Phasen AF
- `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md` — APIs, Tests
- `activity_data_canon.py``ACTIVITY_LOG_PATCHABLE_COLUMNS`, Legacy-Map

View File

@ -0,0 +1,146 @@
# Activity Session Metrics (EAV) Umsetzungs- & Agent-Guide
**Stand:** 2026-04-14
**Status:** Kern-Backend (Migration 054, Layer 1, Admin- & Nutzer-API) umgesetzt; Admin-UI & CSV-Mapping folgen.
**Ziel:** Sportspezifische **Attributprofile** (Kategorie + optional Trainingstyp-Override) administrierbar; Messwerte pro Session in **EAV**; **alle Auswertungen** sollen künftig über **Layer 1** (`data_layer`) laufen.
**Zielarchitektur, Phasenplan (Produktionsreife):** [`ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md`](./ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md) Kanon `activity_log`/EAV, Composites, Import, Layer 1/2, Reihenfolge AF.
**Composite-Parameter (EAV, JSONB, Archetypen):** detailliertes Umsetzungskonzept für Agenten: [`ACTIVITY_COMPOSITE_METRICS_IMPLEMENTATION_CONCEPT.md`](./ACTIVITY_COMPOSITE_METRICS_IMPLEMENTATION_CONCEPT.md).
**Kanon (Code):** `backend/data_layer/activity_data_canon.py` (Repo-Root) — CSV-Modul `activity` vs. EAV-primär; Migration **057**.
---
## 1. Produktions-Migrationen (Pflicht)
- **Nur additive Änderungen** bis zur Stabilisierung: neue Tabellen/Spalten **nullable**, kein `DROP COLUMN` / `DELETE` von Altbestand in derselben Story.
- Neue Migrationen: **`backend/migrations/054_*.sql`** (nächste freie Nummer nach 053 einhalten).
- **Prod-Checkliste vor Deploy:**
1. Backup / Snapshot der DB.
2. Migration auf **Kopie** der Prod-DB laufen lassen; Container-Start (`db_init`) verifizieren.
3. Stichprobe: `activity_log`-Zeilen unverändert; neue Tabellen leer oder nur Seed.
- **Datenhaltung:** Bestehende Spalten in `activity_log` bleiben **Quelle für Alt-Daten**; EAV (`activity_session_metrics`) ist der **kanonische Ort für konfigurierte Session-Metriken**, sobald geschrieben. Backfill Altspalten → EAV ist **separater Schritt** (siehe §6).
---
## 2. Datenmodell (Ist nach Migration 054)
| Tabelle | Zweck |
|---------|--------|
| `training_parameters` | Katalog messbarer Größen (`key`, `data_type`, `unit`, `validation_rules`, …) bereits Migration 013; Admin-API ergänzt. |
| `training_category_parameter` | Welche Parameter für welche **`training_types.category`** (z. B. `cardio`) gelten: `sort_order`, `required`, `ui_group`. |
| `training_type_parameter` | Zusatzparameter oder **Overrides** pro **`training_types.id`**: `sort_order`, `required`, `ui_group` (NULL = von Kategorie erben). |
| `activity_session_metrics` | EAV: `(activity_log_id, training_parameter_id)` eindeutig; genau eine Wertspalte `value_num` / `value_int` / `value_text` / `value_bool`. |
| `activity_log` | **Neu:** `started_at`, `ended_at` (`TIMESTAMPTZ`, nullable) für spätere Dedupe/Intervalle; **kein** Pflichtfeld in v1. |
**Merge-Logik effektives Schema** (Layer 1, eine Funktion):
1. Kategorie ermitteln: aus Zeile `training_category` oder aus `training_types.category` via `training_type_id`.
2. Basis = alle Zeilen `training_category_parameter` für diese Kategorie, Join auf `training_parameters` (aktiv).
3. Für jeden Eintrag in `training_type_parameter` zum gewählten Typ: gleiche `training_parameter_id` → Overrides anwenden; nur im Typ vorhanden → anhängen.
4. Sortierung: `sort_order` aufsteigend, dann `key`.
---
## 3. Layer 1 Kanonische Module
| Modul | Pfad | Aufgabe |
|-------|------|---------|
| Session-Metriken & Schema | `backend/data_layer/activity_session_metrics.py` | `resolve_activity_attribute_schema`, `fetch_activity_session_metrics`, `replace_activity_session_metrics`, `get_activity_session_logical_unit`, `enrich_sessions_with_metrics`, `merge_column_backed_and_eav_metrics`. |
**Spalten vs. EAV (Lesepfad):** `merge_column_backed_and_eav_metrics` / `get_activity_session_logical_unit` / `enrich_sessions_with_metrics` werten Parameter mit `source_field` **primär aus `activity_log`** aus; EAV ist Fallback (z.B. Legacy) oder für Parameter ohne Spalte. **Kein** automatischer Spalte→EAV-Schreib-Sync mehr in `run_activity_post_write_hooks` / Import-Hooks (vermeidet Doppelhaltung).
**Regeln für Agenten:**
- **Keine** zweite Implementierung derselben Merge- oder Validierungslogik in Routern.
- Platzhalter / Charts, die Session-Details brauchen: **nur** diese Layer-1-Helfer erweitern oder aufrufen (z. B. `activity_metrics.get_training_sessions_recent_weeks_data` nutzt `enrich_sessions_with_metrics`).
- Router: `get_db`, `get_cursor`, Auth; Business-Validierung delegieren an `activity_session_metrics`.
**KI-Kontext:** In `training_sessions_recent_json` enthält jedes Element von `session_metrics` neben `key`/`value` die Felder `name_de`, `name_en`, `description_de`, `description_en` (aus dem effektiven Schema). Für nicht selbsterklärende Keys soll im Katalog `training_parameters.description_*` gepflegt werden (Admin). Ergänzend liefert der Platzhalter `{{training_parameters_glossary_md}}` die gesamte aktive Parameter-Legende als Markdown-Tabelle (`get_training_parameters_ki_glossary_data` → `get_training_parameters_glossary_md`).
---
## 4. API (Ist / geplant)
### Admin (`require_admin`)
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| GET/POST | `/api/admin/training-parameters` | Katalog lesen / Parameter anlegen |
| PUT/DELETE | `/api/admin/training-parameters/{id}` | Aktualisieren / Soft-deaktivieren (`is_active`) |
| GET | `/api/admin/training-category-parameters?category=` | Zuordnungen Kategorie |
| POST | `/api/admin/training-category-parameters` | Zuordnung anlegen |
| DELETE | `/api/admin/training-category-parameters/{id}` | Zuordnung entfernen |
| GET | `/api/admin/training-type-parameters?training_type_id=` | Zuordnungen Typ |
| POST | `/api/admin/training-type-parameters` | Zuordnung anlegen |
| DELETE | `/api/admin/training-type-parameters/{id}` | Zuordnung entfernen |
Router: `backend/routers/admin_training_parameters.py`, `backend/routers/admin_activity_attribute_profiles.py`.
### Nutzer (`require_auth`)
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| GET | `/api/activity/{eid}` | Session-Kopf + `schema` + `metrics` (Layer 1) |
| PUT | `/api/activity/{eid}/metrics` | **Voller Ersatz** der EAV-Metriken für diese Session (Liste `{parameter_key, value}`) |
`ActivityEntry` unverändert für bestehende Create/Update-Routen; optionale Erweiterung um `started_at`/`ended_at` in späterem Schritt.
---
## 5. Agent-Checkliste (nächste Iterationen)
**Layer 2a (Platzhalter Aktivität):** Abgleich Registry ↔ Resolver ↔ Layer 1 — [`ACTIVITY_LAYER2A_PLACEHOLDER_AUDIT.md`](./ACTIVITY_LAYER2A_PLACEHOLDER_AUDIT.md) (Issue #53). **Schritt 2:** `semantic_contract` / `known_limitations` für dynamische `session_metrics` und Korrektur `trainingstyp_verteilung` in der Registry.
Siehe **Phasen AF** in [`ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md`](./ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md). Kurz:
- [x] **Phase A:** Kanon-Tabelle (eine Quelle pro Semantik) — [`ACTIVITY_SCALAR_KANON_TABLE.md`](./ACTIVITY_SCALAR_KANON_TABLE.md).
- [ ] **Phase B:** Lesepfad Layer 1 härten (Consumer-Audit fortlaufend — siehe `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` §4 Phase B).
- [ ] **Phase C:** Schreibpfad: Doppelhaltung / Sync stufenweise abschalten.
- [ ] **Phase D:** Composite-MVP (ein Archetyp E2E).
- [ ] **Phase E:** Archetypen ausbauen + CSV-Typkonvertierung vollständig + Mapping-UX.
- [ ] **Phase F:** Härtung Prod (Indizes, Observability, Doku).
Legacy-Punkte:
- [x] Admin-UI: `frontend/src/pages/AdminActivityAttributeProfilesPage.jsx`, Route `/admin/activity-attribute-profiles`, Admin-Nav-Gruppe „Trainingstypen“.
- [x] `/activity` Frontend: Bearbeiten lädt `GET /api/activity/{id}`, dynamische Felder + `PUT /api/activity/{id}/metrics`.
- [ ] Universal CSV: Mapping inkl. EAV/Composite-Ziele + Executor (fortlaufend).
- [ ] Optional: Backfill / Abschluss `source_field`-Pfad nach Kanon (Phase A/C).
- [ ] Dedupe Polar/Apple: nach stabilen `started_at`/`ended_at` + Policy (eigenes Issue).
---
## 6. Backfill (nicht in Migration 054)
Separates Skript oder Migration **055+**, wenn fachlich freigegeben:
- Pro aktivem `training_parameter` mit gesetztem `source_field`: Wert aus `activity_log` lesen, in EAV schreiben, wenn noch keine Zeile existiert.
- Idempotent (`ON CONFLICT DO NOTHING` oder Upsert-Regel dokumentieren).
---
## 7. Automatische Tests (pytest, ohne DB)
Aus **`backend/`**:
```bash
python -m pytest tests/test_activity_session_metrics.py -v
```
Abdeckung: reine Merge-Logik (`merge_parameter_schema_rows`), Validierung (`_validate_single_value`), `resolve_activity_attribute_schema` mit Mock-Cursor, `enrich_sessions_with_metrics` mit Mock-Cursor.
---
## 8. Referenzen
- Migration 013: `training_parameters`
- Migration 004/014: `training_types`, `activity_log`-Erweiterungen
- Pattern Admin-Katalog: `routers/admin_reference_value_types.py`
- Platzhalter Session-JSON: `data_layer/activity_metrics.py``get_training_sessions_recent_weeks_data`
- KI-Legende: `get_training_parameters_ki_glossary_data`, Platzhalter `{{training_parameters_glossary_md}}`
---
**Version:** 1.1 · Bei Schema- oder API-Änderungen dieses Dokument und ggf. `CLAUDE.md` Kurzverweis aktualisieren.

View File

@ -0,0 +1,387 @@
# Aggregation Methods Goal Value Calculation
**Zweck:** Dokumentation für Entwicklung und Erweiterung von Aggregationsmethoden im Goal-System.
**Datum:** 2026-03-28
**Version:** 1.0
**Modul:** `backend/goal_utils.py``_fetch_by_aggregation_method()`
---
## Übersicht
Aggregationsmethoden berechnen den `current_value` von Goals aus Rohdaten (z.B. Trainings, Gewicht, Ernährung). Sie sind der Kern des dynamischen Goal-Tracking-Systems.
**Beispiel:**
```python
Goal: "Trainingshäufigkeit Krafttraining"
source_table: activity_log
source_column: id (nur für COUNT relevant)
aggregation_method: avg_per_week_30d
filter_conditions: {"training_category": "strength"}
→ Berechnet: Durchschnittliche Anzahl Krafttrainings pro Woche (über 30 Tage)
```
---
## Architektur
### 1. Wo sind Methoden definiert?
**Datei:** `backend/goal_utils.py`
**Funktion:** `_fetch_by_aggregation_method(conn, profile_id, table, column, method, filter_conditions)`
**Aufruf-Hierarchie:**
```
goal_utils.fetch_goal_value()
└─> _fetch_by_aggregation_method()
└─> SQL Query mit method-spezifischer Logik
```
### 2. Verfügbare Methoden (Stand: 2026-03-28)
| Methode | Beschreibung | SQL Aggregat | Zeitfenster | Use Case |
|---------|--------------|--------------|-------------|----------|
| `latest` | Aktuellster Wert | SELECT {column} ORDER BY date DESC LIMIT 1 | — | Gewicht, Körperfett, VO2max |
| `avg_7d` | 7-Tage-Durchschnitt | AVG({column}) | 7 Tage | Durchschn. Ruhepuls, HRV |
| `avg_30d` | 30-Tage-Durchschnitt | AVG({column}) | 30 Tage | Durchschn. Kalorien, Protein |
| `sum_30d` | 30-Tage-Summe | SUM({column}) | 30 Tage | Gesamtkalorien, Trainingsminuten |
| `count_7d` | Anzahl Einträge (7d) | COUNT(*) | 7 Tage | Trainings letzte Woche |
| `count_30d` | Anzahl Einträge (30d) | COUNT(*) | 30 Tage | Trainings letzter Monat |
| `min_30d` | Minimum (30d) | MIN({column}) | 30 Tage | Niedrigster Ruhepuls |
| `max_30d` | Maximum (30d) | MAX({column}) | 30 Tage | Höchster VO2max |
| `avg_per_week_30d` | Durchschn. pro Woche | COUNT(*) / 4.3 | 30 Tage | Trainingsfrequenz/Woche |
### 3. Filter-Mechanismus
Alle Methoden unterstützen **optionale Filter** via `filter_conditions` (JSON):
```python
filter_conditions = {"training_category": "strength"}
# Wird zu SQL:
# ... WHERE profile_id = %s AND training_category = %s
```
**Unterstützte Filter-Typen:**
- **Equality:** `{"column": "value"}``WHERE column = 'value'`
- **IN-Clause:** `{"column": ["val1", "val2"]}``WHERE column IN ('val1', 'val2')`
---
## Neue Aggregationsmethode hinzufügen
### Schritt 1: Anforderungen definieren
**Checkliste:**
- [ ] **Name:** Eindeutig, beschreibend (z.B. `avg_per_week_30d`)
- [ ] **SQL-Aggregat:** Welche Funktion? (COUNT, AVG, SUM, MIN, MAX, oder Custom)
- [ ] **Zeitfenster:** Fixed (7d, 30d) oder dynamisch?
- [ ] **Spaltentyp:** Numerisch (DECIMAL, INT) oder UUID/TEXT (nur COUNT)?
- [ ] **Filter-Support:** Ja/Nein?
- [ ] **Return-Typ:** `float` oder `None`
### Schritt 2: Code-Template
**Location:** `backend/goal_utils.py``_fetch_by_aggregation_method()`
```python
elif method == 'neue_methode':
# 1. Zeitfenster definieren (falls relevant)
days_ago = date.today() - timedelta(days=30)
# 2. Parameter vorbereiten (inkl. filter_params)
params = [profile_id, days_ago] + filter_params
# 3. SQL Query (mit date_col und filter_sql)
cur.execute(f"""
SELECT AGG_FUNCTION({column}) as result_value
FROM {table}
WHERE profile_id = %s
AND {date_col} >= %s
AND {column} IS NOT NULL{filter_sql}
""", params)
# 4. Result extrahieren und konvertieren
row = cur.fetchone()
return float(row['result_value']) if row and row['result_value'] is not None else None
```
### Schritt 3: Spaltentyp-Validierung
**Wichtig:** Nur numerische Aggregationen (AVG, SUM, MIN, MAX) auf numerischen Spalten!
**Spaltentypen:**
- ✅ **AVG/SUM/MIN/MAX:** DECIMAL, INT, FLOAT
- ❌ **AVG/SUM/MIN/MAX:** UUID, TEXT, VARCHAR
- ✅ **COUNT:** Beliebiger Typ (UUID, TEXT, etc.)
**Bei Fehlkonfiguration:**
```python
# Wird automatisch geloggt + None returned (siehe except-Block Zeile 414-430)
[ERROR] Failed to fetch value from activity_log.id using avg_7d:
function avg(uuid) does not exist
```
### Schritt 4: Testen
**Manueller Test:**
```python
from goal_utils import _fetch_by_aggregation_method
from db import get_db
with get_db() as conn:
result = _fetch_by_aggregation_method(
conn,
profile_id='...',
table='activity_log',
column='id',
method='avg_per_week_30d',
filter_conditions={"training_category": "strength"}
)
print(f"Result: {result}")
```
**Unit-Test (TODO):**
```python
# backend/tests/test_goal_utils.py
def test_avg_per_week_30d():
# Setup: Insert 12 activities in last 30 days
# Expected: 12 / 4.3 ≈ 2.79
assert result == pytest.approx(2.79, abs=0.1)
```
---
## Beispiel-Implementierung: avg_per_week_30d
**Use Case:** Trainingshäufigkeit pro Woche (geglättet über 30 Tage)
**Berechnung:** `(Anzahl Trainings in 30 Tagen) / 4.3 Wochen`
**Code:**
```python
elif method == 'avg_per_week_30d':
days_ago = date.today() - timedelta(days=30)
params = [profile_id, days_ago] + filter_params
cur.execute(f"""
SELECT COUNT(*) as count_value FROM {table}
WHERE profile_id = %s AND {date_col} >= %s{filter_sql}
""", params)
row = cur.fetchone()
if row and row['count_value'] is not None:
# 30 Tage = 4.285 Wochen (30/7)
return round(float(row['count_value']) / 4.285, 2)
return None
```
**Warum 4.285?**
- 30 Tage ÷ 7 Tage/Woche = 4.285 Wochen
- Alternativ: 4.3 (gerundet) für einfachere Rechnung
---
## Best Practices
### 1. Naming Conventions
**Pattern:** `{aggregat}_{spalte}_{zeitfenster}`
- ✅ `avg_hr_7d` Average heart rate, 7 days
- ✅ `count_per_week_30d` Count per week, averaged over 30 days
- ✅ `sum_calories_30d` Sum of calories, 30 days
- ❌ `get_training_count` Unklar, kein Zeitfenster
- ❌ `calc_average` Zu generisch
### 2. Return-Werte
**Konsistenz:**
- **Erfolg:** `float` (auch bei 0.0)
- **Keine Daten:** `None` (nicht 0.0!)
- **Fehler:** `None` (geloggt im except-Block)
**Warum None statt 0.0?**
```python
# None = "Keine Daten vorhanden"
# 0.0 = "Gemessen, aber Wert ist tatsächlich 0"
```
### 3. Date-Columns
Nicht alle Tabellen nutzen `date` als Spaltenname:
```python
DATE_COLUMN_MAP = {
'blood_pressure_log': 'measured_at', # TIMESTAMP
'activity_log': 'date', # DATE
'fitness_tests': 'test_date', # DATE
# ... siehe goal_utils.py Zeile 289-300
}
```
**Nutzung:** `date_col = DATE_COLUMN_MAP.get(table, 'date')`
### 4. Filter-Safety
**SQL-Injection-Schutz:**
- ✅ **Parametrisierte Queries:** `WHERE col = %s` + `params`
- ❌ **String-Interpolation:** `WHERE col = '{value}'`
**Filter-Validierung:**
```python
try:
filters = json.loads(filter_conditions) if isinstance(filter_conditions, str) else filter_conditions
# ... build filter_sql
except (json.JSONDecodeError, TypeError, AttributeError) as e:
print(f"[WARNING] Invalid filter_conditions: {e}, ignoring filters")
```
### 5. Performance
**Query-Optimierung:**
- `WHERE profile_id = %s` ist **immer** erste Bedingung (Index)
- `AND {column} IS NOT NULL` vor Aggregation (reduziert NULL-Handling)
- `ORDER BY {date_col} DESC LIMIT 1` für `latest` (schneller als MAX)
---
## Erweiterte Methoden (Future)
### Statistische Analysen
**Median:**
```python
elif method == 'median_30d':
# PostgreSQL: PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY column)
cur.execute(f"""
SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY {column}) as median_value
FROM {table}
WHERE profile_id = %s AND {date_col} >= %s{filter_sql}
""", params)
```
**Standard Deviation:**
```python
elif method == 'stddev_30d':
cur.execute(f"""
SELECT STDDEV({column}) as stddev_value FROM {table}
WHERE profile_id = %s AND {date_col} >= %s{filter_sql}
""", params)
```
**Trend (Linear Regression):**
```python
elif method == 'trend_30d':
# Slope via REGR_SLOPE(y, x)
cur.execute(f"""
SELECT REGR_SLOPE(
{column},
EXTRACT(EPOCH FROM {date_col})
) as slope FROM {table}
WHERE profile_id = %s AND {date_col} >= %s{filter_sql}
""", params)
```
### Kalenderwoche
```python
elif method == 'count_calendar_week':
# Montag der aktuellen Woche
today = date.today()
monday = today - timedelta(days=today.weekday())
cur.execute(f"""
SELECT COUNT(*) as count_value FROM {table}
WHERE profile_id = %s
AND {date_col} >= %s
AND {date_col} < %s + INTERVAL '7 days'{filter_sql}
""", [profile_id, monday] + filter_params)
```
---
## Fehlerbehandlung
### Exception-Handling
**Alle Methoden sind wrapped in try-except** (Zeile 329-430):
```python
try:
# ... method logic
except Exception as e:
print(f"[ERROR] Failed to fetch value from {table}.{column} using {method}: {e}")
print(f"[ERROR] Filter conditions: {filter_conditions}")
# CRITICAL: Rollback transaction
conn.rollback()
return None
```
**Warum Rollback?**
- PostgreSQL bleibt in `InFailedSqlTransaction` bis Rollback
- Ohne Rollback: Alle nachfolgenden Queries schlagen fehl
### Typische Fehler
| Fehler | Ursache | Lösung |
|--------|---------|--------|
| `function avg(uuid) does not exist` | AVG auf UUID-Spalte | Methode auf `count_*` ändern |
| `column "xyz" does not exist` | Falsche source_column | Schema prüfen, Spalte korrigieren |
| `division by zero` | Keine Daten für Durchschnitt | None-Check vor Division |
| `UndefinedColumn: training_category` | Filter-Spalte existiert nicht | Filter entfernen oder Spalte anlegen |
---
## Migration zu neuer Methode
**Szenario:** Bestehende Goal-Type-Definition ändern
**Beispiel:** `sport_pro_woche` von `avg_7d` zu `avg_per_week_30d`
**SQL:**
```sql
UPDATE goal_type_definitions
SET aggregation_method = 'avg_per_week_30d'
WHERE type_key = 'sport_pro_woche';
```
**Wichtig:**
- Bestehende Goals behalten ihre `current_value` (historisch)
- Nächste Berechnung nutzt neue Methode
- UI zeigt dann neuen Wert
---
## Dokumentations-Pflicht
**Bei jeder neuen Methode:**
1. ✅ Eintrag in dieser Datei (Tabelle "Verfügbare Methoden")
2. ✅ Docstring in `_fetch_by_aggregation_method()`
3. ✅ Beispiel-Anwendung (Use Case)
4. ✅ Unit-Test (wenn möglich)
5. ✅ Update in `goal_types.py` Schema-Info (falls relevant für Admin-UI)
---
## Zusammenfassung
**Aggregationsmethoden sind:**
- ✅ Zentral in `goal_utils.py`
- ✅ SQL-basiert (PostgreSQL-Funktionen)
- ✅ Filter-fähig (JSON-basiert)
- ✅ Error-safe (Rollback + None-Return)
- ✅ Erweiterbar (einfaches elif-Pattern)
**Für neue Methoden:**
1. Name definieren (`{aggregat}_{zeitfenster}`)
2. SQL Query schreiben (mit filter_sql)
3. Testen (manuell + Unit-Test)
4. Dokumentieren (diese Datei)
**Bei Fragen:**
- Siehe `backend/goal_utils.py` Zeile 259-430
- Siehe bestehende Methoden als Template
- Siehe `.claude/docs/working/GOALS_SYSTEM_UNIFIED_ANALYSIS.md` für Kontext

View File

@ -0,0 +1,575 @@
# API-Referenz
## Basis-URLs
| Umgebung | URL |
|----------|-----|
| **Production** | `https://mitai.jinkendo.de/api` |
| **Development** | `https://dev.mitai.jinkendo.de/api` |
| **Local** | `http://localhost:8000/api` (Backend direkt) |
---
## Authentifizierung
**Alle geschützten Endpoints** benötigen einen Auth-Token im Header:
```http
GET /api/weight
X-Auth-Token: jT9z3xK...pQ2vL
```
**Token-Beschaffung:** `POST /api/auth/login``{"token": "..."}`
**Storage:** `localStorage.bodytrack_token` (Frontend)
---
## Fehler-Codes
| Status | Bedeutung | Beispiel |
|--------|-----------|----------|
| **200** | Erfolg | `{"data": [...]}` |
| **201** | Erstellt | `{"id": "uuid", ...}` |
| **400** | Bad Request | `{"detail": "Ungültige Eingabe"}` |
| **401** | Unauthorized | `{"detail": "Nicht eingeloggt"}` |
| **403** | Forbidden | `{"detail": "Nur für Admins"}` oder `{"detail": "Feature-Limit erreicht"}` |
| **404** | Not Found | `{"detail": "Eintrag nicht gefunden"}` |
| **429** | Too Many Requests | `{"detail": "Rate limit exceeded: 5 per 1 minute"}` |
| **500** | Server Error | `{"detail": "Interner Fehler"}` |
**Standard-Fehler-Format:**
```json
{
"detail": "Fehlermeldung"
}
```
---
## Rate Limits
| Endpoint | Limit | Grund |
|----------|-------|-------|
| `POST /api/auth/login` | 5/minute | Brute-Force-Schutz |
| `POST /api/auth/register` | 3/hour | Spam-Prevention |
| `POST /api/auth/forgot-password` | 3/minute | E-Mail-Flooding-Schutz |
| `POST /api/auth/resend-verification` | 3/hour | E-Mail-Flooding-Schutz |
**Andere Endpoints:** Keine Rate-Limits (Feature-Limits via Membership-System)
---
## Endpoints nach Modul
### 1. Auth (`/api/auth/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `POST` | `/auth/login` | ❌ | `{email, password}` | `{token, profile_id, name, role, expires_at}` | Login mit E-Mail + Passwort |
| `POST` | `/auth/logout` | ✅ | | `{ok: true}` | Logout (löscht Session) |
| `GET` | `/auth/me` | ✅ | | `{id, name, email, role, tier, ...}` | Aktuelles Profil abrufen |
| `GET` | `/auth/status` | ❌ | | `{status: "ok", version: "v9b"}` | Health Check |
| `PUT` | `/auth/pin` | ✅ | `{pin}` | `{ok: true}` | PIN/Passwort ändern |
| `POST` | `/auth/forgot-password` | ❌ | `{email}` | `{ok: true, message}` | Passwort-Reset anfordern |
| `POST` | `/auth/reset-password` | ❌ | `{token, new_password}` | `{ok: true, message}` | Passwort-Reset bestätigen |
| `POST` | `/auth/register` | ❌ | `{name, email, password}` | `{ok: true, message}` | Selbst-Registrierung |
| `GET` | `/auth/verify/{token}` | ❌ | | `{ok: true, token, profile}` | E-Mail-Verifizierung |
| `POST` | `/auth/resend-verification` | ❌ | `{email}` | `{ok: true, message}` | Verifizierungs-E-Mail erneut senden |
**Rate Limits:** Siehe Tabelle oben
---
### 2. Profiles (`/api/profiles/*`, `/api/profile`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/profile` | ✅ | | `{id, name, email, role, tier, ...}` | Aktives Profil |
| `PUT` | `/profile` | ✅ | `{name?, sex?, dob?, height?, goal_weight?, goal_bf_pct?, avatar_color?}` | `{ok: true}` | Profil aktualisieren |
| `GET` | `/profiles` | ✅ | | `[{id, name, ...}, ...]` | Alle Profile (Multi-User, derzeit nicht genutzt) |
| `POST` | `/profiles` | ✅ | `{name, ...}` | `{id, ...}` | Profil erstellen (Multi-User) |
| `PUT` | `/profiles/{id}` | ✅ | `{name?, ...}` | `{ok: true}` | Profil bearbeiten |
| `DELETE` | `/profiles/{id}` | ✅ | | `{ok: true}` | Profil löschen |
---
### 3. Weight (`/api/weight/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/weight` | ✅ | `?limit=365` | `[{id, date, weight, note, source, created}, ...]` | Gewichtseinträge abrufen |
| `POST` | `/weight` | ✅ | `{date, weight, note?}` | `{id, date, weight, ...}` | Gewicht eintragen (Upsert) |
| `PUT` | `/weight/{id}` | ✅ | `{date, weight, note?}` | `{ok: true}` | Eintrag bearbeiten |
| `DELETE` | `/weight/{id}` | ✅ | | `{ok: true}` | Eintrag löschen |
| `GET` | `/weight/stats` | ✅ | | `{latest, avg_7d, avg_30d, delta_7d, delta_30d, trend}` | Gewichts-Statistiken |
**Feature-Limits:** `weight_entries` (v9c Phase 4: Enforcement aktiv)
---
### 4. Circumferences (`/api/circumferences/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/circumferences` | ✅ | `?limit=100` | `[{id, date, c_neck, c_chest, c_waist, c_belly, c_hip, c_thigh, c_calf, c_arm, notes, photo_id}, ...]` | Umfangsmessungen |
| `POST` | `/circumferences` | ✅ | `{date, c_neck?, c_chest?, ...}` | `{id, ...}` | Messung eintragen (Upsert) |
| `PUT` | `/circumferences/{id}` | ✅ | `{date, ...}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/circumferences/{id}` | ✅ | | `{ok: true}` | Löschen |
**Feature-Limits:** `circumference_entries`
---
### 5. Caliper (`/api/caliper/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/caliper` | ✅ | `?limit=100` | `[{id, date, sf_method, sf_chest, sf_abdomen, ..., body_fat_pct, lean_mass, fat_mass, notes}, ...]` | Hautfaltenmessungen |
| `POST` | `/caliper` | ✅ | `{date, sf_method, sf_chest?, ...}` | `{id, body_fat_pct, ...}` | Messung eintragen (berechnet KF% automatisch) |
| `PUT` | `/caliper/{id}` | ✅ | `{date, ...}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/caliper/{id}` | ✅ | | `{ok: true}` | Löschen |
**Methoden:** `jackson3`, `jackson7`, `durnin`, `parrillo`
**Feature-Limits:** `caliper_entries`
---
### 6. Activity (`/api/activity/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/activity` | ✅ | `?limit=200` | `[{id, date, start_time, end_time, activity_type, duration_min, kcal_active, hr_avg, hr_max, distance_km, rpe, source, notes}, ...]` | Aktivitäten |
| `POST` | `/activity` | ✅ | `{date, activity_type, duration_min, ...}` | `{id, ...}` | Aktivität erstellen |
| `PUT` | `/activity/{id}` | ✅ | `{date, ...}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/activity/{id}` | ✅ | | `{ok: true}` | Löschen |
| `GET` | `/activity/stats` | ✅ | | `{total_activities, total_kcal, avg_duration, ...}` | Statistiken |
| `GET` | `/activity/uncategorized` | ✅ | | `[{activity_type, count}, ...]` | Unkategorisierte Aktivitäten |
| `POST` | `/activity/bulk-categorize` | ✅ | `[{activity_type, training_type_id}, ...]` | `{ok: true, updated_count}` | Bulk-Kategorisierung (lernendes System) |
| `POST` | `/activity/import-csv` | ✅ | `FormData(file)` | `{imported, skipped, failed, errors}` | Apple Health CSV-Import |
**Feature-Limits:** `activity_entries`
---
### 7. Nutrition (`/api/nutrition/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/nutrition` | ✅ | `?limit=365` | `[{id, date, kcal, protein_g, fat_g, carbs_g, source}, ...]` | Ernährungsdaten |
| `GET` | `/nutrition/by-date/{date}` | ✅ | | `{id, date, kcal, ...}` oder `null` | Eintrag für bestimmtes Datum |
| `POST` | `/nutrition` | ✅ | `?date=YYYY-MM-DD&kcal=2000&protein_g=150&fat_g=70&carbs_g=200` | `{id, ...}` | Eintrag erstellen (Upsert) |
| `PUT` | `/nutrition/{id}` | ✅ | `?kcal=2000&...` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/nutrition/{id}` | ✅ | | `{ok: true}` | Löschen |
| `GET` | `/nutrition/correlations` | ✅ | | `{weight_vs_kcal: [...], bf_vs_protein: [...]}` | Korrelationen |
| `GET` | `/nutrition/weekly` | ✅ | `?weeks=16` | `[{week, year, avg_kcal, avg_protein, ...}, ...]` | Wochendaten |
| `GET` | `/nutrition/import-history` | ✅ | | `[{date, count}, ...]` | Import-Historie |
| `POST` | `/nutrition/import-csv` | ✅ | `FormData(file)` | `{imported, skipped, failed, errors}` | CSV-Import (FDDB, MyFitnessPal) |
**Feature-Limits:** `nutrition_entries`, `data_import`
---
### 8. Photos (`/api/photos/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/photos` | ✅ | | `[{id, date, path, created}, ...]` | Alle Fotos |
| `GET` | `/photos/{id}` | ✅ | `?token=...` (optional) | Binary (JPEG) | Foto abrufen (Token für <img> tag) |
| `POST` | `/photos` | ✅ | `FormData(file, date?)` | `{id, path, date}` | Foto hochladen |
| `DELETE` | `/photos/{id}` | ✅ | | `{ok: true}` | Foto löschen |
**Feature-Limits:** `photos`
**Hinweis:** Token-Parameter für `GET /photos/{id}` erlaubt Zugriff via `<img>` tag (ohne Header-Support)
---
### 9. AI Insights (`/api/insights/*`, `/api/ai/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/insights` | ✅ | | `[{id, scope, content, created}, ...]` | Alle Insights |
| `GET` | `/insights/latest` | ✅ | | `{slug: content, ...}` | Neueste Insights pro Scope |
| `POST` | `/insights/trend` | ✅ | | `{content, usage}` | Trend-Analyse (Gewicht) |
| `POST` | `/insights/run/{slug}` | ✅ | | `{content, usage}` | Einzelnen Prompt ausführen |
| `POST` | `/insights/pipeline` | ✅ | | `{content, usage}` | 3-stufige Pipeline |
**Feature-Limits:** `ai_calls` (pro Aufruf), `ai_pipeline` (für Pipeline)
**Prompts:** Konfigurierbar via `/api/prompts`
---
### 10. AI Prompts (`/api/prompts/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/prompts` | ✅ | | `[{id, slug, name, description, template, active, sort_order}, ...]` | Alle Prompts |
| `PUT` | `/prompts/{id}` | 🔒 Admin | `{name?, description?, template?, active?, sort_order?}` | `{ok: true}` | Prompt bearbeiten |
**Standard-Prompts:**
- `weight-trend` Gewichts-Trend-Analyse
- `nutrition-analysis` Ernährungs-Auswertung
- `training-plan` Trainings-Empfehlungen
- `body-composition` Körperzusammensetzung
- `progress-summary` Fortschritts-Zusammenfassung
- `pipeline` Master-Schalter für Pipeline
---
### 11. Admin (`/api/admin/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/admin/profiles` | 🔒 Admin | | `[{id, name, email, role, tier, ...}, ...]` | Alle Profile |
| `POST` | `/admin/profiles` | 🔒 Admin | `{name, email, password, role?}` | `{id, ...}` | Profil erstellen |
| `DELETE` | `/admin/profiles/{id}` | 🔒 Admin | | `{ok: true}` | Profil löschen |
| `PUT` | `/admin/profiles/{id}/permissions` | 🔒 Admin | `{ai_enabled?, ai_limit_day?, export_enabled?}` | `{ok: true}` | Permissions setzen |
---
### 12. Stats (`/api/stats`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/stats` | ✅ | | `{weight: {...}, nutrition: {...}, activity: {...}, body_comp: {...}}` | Dashboard-Stats |
**Response-Struktur:**
```json
{
"weight": {
"latest": 75.5,
"avg_7d": 75.8,
"avg_30d": 76.2,
"delta_7d": -0.3,
"delta_30d": -0.7
},
"nutrition": {
"avg_kcal_7d": 2100,
"avg_protein_7d": 150,
"days_logged_7d": 6
},
"activity": {
"total_activities_7d": 5,
"total_kcal_7d": 2500,
"avg_duration_7d": 45
},
"body_comp": {
"latest_bf_pct": 12.5,
"latest_lean_mass": 65.8
}
}
```
---
### 13. Export (`/api/export/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/export/csv` | ✅ | | Binary (CSV) | Alle Daten als CSV |
| `GET` | `/export/json` | ✅ | | Binary (JSON) | Alle Daten als JSON |
| `GET` | `/export/zip` | ✅ | | Binary (ZIP) | Alle Daten + Fotos als ZIP |
**Feature-Limits:** `data_export`
**Dateiname:** `mitai-export-YYYY-MM-DD.[csv|json|zip]`
**ZIP-Struktur:**
```
mitai-export-2026-03-23.zip
├── data.json
├── photos/
│ ├── photo_uuid1.jpg
│ └── photo_uuid2.jpg
└── README.txt
```
---
### 14. Import (`/api/import/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `POST` | `/import/backup` | ✅ | `FormData(file)` | `{imported: {...}, skipped: {...}, failed: {...}}` | JSON-Backup importieren |
**Feature-Limits:** `data_import`
**Format:** JSON-Export von `/export/json`
**Hinweis:** Überschreibt keine existierenden Einträge (Upsert-Logik)
---
## Subscription System (v9c)
### 15. Subscription (`/api/subscription/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/subscription/me` | ✅ | | `{tier, tier_expires_at, trial_ends_at, invited_by, ...}` | Abo-Status |
| `GET` | `/subscription/usage` | ✅ | | `{feature_id: {used, limit, remaining, allowed}, ...}` | Feature-Usage |
| `GET` | `/subscription/limits` | ✅ | | `{feature_id: limit, ...}` | Feature-Limits für aktuelles Tier |
---
### 16. Coupons (`/api/coupons/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `POST` | `/coupons/redeem` | ✅ | `{code}` | `{ok: true, tier_id, valid_days, message}` | Coupon einlösen |
| `GET` | `/coupons` | 🔒 Admin | | `[{id, code, tier_id, valid_days, max_uses, ...}, ...]` | Alle Coupons |
| `POST` | `/coupons` | 🔒 Admin | `{code, tier_id, valid_days, max_uses?}` | `{id, ...}` | Coupon erstellen |
| `PUT` | `/coupons/{id}` | 🔒 Admin | `{...}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/coupons/{id}` | 🔒 Admin | | `{ok: true}` | Löschen |
| `GET` | `/coupons/{id}/redemptions` | 🔒 Admin | | `[{profile_id, redeemed_at}, ...]` | Einlösungen |
---
### 17. Features (`/api/features/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/features` | ✅ | | `[{id, name, description, limit_type, reset_period, default_limit, active}, ...]` | Alle Features |
| `GET` | `/features/usage` | ✅ | | `[{feature_id, feature_name, limit, used, remaining, allowed, reason}, ...]` | Feature-Usage für aktuellen User |
| `POST` | `/features` | 🔒 Admin | `{id, name, description, limit_type, reset_period, default_limit}` | `{id, ...}` | Feature erstellen |
| `PUT` | `/features/{id}` | 🔒 Admin | `{...}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/features/{id}` | 🔒 Admin | | `{ok: true}` | Löschen |
**Limit-Types:** `count` (zählbar), `boolean` (on/off)
**Reset-Periods:** `never`, `daily`, `monthly`
---
### 18. Tiers (`/api/tiers/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/tiers` | 🔒 Admin | | `[{id, name, description, price_monthly, active}, ...]` | Alle Tiers |
| `POST` | `/tiers` | 🔒 Admin | `{id, name, description, price_monthly}` | `{id, ...}` | Tier erstellen |
| `PUT` | `/tiers/{id}` | 🔒 Admin | `{...}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/tiers/{id}` | 🔒 Admin | | `{ok: true}` | Löschen |
**Standard-Tiers:** `free`, `basic`, `premium`, `selfhosted`
---
### 19. Tier Limits (`/api/tier-limits/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/tier-limits` | 🔒 Admin | | `{tiers: [...], features: [...], matrix: {...}}` | Tier-Limits-Matrix |
| `PUT` | `/tier-limits` | 🔒 Admin | `{tier_id, feature_id, limit_value}` | `{ok: true}` | Limit setzen |
| `PUT` | `/tier-limits/batch` | 🔒 Admin | `{updates: [{tier_id, feature_id, limit_value}, ...]}` | `{ok: true}` | Batch-Update |
**Matrix-Format:**
```json
{
"tiers": ["free", "basic", "premium", "selfhosted"],
"features": [
{"id": "weight_entries", "name": "Gewichtseinträge", ...},
...
],
"matrix": {
"weight_entries": {
"free": 100,
"basic": 1000,
"premium": null,
"selfhosted": null
},
...
}
}
```
---
### 20. User Restrictions (`/api/user-restrictions/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/user-restrictions` | 🔒 Admin | `?profile_id=...` | `[{id, profile_id, feature_id, limit_value}, ...]` | User-spezifische Limits |
| `POST` | `/user-restrictions` | 🔒 Admin | `{profile_id, feature_id, limit_value}` | `{id, ...}` | Limit setzen |
| `PUT` | `/user-restrictions/{id}` | 🔒 Admin | `{limit_value}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/user-restrictions/{id}` | 🔒 Admin | | `{ok: true}` | Löschen |
**Verwendung:** Individuelle Limits überschreiben Tier-Limits
---
### 21. Access Grants (`/api/access-grants/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/access-grants` | 🔒 Admin | `?profile_id=...&active_only=true` | `[{id, profile_id, tier_id, valid_from, valid_until, source, is_active}, ...]` | Zeitlich begrenzte Tier-Zugriffe |
| `POST` | `/access-grants` | 🔒 Admin | `{profile_id, tier_id, valid_from, valid_until, source?}` | `{id, ...}` | Grant erstellen |
| `PUT` | `/access-grants/{id}` | 🔒 Admin | `{...}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/access-grants/{id}` | 🔒 Admin | | `{ok: true}` | Revoke |
**Quellen:** `coupon`, `trial`, `manual`, `gift`
---
## Training Types (v9d)
### 22. Training Types (`/api/training-types/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/training-types` | ✅ | | `{category: [{id, name, category, color, icon}, ...], ...}` | Gruppiert nach Kategorie |
| `GET` | `/training-types/flat` | ✅ | | `[{id, name, category, ...}, ...]` | Flache Liste |
| `GET` | `/training-types/categories` | ✅ | | `[{id, name, icon, color}, ...]` | Kategorien-Metadaten |
**Kategorien:** Kraft, Cardio, Flexibilität, Spiel & Sport, Alltag & Bewegung, Outdoor & Natur, Geist & Meditation
---
### 23. Admin Training Types (`/api/admin/training-types/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/admin/training-types` | 🔒 Admin | | `[{id, name, category, color, icon, abilities}, ...]` | Alle Typen (inkl. abilities JSONB) |
| `GET` | `/admin/training-types/{id}` | 🔒 Admin | | `{id, name, ...}` | Einzelner Typ |
| `POST` | `/admin/training-types` | 🔒 Admin | `{name, category, color?, icon?}` | `{id, ...}` | Typ erstellen |
| `PUT` | `/admin/training-types/{id}` | 🔒 Admin | `{name?, category?, color?, icon?, abilities?}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/admin/training-types/{id}` | 🔒 Admin | | `{ok: true}` | Löschen |
| `GET` | `/admin/training-types/taxonomy/abilities` | 🔒 Admin | | `{categories: [...], abilities: [...]}` | Abilities-Taxonomie (v9f) |
---
### 24. Activity Mappings (`/api/admin/activity-mappings/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/admin/activity-mappings` | 🔒 Admin | `?profile_id=...&global_only=true` | `[{id, activity_type, training_type_id, profile_id, is_global}, ...]` | Lernendes Mapping-System |
| `GET` | `/admin/activity-mappings/{id}` | 🔒 Admin | | `{id, ...}` | Einzelnes Mapping |
| `POST` | `/admin/activity-mappings` | 🔒 Admin | `{activity_type, training_type_id, profile_id?, is_global?}` | `{id, ...}` | Mapping erstellen |
| `PUT` | `/admin/activity-mappings/{id}` | 🔒 Admin | `{training_type_id?, is_global?}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/admin/activity-mappings/{id}` | 🔒 Admin | | `{ok: true}` | Löschen |
| `GET` | `/admin/activity-mappings/stats/coverage` | 🔒 Admin | | `{total_activities, mapped, unmapped, coverage_pct}` | Mapping-Coverage |
**Auto-Learning:** Bulk-Kategorisierung in ActivityPage speichert neue Mappings automatisch
---
### 25. Training Profiles (`/api/evaluation/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/evaluation/parameters` | 🔒 Admin | | `{categories: [...], abilities: [...]}` | Training-Parameter-Taxonomie |
| `POST` | `/evaluation/batch` | 🔒 Admin | | `{evaluated, failed, errors}` | Batch-Evaluierung aller Aktivitäten (v9d #15) |
---
## Sleep & Vitals (v9d Phase 2)
### 26. Sleep (`/api/sleep/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/sleep` | ✅ | `?limit=90` | `[{id, date, bedtime, wakeup, duration_min, quality, sleep_segments, notes, source}, ...]` | Schlaf-Einträge |
| `GET` | `/sleep/by-date/{date}` | ✅ | | `{id, date, ...}` oder `null` | Eintrag für Datum |
| `POST` | `/sleep` | ✅ | `{date, bedtime, wakeup, duration_min, quality?, sleep_segments?, notes?}` | `{id, ...}` | Eintrag erstellen (Upsert) |
| `PUT` | `/sleep/{id}` | ✅ | `{...}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/sleep/{id}` | ✅ | | `{ok: true}` | Löschen |
| `GET` | `/sleep/stats` | ✅ | `?days=7` | `{avg_duration, avg_quality, total_deep, total_rem, ...}` | Stats |
| `GET` | `/sleep/debt` | ✅ | `?days=14` | `{sleep_debt_min, avg_duration, target_duration}` | Schlafschuld |
| `GET` | `/sleep/trend` | ✅ | `?days=30` | `[{date, duration_min, quality}, ...]` | Trend |
| `GET` | `/sleep/phases` | ✅ | `?days=30` | `[{date, deep_min, rem_min, light_min, awake_min}, ...]` | Schlafphasen |
| `POST` | `/sleep/import/apple-health` | ✅ | `FormData(file)` | `{imported, skipped, failed, errors}` | Apple Health CSV-Import |
**sleep_segments Format (JSONB):**
```json
[
{"phase": "deep", "start": "23:30", "end": "01:15"},
{"phase": "rem", "start": "01:15", "end": "02:45"},
{"phase": "light", "start": "02:45", "end": "06:00"},
{"phase": "awake", "start": "06:00", "end": "06:15"}
]
```
---
### 27. Rest Days (`/api/rest-days/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/rest-days` | ✅ | `?limit=90` | `[{id, date, rest_type, reason, notes}, ...]` | Ruhetage |
| `GET` | `/rest-days/{id}` | ✅ | | `{id, ...}` | Einzelner Eintrag |
| `POST` | `/rest-days` | ✅ | `{date, rest_type, reason?, notes?}` | `{id, ...}` | Ruhetag eintragen |
| `PUT` | `/rest-days/{id}` | ✅ | `{...}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/rest-days/{id}` | ✅ | | `{ok: true}` | Löschen |
| `GET` | `/rest-days/stats` | ✅ | `?weeks=4` | `{total_rest_days, kraft_days, cardio_days, entspannung_days}` | Stats |
| `POST` | `/rest-days/validate-activity` | ✅ | `{date, activity_type}` | `{conflicts: [{rest_type, reason}, ...]}` | Validierung gegen Ruhetage |
**rest_type:** `kraft`, `cardio`, `entspannung` (Multi-Dimensional Rest)
---
### 28. Vitals Baseline (`/api/vitals/baseline/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/vitals/baseline` | ✅ | `?limit=90` | `[{id, date, resting_hr, hrv, vo2_max, spo2, respiratory_rate, notes}, ...]` | Morgenmessungen |
| `GET` | `/vitals/baseline/by-date/{date}` | ✅ | | `{id, ...}` oder `null` | Eintrag für Datum |
| `POST` | `/vitals/baseline` | ✅ | `{date, resting_hr?, hrv?, vo2_max?, spo2?, respiratory_rate?, notes?}` | `{id, ...}` | Eintrag erstellen (Upsert) |
| `PUT` | `/vitals/baseline/{id}` | ✅ | `{...}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/vitals/baseline/{id}` | ✅ | | `{ok: true}` | Löschen |
| `GET` | `/vitals/baseline/stats` | ✅ | `?days=30` | `{avg_resting_hr, avg_hrv, trend_resting_hr, trend_hrv}` | Stats |
| `POST` | `/vitals/baseline/import/apple-health` | ✅ | `FormData(file)` | `{imported, skipped, failed, errors}` | Apple Health CSV-Import |
**Messung:** 1x täglich, morgens nüchtern
---
### 29. Blood Pressure (`/api/blood-pressure/*`)
| Methode | Pfad | Auth | Parameter | Response | Beschreibung |
|---------|------|------|-----------|----------|--------------|
| `GET` | `/blood-pressure` | ✅ | `?limit=90` | `[{id, date, time, systolic, diastolic, pulse, context, irregular_heartbeat, afib_warning, notes}, ...]` | Blutdruck-Messungen |
| `GET` | `/blood-pressure/by-date/{date}` | ✅ | | `[{id, time, ...}, ...]` | Alle Messungen für Datum |
| `POST` | `/blood-pressure` | ✅ | `{date, time, systolic, diastolic, pulse?, context?, irregular_heartbeat?, afib_warning?, notes?}` | `{id, ...}` | Messung eintragen |
| `PUT` | `/blood-pressure/{id}` | ✅ | `{...}` | `{ok: true}` | Bearbeiten |
| `DELETE` | `/blood-pressure/{id}` | ✅ | | `{ok: true}` | Löschen |
| `GET` | `/blood-pressure/stats` | ✅ | `?days=30` | `{avg_systolic, avg_diastolic, avg_pulse, classification, trend}` | Stats |
| `POST` | `/blood-pressure/import/omron` | ✅ | `FormData(file)` | `{imported, skipped, failed, errors}` | Omron CSV-Import (Deutsch) |
**Contexts:** `fasting`, `after_meal`, `exercise`, `stress`, `rest`, `before_sleep`, `after_sleep`, `medication`
**WHO/ISH-Klassifizierung:**
- Optimal: <120/<80
- Normal: 120-129/80-84
- Hoch-Normal: 130-139/85-89
- Hypertonie Grad 1: 140-159/90-99
- Hypertonie Grad 2: 160-179/100-109
- Hypertonie Grad 3: ≥180/≥110
---
## Zusammenfassung
**Gesamt:** 29 Router-Module, ~200 Endpoints
**Authentifizierung:** Token-basiert (X-Auth-Token Header)
**Fehlerformat:** `{"detail": "Fehlermeldung"}`
**Rate Limits:** Nur Auth-Endpoints (5/min Login, 3/hour Register)
**Feature-Limits:** Membership-basiert (v9c), enforcement via HTTP 403
**Import-Formate:** CSV (Apple Health, Omron, FDDB), JSON (Backup)
**Export-Formate:** CSV, JSON, ZIP (mit Fotos)
**Besonderheiten:**
- Upsert-Logik für viele Endpoints (Date-basiert)
- Inline-Editing-Support (GET by date, PUT by id)
- CSV-Import mit Duplikat-Erkennung
- Lernendes Mapping-System (Activity Types)
- JSONB für flexible Datenstrukturen (sleep_segments, abilities)
- Auto-Migration SHA256 → bcrypt
- E-Mail-Verifizierung + Passwort-Reset

View File

@ -0,0 +1,634 @@
# Architektur-Übersicht Mitai Jinkendo
## System-Überblick
**Mitai Jinkendo** ist eine selbst-gehostete Progressive Web App (PWA) für Körper-Tracking mit KI-gestützter Auswertung. Die Architektur folgt einem klassischen **3-Tier-Modell** mit klarer Trennung von Präsentation, Business-Logik und Datenhaltung.
```
Internet
Fritz!Box (privat.stommer.com)
Synology NAS
Raspberry Pi 5 (192.168.2.49)
┌────────────────────────────────────┐
│ Docker Compose Environment │
├────────────────────────────────────┤
│ Frontend (React + Vite) │ Port 3002 (Prod) / 3099 (Dev)
│ Backend (FastAPI + Python) │ Port 8002 (Prod) / 8099 (Dev)
│ Database (PostgreSQL 16 Alpine) │ Port 5432 (internal)
└────────────────────────────────────┘
```
---
## Tech-Stack
| Komponente | Technologie | Version | Zweck |
|-----------|-------------|---------|-------|
| **Frontend** | React | 18 | UI Framework |
| | Vite | Latest | Build Tool + Dev Server |
| | React Router | 6 | Client-side Routing |
| | Lucide React | Latest | Icon Library |
| **Backend** | FastAPI | Latest | REST API Framework |
| | Python | 3.12 | Programmiersprache |
| | psycopg2-binary | Latest | PostgreSQL Driver |
| | bcrypt | Latest | Passwort-Hashing |
| | slowapi | Latest | Rate Limiting |
| **Database** | PostgreSQL | 16 Alpine | Primäre Datenbank |
| **Container** | Docker | Latest | Container Runtime |
| | Docker Compose | v2 | Multi-Container Orchestration |
| **KI** | OpenRouter API | - | Claude Sonnet 4 |
| | Anthropic API | - | Direkt-Integration (optional) |
| **Email** | SMTP | - | E-Mail-Versand (Verifikation, Reset) |
| **Infrastruktur** | Raspberry Pi 5 | - | Host-System |
| | Gitea | 3000 | Git Server + CI/CD |
| | Synology NAS | - | Reverse Proxy |
---
## Deployment-Architektur
### Umgebungen
| Umgebung | Domain | Branch | Ports | Deployment |
|----------|--------|--------|-------|-----------|
| **Production** | mitai.jinkendo.de | `main` | 3002/8002 | Auto-Deploy via Gitea |
| **Development** | dev.mitai.jinkendo.de | `develop` | 3099/8099 | Auto-Deploy via Gitea |
### Git-Workflow
```
develop → Push → Gitea Webhook → Runner → docker-compose.dev-env.yml → dev.mitai.jinkendo.de
main → Push → Gitea Webhook → Runner → docker-compose.yml → mitai.jinkendo.de
```
**Runner-Details:**
- Läuft auf Raspberry Pi 5 (`/home/lars/gitea-runner/`)
- Watchtower für automatische Updates
- Docker Compose Build + Restart bei neuen Commits
### Verzeichnisstruktur auf dem Server
```
/home/lars/docker/
├── bodytrack/ # Production
│ ├── docker-compose.yml
│ └── .env
└── bodytrack-dev/ # Development
├── docker-compose.dev-env.yml
└── .env
```
**Externe Volumes:**
- `bodytrack_bodytrack-data``/app/data` (Backend JSON-Daten, Legacy)
- `bodytrack_bodytrack-photos``/app/photos` (Progress-Fotos)
- `mitai_postgres_data` → PostgreSQL Datenbank
---
## Komponenten-Übersicht
### Backend-Module (26 Router)
| Router | Endpunkte | Beschreibung |
|--------|-----------|--------------|
| **auth** | `/api/auth/*` | Login, Register, Verify, Password Reset |
| **profiles** | `/api/profiles/*`, `/api/profile` | Nutzerverwaltung |
| **weight** | `/api/weight/*` | Gewichts-Tracking |
| **circumference** | `/api/circumferences/*` | Umfangsmessungen (8 Punkte) |
| **caliper** | `/api/caliper/*` | Hautfaltenmessungen (4 Methoden) |
| **activity** | `/api/activity/*` | Training & Aktivitäten |
| **nutrition** | `/api/nutrition/*` | Ernährungsdaten (Kalorien + Makros) |
| **photos** | `/api/photos/*` | Progress-Fotos |
| **insights** | `/api/insights/*`, `/api/ai/*` | KI-Auswertungen |
| **prompts** | `/api/prompts/*` | Konfigurierbare KI-Prompts |
| **admin** | `/api/admin/*` | Admin-Panel (Profile, Permissions) |
| **stats** | `/api/stats` | Statistiken für Dashboard |
| **exportdata** | `/api/export/*` | CSV/JSON/ZIP Export |
| **importdata** | `/api/import/*` | CSV Import |
| **subscription** | `/api/subscription/*` | Abo-Status (v9c) |
| **coupons** | `/api/coupons/*` | Coupon-System (v9c) |
| **features** | `/api/features/*` | Feature-Verwaltung (v9c) |
| **tiers_mgmt** | `/api/tiers/*` | Tier-Verwaltung (v9c) |
| **tier_limits** | `/api/tier-limits/*` | Tier-Limits Matrix (v9c) |
| **user_restrictions** | `/api/user-restrictions/*` | User-spezifische Limits (v9c) |
| **access_grants** | `/api/access-grants/*` | Zeitlich begrenzte Zugriffe (v9c) |
| **training_types** | `/api/training-types/*` | Trainingstypen (v9d) |
| **admin_training_types** | `/api/admin/training-types/*` | Trainingstypen-Admin (v9d) |
| **admin_activity_mappings** | `/api/admin/activity-mappings/*` | Activity Mapping Admin (v9d) |
| **sleep** | `/api/sleep/*` | Schlaf-Modul (v9d Phase 2b) |
| **rest_days** | `/api/rest-days/*` | Ruhetage (v9d Phase 2a) |
| **vitals_baseline** | `/api/vitals/baseline/*` | Morgenmessungen (RHR, HRV, VO2 Max) |
| **blood_pressure** | `/api/blood-pressure/*` | Blutdruck (mehrfach täglich) |
| **evaluation** | `/api/evaluation/*` | Training Type Profiling (v9d Phase 2 #15) |
**Registrierung in `main.py`:**
```python
app.include_router(auth.router)
app.include_router(profiles.router)
# ... alle 26 Router
```
### Frontend-Struktur
```
frontend/src/
├── App.jsx # Root-Komponente + Routing
├── app.css # Globales Design-System
├── context/
│ ├── AuthContext.jsx # Session-Management
│ └── ProfileContext.jsx # Aktives Profil
├── pages/ # 30+ Seiten
│ ├── LoginScreen.jsx # Login + Auto-Migration SHA256→bcrypt
│ ├── Register.jsx # Selbst-Registrierung (v9c)
│ ├── Verify.jsx # E-Mail-Verifizierung
│ ├── Dashboard.jsx # Übersicht mit Stats + Charts
│ ├── CaptureHub.jsx # Quick-Entry-Auswahl
│ ├── WeightScreen.jsx # Gewichts-Erfassung
│ ├── CircumScreen.jsx # Umfänge
│ ├── CaliperScreen.jsx # Caliper
│ ├── ActivityPage.jsx # Training (mit Trainingstypen v9d)
│ ├── NutritionPage.jsx # Ernährung (3-Tab: Entry/Import/Charts)
│ ├── SleepPage.jsx # Schlaf (v9d Phase 2b)
│ ├── RestDaysPage.jsx # Ruhetage (v9d Phase 2a)
│ ├── VitalsPage.jsx # Vitalwerte (3-Tab: Baseline/BP/Import)
│ ├── History.jsx # Verlauf-Charts
│ ├── Analysis.jsx # KI-Analyse + Pipeline
│ ├── SettingsPage.jsx # Einstellungen
│ ├── SubscriptionPage.jsx # Membership-UI (v9c)
│ └── Admin*.jsx # 9 Admin-Seiten
└── utils/
├── api.js # ALLE API-Calls (285 Zeilen)
├── calc.js # Body-Fat-Berechnungen
├── interpret.js # Daten-Interpretation
├── Markdown.jsx # Markdown-Renderer
└── guideData.js # Guide-Inhalte
```
---
## Datenfluss
### 1. User Request → Auth → API → Database
```
User Action (Frontend)
api.js (Token injiziert via hdrs())
FastAPI Endpoint
require_auth() Dependency (auth.py)
↓ (validiert X-Auth-Token → session)
get_session() → SELECT FROM sessions JOIN profiles
↓ (returns session dict mit profile_id, role, ai_enabled, ...)
Router-Funktion
db.py → get_db() Context Manager
psycopg2 → PostgreSQL Query (RealDictCursor)
Response (JSON)
```
### 2. Feature Access Control (v9c)
```
Endpoint (z.B. POST /api/insights/run)
check_feature_access(profile_id, 'ai_calls')
Prüf-Hierarchie:
1. user_feature_restrictions (user-spezifisch)
2. tier_limits (Tier-basiert)
3. features.default_limit (Fallback)
get_effective_tier(profile_id)
→ access_grants (Coupon/Trial) ODER profiles.tier
user_feature_usage (aktueller Zähler)
Ergebnis: {allowed: bool, limit: int, used: int, remaining: int, reason: str}
Falls allowed == false → HTTP 403
Falls allowed == true → increment_feature_usage() + execute
```
### 3. KI-Pipeline (3-stufig)
```
User: "Analyse starten"
POST /api/insights/pipeline
check_feature_access('ai_pipeline')
Stufe 1: Gewicht-Trend → claude-sonnet-4 (OpenRouter)
Stufe 2: Ernährung → claude-sonnet-4
Stufe 3: Gesamtanalyse → claude-sonnet-4 (mit Ergebnissen aus 1+2)
Jeder Call: increment_feature_usage('ai_calls')
INSERT INTO ai_insights (scope='pipeline', content=...)
Return: {content: "...", usage: {...}}
```
---
## Sicherheitsarchitektur
### 1. Passwort-Sicherheit
**Hash-Verfahren:**
- **Aktuell:** bcrypt (Salting + Work Factor)
- **Legacy:** SHA256 (wird beim Login automatisch zu bcrypt migriert)
**Passwort-Hashing (`auth.py`):**
```python
def hash_pin(pin: str) -> str:
return bcrypt.hashpw(pin.encode(), bcrypt.gensalt()).decode()
def verify_pin(pin: str, stored_hash: str) -> bool:
if stored_hash.startswith('$2'): # bcrypt
return bcrypt.checkpw(pin.encode(), stored_hash.encode())
# Legacy SHA256 → auto-upgrade beim nächsten Login
return stored_hash == hashlib.sha256(pin.encode()).hexdigest()
```
### 2. Session-Management
**Token-Format:**
- `secrets.token_urlsafe(32)` → 43 Zeichen Base64-URL-safe
- Gespeichert in `sessions` Tabelle mit `expires_at`
- Standard-Lebensdauer: 30 Tage (konfigurierbar pro Profil)
**Auth-Flow:**
```python
# Backend
@router.post("/api/auth/login")
def login(email, password):
profile = SELECT ... WHERE email=...
verify_pin(password, profile.pin_hash) # ✓
token = make_token()
INSERT INTO sessions (token, profile_id, expires_at)
return {"token": token, "profile": {...}}
# Frontend (AuthContext.jsx)
localStorage.setItem('mitai-jinkendo_token', token)
```
**Auth-Middleware (`auth.py`):**
```python
def require_auth(x_auth_token: Optional[str] = Header(default=None)):
session = get_session(x_auth_token)
if not session:
raise HTTPException(401, "Nicht eingeloggt")
return session # dict mit profile_id, role, ai_enabled, ...
```
### 3. CORS-Konfiguration
**Produktion (`docker-compose.yml`):**
```yaml
ALLOWED_ORIGINS: https://mitai.jinkendo.de
```
**Development:**
```yaml
ALLOWED_ORIGINS: https://dev.mitai.jinkendo.de,http://localhost:3099
```
**FastAPI Setup (`main.py`):**
```python
app.add_middleware(
CORSMiddleware,
allow_origins=os.getenv("ALLOWED_ORIGINS", "*").split(","),
allow_credentials=True,
allow_methods=["GET","POST","PUT","DELETE","OPTIONS"],
allow_headers=["*"],
)
```
### 4. Rate Limiting
**Library:** slowapi (Redis-freie In-Memory Rate Limiting)
**Anwendung:**
```python
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
@router.post("/auth/login")
@limiter.limit("5/minute") # Max 5 Login-Versuche pro Minute
def login(request: Request, ...):
...
```
**Geschützte Endpoints:**
- `/api/auth/login` → 5/minute
- `/api/auth/register` → 3/minute
- KI-Endpoints → via Feature-Limits (nicht Rate Limiting)
### 5. SQL Injection Protection
**Parameter-Binding:**
```python
# ✅ Sicher (psycopg2 escaped automatisch):
cur.execute("SELECT * FROM profiles WHERE id = %s", (profile_id,))
# ❌ NIEMALS:
cur.execute(f"SELECT * FROM profiles WHERE id = '{profile_id}'")
```
**RealDictCursor:**
- Automatisches Escaping
- Keine String-Konkatenation
---
## Versions-Historie
### v9c (Komplett) Production seit 21.03.2026 ✅
**Features:**
- Membership-System (5 Tiers: free/basic/premium/selfhosted)
- Coupon-System + Trial (14 Tage)
- Feature-Enforcement (4 Phasen):
- Phase 1: Cleanup ✅
- Phase 2: Monitoring ✅
- Phase 3: Frontend Display ✅
- Phase 4: Enforcement (HTTP 403) ✅
- Selbst-Registrierung + E-Mail-Verifizierung
- Export: CSV/JSON/ZIP
- Ernährungs-Modul erweitert (3-Tab Layout)
### v9d Phase 1b ✅
**Trainingstypen-System:**
- 29 Trainingstypen in 7 Kategorien
- Lernendes Mapping-System (DB-basiert)
- Apple Health Import (Deutsch + English)
- Bulk-Kategorisierung (selbstlernend)
### v9d Phase 2 ✅ (Deployed 23.03.2026)
**Vitalwerte & Erholung:**
- **Schlaf-Modul (v9d Phase 2b):**
- Tabelle `sleep_log` mit JSONB sleep_segments
- Schlafphasen (Deep, REM, Light, Awake)
- Apple Health CSV Import
- **Ruhetage (v9d Phase 2a):**
- Multi-dimensionale Ruhetage (Kraft/Cardio/Entspannung)
- Quick Mode Presets + Custom Entry
- **Vitalwerte erweitert (v9d Phase 2d):**
- **3-Tab Architektur:** Baseline (morgens) / Blutdruck (mehrfach täglich) / Import
- **Baseline Vitals:** Ruhepuls, HRV, VO2 Max, SpO2, Atemfrequenz
- **Blutdruck:** Systolisch/Diastolisch + Puls, WHO/ISH-Klassifizierung
- **Context-Tagging:** 8 Kontexte (nüchtern, nach Essen, Training, Stress, etc.)
- **Inline-Editing:** Alle Messungen direkt in der Liste bearbeitbar
- CSV Import: Omron (Deutsch) + Apple Health (Deutsch/Englisch)
### v9b (PostgreSQL-Migration)
- Migration SQLite → PostgreSQL 16
- Connection Pooling (psycopg2)
- UUID statt Integer Primary Keys
- Trigger für auto-update timestamps
### v9a (Basis)
- Login + Auth-Middleware
- Gewicht, Umfänge, Caliper, Ernährung, Aktivität
- KI-Analyse (6 Prompts + 3-stufige Pipeline)
- PWA + Dashboard
- Admin-Panel
---
## Design-Entscheidungen
### Warum PostgreSQL statt SQLite?
**Vorteile:**
- Concurrent Writes (SQLite locked bei Writes)
- Native UUID Support
- JSONB für flexible Datenstrukturen (z.B. sleep_segments)
- Trigger + Stored Procedures
- Production-ready für Self-Hosting
**Migration:**
- Automatisches Migrations-System (`db_init.py`)
- Rollback-fähig via SQL-Dateien
- Tracking in `schema_migrations` Tabelle
### Warum FastAPI statt Flask/Django?
**Vorteile:**
- Async Support (für zukünftige WebSocket-Features)
- Automatic OpenAPI Docs
- Type Hints → automatische Validierung
- Dependency Injection (z.B. `require_auth`)
- Performance (ASGI statt WSGI)
### Warum React statt Vue/Svelte?
**Entscheidung:**
- Bekanntes Ecosystem
- Context API ausreichend (kein Redux nötig)
- Gute PWA-Integration
- React Router maturity
### Warum kein TypeScript?
**Entscheidung (bewusst):**
- Schnellere Prototyping-Geschwindigkeit
- Weniger Build-Komplexität
- Dokumentation via JSDoc-Kommentare
- Type Safety durch Backend (Pydantic)
### Warum Connection Pooling?
**Problem ohne Pooling:**
- Jeder API-Call → neue DB-Verbindung → Overhead
- PostgreSQL max_connections erreicht bei vielen gleichzeitigen Requests
**Lösung:**
```python
_pool = psycopg2.pool.SimpleConnectionPool(minconn=1, maxconn=10)
@contextmanager
def get_db():
conn = _pool.getconn()
try:
yield conn
conn.commit()
except:
conn.rollback()
raise
finally:
_pool.putconn(conn)
```
**Vorteil:**
- Max 10 gleichzeitige Verbindungen
- Automatisches Recycling
- Auto-Commit/Rollback
---
## Bekannte Limitationen & Workarounds
### 1. Docker Build auf Raspberry Pi
**Problem:** `apt-get install postgresql-client` hängt 30+ Minuten
**Lösung:** Reine Python-Lösung mit `psycopg2-binary` (keine System-Dependencies)
### 2. Apple Health CSV-Import
**Problem:** Dezimalwerte werden als String exportiert (`"65.0"` statt `65`)
**Lösung:**
```python
def safe_float(val):
try:
return float(val) if val else None
except:
return None
```
### 3. Bun Crash nach langen Claude Code Sessions
**Problem:** Bun (JS Runtime für Claude Code CLI) crashed bei >30 Min Sessions
**Workaround:** Bei komplexen Tasks früher committen + neue Session starten
### 4. dayjs.week() ohne Plugin
**Problem:** `dayjs().week()` existiert nicht ohne `isoWeek`-Plugin
**Lösung:** Native ISO-Wochenberechnung:
```javascript
const isoWeek = (d => Math.ceil(((new Date(d.setDate(d.getDate()+4-(d.getDay()||7)))-
new Date(d.getFullYear(),0,1))/86400000+1)/7))(new Date(date))
```
---
## Performance-Optimierungen
### 1. Frontend
- **Code Splitting:** React.lazy() für Admin-Seiten (nicht initial geladen)
- **Image Loading:** `loading="lazy"` für Photos
- **CSS:** Inline Critical CSS, kein CSS-in-JS Overhead
- **PWA Cache:** Service Worker cached statische Assets
### 2. Backend
- **Connection Pooling:** Max 10 Connections statt unlimited
- **Query Optimization:** Indizes auf häufig abgefragte Spalten
- **Lazy Loading:** KI-Analysen nur auf Abruf, nicht im Dashboard
### 3. Database
**Indizes:**
```sql
CREATE INDEX idx_weight_log_profile_date ON weight_log(profile_id, date DESC);
CREATE INDEX idx_sessions_expires_at ON sessions(expires_at);
CREATE INDEX idx_ai_insights_profile_scope ON ai_insights(profile_id, scope, created DESC);
```
**Unique Constraints:**
```sql
CREATE UNIQUE INDEX idx_weight_log_profile_date_unique ON weight_log(profile_id, date);
```
---
## Monitoring & Logging
### 1. Feature Usage Logging (v9c Phase 2)
**Format:** JSON Lines (JSONL)
**Speicherort:** `/app/logs/feature-usage.log`
**Beispiel:**
```json
{"timestamp":"2026-03-23T10:15:30Z","profile_id":"uuid-here","feature":"ai_calls","allowed":true,"limit":10,"used":3,"remaining":7}
{"timestamp":"2026-03-23T10:16:00Z","profile_id":"uuid-here","feature":"data_export","allowed":false,"limit":0,"used":0,"remaining":0,"reason":"limit_exceeded"}
```
**Auswertung:**
```bash
cat feature-usage.log | jq -s 'group_by(.feature) | map({feature: .[0].feature, total: length})'
```
### 2. Health Checks
**Database:**
```yaml
healthcheck:
test: ["CMD-SHELL", "pg_isready -U mitai_prod"]
interval: 10s
```
**API:**
```python
@app.get("/")
def root():
return {"status": "ok", "service": "mitai-jinkendo", "version": "v9c-dev"}
```
### 3. Error Handling
**Einheitliches Format:**
```python
raise HTTPException(status_code=404, detail="Eintrag nicht gefunden")
# → {"detail": "Eintrag nicht gefunden"}
```
**Frontend (`api.js`):**
```javascript
if (!res.ok) {
const err = await res.text()
try {
const parsed = JSON.parse(err)
throw new Error(parsed.detail || err)
} catch {
throw new Error(err)
}
}
```
---
## Zusammenfassung
**Architektur-Highlights:**
- ✅ Modulare Router-Struktur (26 Module, single responsibility)
- ✅ Connection Pooling (max 10 concurrent DB connections)
- ✅ Token-basiertes Auth + bcrypt
- ✅ Feature Access Control mit Tier-System
- ✅ Docker Compose für einfaches Deployment
- ✅ Auto-Deploy via Gitea Webhooks
- ✅ PostgreSQL mit Migrations-System
- ✅ PWA mit Service Worker
- ✅ API-First Prinzip (Backend = Single Source of Truth)
**Nächste Schritte (v9e+):**
- Ziele-Modul (Goal Tracking)
- HF-Zonen + Erholungsstatus
- Stripe-Integration
- Connectoren (Garmin, Withings, etc.)
- Meditation + Selbstwahrnehmung

View File

@ -0,0 +1,904 @@
# Auth-Flow & Sicherheit
## Übersicht
Mitai Jinkendo nutzt **Token-basiertes Session-Management** mit bcrypt-Passwort-Hashing. Die Authentifizierung ist als FastAPI Dependency implementiert (`require_auth()`), die automatisch auf alle geschützten Endpoints angewendet wird.
**Sicherheits-Features:**
- ✅ bcrypt-Hashing (Work Factor ~12 Rounds)
- ✅ Auto-Migration SHA256 → bcrypt
- ✅ Rate Limiting (slowapi)
- ✅ CORS-Konfiguration
- ✅ E-Mail-Verifizierung für Registrierung
- ✅ Passwort-Reset via E-Mail (1h Token)
- ✅ Session-Expiry (30 Tage Standard)
- ✅ Admin-Role-Check
---
## Login-Flow (Schritt für Schritt)
### 1. User-Eingabe (Frontend)
**LoginScreen.jsx:**
```javascript
const handleLogin = async () => {
const data = await login({ email: email.trim().toLowerCase(), password })
window.location.href = '/' // Hard-Redirect nach Login
}
```
### 2. POST /api/auth/login (Backend)
**Request:**
```json
{
"email": "user@example.com",
"password": "geheim123"
}
```
**Backend-Logik (`backend/routers/auth.py`):**
```python
@router.post("/login")
@limiter.limit("5/minute") # Rate Limiting
async def login(req: LoginRequest, request: Request):
# 1. E-Mail-Lookup
cur.execute("SELECT * FROM profiles WHERE email=%s", (req.email.lower().strip(),))
prof = cur.fetchone()
if not prof:
raise HTTPException(401, "Ungültige Zugangsdaten")
# 2. Passwort-Verifizierung
if not verify_pin(req.password, prof['pin_hash']):
raise HTTPException(401, "Ungültige Zugangsdaten")
# 3. Auto-Migration SHA256 → bcrypt
if not prof['pin_hash'].startswith('$2'): # bcrypt-Hash startet mit $2b$ oder $2a$
new_hash = hash_pin(req.password)
cur.execute("UPDATE profiles SET pin_hash=%s WHERE id=%s", (new_hash, prof['id']))
# 4. Session erstellen
token = make_token() # secrets.token_urlsafe(32) → 43 Zeichen
session_days = prof.get('session_days', 30)
expires = datetime.now() + timedelta(days=session_days)
cur.execute("""
INSERT INTO sessions (token, profile_id, expires_at, created)
VALUES (%s, %s, %s, CURRENT_TIMESTAMP)
""", (token, prof['id'], expires))
return {
"token": token,
"profile_id": prof['id'],
"name": prof['name'],
"role": prof['role'],
"expires_at": expires.isoformat()
}
```
**Response:**
```json
{
"token": "jT9z3xK...(43 chars)...pQ2vL",
"profile_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Max Mustermann",
"role": "user",
"expires_at": "2026-04-22T14:30:00"
}
```
### 3. Token-Speicherung (Frontend)
**AuthContext.jsx:**
```javascript
const login = async (credentials) => {
const data = await api.login(credentials)
// Token speichern
localStorage.setItem('bodytrack_token', data.token)
localStorage.setItem('bodytrack_active_profile', data.profile_id)
// Volles Profil laden
const profile = await fetch('/api/auth/me', {
headers: { 'X-Auth-Token': data.token }
})
setSession({
token: data.token,
profile_id: data.profile_id,
role: data.role,
profile: await profile.json()
})
}
```
### 4. Nachfolgende Requests
**api.js:**
```javascript
function hdrs(extra={}) {
const h = {...extra}
const token = getToken() // localStorage.getItem('bodytrack_token')
if (token) h['X-Auth-Token'] = token
return h
}
async function req(path, opts={}) {
const res = await fetch(BASE+path, {...opts, headers:hdrs(opts.headers||{})})
// ...
}
```
**Jeder API-Call sendet automatisch:**
```
GET /api/weight
Headers:
X-Auth-Token: jT9z3xK...pQ2vL
```
### 5. Auth-Validierung (Backend)
**require_auth() Dependency:**
```python
def require_auth(x_auth_token: Optional[str] = Header(default=None)):
"""FastAPI Dependency - requires valid authentication."""
session = get_session(x_auth_token)
if not session:
raise HTTPException(401, "Nicht eingeloggt")
return session
def get_session(token: str):
"""Get session data for a given token."""
if not token:
return None
with get_db() as conn:
cur = get_cursor(conn)
cur.execute("""
SELECT s.*, p.role, p.name, p.ai_enabled, p.ai_limit_day, p.export_enabled
FROM sessions s
JOIN profiles p ON s.profile_id=p.id
WHERE s.token=%s AND s.expires_at > CURRENT_TIMESTAMP
""", (token,))
return cur.fetchone()
```
**Endpoint-Beispiel:**
```python
@router.get("/api/weight")
def list_weight(session: dict = Depends(require_auth)):
profile_id = session['profile_id'] # Immer aus Session, nie aus Header!
# ... Query mit profile_id
```
**Session-Dict:**
```python
{
'profile_id': 'uuid-string',
'role': 'user' | 'admin',
'name': 'Max Mustermann',
'ai_enabled': True,
'ai_limit_day': 10,
'export_enabled': True,
'expires_at': datetime(2026, 4, 22, 14, 30, 0)
}
```
---
## Registrierung-Flow (v9c)
### 1. Selbst-Registrierung
**POST /api/auth/register:**
```json
{
"name": "Max Mustermann",
"email": "max@example.com",
"password": "sicheresPasswort123"
}
```
**Validierung:**
- E-Mail: Muss `@` enthalten
- Passwort: Mindestens 8 Zeichen
- Name: Mindestens 2 Zeichen
- E-Mail-Duplikat-Check
**Backend:**
```python
@router.post("/register")
@limiter.limit("3/hour") # Rate Limiting
async def register(req: RegisterRequest, request: Request):
email = req.email.lower().strip()
# Duplikat-Check
cur.execute("SELECT id FROM profiles WHERE email=%s", (email,))
if cur.fetchone():
raise HTTPException(400, "E-Mail-Adresse bereits registriert")
# Profil erstellen (inaktiv bis verifiziert)
profile_id = str(secrets.token_hex(16))
pin_hash = hash_pin(req.password)
verification_token = secrets.token_urlsafe(32)
verification_expires = datetime.now() + timedelta(hours=24)
trial_ends = datetime.now() + timedelta(days=14) # 14-Tage-Trial
cur.execute("""
INSERT INTO profiles (
id, name, email, pin_hash, auth_type, role, tier,
email_verified, verification_token, verification_expires,
trial_ends_at, created
) VALUES (%s, %s, %s, %s, 'email', 'user', 'free', FALSE, %s, %s, %s, CURRENT_TIMESTAMP)
""", (profile_id, req.name, email, pin_hash, verification_token, verification_expires, trial_ends))
# Verifizierungs-E-Mail senden
send_email(email, "Willkommen bei Mitai Jinkendo", f"Verify: {APP_URL}/verify?token={verification_token}")
```
**Response:**
```json
{
"ok": true,
"message": "Registrierung erfolgreich! Bitte prüfe dein E-Mail-Postfach."
}
```
### 2. E-Mail-Verifizierung
**User klickt Link in E-Mail:**
```
https://mitai.jinkendo.de/verify?token=jT9z3xK...pQ2vL
```
**GET /api/auth/verify/{token}:**
```python
@router.get("/verify/{token}")
async def verify_email(token: str):
# Token-Lookup
cur.execute("""
SELECT id, name, email, email_verified, verification_expires
FROM profiles
WHERE verification_token=%s
""", (token,))
prof = cur.fetchone()
if not prof:
raise HTTPException(400, "Verifikations-Link ungültig")
if prof['email_verified']:
raise HTTPException(400, "E-Mail bereits bestätigt")
if datetime.now() > prof['verification_expires']:
raise HTTPException(400, "Link abgelaufen")
# Verifizierung
cur.execute("""
UPDATE profiles
SET email_verified=TRUE, verification_token=NULL, verification_expires=NULL
WHERE id=%s
""", (prof['id'],))
# Auto-Login (Session erstellen)
session_token = make_token()
expires = datetime.now() + timedelta(days=30)
cur.execute("""
INSERT INTO sessions (token, profile_id, expires_at, created)
VALUES (%s, %s, %s, CURRENT_TIMESTAMP)
""", (session_token, prof['id'], expires))
return {
"ok": True,
"token": session_token,
"profile": {"id": prof['id'], "name": prof['name'], "email": prof['email']}
}
```
**Frontend (Verify.jsx):**
```javascript
const verifyToken = urlParams.get('token')
const data = await api.verifyEmail(verifyToken)
// Auto-Login nach Verifizierung
setAuthFromToken(data.token, data.profile)
window.location.href = '/'
```
### 3. Resend Verification
**POST /api/auth/resend-verification:**
```json
{
"email": "max@example.com"
}
```
**Backend:**
- Generiert neuen Token (24h Gültigkeit)
- Sendet erneut E-Mail
- Rate Limit: 3/hour
---
## Passwort-Reset-Flow
### 1. Passwort vergessen
**POST /api/auth/forgot-password:**
```json
{
"email": "max@example.com"
}
```
**Backend:**
```python
@router.post("/forgot-password")
@limiter.limit("3/minute")
async def password_reset_request(req: PasswordResetRequest, request: Request):
email = req.email.lower().strip()
cur.execute("SELECT id, name FROM profiles WHERE email=%s", (email,))
prof = cur.fetchone()
if not prof:
# Don't reveal if email exists (Anti-Enumeration)
return {"ok": True, "message": "Falls die E-Mail existiert, wurde ein Link gesendet."}
# Reset-Token erstellen
token = secrets.token_urlsafe(32)
expires = datetime.now() + timedelta(hours=1) # 1 Stunde gültig
# In sessions-Tabelle speichern (mit Präfix "reset_")
cur.execute("""
INSERT INTO sessions (token, profile_id, expires_at, created)
VALUES (%s, %s, %s, CURRENT_TIMESTAMP)
""", (f"reset_{token}", prof['id'], expires))
# E-Mail senden
send_email(prof['email'], "Passwort zurücksetzen", f"Reset: {APP_URL}/reset-password?token={token}")
```
### 2. Neues Passwort setzen
**User klickt Link in E-Mail:**
```
https://mitai.jinkendo.de/reset-password?token=jT9z3xK...pQ2vL
```
**POST /api/auth/reset-password:**
```json
{
"token": "jT9z3xK...pQ2vL",
"new_password": "neuesPasswort123"
}
```
**Backend:**
```python
@router.post("/reset-password")
def password_reset_confirm(req: PasswordResetConfirm):
cur.execute("""
SELECT profile_id FROM sessions
WHERE token=%s AND expires_at > CURRENT_TIMESTAMP
""", (f"reset_{req.token}",))
sess = cur.fetchone()
if not sess:
raise HTTPException(400, "Ungültiger oder abgelaufener Reset-Link")
# Passwort ändern
new_hash = hash_pin(req.new_password)
cur.execute("UPDATE profiles SET pin_hash=%s WHERE id=%s", (new_hash, sess['profile_id']))
# Reset-Token löschen
cur.execute("DELETE FROM sessions WHERE token=%s", (f"reset_{req.token}",))
return {"ok": True, "message": "Passwort erfolgreich zurückgesetzt"}
```
---
## Session-Management
### Session-Struktur (Datenbank)
**Tabelle: `sessions`**
```sql
CREATE TABLE sessions (
token VARCHAR(64) PRIMARY KEY, -- secrets.token_urlsafe(32)
profile_id UUID NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
created TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_sessions_profile_id ON sessions(profile_id);
CREATE INDEX idx_sessions_expires_at ON sessions(expires_at);
```
### Token-Format
**`secrets.token_urlsafe(32)`**
- 32 Bytes Zufallsdaten
- Base64-URL-safe-kodiert
- Resultierende Länge: 43 Zeichen
- Charset: `A-Za-z0-9_-`
**Beispiel:** `jT9z3xKpLmN8vQrStUwXyZ1aB2cD3eF4gH5iJ6kL7mN8oP9qR`
### Session-Lebensdauer
**Standard:** 30 Tage (konfigurierbar pro Profil via `profiles.session_days`)
**Nach Login:**
```python
session_days = prof.get('session_days', 30)
expires = datetime.now() + timedelta(days=session_days)
```
**Automatische Bereinigung:**
- Abgelaufene Sessions werden bei Login automatisch gelöscht (via `WHERE expires_at > CURRENT_TIMESTAMP`)
- Geplant: Cron-Job für Cleanup alter Sessions (v10+)
### Logout
**POST /api/auth/logout:**
```python
@router.post("/logout")
def logout(x_auth_token: Optional[str]=Header(default=None)):
if x_auth_token:
with get_db() as conn:
cur = get_cursor(conn)
cur.execute("DELETE FROM sessions WHERE token=%s", (x_auth_token,))
return {"ok": True}
```
**Frontend:**
```javascript
const logout = async () => {
await fetch('/api/auth/logout', {
method: 'POST',
headers: { 'X-Auth-Token': token }
})
localStorage.removeItem('bodytrack_token')
setSession(null)
}
```
---
## Passwort-Sicherheit
### 1. bcrypt-Hashing
**Verwendete Bibliothek:** `bcrypt` (Python)
**Konfiguration:**
- Work Factor: Default (~12 Rounds)
- Automatisches Salting (integriert in bcrypt)
**Hash-Format:**
```
$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz3/yDZL1AJ.zCBU8fKWChSrW8GZF1a
│ │ │ │ │
│ │ │ └─ Salt (22 Zeichen) └─ Hash (31 Zeichen)
│ │ └─ Cost-Faktor (12 = 2^12 = 4096 Iterationen)
│ └─ bcrypt-Variante ('a' oder 'b')
└─ Präfix
```
**Hashing-Funktion (`auth.py`):**
```python
import bcrypt
def hash_pin(pin: str) -> str:
"""Hash password with bcrypt."""
return bcrypt.hashpw(pin.encode(), bcrypt.gensalt()).decode()
```
**Verifizierung:**
```python
def verify_pin(pin: str, stored_hash: str) -> bool:
"""Verify password - supports both bcrypt and legacy SHA256."""
if not stored_hash:
return False
# Detect bcrypt hash (starts with $2b$ or $2a$)
if stored_hash.startswith('$2'):
try:
return bcrypt.checkpw(pin.encode(), stored_hash.encode())
except Exception:
return False
# Legacy SHA256 support (auto-upgrade to bcrypt on next login)
return stored_hash == hashlib.sha256(pin.encode()).hexdigest()
```
### 2. SHA256 → bcrypt Auto-Migration
**Problem:** Alte Accounts hatten SHA256-Hashes (unsicher, kein Salting)
**Lösung:** Automatische Migration beim Login
**Logik:**
```python
# Beim Login
if prof['pin_hash'] and not prof['pin_hash'].startswith('$2'):
# Passwort verifiziert erfolgreich (via SHA256)
# → Upgrade zu bcrypt
new_hash = hash_pin(req.password)
cur.execute("UPDATE profiles SET pin_hash=%s WHERE id=%s", (new_hash, prof['id']))
```
**Ablauf:**
1. User loggt sich mit altem Passwort ein
2. Backend verifiziert gegen SHA256-Hash (erfolgreich)
3. Backend erstellt bcrypt-Hash vom Klartext-Passwort
4. SHA256-Hash wird in DB durch bcrypt-Hash ersetzt
5. Nächster Login → bcrypt-Verifizierung
**Vorteil:** Keine Passwort-Resets nötig, Migration transparent
### 3. Passwort-Anforderungen
**Minimum:**
- Länge: 8 Zeichen (bei Registrierung)
- Länge: 4 Zeichen (bei PIN-Change, für Abwärtskompatibilität)
**Empfohlen (nicht erzwungen):**
- Groß- und Kleinbuchstaben
- Zahlen
- Sonderzeichen
**Keine Komplexitäts-Prüfung:** Bewusst nicht implementiert (Fokus auf Länge statt Komplexität)
---
## Rate Limiting
**Bibliothek:** slowapi (Redis-freie In-Memory Rate Limiting)
### Konfiguration
**main.py:**
```python
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
```
### Rate Limits
| Endpoint | Limit | Grund |
|----------|-------|-------|
| `/api/auth/login` | 5/minute | Brute-Force-Schutz |
| `/api/auth/register` | 3/hour | Spam-Prevention |
| `/api/auth/forgot-password` | 3/minute | E-Mail-Flooding-Schutz |
| `/api/auth/resend-verification` | 3/hour | E-Mail-Flooding-Schutz |
**Verwendung:**
```python
from slowapi import Limiter
@router.post("/login")
@limiter.limit("5/minute")
async def login(req: LoginRequest, request: Request):
# Request-Objekt muss übergeben werden für IP-Extraktion
pass
```
**Response bei Überschreitung:**
```
HTTP 429 Too Many Requests
{
"detail": "Rate limit exceeded: 5 per 1 minute"
}
```
**Key-Funktion:** `get_remote_address` → IP-basiert (nicht User-basiert)
**Hinweis:** In-Memory = Reset bei Server-Neustart
---
## CORS-Konfiguration
### Produktion
**docker-compose.yml:**
```yaml
ALLOWED_ORIGINS: https://mitai.jinkendo.de
```
**main.py:**
```python
app.add_middleware(
CORSMiddleware,
allow_origins=os.getenv("ALLOWED_ORIGINS", "*").split(","),
allow_credentials=True,
allow_methods=["GET","POST","PUT","DELETE","OPTIONS"],
allow_headers=["*"],
)
```
### Development
**docker-compose.dev-env.yml:**
```yaml
ALLOWED_ORIGINS: https://dev.mitai.jinkendo.de,http://localhost:3099
```
**Wichtig:** Keine Wildcards (`*`) in Produktion!
---
## Öffentliche vs. geschützte Endpoints
### Öffentliche Endpoints (kein Auth)
| Endpoint | Methode | Zweck |
|----------|---------|-------|
| `/` | GET | Health Check |
| `/api/auth/status` | GET | Status-Check (First-Run-Detection) |
| `/api/auth/login` | POST | Login |
| `/api/auth/register` | POST | Registrierung |
| `/api/auth/verify/{token}` | GET | E-Mail-Verifizierung |
| `/api/auth/forgot-password` | POST | Passwort-Reset anfordern |
| `/api/auth/reset-password` | POST | Passwort-Reset bestätigen |
| `/api/auth/resend-verification` | POST | Verifizierungs-E-Mail erneut senden |
### Geschützte Endpoints (require_auth)
**Alle anderen Endpoints** benötigen `X-Auth-Token` Header.
**Beispiel:**
```python
@router.get("/api/weight")
def list_weight(session: dict = Depends(require_auth)):
profile_id = session['profile_id']
# ...
```
### Admin-Only Endpoints (require_admin)
| Endpoint | Zweck |
|----------|-------|
| `/api/admin/*` | Admin-Panel |
| `/api/features` | Feature-Verwaltung (POST/PUT/DELETE) |
| `/api/tiers` | Tier-Verwaltung (POST/PUT/DELETE) |
| `/api/tier-limits` | Tier-Limits-Matrix (PUT) |
| `/api/coupons` | Coupon-Verwaltung (POST/PUT/DELETE) |
| `/api/user-restrictions` | User-Restrictions (POST/PUT/DELETE) |
| `/api/access-grants` | Access-Grants (POST/PUT/DELETE) |
| `/api/admin/training-types` | Trainingstypen-Admin (POST/PUT/DELETE) |
| `/api/admin/activity-mappings` | Activity-Mappings (POST/PUT/DELETE) |
**require_admin() Dependency:**
```python
def require_admin(x_auth_token: Optional[str] = Header(default=None)):
"""FastAPI dependency - requires admin authentication."""
session = get_session(x_auth_token)
if not session:
raise HTTPException(401, "Nicht eingeloggt")
if session['role'] != 'admin':
raise HTTPException(403, "Nur für Admins")
return session
```
---
## E-Mail-System
### SMTP-Konfiguration
**Umgebungsvariablen:**
```env
SMTP_HOST=smtp.strato.de
SMTP_PORT=587
SMTP_USER=noreply@jinkendo.de
SMTP_PASS=*****
SMTP_FROM=noreply@jinkendo.de
APP_URL=https://mitai.jinkendo.de
```
### E-Mail-Versand
**Helper-Funktion (`backend/routers/auth.py`):**
```python
def send_email(to_email: str, subject: str, body: str):
"""Send email via SMTP (reusable helper)."""
try:
smtp_host = os.getenv("SMTP_HOST")
smtp_port = int(os.getenv("SMTP_PORT", 587))
smtp_user = os.getenv("SMTP_USER")
smtp_pass = os.getenv("SMTP_PASS")
smtp_from = os.getenv("SMTP_FROM", "noreply@jinkendo.de")
if not smtp_host or not smtp_user or not smtp_pass:
print("SMTP not configured, skipping email")
return False
msg = MIMEText(body)
msg['Subject'] = subject
msg['From'] = smtp_from
msg['To'] = to_email
with smtplib.SMTP(smtp_host, smtp_port) as server:
server.starttls()
server.login(smtp_user, smtp_pass)
server.send_message(msg)
return True
except Exception as e:
print(f"Email error: {e}")
return False
```
### E-Mail-Templates
**Registrierung (Verifizierung):**
```
Betreff: Willkommen bei Mitai Jinkendo E-Mail bestätigen
Hallo {name},
willkommen bei Mitai Jinkendo!
Bitte bestätige deine E-Mail-Adresse um die Registrierung abzuschließen:
https://mitai.jinkendo.de/verify?token={verification_token}
Der Link ist 24 Stunden gültig.
Dein Mitai Jinkendo Team
```
**Passwort-Reset:**
```
Betreff: Passwort zurücksetzen Mitai Jinkendo
Hallo {name},
du hast einen Passwort-Reset angefordert.
Reset-Link: https://mitai.jinkendo.de/reset-password?token={token}
Der Link ist 1 Stunde gültig.
Falls du diese Anfrage nicht gestellt hast, ignoriere diese E-Mail.
Dein Mitai Jinkendo Team
```
---
## Bekannte Sicherheitsentscheidungen
### 1. Profile-ID aus Session, nie aus Header
**❌ Falsch (Sicherheitslücke):**
```python
@router.get("/weight")
def list_weight(x_profile_id: str = Header(default=None), session=Depends(require_auth)):
profile_id = x_profile_id # User könnte beliebige ID senden!
```
**✅ Richtig:**
```python
@router.get("/weight")
def list_weight(session: dict = Depends(require_auth)):
profile_id = session['profile_id'] # Immer aus validierter Session
```
**Grund:** Session ist an Token gebunden → User kann nur eigene Daten abrufen
### 2. E-Mail-Enumeration-Schutz
**Problem:** Registrierung könnte verraten ob E-Mail bereits existiert
**Lösung:**
```python
if cur.fetchone():
raise HTTPException(400, "E-Mail-Adresse bereits registriert")
```
**Passwort-Reset:**
```python
if not prof:
# Don't reveal if email exists
return {"ok": True, "message": "Falls die E-Mail existiert, wurde ein Link gesendet."}
```
**Trade-off:** Registrierung gibt Info preis (UX > Sicherheit), Reset nicht (Sicherheit > UX)
### 3. Reset-Token-Präfix
**Problem:** Reset-Token könnte mit regulären Session-Token kollidieren
**Lösung:**
```python
cur.execute("INSERT INTO sessions (token, ...) VALUES (%s, ...)", (f"reset_{token}", ...))
```
**Vorteil:** Eindeutige Identifikation, kein Risiko von Kollisionen
### 4. Keine Passwort-Komplexitäts-Prüfung
**Entscheidung:** Nur Mindestlänge (8 Zeichen), keine Sonderzeichen-Pflicht
**Grund:**
- Länge > Komplexität (NIST-Empfehlung)
- Komplexitäts-Anforderungen führen zu schlechteren Passwörtern (z.B. `Password123!`)
- Benutzerfreundlichkeit
**Alternative:** Passwort-Strength-Meter im Frontend (geplant)
### 5. In-Memory Rate Limiting
**Problem:** Rate Limits resetten bei Server-Neustart
**Akzeptiert weil:**
- Redis-Overhead für Self-Hosting zu hoch
- Server-Neustarts selten (<1x pro Woche)
- Bei Neustart = Attack-Vektoren resetten sich auch (DDoS-Protection)
**Geplant (v10+):** Redis-Integration optional
---
## Zusammenfassung: Auth-Flow
```
┌─────────────────────────────────────────────────────────────┐
│ 1. Login (POST /api/auth/login) │
│ ↓ E-Mail + Passwort │
│ ↓ verify_pin(password, pin_hash) │
│ ↓ SHA256 → bcrypt Migration (falls nötig) │
│ ↓ Token generieren (secrets.token_urlsafe(32)) │
│ ↓ INSERT INTO sessions (token, profile_id, expires_at) │
│ → Return {token, profile_id, role, expires_at} │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 2. Frontend speichert Token │
│ localStorage.setItem('bodytrack_token', token) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 3. Nachfolgende Requests │
│ GET /api/weight │
│ Headers: X-Auth-Token: {token} │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 4. Backend validiert Token (require_auth) │
│ ↓ SELECT FROM sessions WHERE token=... AND expires_at>NOW│
│ ↓ JOIN profiles ON profile_id │
│ → Return session dict {profile_id, role, ai_enabled, ...}│
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 5. Endpoint-Logik │
│ profile_id = session['profile_id'] │
│ data = SELECT FROM weight_log WHERE profile_id=... │
│ → Return data │
└─────────────────────────────────────────────────────────────┘
```
**Sicherheits-Highlights:**
- ✅ bcrypt mit Auto-Salting
- ✅ SHA256 → bcrypt Migration (transparent)
- ✅ Rate Limiting (5/min Login, 3/hour Register)
- ✅ E-Mail-Verifizierung (24h Token)
- ✅ Passwort-Reset (1h Token via E-Mail)
- ✅ Session-Expiry (30 Tage)
- ✅ Admin-Role-Check (require_admin)
- ✅ Profile-ID-Isolation (immer aus Session)
- ✅ CORS-Whitelisting (Production)
**Bekannte Limitationen:**
- In-Memory Rate Limiting (Reset bei Server-Neustart)
- Keine 2FA (geplant für v10+)
- Keine Passwort-Strength-Meter (geplant)
- Keine Session-Revocation-UI (nur via DB)

View File

@ -0,0 +1,205 @@
# Zentrales Abo-System (Zukunft)
## Vision
**Ein zentrales Abo-System für alle Jinkendo Apps:**
- mitai.jinkendo.de (Körper-Tracking) 身体
- miken.jinkendo.de (Meditation) 眉間
- ikigai.jinkendo.de (Lebenssinn) 生き甲斐
- shinkan.jinkendo.de (Kampfsport) 真観
## Konzept
### Zentrale Webseite: jinkendo.de
- Zentrale Landing-Page mit allen Apps
- **Zentrale Abo-Verwaltung** (Stripe-Integration)
- User-Account übergreifend für alle Apps
- Single Sign-On (SSO) zwischen Apps
### Abo-Modelle (Ideen)
#### Option 1: App-spezifische Abos
```
mitai Basic: €5/Monat → Nur Mitai Premium
miken Basic: €5/Monat → Nur Miken Premium
```
#### Option 2: Kombinierte Abos
```
Jinkendo Basic: €8/Monat → 2 Apps
Jinkendo Premium: €12/Monat → Alle 4 Apps
Jinkendo Family: €20/Monat → Alle Apps + 3 Profile
```
#### Option 3: Feature-basiert
```
Free: Basis-Features alle Apps
Basic: Erweiterte Features (KI, Export, etc.)
Premium: Unlimited + Priority Support
```
---
## Technische Umsetzung
### Backend
#### Zentrale Auth-API
```
auth.jinkendo.de
POST /register → User-Account erstellen
POST /login → JWT Token für alle Apps
POST /refresh → Token erneuern
GET /me → User-Info mit Abo-Status
```
#### Subscription-API
```
subscriptions.jinkendo.de
GET /plans → Verfügbare Abos
POST /subscribe → Stripe Checkout Session
GET /my-subscription → Aktuelles Abo + Features
POST /cancel → Abo kündigen
POST /webhook → Stripe Webhook
```
#### App-Integration
Jede App prüft beim Start:
```javascript
const subscription = await fetch('https://subscriptions.jinkendo.de/my-subscription', {
headers: { 'Authorization': `Bearer ${jwt_token}` }
})
// subscription.features: ['mitai_premium', 'miken_basic', ...]
// App aktiviert entsprechende Features
```
### Frontend
#### Zentrale Webseite (jinkendo.de)
- Next.js oder React + Vite
- Stripe Elements für Payment
- Dashboard: Übersicht alle Apps + Abo-Status
- Rechnung-Historie
#### App-Anpassungen
**TrialBanner:**
```jsx
<a href="https://jinkendo.de/upgrade?app=mitai">
Jetzt upgraden
</a>
```
**Settings → Abo:**
- Link zu `https://jinkendo.de/account/subscription`
- Oder Embedded iFrame
---
## Datenbank-Schema (zentral)
### users
```sql
CREATE TABLE users (
id UUID PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
name VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
### subscriptions
```sql
CREATE TABLE subscriptions (
id SERIAL PRIMARY KEY,
user_id UUID REFERENCES users(id),
stripe_customer_id VARCHAR(100),
stripe_subscription_id VARCHAR(100),
plan VARCHAR(50), -- 'basic', 'premium', 'family'
status VARCHAR(20), -- 'active', 'canceled', 'past_due'
current_period_end TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
canceled_at TIMESTAMP
);
```
### subscription_features
```sql
CREATE TABLE subscription_features (
subscription_id INT REFERENCES subscriptions(id),
app VARCHAR(50), -- 'mitai', 'miken', 'ikigai', 'shinkan'
tier VARCHAR(50), -- 'basic', 'premium'
PRIMARY KEY (subscription_id, app)
);
```
### app_access_tokens
```sql
-- Mapping: Zentrale User → App-spezifische Profile
CREATE TABLE app_access_tokens (
user_id UUID REFERENCES users(id),
app VARCHAR(50),
app_profile_id VARCHAR(100), -- ID in der jeweiligen App-DB
PRIMARY KEY (user_id, app)
);
```
---
## Migration: Bestehende Apps
### Schritt 1: Zentrale Auth aufbauen
1. `auth.jinkendo.de` API deployen
2. User aus `mitai` DB migrieren zu zentraler DB
3. Mapping erstellen: zentrale User ID → mitai Profile ID
### Schritt 2: Apps auf zentrale Auth umstellen
1. Login/Register in Apps deaktivieren
2. "Mit Jinkendo anmelden" Button → SSO-Flow
3. JWT von `auth.jinkendo.de` verwenden
4. Profile-ID Mapping bei jedem Request
### Schritt 3: Subscription-System
1. `subscriptions.jinkendo.de` API deployen
2. Stripe-Integration
3. Apps prüfen Abo-Status bei jedem Feature-Zugriff
### Schritt 4: Zentrale Webseite
1. `jinkendo.de` Landing Page
2. Account-Dashboard
3. Abo-Verwaltung
---
## Status (März 2026)
🔲 **Noch nicht gestartet**
**Aktuell:**
- Jede App hat eigene User-Verwaltung
- `mitai` hat Membership-System (v9c)
- TrialBanner Link → `mailto:mitai@jinkendo.de`
**Nächste Schritte:**
1. Weitere Apps entwickeln (miken, ikigai, shinkan)
2. Zentrale Infrastruktur planen
3. Migration vorbereiten
---
## Offene Fragen
- **Pricing:** Welche Preise pro App / kombiniert?
- **Stripe vs. Paddle:** Welcher Payment Provider?
- **Single DB vs. Separate:** Eine PostgreSQL-DB für alles oder separate?
- **Hosting:** Eigener Server oder Cloud (Vercel, Railway, Fly.io)?
- **Domain-Strategie:** Subdomains (api.jinkendo.de) oder Paths (jinkendo.de/api)?
---
## Related
- `MEMBERSHIP_SYSTEM.md` - Aktuelles System in mitai (v9c)
- `FEATURE_ENFORCEMENT.md` - Feature-Limiting Mechanismus
- Backlog: v9h (Connectoren & Stripe)

View File

@ -0,0 +1,163 @@
# Dashboard-Widgets Anleitung für Coding-Agenten
Ziel: Ein neues Dashboard-Widget **end-to-end** korrekt einbinden (Backend-Katalog, Validierung, API-Layout, Frontend-Registrierung, optional Editor für `config` in **Übersicht anpassen**).
Kontext: Geschützte Endpoints `GET/PUT /api/app/...` (siehe `backend/routers/app_dashboard.py`). Layout liegt pro Profil in `profiles.dashboard_layout` (JSON). Nutzer-Oberfläche: `frontend/src/pages/DashboardConfigurePage.jsx` (Route z.B. `/settings/dashboard-layout`).
---
## 0. Architekturanforderung: Subscription / Feature-System vs. Widget-Katalog
### 0.1 Ist-Stand (Verifikation)
- **Bereits vorhanden:** Membership- und Feature-Modell (`features`, `tier_limits`, `user_feature_restrictions`, `check_feature_access` in `backend/auth.py`). Siehe `.claude/docs/architecture/FEATURE_ENFORCEMENT.md`.
- **Umgesetzt:** `GET /api/app/widgets/catalog` liefert pro Widget **`allowed`** (aus `requires_feature` im Katalog + `check_feature_access`). `GET/PUT /api/app/dashboard-layout` wendet **`apply_entitlements_to_layout_dict`** an (nicht erlaubte Einträge: `enabled: false`; Standard-Layout ebenfalls bereinigt). Implementierung: `backend/dashboard_widget_entitlements.py`.
- Optional pro Katalogzeile: **`requires_feature`** (`features.id`) in `widget_catalog.py`; fehlt der Key → Widget für alle authentifizierten Nutzer katalog-sichtbar (ohne zusätzliches Feature-Gate).
### 0.2 Soll: eine Wahrheit für „darf angezeigt werden“
- **Komplexität** (Module aus, Cluster, Stufen: z.B. Ernährung an, aber bestimmte Auswertungen nur in höherem Tier) gehört in die **Feature-/Subscription-Schicht** (inkl. späterer Feature-Cluster), nicht in einzelne React-Widgets.
- **Widgets** sollen das Ergebnis nur **abrufen** (z.B. `allowed` / sichtbar im Katalog), nicht die Tier-Logik duplizieren.
### 0.3 Bindende Anforderungen (wenn Feature-Gating umgesetzt wird)
| Anforderung | Beschreibung |
|-------------|--------------|
| **A1 Zentrale Auflösung** | Backend ermittelt pro Profil (effektiver Tier + Restrictions), welche Widget-IDs **erlaubt** sind idealerweise in **einer** Stelle (Erweiterung des Katalog-Endpoints oder dedizierter Entitlements-Teil der Response). Intern: `check_feature_access` und später ggf. Mapping Widget-ID → Feature-ID(n) / Cluster. |
| **A2 Nutzer-Konfigurator** | Im Layout-Konfigurator (**Übersicht anpassen**): Widgets **ohne Berechtigung nicht anbieten** (ausgeblendet oder gar nicht in der Liste). Alle **erlaubten** Widgets bleiben wie heute wählbar. |
| **A3 Layout-Persistenz** | `PUT /api/app/dashboard-layout`: Layout darf **keine** nicht erlaubten Widgets dauerhaft speichern entweder **ablehnen** (422) oder **beim Speichern entfernen/deaktivieren** (Policy festlegen und dokumentieren). Verhindert „gespeichert, aber nie sichtbar“-Zombies. |
| **A4 API-/Datenschutz** | Sichtbarkeit im UI reicht nicht: Endpoints, die **Inhalte** für gated Widgets liefern (Charts, KI, …), müssen weiterhin wie heute **eigenständig** über Features abgesichert sein (`check_feature_access`, 403). |
### 0.4 Katalog-Erweiterung (Vorbereitung ohne feste Tier-Namen)
- Tiers bleiben **in der DB konfigurierbar**; im Code keine Annahme „free vs. pro“.
- Pro Widget-Eintrag (oder separater Mapping-Layer) kann später **`required_feature_id`** (ein Key aus `features.id`) oder ein **Cluster-Key** ergänzt werden, der auf **eine oder mehrere** `check_feature_access`-Abfragen abgebildet wird Details bei Implementierung festlegen.
- Neue Widget-Doku: Wenn ein Widget an ein Feature hängt, in `widget_catalog`-`description` und in dieser Anleitung vermerken.
**Verweis:** Verbindliche Regel auf Projektebene: `.claude/rules/ARCHITECTURE.md` § 9.
---
## 1. Datenfluss (kurz)
1. **`backend/widget_catalog.py`** `WIDGET_CATALOG`: erlaubte Widget-IDs, Reihenfolge, Titel/Beschreibung für API und Default-Layout.
2. **`backend/dashboard_layout_schema.py`** `DashboardLayoutPayload`: jede Zeile hat `id`, `enabled`, optional `config`. IDs müssen in `ALLOWED_WIDGET_IDS` sein (aus dem Katalog abgeleitet).
3. **`backend/dashboard_widget_config.py`** `validate_widget_entry_config`: **nur** Widgets in `WIDGETS_ALLOWING_CONFIG` dürfen **nicht-leere** `config` haben; Keys werden streng validiert (unbekannte Keys → Fehler).
4. **Frontend** `ensureDashboardWidgetsRegistered()` in `frontend/src/widgetSystem/registerDashboardWidgets.js`: verbindet jede Katalog-ID mit einer React-Komponente und mappt `ctx.layoutEntry.config` auf Props.
5. **Layout-Editor (Produkt)** `frontend/src/pages/DashboardConfigurePage.jsx`: Umsortieren, Ein/Aus, Speichern; **zusätzliche** UI nur nötig, wenn das Widget konfigurierbare Felder braucht.
---
## 2. Checkliste: neues Widget ohne Konfiguration
| Schritt | Datei | Aktion |
|--------|--------|--------|
| A | `backend/widget_catalog.py` | Neuen Eintrag `{ "id", "title", "description" }` in `WIDGET_CATALOG` einfügen (Reihenfolge = Default-Reihenfolge im Layout). Optional `"requires_feature": "<features.id>"` für Tarif-Gating (`dashboard_widget_entitlements`). |
| B | `backend/widget_catalog.py` | Optional: ID zu `DEFAULT_LAB_WIDGET_IDS` hinzufügen, wenn es im Server-Standardlayout **aktiv** sein soll (Feld `lab_default_layout` in der Layout-API). |
| C | `frontend/src/components/dashboard-widgets/MyWidget.jsx` (oder Legacy-Widget unter `dashboard-widgets-legacy/`) | React-Komponente implementieren; typischerweise `refreshTick` aus `mapProps` nutzen, um Daten neu zu laden. |
| D | `frontend/src/widgetSystem/registerDashboardWidgets.js` | `import` + `registerDashboardWidget({ id, Component, mapProps })` `id` **exakt** wie im Katalog. |
| E | `backend/tests/test_widget_catalog.py` | Läuft implizit mit; bei Strukturänderungen Katalog-Tests beachten. |
| F | `backend/version.py` | `MODULE_VERSIONS["app_dashboard"]` MINOR erhöhen und kurz kommentieren. |
| G | Build/Tests | `pytest` (z.B. `tests/test_dashboard_layout_schema.py`, `test_widget_catalog.py`); `npm run build` im `frontend`. |
**Nicht nötig:** `WIDGETS_ALLOWING_CONFIG` oder `validate_widget_entry_config`-Zweig, solange `config` immer `{}` bleibt.
**Wichtig:** Widget-IDs im Frontend-Registry **ohne** Registrierung führen im UI zu „Unbekanntes Widget“ (`dashboardWidgetRegistry.jsx`).
---
## 3. Checkliste: Widget mit konfigurierbaren Einstellungen (`config`)
### 3.1 Backend
1. **`WIDGETS_ALLOWING_CONFIG`** in `backend/dashboard_widget_config.py` um die neue `widget_id` ergänzen.
2. In **`validate_widget_entry_config`** einen eigenen Zweig oder Aufruf einer Hilfsfunktion hinzufügen (siehe bestehende Muster unten).
3. **`MAX_WIDGET_CONFIG_JSON_BYTES`** (3072): keine großen Blobs in `config`.
4. Regeln konsistent halten:
- Unbekannte Keys **ablehnen** (wie bei `kpi_board`, `quick_capture`, `chart_days`-only).
- Leeres Objekt `{}` erlauben, wenn alle Keys optional sind (Validator entscheidet).
**Referenz-Muster im Code:**
| Muster | Verwendung | Implementierung |
|--------|------------|-----------------|
| Nur `chart_days` (790) | Chart-Kacheln | `_validate_chart_days_only(raw, label="...")` |
| KPI-Kacheln | `tiles`-Liste, max. 9 | `_validate_kpi_board_config` |
| Booleans + Mindestens eines true | Schnelleingabe-Sichtbarkeit | `_validate_quick_capture_config` |
Neue komplexe Config: eigene `_validate_my_widget_config` schreiben, Keys als `frozenset` whitelisten, Typen prüfen, sinnvoll normalisieren/abrunden.
5. **Tests** in `backend/tests/test_dashboard_widget_config.py`: Happy-Path, ein ungültiger Wert, unbekannter Key, ggf. Größe/Limits.
### 3.2 Katalog-Beschreibung
In `widget_catalog.py` bei `description` die **konfigurierbaren Keys** kurz nennen (hilft Admin/API-Nutzern). Einheitliche Benennung mit dem Backend (z.B. `chart_days 790`).
### 3.3 Frontend: Props aus Layout
`registerDashboardWidget` erhält `mapProps(ctx)`:
- **`ctx.layoutEntry`**: `{ id, enabled, config? }` hierher kommt die gespeicherte Konfiguration.
- **`ctx.refreshTick`** / **`ctx.requestRefresh()`**: Datenaktualisierung nach Aktionen.
Typische Zuordnung:
```javascript
mapProps: (ctx) => ({
refreshTick: ctx.refreshTick,
myOption: ctx.layoutEntry?.config?.my_option,
})
```
**Abgleich mit Chart-Zeitraum:** Für `chart_days` existiert `frontend/src/widgetSystem/bodyChartDays.js` (`BODY_CHART_DAYS_MIN/MAX`, `normalizeBodyChartDays`). Entweder in `mapProps` normalisieren (wie `body_overview`) oder rohen Wert durchreichen und in der Widget-Komponente normalisieren (wie `nutrition_detail_charts` / `TrendKcalWeightWidget`) **beides** ist im Projekt vertreten; wichtig ist Konsistenz mit der Backend-Grenze 790.
### 3.4 Layout-Editor (`DashboardConfigurePage.jsx`)
Ohne UI-Änderung bleibt `config` beim Nutzer `{}` konfigurierbare Widgets brauchen **Editor-Controls**:
- **Einfaches Zahlfeld `chart_days`:** Eintrag in `CHART_DAYS_WIDGET_IDS` (Set oben in `DashboardConfigurePage.jsx`) + bestehendes Label/`aria-label`-Pattern für die Zeitraum-Zeile erweitern (siehe `body_overview`, `nutrition_detail_charts`).
- **Strukturierte Config (Listen, mehrere Booleans):** Eigenes Editor-Komponenten-File nach Vorbild `KpiBoardConfigEditor.jsx` / `QuickCaptureConfigEditor.jsx` einbinden und `setLayout` + `normalizeLayoutForEditor` wie bei den bestehenden Blöcken verwenden.
Nach Speichern ruft die Seite `api.putAppDashboardLayout(layout)` auf; das Backend validiert über `DashboardLayoutPayload``validate_widget_entry_config`.
---
## 4. Grenzen und Fehlerbilder
| Thema | Detail |
|--------|--------|
| Erlaubte IDs | Nur IDs aus `WIDGET_CATALOG`. `ALLOWED_WIDGET_IDS` wird daraus abgeleitet nicht manuell duplizieren. |
| Doppelte IDs | Im Layout sind **keine** doppelten `widget.id` erlaubt (`DashboardLayoutPayload`). |
| Max. Widgets | `widgets` max. 32 Einträge (`DashboardLayoutPayload`). |
| Config verboten | Widget **nicht** in `WIDGETS_ALLOWING_CONFIG` → jede nicht-leere `config` → Validierungsfehler beim Speichern. |
| Frontend ≠ Katalog | Komponente registriert, ID fehlt im Katalog → PUT schlägt fehl. |
| Katalog ohne Registry | GET Layout ok, Render zeigt „Unbekanntes Widget“. |
---
## 5. API zum Prüfen
- `GET /api/app/widgets/catalog` Katalog inkl. `allowed` je Widget (Auth + `X-Profile-Id` wie andere App-Endpoints).
- `GET /api/app/dashboard-layout` `layout` (effektiv, bereinigt), `custom`, `product_default_layout` (Übersichts-Standard), `lab_default_layout` (Servertemplate für Editor/Reset; Feldname historisch).
- `PUT /api/app/dashboard-layout` Body `{ "version": 1, "widgets": [ ... ] }` (unerlaubte Widgets werden auf `enabled: false` gesetzt).
---
## 6. Nach getaner Arbeit
- `pytest` für `dashboard_widget_config` und `widget_catalog` / `dashboard_layout_schema`.
- `npm run build`.
- `MODULE_VERSIONS["app_dashboard"]` in `backend/version.py` anheben.
---
## 7. Verwandte Dateien (Referenz)
| Zweck | Pfad |
|--------|------|
| Katalog | `backend/widget_catalog.py` |
| Config-Validierung | `backend/dashboard_widget_config.py` |
| Layout-Pydantic | `backend/dashboard_layout_schema.py` |
| HTTP | `backend/routers/app_dashboard.py` |
| Registry + Render | `frontend/src/widgetSystem/dashboardWidgetRegistry.jsx` |
| Dashboard-Widget-Registrierung | `frontend/src/widgetSystem/registerDashboardWidgets.js` |
| Layout-Editor (Nutzer) | `frontend/src/pages/DashboardConfigurePage.jsx` |

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,780 @@
# Data Layer Extension Guide
**Version:** 1.0
**Erstellt:** 28. März 2026
**Zielgruppe:** Entwickler, Claude Code
**Phase:** Post Phase 0c
---
## Überblick
Dieser Guide beschreibt, wie man das Data Layer System erweitert mit:
- Neuen Modulen
- Neuen Funktionen in bestehenden Modulen
- Neuen Berechnungslogiken
- Neuen Aggregationsmethoden
**Voraussetzung:** Phase 0c abgeschlossen (Multi-Layer Architecture implementiert)
---
## Modul-Struktur
### Bestehende Module (Phase 0c)
```
backend/data_layer/
├── __init__.py # Exports all functions
├── body_metrics.py # Gewicht, FM, LBM, Umfänge
├── nutrition_metrics.py # Kalorien, Protein, Makros
├── activity_metrics.py # Training, Volumen, Abilities
├── recovery_metrics.py # Sleep, RHR, HRV, Recovery Score
├── health_metrics.py # BP, VO2Max, Health Stability
├── goals.py # Active goals, progress
├── correlations.py # Lag-analysis, plateau detection
└── utils.py # Shared: confidence, baseline, outliers
```
### Modul-Namenskonventionen
- **Singular:** `body_metrics.py` (nicht `bodies_metrics.py`)
- **Domain-focused:** Ein Modul pro fachlichem Bereich
- **Max ~500 Zeilen:** Bei >500 Zeilen → Split erwägen
---
## Neue Funktion hinzufügen
### Template
```python
# backend/data_layer/<module>.py
def get_<metric>_data(
profile_id: str,
days: int = 28,
**kwargs
) -> dict:
"""
[Eine Zeile: Was liefert diese Funktion?]
[Optional: Ausführliche Beschreibung der Berechnung]
Args:
profile_id: User profile ID
days: Analysis window (default 28)
**kwargs: Additional parameters (z.B., goal_mode)
Returns:
{
"<field>": <type>, # Main result
"confidence": str, # REQUIRED: "high"/"medium"/"low"/"insufficient"
"data_points": int, # REQUIRED: Number of data points used
"<additional>": <type> # Any additional data
}
Confidence Rules:
- "high": >= X points
- "medium": >= Y points
- "low": >= Z points
- "insufficient": < Z points
Example:
>>> data = get_<metric>_data("profile_123", days=28)
>>> print(data['<field>'])
42.0
"""
with get_db() as conn:
cur = get_cursor(conn)
# 1. DATA RETRIEVAL
cur.execute("""
SELECT ...
FROM ...
WHERE profile_id = %s
AND date >= NOW() - INTERVAL '%s days'
ORDER BY date
""", (profile_id, days))
rows = cur.fetchall()
# 2. CONFIDENCE CALCULATION
from data_layer.utils import calculate_confidence
confidence = calculate_confidence(
data_points=len(rows),
days_requested=days,
metric_type="general" # or "correlation" or "trend"
)
# 3. EARLY RETURN IF INSUFFICIENT
if confidence == 'insufficient':
return {
"confidence": "insufficient",
"data_points": len(rows),
# Include all fields with safe defaults
"<field>": 0.0,
}
# 4. CALCULATION
# ... your logic here ...
# 5. RETURN STRUCTURED DATA
return {
"<field>": result,
"confidence": confidence,
"data_points": len(rows),
# Additional fields as needed
}
```
### Pflicht-Felder
**Jede Funktion MUSS zurückgeben:**
```python
{
"confidence": str, # "high" | "medium" | "low" | "insufficient"
"data_points": int, # Anzahl verwendeter Datenpunkte
}
```
**Warum?**
- Confidence: UI kann User warnen bei niedriger Datenqualität
- Data Points: Debugging + Monitoring
### Optionale Felder (Best Practices)
```python
{
"first_date": date, # Ältester Datenpunkt
"last_date": date, # Neuester Datenpunkt
"avg": float, # Durchschnitt
"std_dev": float, # Standardabweichung
"min": float, # Minimum
"max": float, # Maximum
"outliers": list[int], # Indices von Ausreißern
}
```
---
## Neue Berechnungslogik hinzufügen
### 1. Statistik-Funktionen (utils.py)
**Wenn du eine neue statistische Berechnung brauchst:**
```python
# backend/data_layer/utils.py
def calculate_<statistic>(
values: list[float],
**kwargs
) -> float:
"""
[Beschreibung der Statistik]
Args:
values: List of measurements
**kwargs: Additional parameters
Returns:
Calculated statistic (float)
Example:
>>> calculate_<statistic>([1.0, 2.0, 3.0])
2.0
"""
# Implementation
...
```
**Beispiele:**
```python
def calculate_median_absolute_deviation(values: list[float]) -> float:
"""
MAD = median(|xi - median(x)|)
More robust than standard deviation for outlier detection.
"""
import statistics
median = statistics.median(values)
deviations = [abs(x - median) for x in values]
return statistics.median(deviations)
def calculate_coefficient_of_variation(values: list[float]) -> float:
"""
CV = (std_dev / mean) * 100
Measures relative variability.
"""
import statistics
mean = statistics.mean(values)
std_dev = statistics.stdev(values)
return (std_dev / mean) * 100 if mean != 0 else 0.0
def calculate_z_score(value: float, mean: float, std_dev: float) -> float:
"""
Z = (x - μ) / σ
Standardized score.
"""
return (value - mean) / std_dev if std_dev != 0 else 0.0
```
### 2. Aggregations-Funktionen (utils.py)
**Neue Aggregationsmethoden für Goal Types:**
```python
# backend/data_layer/utils.py
def aggregate_data(
values: list[tuple], # [(date, value), ...]
method: str,
**kwargs
) -> float:
"""
Aggregate data points using specified method.
Args:
values: List of (date, value) tuples
method: Aggregation method (see below)
**kwargs: Method-specific parameters
Returns:
Aggregated value (float)
Supported Methods:
- "latest": Most recent value
- "avg_7d": Average last 7 days
- "avg_30d": Average last 30 days
- "avg_90d": Average last 90 days
- "sum_7d": Sum last 7 days
- "sum_30d": Sum last 30 days
- "count_7d": Count last 7 days
- "count_30d": Count last 30 days
- "min_30d": Minimum last 30 days
- "max_30d": Maximum last 30 days
- "median_7d": Median last 7 days
- "median_30d": Median last 30 days
- "rolling_avg": Rolling average (window from kwargs)
- "percentile": Nth percentile (n from kwargs)
Example:
>>> values = [(date1, 85.0), (date2, 84.5), ...]
>>> aggregate_data(values, "avg_7d")
84.7
"""
from datetime import date, timedelta
import statistics
if not values:
return 0.0
# Sort by date (most recent first)
sorted_values = sorted(values, key=lambda x: x[0], reverse=True)
if method == "latest":
return float(sorted_values[0][1])
elif method.startswith("avg_"):
days = int(method.split("_")[1].replace("d", ""))
cutoff = date.today() - timedelta(days=days)
recent = [v for d, v in sorted_values if d >= cutoff]
return statistics.mean(recent) if recent else 0.0
elif method.startswith("sum_"):
days = int(method.split("_")[1].replace("d", ""))
cutoff = date.today() - timedelta(days=days)
recent = [v for d, v in sorted_values if d >= cutoff]
return sum(recent)
elif method.startswith("count_"):
days = int(method.split("_")[1].replace("d", ""))
cutoff = date.today() - timedelta(days=days)
return len([v for d, v in sorted_values if d >= cutoff])
elif method.startswith("min_") or method.startswith("max_"):
func_name, days_str = method.split("_")
days = int(days_str.replace("d", ""))
cutoff = date.today() - timedelta(days=days)
recent = [v for d, v in sorted_values if d >= cutoff]
if not recent:
return 0.0
return min(recent) if func_name == "min" else max(recent)
elif method.startswith("median_"):
days = int(method.split("_")[1].replace("d", ""))
cutoff = date.today() - timedelta(days=days)
recent = [v for d, v in sorted_values if d >= cutoff]
return statistics.median(recent) if recent else 0.0
elif method == "rolling_avg":
window = kwargs.get("window", 7)
if len(sorted_values) < window:
return statistics.mean([v for _, v in sorted_values])
recent = sorted_values[:window]
return statistics.mean([v for _, v in recent])
elif method == "percentile":
n = kwargs.get("n", 50) # Default: median
values_only = [v for _, v in sorted_values]
return statistics.quantiles(values_only, n=100)[n - 1] if len(values_only) > 1 else values_only[0]
else:
raise ValueError(f"Unknown aggregation method: {method}")
```
### 3. Korrelations-Funktionen (correlations.py)
**Neue Korrelations-Analysen:**
```python
# backend/data_layer/correlations.py
def get_<metric_a>_<metric_b>_correlation(
profile_id: str,
days: int = 90,
max_lag: int = 7
) -> dict:
"""
Correlation between <metric_a> and <metric_b> with lag analysis.
Args:
profile_id: User profile ID
days: Analysis window
max_lag: Maximum lag in days to test
Returns:
{
"correlation": float, # Pearson r at best lag
"best_lag": int, # Days of lag
"p_value": float, # Statistical significance
"confidence": str,
"paired_points": int,
"interpretation": str # "strong"/"moderate"/"weak"/"none"
}
Interpretation:
|r| > 0.7: "strong"
|r| > 0.5: "moderate"
|r| > 0.3: "weak"
|r| <= 0.3: "none"
"""
# Implementation using scipy.stats or numpy
...
```
---
## Neues Modul erstellen
### Wann ein neues Modul?
**Erstelle ein neues Modul wenn:**
- ✅ Neue fachliche Domäne (z.B., `stress_metrics.py`, `hormone_metrics.py`)
- ✅ Bestehendes Modul >500 Zeilen
- ✅ Klare thematische Trennung möglich
**KEIN neues Modul wenn:**
- ❌ Nur 1-2 Funktionen (füge zu bestehendem Modul hinzu)
- ❌ Starke Abhängigkeit zu bestehendem Modul (merge statt split)
### Modul-Template
```python
# backend/data_layer/<new_module>.py
"""
<Module Name> - <Brief description>
This module provides data functions for <domain>.
Functions:
- get_<metric1>_data()
- get_<metric2>_data()
- ...
Usage:
from data_layer.<new_module> import get_<metric>_data
data = get_<metric>_data(profile_id="123", days=28)
"""
from typing import Optional, List, Dict, Tuple
from datetime import date, timedelta
from db import get_db, get_cursor
# ── PUBLIC FUNCTIONS ─────────────────────────────────────────────
def get_<metric>_data(
profile_id: str,
days: int = 28,
**kwargs
) -> dict:
"""
[Docstring as per template above]
"""
...
# ── PRIVATE HELPERS ──────────────────────────────────────────────
def _calculate_<internal_metric>(values: list[float]) -> float:
"""
Internal helper for <module>.
NOT exported from module.
"""
...
def _validate_<data>(data: dict) -> bool:
"""
Internal validation helper.
"""
...
```
### Exports in __init__.py
```python
# backend/data_layer/__init__.py
# Existing modules
from .body_metrics import *
from .nutrition_metrics import *
from .activity_metrics import *
from .recovery_metrics import *
from .health_metrics import *
from .goals import *
from .correlations import *
from .utils import *
# NEW MODULE
from .<new_module> import *
__all__ = [
# Existing exports...
# NEW MODULE exports
'get_<metric1>_data',
'get_<metric2>_data',
]
```
---
## Integration mit Goal Types
### Goal Type mit neuer Aggregationsmethode
**Scenario:** Du hast eine neue Aggregationsmethode `avg_per_week_30d` implementiert.
#### 1. In utils.py implementieren
```python
# backend/data_layer/utils.py
def aggregate_data(values, method, **kwargs):
# ... existing methods ...
elif method == "avg_per_week_30d":
# Group by week, calculate average per week
from collections import defaultdict
weeks = defaultdict(list)
for d, v in values:
week_start = d - timedelta(days=d.weekday())
weeks[week_start].append(v)
week_avgs = [sum(vals) / len(vals) for vals in weeks.values()]
return sum(week_avgs) / len(week_avgs) if week_avgs else 0.0
# ...
```
#### 2. In goal_utils.py nutzen
```python
# backend/goal_utils.py
def _fetch_by_aggregation_method(
cur,
profile_id: str,
source_table: str,
source_column: str,
aggregation_method: str,
date_column: str = 'date',
filter_conditions: dict = None
) -> Optional[float]:
"""
Fetch current value using aggregation method.
Now supports:
- latest, avg_7d, avg_30d, sum_30d, count_7d, etc.
- avg_per_week_30d (NEW)
"""
# Fetch data
cur.execute(f"""
SELECT {date_column}, {source_column}
FROM {source_table}
WHERE profile_id = %s
ORDER BY {date_column} DESC
LIMIT 100
""", (profile_id,))
rows = cur.fetchall()
if not rows:
return None
# Use aggregate_data from utils
from data_layer.utils import aggregate_data
return aggregate_data(rows, aggregation_method)
```
#### 3. In Frontend verfügbar machen
```javascript
// frontend/src/pages/AdminGoalTypesPage.jsx
const AGGREGATION_METHODS = [
{ value: 'latest', label: 'Aktuellster Wert' },
{ value: 'avg_7d', label: 'Durchschnitt 7 Tage' },
{ value: 'avg_30d', label: 'Durchschnitt 30 Tage' },
{ value: 'sum_30d', label: 'Summe 30 Tage' },
{ value: 'avg_per_week_30d', label: 'Durchschnitt pro Woche (30d)' }, // NEW
// ...
]
```
---
## Testing-Strategie
### Unit Tests für neue Funktionen
```python
# backend/tests/test_data_layer.py
import pytest
from data_layer.<module> import get_<metric>_data
@pytest.fixture
def test_profile_with_data(db_connection):
"""Create test profile with sample data"""
# Setup
profile_id = "test_profile_123"
# Insert test data into relevant tables
...
yield profile_id
# Teardown
...
def test_get_metric_data_sufficient(test_profile_with_data):
"""Test with sufficient data points"""
data = get_<metric>_data(test_profile_with_data, days=28)
assert data['confidence'] in ['high', 'medium', 'low']
assert data['data_points'] >= 18
assert '<field>' in data
assert isinstance(data['<field>'], float)
def test_get_metric_data_insufficient():
"""Test with insufficient data"""
data = get_<metric>_data("no_data_profile", days=28)
assert data['confidence'] == 'insufficient'
assert data['data_points'] == 0
def test_get_metric_data_edge_cases(test_profile_with_data):
"""Test edge cases: outliers, missing values, etc."""
# Test with extreme values
# Test with gaps in data
# Test with all same values
...
def test_get_metric_data_parameters(test_profile_with_data):
"""Test different parameter combinations"""
# Test different days values
for days in [7, 28, 90]:
data = get_<metric>_data(test_profile_with_data, days=days)
assert data is not None
# Test additional parameters
data = get_<metric>_data(test_profile_with_data, days=28, goal_mode="strength")
assert data is not None
```
### Integration Tests
```python
# backend/tests/test_charts_integration.py
def test_chart_uses_data_layer(client, auth_token):
"""Test that chart endpoint uses data layer correctly"""
response = client.get(
"/api/charts/<metric>",
headers={"X-Auth-Token": auth_token}
)
assert response.status_code == 200
data = response.json()
# Verify Chart.js structure
assert 'chart_type' in data
assert 'data' in data
assert 'metadata' in data
# Verify metadata includes confidence
assert 'confidence' in data['metadata']
```
---
## Performance Considerations
### 1. Query Optimization
**Problem:** N+1 Queries
```python
# ❌ BAD:
for goal_id in goal_ids:
cur.execute("SELECT * FROM goals WHERE id = %s", (goal_id,))
# ... process each goal ...
# ✅ GOOD:
cur.execute("SELECT * FROM goals WHERE id = ANY(%s)", (goal_ids,))
```
**Problem:** Unindexed Columns
```sql
-- Add index if querying frequently by date range
CREATE INDEX IF NOT EXISTS idx_weight_log_profile_date
ON weight_log(profile_id, date DESC);
```
### 2. Caching
**For expensive calculations:**
```python
from functools import lru_cache
@lru_cache(maxsize=128)
def get_expensive_calculation(profile_id: str, days: int) -> dict:
"""Cache results for 128 most recent calls"""
...
```
**Note:** In-memory cache resets on restart. For persistent cache → Redis (later).
### 3. Pagination
**For large datasets:**
```python
def get_<metric>_data(
profile_id: str,
days: int = 28,
limit: int = 1000,
offset: int = 0
) -> dict:
"""
Paginated data retrieval.
"""
cur.execute("""
SELECT ...
FROM ...
WHERE profile_id = %s
ORDER BY date DESC
LIMIT %s OFFSET %s
""", (profile_id, limit, offset))
```
---
## Checkliste: Neue Funktion
```
[ ] Richtiges Modul gewählt (oder neues Modul erstellt)
[ ] Funktion implementiert mit korrekter Signatur
[ ] Docstring vollständig (Args, Returns, Example)
[ ] Confidence calculation included
[ ] Returns structured data (dict with primitives)
[ ] NO formatting (no strings with units)
[ ] Decimal → Float conversion wo nötig
[ ] Safe dict access (.get() mit defaults)
[ ] SQL parameter binding (keine String-Concatenation)
[ ] Unit tests geschrieben (sufficient/insufficient/edge cases)
[ ] Integration test geschrieben (wenn Chart/API endpoint)
[ ] Performance geprüft (< 500ms)
[ ] In __init__.py exportiert
[ ] Dokumentation aktualisiert (CLAUDE.md)
[ ] Commit mit aussagekräftiger Message
```
---
## Häufige Fehler
### 1. Vergessen Confidence zu berechnen
```python
# ❌ WRONG:
return {"value": result}
# ✅ CORRECT:
from data_layer.utils import calculate_confidence
confidence = calculate_confidence(len(rows), days, "general")
return {"value": result, "confidence": confidence, "data_points": len(rows)}
```
### 2. Formatierung im Data Layer
```python
# ❌ WRONG (Data Layer):
return {"slope": f"{slope:.2f} kg/Woche"}
# ✅ CORRECT (Data Layer):
return {"slope": 0.23} # Just the number
# ✅ FORMATTING (KI Layer):
return f"{data['slope']:.2f} kg/Woche"
```
### 3. Hardcoded Thresholds
```python
# ❌ WRONG:
if len(rows) < 18: # Magic number
return {"confidence": "insufficient"}
# ✅ CORRECT:
confidence = calculate_confidence(len(rows), days, "general")
if confidence == "insufficient":
return {"confidence": "insufficient", ...}
```
---
## Support & Hilfe
**Bei Fragen:**
1. Lies PLACEHOLDER_DEVELOPMENT_GUIDE.md
2. Prüfe bestehende Funktionen als Beispiel
3. Frag im Team oder erstelle Gitea Issue
**Debugging:**
1. Unit Test schreiben
2. Print intermediate results
3. Check SQL query mit `EXPLAIN ANALYZE`
4. Profile mit `cProfile` wenn Performance-Problem
---
**Autor:** Claude Sonnet 4.5
**Version:** 1.0
**Letzte Aktualisierung:** 28. März 2026

View File

@ -0,0 +1,337 @@
# Feature Enforcement Mapping
**Version:** v9c Phase 2
**Status:** Planning
**Datum:** 20. März 2026
---
## Übersicht
Dieses Dokument definiert, welche API-Endpoints welche Features prüfen müssen.
---
## Feature-Katalog (nach Cleanup)
### Data Features (count, never)
1. `weight_entries` - Gewichtseinträge
2. `circumference_entries` - Umfangsmessungen
3. `caliper_entries` - Hautfaltenmessungen
4. `nutrition_entries` - Ernährungseinträge
5. `activity_entries` - Trainingseinträge
6. `photos` - Progress-Fotos
### AI Features
7. `ai_calls` - KI-Einzelanalysen (count, monthly)
8. `ai_pipeline` - KI-Pipeline-Analyse (boolean, never)
### Export/Import Features
9. `data_export` - Daten exportieren (count, monthly)
10. `data_import` - Daten importieren (count, monthly)
---
## Endpoint → Feature Mapping
### Weight Router (`/api/weight`)
| Endpoint | Method | Feature | Action |
|----------|--------|---------|--------|
| `/api/weight` | POST | `weight_entries` | Check before create, increment after |
| `/api/weight` | GET | - | No check (reading is always allowed) |
| `/api/weight/{id}` | PUT | - | No check (editing existing is allowed) |
| `/api/weight/{id}` | DELETE | - | No check (deleting is allowed) |
**Rationale:** Limit bezieht sich auf Gesamtanzahl Einträge (COUNT), nicht auf API-Calls.
---
### Circumference Router (`/api/circumference`)
| Endpoint | Method | Feature | Action |
|----------|--------|---------|--------|
| `/api/circumference` | POST | `circumference_entries` | Check before, increment after |
| `/api/circumference` | GET | - | No check |
| `/api/circumference/{id}` | PUT | - | No check |
| `/api/circumference/{id}` | DELETE | - | No check |
---
### Caliper Router (`/api/caliper`)
| Endpoint | Method | Feature | Action |
|----------|--------|---------|--------|
| `/api/caliper` | POST | `caliper_entries` | Check before, increment after |
| `/api/caliper` | GET | - | No check |
| `/api/caliper/{id}` | PUT | - | No check |
| `/api/caliper/{id}` | DELETE | - | No check |
---
### Nutrition Router (`/api/nutrition`)
| Endpoint | Method | Feature | Action |
|----------|--------|---------|--------|
| `/api/nutrition` | POST | `nutrition_entries` | Check before, increment after |
| `/api/nutrition` | GET | - | No check |
| `/api/nutrition/{id}` | PUT | - | No check |
| `/api/nutrition/{id}` | DELETE | - | No check |
---
### Activity Router (`/api/activity`)
| Endpoint | Method | Feature | Action |
|----------|--------|---------|--------|
| `/api/activity` | POST | `activity_entries` | Check before, increment after |
| `/api/activity` | GET | - | No check |
| `/api/activity/{id}` | PUT | - | No check |
| `/api/activity/{id}` | DELETE | - | No check |
---
### Photos Router (`/api/photos`)
| Endpoint | Method | Feature | Action |
|----------|--------|---------|--------|
| `/api/photos/upload` | POST | `photos` | Check before, increment after |
| `/api/photos` | GET | - | No check |
| `/api/photos/{id}` | DELETE | - | No check (deleting is allowed) |
---
### Insights Router (`/api/insights`)
| Endpoint | Method | Feature | Action |
|----------|--------|---------|--------|
| `/api/insights/run/{slug}` | POST | `ai_calls` | Check before, increment after |
| `/api/insights/pipeline` | POST | `ai_pipeline` (boolean) | Check before (no increment for boolean) |
| `/api/insights` | GET | - | No check |
| `/api/insights/{id}` | GET | - | No check |
**Rationale:**
- `ai_calls` = count-based, monthly reset
- `ai_pipeline` = boolean (enabled/disabled), no usage tracking
---
### Export Router (`/api/export`)
| Endpoint | Method | Feature | Action |
|----------|--------|---------|--------|
| `/api/export/csv` | GET | `data_export` | Check before, increment after |
| `/api/export/json` | GET | `data_export` | Check before, increment after |
| `/api/export/zip` | GET | `data_export` | Check before, increment after |
**Rationale:** Ein Feature für alle 3 Export-Typen (konsolidiert).
---
### Import Router (`/api/import`)
| Endpoint | Method | Feature | Action |
|----------|--------|---------|--------|
| `/api/nutrition/import/fddb` | POST | `data_import` | Check before, increment after |
| `/api/activity/import/csv` | POST | `data_import` | Check before, increment after |
| `/api/import/zip` | POST | `data_import` | Check before, increment after |
**Rationale:** Ein Feature für alle Import-Typen.
---
## Implementation Pattern (Phase 2: Non-Blocking Logging)
### Pattern für count-based Features
```python
from auth import require_auth, check_feature_access, increment_feature_usage
import logging
logger = logging.getLogger(__name__)
@router.post("/api/weight")
def create_weight(data: dict, session: dict = Depends(require_auth)):
profile_id = session['profile_id']
# Phase 2: Check access (log only, don't block)
access = check_feature_access(profile_id, 'weight_entries')
if not access['allowed']:
logger.warning(
f"[FEATURE-LIMIT] User {profile_id} would be blocked: "
f"weight_entries limit_exceeded ({access['used']}/{access['limit']})"
)
# NOTE: Phase 2 does NOT raise HTTPException - just logs!
# Actual logic
# ... create weight entry ...
# Phase 2: Increment usage (even if limit would be exceeded)
increment_feature_usage(profile_id, 'weight_entries')
return {"ok": True, "id": entry_id}
```
### Pattern für boolean Features
```python
@router.post("/api/insights/pipeline")
def run_pipeline(session: dict = Depends(require_auth)):
profile_id = session['profile_id']
# Phase 2: Check access (log only)
access = check_feature_access(profile_id, 'ai_pipeline')
if not access['allowed']:
logger.warning(
f"[FEATURE-LIMIT] User {profile_id} would be blocked: "
f"ai_pipeline disabled"
)
# NOTE: Phase 2 does NOT raise HTTPException!
# Actual logic
# ... run pipeline ...
# No increment for boolean features
return {"ok": True}
```
---
## Phase 3: Frontend Display (ohne Gates)
### Usage-Counter anzeigen
```jsx
// Example: WeightPage.jsx
import { useEffect, useState } from 'react'
import api from '../utils/api'
function WeightPage() {
const [usage, setUsage] = useState(null)
useEffect(() => {
// Fetch usage info
api.get('/api/features/weight_entries/check-access')
.then(res => setUsage(res))
}, [])
return (
<div>
<h1>Gewicht</h1>
{/* Phase 3: Display usage (non-blocking) */}
{usage && usage.limit !== null && (
<div className="usage-badge">
{usage.used} / {usage.limit} Einträge
{usage.remaining !== null && usage.remaining < 5 && (
<span className="warning">
Nur noch {usage.remaining} Einträge verfügbar
</span>
)}
</div>
)}
{/* Button is NOT disabled in Phase 3 */}
<button onClick={createEntry}>
Gewicht hinzufügen
</button>
</div>
)
}
```
---
## Phase 4: Enforcement aktivieren (opt-in)
### Feature-Flag System
```python
# In app_settings table
INSERT INTO app_settings (key, value, description)
VALUES ('feature_enforcement_enabled', 'false', 'Enable/disable feature limit enforcement');
```
### Modified Pattern (mit Enforcement)
```python
def create_weight(data: dict, session: dict = Depends(require_auth)):
profile_id = session['profile_id']
# Check if enforcement is enabled
enforcement_enabled = get_app_setting('feature_enforcement_enabled', False)
# Check access
access = check_feature_access(profile_id, 'weight_entries')
if not access['allowed']:
if enforcement_enabled:
# Phase 4: BLOCK
raise HTTPException(
status_code=429,
detail=f"Limit erreicht: {access['used']}/{access['limit']} Gewichtseinträge. Upgrade für mehr."
)
else:
# Phase 2/3: LOG ONLY
logger.warning(
f"[FEATURE-LIMIT] User {profile_id} would be blocked: "
f"weight_entries limit_exceeded ({access['used']}/{access['limit']})"
)
# Actual logic
# ...
```
---
## Rollout-Strategie
### Phase 2: Log-Only (1-2 Wochen)
- Alle Checks implementiert
- Nur Logging, keine Blocks
- **Monitoring**: Wie oft würde blockiert?
- **Analyse**: Gibt es falsche Limits?
### Phase 3: Display-Only (1 Woche)
- Frontend zeigt Usage an
- Buttons NICHT disabled
- **User-Feedback**: Ist Usage-Anzeige klar?
- **Testing**: Funktioniert Counter korrekt?
### Phase 4: Enforcement (schrittweise)
1. Admin-Account testen (enforcement=true nur für Admin)
2. Test-User (1-2 Accounts)
3. Rollout an alle (feature_enforcement_enabled=true)
### Rollback-Plan
- `UPDATE app_settings SET value='false' WHERE key='feature_enforcement_enabled'`
- Sofortiger Rollback ohne Code-Deploy
---
## Testing-Checklist
### Unit-Tests (Backend)
- [ ] `check_feature_access()` mit allen Hierarchien
- [ ] `increment_feature_usage()` mit Reset-Logik
- [ ] Count-based Features (limit erreicht)
- [ ] Boolean Features (enabled/disabled)
- [ ] Monthly reset funktioniert
### Integration-Tests
- [ ] POST weight-entry bis Limit erreicht
- [ ] Limit wird korrekt in Response angezeigt
- [ ] Reset nach Monatswechsel
- [ ] User-Override überschreibt Tier-Limit
- [ ] Access-Grant überschreibt Base-Tier
### Frontend-Tests
- [ ] Usage-Counter aktualisiert nach Create
- [ ] Warning bei < 5 remaining
- [ ] Unlimited zeigt "∞"
- [ ] Disabled-Features zeigen Upgrade-Hinweis
---
**Letzte Aktualisierung:** 20. März 2026
**Autor:** Lars Stommer + Claude Opus 4.6

View File

@ -0,0 +1,923 @@
# Frontend-Dokumentation
## Übersicht
Das Frontend ist eine **Progressive Web App (PWA)** gebaut mit React 18, Vite und React Router. Die Architektur folgt einem **Component-based Pattern** mit Context-basiertem State Management (kein Redux).
**Technologien:**
- React 18 (ohne TypeScript)
- Vite (Build Tool + Dev Server)
- React Router v6 (Client-side Routing)
- Recharts (Chart-Bibliothek)
- Lucide React (Icon Library)
- Day.js (Datum-Handling)
**Bundle-Größe:** ~450 KB (gzip), PWA-Cache für Offline-Nutzung
---
## Seiten-Übersicht
| Seite | Route | Beschreibung | Auth | Admin |
|-------|-------|--------------|------|-------|
| **LoginScreen** | `/` (ohne Auth) | E-Mail + Passwort Login, SHA256→bcrypt Auto-Migration | ❌ | ❌ |
| **Register** | `/register` | Selbst-Registrierung + E-Mail-Verifizierung | ❌ | ❌ |
| **Verify** | `/verify?token=...` | E-Mail-Verifizierung nach Registrierung | ❌ | ❌ |
| **SetupScreen** | `/` (First Run) | Initiales Setup (erster Admin-Account) | ❌ | ❌ |
| **Dashboard** | `/` | Übersicht: Quick Weight, Stats, Charts, Widgets | ✅ | ❌ |
| **CaptureHub** | `/capture` | Quick-Entry-Auswahl (Gewicht/Umfänge/Caliper/Fotos/Aktivität/Schlaf) | ✅ | ❌ |
| **WeightScreen** | `/weight` | Gewichts-Tracking mit Inline-Edit | ✅ | ❌ |
| **CircumScreen** | `/circum` | Umfänge (8 Punkte) | ✅ | ❌ |
| **CaliperScreen** | `/caliper` | Hautfaltenmessungen (4 Methoden) | ✅ | ❌ |
| **MeasureWizard** | `/wizard` | Geführte Messung (Schritt-für-Schritt) | ✅ | ❌ |
| **ActivityPage** | `/activity` | Training + Trainingstypen (v9d) | ✅ | ❌ |
| **NutritionPage** | `/nutrition` | 3-Tab Layout: Entry / Import / Charts | ✅ | ❌ |
| **SleepPage** | `/sleep` | Schlaf-Tracking + Phasen + Apple Health Import | ✅ | ❌ |
| **RestDaysPage** | `/rest-days` | Ruhetage (Kraft/Cardio/Entspannung) | ✅ | ❌ |
| **VitalsPage** | `/vitals` | 3-Tab: Baseline / Blutdruck / Import | ✅ | ❌ |
| **History** | `/history` | Verlauf mit Charts (Gewicht, KF%, Umfänge, etc.) | ✅ | ❌ |
| **Analysis** | `/analysis` | KI-Auswertung + Pipeline | ✅ | ❌ |
| **SettingsPage** | `/settings` | Profil, PIN-Change, Export, Feature-Usage-Übersicht | ✅ | ❌ |
| **SubscriptionPage** | `/subscription` | Membership-Status (v9c) | ✅ | ❌ |
| **GuidePage** | `/guide` | Anleitungen (Caliper, Umfänge) | ✅ | ❌ |
| **AdminPanel** | `/admin/*` (in Settings) | Admin-Übersicht | ✅ | ✅ |
| **AdminTierLimitsPage** | `/admin/tier-limits` | Tier-Limits Matrix (v9c) | ✅ | ✅ |
| **AdminFeaturesPage** | `/admin/features` | Feature-Verwaltung (v9c) | ✅ | ✅ |
| **AdminTiersPage** | `/admin/tiers` | Tier-Verwaltung (v9c) | ✅ | ✅ |
| **AdminCouponsPage** | `/admin/coupons` | Coupon-System (v9c) | ✅ | ✅ |
| **AdminUserRestrictionsPage** | `/admin/user-restrictions` | User-spezifische Limits (v9c) | ✅ | ✅ |
| **AdminTrainingTypesPage** | `/admin/training-types` | Trainingstypen-CRUD (v9d) | ✅ | ✅ |
| **AdminActivityMappingsPage** | `/admin/activity-mappings` | Activity Mapping-Verwaltung (v9d) | ✅ | ✅ |
| **AdminTrainingProfiles** | `/admin/training-profiles` | Training Type Profiling (v9d #15) | ✅ | ✅ |
**Gesamt:** 31 Seiten (22 User-facing, 9 Admin)
---
## Komponenten
### Wiederverwendbare Komponenten
| Komponente | Props | Beschreibung |
|-----------|-------|--------------|
| **Avatar** | `profile, size` | Runder Avatar mit Initialen + Farbe |
| **Markdown** | `text` | Lightweight Markdown-Renderer (## Headings, **bold**, Listen) |
| **TrialBanner** | | Trial-Countdown-Banner (3 Urgency-Level) |
| **EmailVerificationBanner** | | E-Mail-Verifizierungs-Hinweis |
| **FeatureUsageOverview** | | Tabelle mit allen Feature-Limits + Usage (v9c Phase 3) |
| **UsageBadge** | `feature` | Inline-Badge mit Limit-Status (z.B. "3/10") |
| **TrainingTypeDistribution** | `days` | Pie-Chart für Trainingstypen-Verteilung |
| **SleepWidget** | `days` | Dashboard-Widget mit Schlaf-Stats |
| **RestDaysWidget** | `weeks` | Dashboard-Widget mit aktuellen Ruhetagen |
**Location:** `frontend/src/components/`
### Inline-Komponenten (in Seiten definiert)
**Dashboard.jsx:**
- `QuickWeight` Schnelle Gewichts-Eingabe mit Feature-Limit-Check
- `StatCard` Statistik-Karte mit Delta-Anzeige
- `Pill` Status-Pill mit Tooltip (WHR, WHtR, KF, Protein Ø7T)
**SettingsPage.jsx:**
- `ProfileForm` Formular für Profil-Bearbeitung
**NutritionPage.jsx:**
- `EntryTab` Manuelle Eingabe + CSV-Import
- `ImportHistoryTab` Import-Historie mit Gruppierung
- `ChartsTab` Korrelationen + Wochendaten
**VitalsPage.jsx:**
- `BaselineTab` Morgenmessungen (RHR, HRV, VO2 Max, SpO2)
- `BloodPressureTab` Blutdruck mehrfach täglich + Context-Tagging
- `ImportTab` CSV-Import (Omron Deutsch, Apple Health)
---
## Context / State Management
### 1. AuthContext (`frontend/src/context/AuthContext.jsx`)
**Verantwortlichkeit:** Session-Management + Login/Logout
**State:**
```javascript
{
session: {
token: string,
profile_id: string,
role: 'user' | 'admin',
profile: { id, name, email, tier, ... }
},
loading: boolean,
needsSetup: boolean, // First-run detection
}
```
**Methods:**
- `login(credentials)` Login mit E-Mail + Passwort (oder Legacy profile_id + PIN)
- `setup(formData)` Initial Setup (First Run)
- `logout()` Logout + Token-Löschung
- `setAuthFromToken(token, profile)` Direkt-Login (für E-Mail-Verifizierung)
- `checkStatus()` Auth-Status prüfen (beim App-Start)
**Computed:**
- `isAdmin` `session.role === 'admin'`
- `canUseAI` `session.profile.ai_enabled !== 0`
- `canExport` `session.profile.export_enabled !== 0`
**Storage:**
- `localStorage.bodytrack_token` Auth-Token
- `localStorage.bodytrack_active_profile` Aktive Profile-ID
**Flow:**
```
App-Start → checkStatus()
GET /api/auth/status → {needs_setup: true/false}
↓ (wenn needs_setup = false)
GET /api/auth/me (mit Token aus localStorage)
Session gesetzt → App.jsx zeigt Dashboard
```
### 2. ProfileContext (`frontend/src/context/ProfileContext.jsx`)
**Verantwortlichkeit:** Aktives Profil + Profil-Liste
**State:**
```javascript
{
profiles: Array<Profile>, // Alle Profile
activeProfile: Profile, // Aktuelles Profil
loading: boolean,
}
```
**Methods:**
- `setActiveProfile(profile)` Profil wechseln (speichert in localStorage)
- `refreshProfiles()` Profile neu laden (nach Update)
**Flow:**
```
session.profile_id ändert sich
GET /api/profiles (mit X-Auth-Token)
profiles gesetzt, activeProfile = match(session.profile_id)
```
**Hinweis:** Profile-Wechsel ist derzeit Single-User-optimiert (Multi-User-Support in Planung).
---
## API-Integration (`frontend/src/utils/api.js`)
**Zweck:** Zentrale API-Schnittstelle **ALLE** API-Calls gehen über `api.js`
**Features:**
- Automatisches Token-Injection (`X-Auth-Token` Header)
- Automatisches Profile-ID-Injection (`X-Profile-Id` Header, derzeit deprecated)
- Einheitliche Fehlerbehandlung (parst `{detail: "..."}` aus Backend)
- Typed-like API (alle Methoden dokumentiert)
**Beispiel:**
```javascript
import { api } from '../utils/api'
// GET-Request
const weights = await api.listWeight(365) // limit=365
// POST-Request
await api.upsertWeight('2026-03-23', 75.5, 'Morgens nüchtern')
// DELETE-Request
await api.deleteWeight(entryId)
// File-Upload
const result = await api.importCsv(file)
```
**Headers-Injection:**
```javascript
function hdrs(extra={}) {
const h = {...extra}
if (_profileId) h['X-Profile-Id'] = _profileId // Deprecated, bleibt für Legacy
const token = getToken()
if (token) h['X-Auth-Token'] = token
return h
}
```
**Error-Handling:**
```javascript
if (!res.ok) {
const err = await res.text()
try {
const parsed = JSON.parse(err)
throw new Error(parsed.detail || err)
} catch {
throw new Error(err)
}
}
```
**API-Methoden (285 Zeilen):**
- **Profiles:** `getActiveProfile, listProfiles, createProfile, updateProfile, deleteProfile`
- **Weight:** `listWeight, upsertWeight, updateWeight, deleteWeight, weightStats`
- **Circumferences:** `listCirc, upsertCirc, updateCirc, deleteCirc`
- **Caliper:** `listCaliper, upsertCaliper, updateCaliper, deleteCaliper`
- **Activity:** `listActivity, createActivity, updateActivity, deleteActivity, activityStats, bulkCategorizeActivities, importActivityCsv`
- **Nutrition:** `importCsv, listNutrition, nutritionCorrelations, nutritionWeekly, nutritionImportHistory, createNutrition, updateNutrition, deleteNutrition`
- **Photos:** `uploadPhoto, listPhotos, photoUrl`
- **AI:** `insightTrend, listPrompts, runInsight, insightPipeline, listInsights, latestInsights`
- **Export:** `exportZip, exportJson, exportCsv` (Download-Handling inkludiert)
- **Admin:** `adminListProfiles, adminCreateProfile, adminDeleteProfile, adminSetPermissions, changePin`
- **Auth:** `register, verifyEmail, resendVerification`
- **Subscription (v9c):** `getMySubscription, getMyUsage, getMyLimits, redeemCoupon, getFeatureUsage`
- **Admin Features (v9c):** `listFeatures, createFeature, updateFeature, deleteFeature`
- **Admin Tiers (v9c):** `listTiers, createTier, updateTier, deleteTier, getTierLimitsMatrix, updateTierLimit, updateTierLimitsBatch`
- **Admin User Restrictions (v9c):** `listUserRestrictions, createUserRestriction, updateUserRestriction, deleteUserRestriction`
- **Admin Coupons (v9c):** `listCoupons, createCoupon, updateCoupon, deleteCoupon, getCouponRedemptions`
- **Admin Access Grants (v9c):** `listAccessGrants, createAccessGrant, updateAccessGrant, revokeAccessGrant`
- **Training Types (v9d):** `listTrainingTypes, listTrainingTypesFlat, getTrainingCategories, adminListTrainingTypes, adminCreateTrainingType, adminUpdateTrainingType, adminDeleteTrainingType, getAbilitiesTaxonomy`
- **Training Profiles (v9d #15):** `getProfileStats, getProfileTemplates, getProfileTemplate, applyProfileTemplate, getTrainingParameters, batchEvaluateActivities`
- **Activity Mappings (v9d):** `adminListActivityMappings, adminCreateActivityMapping, adminUpdateActivityMapping, adminDeleteActivityMapping, adminGetMappingCoverage`
- **Sleep (v9d):** `listSleep, getSleepByDate, createSleep, updateSleep, deleteSleep, getSleepStats, getSleepDebt, getSleepTrend, getSleepPhases, importAppleHealthSleep`
- **Rest Days (v9d):** `listRestDays, createRestDay, getRestDay, updateRestDay, deleteRestDay, getRestDaysStats, validateActivity`
- **Vitals Baseline (v9d):** `listBaseline, getBaselineByDate, createBaseline, updateBaseline, deleteBaseline, getBaselineStats, importBaselineAppleHealth`
- **Blood Pressure (v9d):** `listBloodPressure, getBPByDate, createBloodPressure, updateBloodPressure, deleteBloodPressure, getBPStats, importBPOmron`
---
## Berechnungs-Utils
### 1. calc.js (`frontend/src/utils/calc.js`)
**Zweck:** Körperfett-Berechnungen + Derived Metrics
**Funktionen:**
**`calcBodyFat(method, skinfolds, sex, age)`**
- Berechnet Körperfett-% nach 4 Methoden:
- `jackson3` Jackson-Pollock 3-Punkt (Standard)
- `jackson7` Jackson-Pollock 7-Punkt
- `durnin` Durnin-Womersley 4-Punkt
- `parrillo` Parrillo 9-Punkt (linear)
- Nutzt Siri-Formel: `BF% = (495 / D) - 450`
- Parameter:
- `method`: String ('jackson3', 'jackson7', 'durnin', 'parrillo')
- `skinfolds`: Object mit Hautfalten in mm (z.B. `{chest: 12, abdomen: 24, thigh: 18}`)
- `sex`: 'm' | 'f'
- `age`: Number
**`getBfCategory(pct, sex)`**
- Kategorisiert Körperfett-% in Bereiche:
- Männer: Essenziell (<6%), Athletisch (6-14%), Fit (14-18%), Durchschnitt (18-25%), Übergewicht (>25%)
- Frauen: Essenziell (<14%), Athletisch (14-21%), Fit (21-25%), Durchschnitt (25-32%), Übergewicht (>32%)
- Returns: `{max, label, color, desc}`
**`calcDerived(measurement, height)`**
- Berechnet abgeleitete Metriken:
- **WHR** (Waist-Hip-Ratio): `waist / hip` (Ziel: <0.90 M / <0.85 F)
- **WHtR** (Waist-to-Height-Ratio): `waist / height` (Ziel: <0.50)
- **FFMI** (Fat-Free Mass Index): `lean_mass / (height_m²)` (Natural Limit: ~25 M / ~22 F)
- Returns: `{whr, whtr, ffmi}`
**`getRuleBasedAssessment(current, previous, profile)`**
- Generiert automatische Interpretationen basierend auf:
- Körperfett-Kategorie
- Änderungen seit letzter Messung
- FFMI (Muskel-Index)
- WHR / WHtR (Fettverteilung)
- Taillenumfang (WHO-Grenzwerte)
- Returns: `{findings: Array, summary: string, summaryType: 'good'|'warn'|'bad'}`
**Guide-Daten:**
- `CIRCUMFERENCE_GUIDE` Messanleitung für 8 Umfangspunkte (wo, wie, Posture, Tipps)
- `CALIPER_GUIDE` Messanleitung für Hautfalten-Punkte
### 2. interpret.js (`frontend/src/utils/interpret.js`)
**Zweck:** Interpretation von Messwerten
**`getInterpretation(measurement, profile, prevMeasurement)`**
- Analysiert Messung und generiert strukturierte Interpretation:
- Körperfett-Status (mit Kategorie + Farbe)
- WHR-Status
- WHtR-Status
- FFMI-Status
- BMI-Status
- Vergleich zur letzten Messung (Deltas)
- Returns: Array von Interpretations-Objects:
```javascript
{
category: 'Körperfett',
icon: '🫧',
status: 'good' | 'warn' | 'bad',
title: 'Athletischer Körperfettanteil',
detail: 'Ausgezeichnet. Typisch für aktive Sportler...',
value: '12.5%',
badge: 'Athletisch',
color: '#1D9E75',
}
```
**`getStatusColor(status)`** Farbe für Status ('good'→Grün, 'warn'→Orange, 'bad'→Rot)
**`getStatusBg(status)`** Background-Farbe für Status
### 3. Markdown.jsx (`frontend/src/utils/Markdown.jsx`)
**Zweck:** Leichtgewichtiger Markdown-Renderer für KI-Texte
**Unterstützte Syntax:**
- `# Heading 1`, `## Heading 2`, `### Heading 3`
- `**bold**`, `*italic*`
- `- Bullet List`, `1. Numbered List`
- `---` (Horizontal Rule)
- Line Breaks
**Verwendung:**
```jsx
<Markdown text={aiInsight.content} />
```
**Vorteil:** Kein remark/rehype-Dependency nur 134 Zeilen pures React
---
## CSS-System (`frontend/src/app.css`)
### CSS-Variablen (Light + Dark Mode)
**Farben:**
```css
:root {
--bg: #f4f3ef; /* Hintergrund */
--surface: #ffffff; /* Cards */
--surface2: #f9f8f5; /* Inputs, Secondary */
--border: rgba(0,0,0,0.09); /* Standard-Border */
--border2: rgba(0,0,0,0.16);/* Input-Border */
--text1: #1c1b18; /* Primär-Text */
--text2: #5a5955; /* Sekundär-Text */
--text3: #9a9892; /* Muted */
--accent: #1D9E75; /* Primär-Farbe */
--accent-light: #E1F5EE; /* Accent-Background */
--accent-dark: #0a5c43; /* Hover */
--danger: #D85A30; /* Fehler/Löschen */
--warn: #EF9F27; /* Warnung */
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #181816;
--surface: #222220;
--surface2: #1e1e1c;
--border: rgba(255,255,255,0.08);
--text1: #eeecea;
--text2: #aaa9a4;
--text3: #686762;
--accent-light: #04342C;
--accent-dark: #5DCAA5;
}
}
```
**Layout:**
```css
--nav-h: 64px; /* Bottom Navigation Höhe */
--header-h: 52px; /* App-Header Höhe */
```
### Utility Classes
**Cards:**
```css
.card /* Standard-Card (white background, border, rounded) */
.card-title /* Card-Überschrift (uppercase, small, muted) */
```
**Stats:**
```css
.stats-grid /* 2-Column Grid für Stats */
.stat-card /* Einzelne Stat-Card */
.stat-val /* Wert (groß, bold) */
.stat-label /* Label (klein, muted) */
.stat-delta /* Delta (z.B. "+2.5 kg") */
.delta-pos /* Positive Änderung (grün) */
.delta-neg /* Negative Änderung (rot) */
```
**Forms:**
```css
.form-section /* Formular-Sektion mit Abstand */
.form-section-title /* Sektions-Titel (uppercase, border-bottom) */
.form-row /* Zeile mit Label + Input + Unit */
.form-label /* Label (links, flex:1) */
.form-input /* Input (90px breit, text-align:right) */
.form-unit /* Einheit (z.B. "kg", 24px breit) */
.form-select /* Select-Dropdown */
.form-sub /* Sub-Label (klein, muted) */
```
**Buttons:**
```css
.btn /* Base Button */
.btn-primary /* Primär-Button (accent) */
.btn-secondary /* Sekundär-Button (grau) */
.btn-danger /* Löschen-Button (rot) */
.btn-full /* Full-Width Button */
```
**Tabs:**
```css
.tabs /* Tab-Container (segmented control) */
.tab /* Einzelner Tab */
.tab.active /* Aktiver Tab (white background, shadow) */
```
**Misc:**
```css
.badge /* Inline-Badge (klein, rounded) */
.spinner /* Loading-Spinner (CSS-Animation) */
.empty-state /* Leerer Zustand (zentriert, muted) */
.muted /* Muted-Text (text3) */
```
### Responsive Design
**Mobile-First Approach:**
- Standard-Layout für 375px600px (Mobile)
- Max-Width: 600px (zentriert auf Desktop)
- Bottom-Navigation für Mobile (64px hoch)
- Touch-optimierte Button-Größen (min 44px)
**Bottom Navigation:**
```css
.bottom-nav {
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 100%;
max-width: 600px;
height: var(--nav-h);
z-index: 20;
}
```
**Safe Area (iPhone):**
```css
padding-bottom: env(safe-area-inset-bottom, 0); /* Notch-Handling */
```
**Desktop-Optimierung:**
- App zentriert mit max-width: 600px
- Kein responsives Layout für >600px (bewusst Mobile-optimiert)
---
## PWA-Konfiguration
### Service Worker
**Location:** `frontend/public/service-worker.js`
**Cache-Strategie:**
- **Static Assets:** Cache-First (HTML, CSS, JS, Icons)
- **API-Calls:** Network-First mit Fallback
- **Photos:** Cache-First mit Expiry
**Registrierung:**
```javascript
// frontend/src/main.jsx
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
}
```
### Manifest
**Location:** `frontend/public/manifest.json`
**Wichtige Felder:**
```json
{
"name": "Mitai Jinkendo",
"short_name": "Mitai",
"theme_color": "#1D9E75",
"background_color": "#f4f3ef",
"display": "standalone",
"icons": [
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }
]
}
```
**Installation:**
- iOS: "Zum Home-Bildschirm"
- Android: "Installieren"-Prompt
- Desktop: Chrome/Edge Install-Button
---
## Chart-Bibliothek (Recharts)
**Verwendete Charts:**
| Chart-Typ | Verwendung | Seite |
|-----------|-----------|-------|
| **LineChart** | Gewicht, Körperfett, Umfänge, Vitalwerte | Dashboard, History |
| **BarChart** | Wöchentliche Ernährung, Aktivität | NutritionPage, History |
| **PieChart** | Trainingstypen-Verteilung | Dashboard, ActivityPage |
| **ScatterChart** | Korrelationen (Gewicht vs. Kalorien) | NutritionPage |
| **ComposedChart** | Multi-Axis (Gewicht + KF% kombiniert) | History |
**Standard-Konfiguration:**
```jsx
<ResponsiveContainer width="100%" height={240}>
<LineChart data={data}>
<CartesianGrid strokeDasharray="3 3" stroke="var(--border)" />
<XAxis dataKey="date" tick={{ fontSize: 11 }} stroke="var(--text3)" />
<YAxis tick={{ fontSize: 11 }} stroke="var(--text3)" />
<Tooltip contentStyle={{ background: 'var(--surface)', border: '1px solid var(--border)' }} />
<Line type="monotone" dataKey="weight" stroke="var(--accent)" strokeWidth={2} dot={false} />
</LineChart>
</ResponsiveContainer>
```
**Farb-Schema:**
- Gewicht: `var(--accent)` (#1D9E75)
- Körperfett: `#D85A30` (Danger)
- Umfänge: Individual Colors (siehe `CIRCUMFERENCE_GUIDE`)
- 7-Tage-Durchschnitt: `var(--accent-dark)` (#0a5c43, gestrichelt)
---
## Feature Usage Badges (v9c Phase 3)
**Zweck:** Sichtbarkeit der Feature-Limits direkt in der UI
**Komponenten:**
### 1. UsageBadge (`components/UsageBadge.jsx`)
**Inline-Badge mit Limit-Status:**
```jsx
<UsageBadge feature="weight_entries" />
// Rendert: "5/10" (grün) oder "10/10 🔒" (rot)
```
**Logik:**
```javascript
const { allowed, used, limit, remaining } = await api.getFeatureUsage()
const color = allowed ? 'var(--accent)' : 'var(--danger)'
const text = limit === null ? '∞' : `${used}/${limit}`
```
**Verwendung:** In Buttons (z.B. "Speichern 5/10")
### 2. FeatureUsageOverview (`components/FeatureUsageOverview.jsx`)
**Tabelle mit allen Features:**
```jsx
<FeatureUsageOverview />
```
**Darstellung:**
| Feature | Genutzt | Limit | Verbleibend | Status |
|---------|---------|-------|-------------|--------|
| Gewichtseinträge | 45 | 100 | 55 | ✓ OK |
| KI-Aufrufe | 10 | 10 | 0 | 🔒 Limit erreicht |
| Daten-Export | 1 | 5 | 4 | ✓ OK |
**Farbcodierung:**
- Grün: `allowed === true`
- Rot: `allowed === false`
- Gelb: `remaining < 10% && allowed`
**Location:** Settings-Seite (Tab "Quota")
---
## Routing-Architektur
### App-Struktur (`App.jsx`)
```
AuthProvider
ProfileProvider
BrowserRouter
AppShell
├── Public Routes (ohne Auth)
│ ├── /register → Register
│ ├── /verify?token=... → Verify
│ └── /reset-password?token=... → ResetPassword
├── Auth Gates
│ ├── authLoading → Spinner
│ ├── needsSetup → SetupScreen
│ └── !session → LoginScreen
└── Authenticated Routes
├── Header (Logo + Logout + Avatar)
├── Main (Scrollable Content)
│ └── Routes (31 Seiten)
└── Nav (Bottom Navigation, 5 Items)
```
### Navigation-Items
```javascript
const links = [
{ to: '/', icon: <LayoutDashboard/>, label: 'Übersicht' },
{ to: '/capture', icon: <PlusSquare/>, label: 'Erfassen' },
{ to: '/history', icon: <TrendingUp/>, label: 'Verlauf' },
{ to: '/analysis', icon: <BarChart2/>, label: 'Analyse' },
{ to: '/settings', icon: <Settings/>, label: 'Einst.' },
]
```
**Besonderheit:** Active-State via React Router `NavLink` (`isActive` prop)
### Route-Guards
**Auth-Schutz:**
```jsx
if (!session) return <LoginScreen/>
```
**Admin-Schutz:**
```jsx
// In AdminPanel-Seiten:
const { isAdmin } = useAuth()
if (!isAdmin) return <div>Nur für Admins</div>
```
**Setup-Check:**
```jsx
if (needsSetup) return <SetupScreen/>
```
---
## Performance-Optimierungen
### 1. Code Splitting
**React.lazy() für Admin-Seiten:**
```javascript
const AdminPanel = React.lazy(() => import('./pages/AdminPanel'))
```
**Vorteil:** Admin-Code nicht im Initial Bundle (~80 KB gespart)
### 2. Memoization
**useMemo für teure Berechnungen:**
```javascript
const stats = useMemo(() => {
return calculateStats(data)
}, [data])
```
**Verwendung:** Chart-Daten-Transformation, Aggregationen
### 3. Lazy Loading
**Images:**
```jsx
<img src={photoUrl} loading="lazy" />
```
**Charts:**
- Nur sichtbare Charts rendern (Intersection Observer in Planung)
### 4. API-Call-Batching
**Parallel-Loading:**
```javascript
const [stats, insights, weights] = await Promise.all([
api.getStats(),
api.latestInsights(),
api.listWeight(30),
])
```
**Verwendung:** Dashboard initial load
---
## Error-Handling
### 1. API-Fehler
**Pattern in allen Seiten:**
```javascript
const [error, setError] = useState(null)
try {
const data = await api.someEndpoint()
setData(data)
} catch(e) {
setError(e.message) // api.js parsed bereits {detail: "..."}
} finally {
setLoading(false)
}
```
**Anzeige:**
```jsx
{error && (
<div style={{
background: 'rgba(216,90,48,0.1)',
color: 'var(--danger)',
padding: '10px 14px',
borderRadius: 8,
border: '1px solid rgba(216,90,48,0.2)'
}}>
{error}
</div>
)}
```
### 2. Network-Fehler
**Offline-Detection:**
```javascript
useEffect(() => {
const handleOnline = () => setOnline(true)
const handleOffline = () => setOnline(false)
window.addEventListener('online', handleOnline)
window.addEventListener('offline', handleOffline)
return () => {
window.removeEventListener('online', handleOnline)
window.removeEventListener('offline', handleOffline)
}
}, [])
```
**Anzeige:** Banner "Keine Internetverbindung Änderungen werden gespeichert sobald Online"
### 3. Form-Validierung
**Client-Side:**
```javascript
if (!weight || weight < 20 || weight > 300) {
setError('Gewicht zwischen 20 und 300 kg')
return
}
```
**Server-Side:**
- Backend wirft `HTTPException(400, detail="...")` → Frontend zeigt `detail`
---
## Besonderheiten & Design-Entscheidungen
### 1. Warum kein TypeScript?
**Entscheidung:** Bewusst auf TypeScript verzichtet
**Gründe:**
- Schnellere Prototyping-Geschwindigkeit
- Weniger Build-Komplexität
- JSDoc-Kommentare für Dokumentation ausreichend
- Type Safety durch Backend (Pydantic validiert alle Inputs)
### 2. Warum Context statt Redux?
**Entscheidung:** Context API ausreichend für diesen Use-Case
**Gründe:**
- Nur 2 globale States (Auth + Profile)
- Kein komplexes State-Update-Pattern nötig
- Weniger Boilerplate
- Performance ausreichend (keine häufigen Re-Renders)
**Hinweis:** Bei >5 Contexts würde Redux Sinn machen
### 3. Warum Custom Markdown statt remark/rehype?
**Entscheidung:** Eigener Markdown-Renderer (134 Zeilen)
**Gründe:**
- Nur Subset von Markdown benötigt (Headings, Bold, Listen)
- remark + rehype + plugins = ~200 KB Bundle-Size
- Custom-Renderer = 0 Dependencies
- Full Control über Styling
### 4. Warum Recharts statt Chart.js?
**Entscheidung:** Recharts für alle Charts
**Gründe:**
- React-native (kein Canvas, sondern SVG)
- Declarative API passt zu React
- Responsive by default
- Kleineres Bundle als Chart.js
### 5. Inline-Editing statt Modal-Forms
**Entscheidung:** Inline-Edit für alle Listen (Gewicht, Ernährung, Vitalwerte)
**Pattern:**
```javascript
const [editingId, setEditingId] = useState(null)
{entries.map(e => (
editingId === e.id
? <EditForm entry={e} onSave={...} onCancel={...} />
: <ViewRow entry={e} onEdit={() => setEditingId(e.id)} />
))}
```
**Vorteil:**
- Keine Modal-Komponente nötig
- Besserer Mobile-UX (kein Overlay)
- Schnelleres Editing (kein Dialog öffnen)
---
## Bekannte Limitationen
### 1. Desktop-Optimierung
**Problem:** App ist Mobile-First, Desktop-Layout nicht optimiert
**Aktuell:** Max-Width 600px, zentriert auf Desktop
**Geplant (v10+):** Responsive Grid-Layout für Desktop (Sidebar + Multi-Column)
### 2. Offline-Modus
**Problem:** Service Worker cached nur Static Assets, nicht API-Responses
**Aktuell:** Offline = Keine Daten-Eingabe möglich
**Geplant (v10+):** IndexedDB für Offline-Queue
### 3. Multi-Profil-Support
**Problem:** Profile-Wechsel funktioniert, aber Session ist Single-User
**Aktuell:** Logout + Login für Profil-Wechsel
**Geplant (v9f+):** Multi-Session-Support (Switch ohne Logout)
### 4. Accessibility
**Problem:** ARIA-Labels fehlen, Keyboard-Navigation unvollständig
**Aktuell:** Maus/Touch-optimiert
**Geplant (v10+):** WCAG 2.1 AA Compliance
---
## Testing
**Aktueller Stand:** Kein automatisiertes Testing implementiert
**Geplant (v10+):**
- Unit-Tests: Vitest für utils (calc.js, interpret.js)
- Component-Tests: React Testing Library
- E2E-Tests: Playwright für kritische Flows (Login, Gewicht-Eingabe, KI-Analyse)
**Manual Testing:**
- Alle Features manuell auf iOS Safari, Android Chrome, Desktop Firefox getestet
- Regression-Tests bei jedem Deploy
---
## Zusammenfassung
**Architektur-Highlights:**
- ✅ 31 Seiten (22 User, 9 Admin)
- ✅ Context-basiertes State Management (Auth + Profile)
- ✅ Zentrale API-Schnittstelle (api.js)
- ✅ Berechnungs-Utils für Body-Metrics (calc.js, interpret.js)
- ✅ CSS-Variablen für Light/Dark Mode
- ✅ PWA mit Service Worker
- ✅ Recharts für alle Charts
- ✅ Feature Usage Badges (v9c Phase 3)
- ✅ Mobile-First Design (max-width 600px)
- ✅ Inline-Editing statt Modals
- ✅ Custom Markdown-Renderer (0 Dependencies)
**Performance:**
- Initial Bundle: ~450 KB (gzip)
- Code Splitting: Admin-Seiten lazy-loaded
- API-Call-Batching: Parallel-Loading für Dashboard
**Nächste Schritte:**
- Testing (Vitest + React Testing Library)
- Desktop-Responsive-Layout
- Offline-Modus (IndexedDB)
- Accessibility (WCAG 2.1 AA)

View File

@ -0,0 +1,212 @@
# Internal API Reference
**Purpose:** Prevent guessing function signatures and module exports.
Last updated: 2026-03-28
---
## goal_utils.py
### Focus Area Functions
```python
def get_focus_weights(conn, profile_id: str) -> Dict[str, float]
```
Returns user's focus area weights as `{area_key: weight_percent}`.
Keys are **English** (weight_loss, muscle_gain, etc.).
```python
def get_focus_weights_v2(conn, profile_id: str) -> Dict[str, float]
```
Newer version with auto-normalization. Use this for new code.
```python
def get_primary_focus(conn, profile_id: str) -> str
```
Returns area_key of highest weighted focus area.
```python
def get_focus_description(focus_area: str) -> str
```
Returns German description for a focus area key.
---
### Goal Functions
```python
def get_active_goals(profile_id: str) -> List[Dict]
```
Returns ALL active goals for a profile.
Each dict has: id, type_key, current_value, target_value, is_primary, etc.
**To filter by type:**
```python
goals = get_active_goals(profile_id)
weight_goals = [g for g in goals if g.get('type_key') == 'weight']
```
```python
def get_goal_by_id(goal_id: str) -> Optional[Dict]
```
Returns single goal by UUID.
```python
def get_goal_type_config(conn, type_key: str) -> Optional[Dict[str, Any]]
```
Returns goal type metadata from `goal_type_definitions` table:
- source_table, source_column, aggregation_method, unit
```python
def get_current_value_for_goal(conn, profile_id: str, goal_type: str) -> Optional[float]
```
Calculates current value for a goal type using its aggregation method.
---
### Aggregation Functions
```python
def calculate_current_value(
profile_id: str,
table: str,
column: str,
method: str,
date_column: str = 'date',
filter_conditions: Optional[List[Tuple[str, Any]]] = None
) -> Optional[float]
```
**Available methods:**
- `latest` - Most recent value
- `avg_7d` - 7-day average (numeric values only)
- `avg_30d` - 30-day average
- `max_30d` - Maximum in 30 days
- `avg_per_week_30d` - Count per week over 30 days (for frequency tracking)
**Filter conditions format:**
```python
[("training_type", "strength"), ("quality", "good")]
```
---
## calculations/body_metrics.py
### Score Functions
```python
def calculate_body_progress_score(profile_id: str, focus_weights: Dict[str, float] = None) -> Optional[int]
```
Returns 0-100 score for body composition progress.
Weighted by focus areas: weight_loss, muscle_gain, body_recomposition.
**Sub-functions (private):**
- `_score_weight_trend(profile_id)` - Alignment with weight goal
- `_score_body_composition(profile_id)` - BF% + lean mass progress
---
## calculations/nutrition_metrics.py
### Score Functions
```python
def calculate_nutrition_score(profile_id: str, focus_weights: Dict[str, float] = None) -> Optional[int]
```
Returns 0-100 score for nutrition adherence.
Weighted by: protein_intake, calorie_balance, macro_consistency, meal_timing, hydration.
**Sub-functions (private):**
- `_score_calorie_adherence(profile_id)` - Energy balance vs goal
- `_score_protein_adequacy(profile_id)` - Protein target adherence
---
## calculations/activity_metrics.py
### Score Functions
```python
def calculate_activity_score(profile_id: str, focus_weights: Dict[str, float] = None) -> Optional[int]
```
Returns 0-100 score for training quality.
Weighted by: strength, endurance (aerobic+anaerobic+cardiovascular), mobility/coordination.
**Sub-functions (private):**
- `_score_training_quality(profile_id)` - Session quality %
- `_score_training_consistency(profile_id)` - Frequency adherence
---
## calculations/scores.py
### Main Score Aggregator
```python
def calculate_goal_progress_score(profile_id: str) -> Optional[int]
```
Master score aggregating body, nutrition, activity progress.
Weighted by user's category weights from focus areas.
```python
def calculate_category_progress(profile_id: str, category: str) -> Optional[int]
```
Maps category name to appropriate score function.
Categories: körper, ernährung, aktivität, erholung, vitalwerte, mental, lebensstil
---
## Common Patterns
### Getting Goals for a Specific Type
```python
# ❌ DON'T (function doesn't exist):
from goal_utils import get_goals_by_type
goals = get_goals_by_type(profile_id, 'weight')
# ✅ DO:
from goal_utils import get_active_goals
goals = get_active_goals(profile_id)
weight_goals = [g for g in goals if g.get('type_key') == 'weight']
```
### Accessing Focus Area Weights
```python
# ❌ DON'T (German keys don't exist in DB):
weight_focus = focus_weights.get('körpergewicht', 0)
# ✅ DO (English keys from Migration 031):
weight_loss = focus_weights.get('weight_loss', 0)
muscle_gain = focus_weights.get('muscle_gain', 0)
```
### Querying Sleep Data
```python
# ❌ DON'T:
SELECT duration FROM sleep_log
# ✅ DO:
SELECT duration_minutes, deep_minutes, rem_minutes FROM sleep_log
```
---
## Verification Checklist
Before using any function:
1. ✅ Verify function exists: `grep "^def function_name" backend/module.py`
2. ✅ Check signature: `Read module.py` to see parameters
3. ✅ Check what it returns: Read docstring or implementation
4. ✅ Verify imported correctly: Check module path
Before writing SQL:
1. ✅ Check table schema: `grep "CREATE TABLE" backend/schema.sql`
2. ✅ Verify column names: Check migration files
3. ✅ Test query logic: Use actual data, not assumptions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,392 @@
# Database Migrations System
**Version:** v9c
**Implementiert:** 2026-03-21
**Dokumentiert:** 2026-03-21
---
## Übersicht
Mitai Jinkendo verwendet ein automatisches Migrations-System für strukturierte Schema-Änderungen. Alle Migrationen werden beim Container-Start automatisch ausgeführt.
## Architektur
### Migration-Tracking
**Tabelle:** `schema_migrations`
```sql
CREATE TABLE schema_migrations (
id SERIAL PRIMARY KEY,
filename VARCHAR(255) UNIQUE NOT NULL,
applied_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
)
```
Diese Tabelle trackt, welche Migrationen bereits angewendet wurden.
### Ablauf beim Container-Start
1. **PostgreSQL Connection Check** (`db_init.py`)
2. **Schema-Initialisierung** (falls `profiles` Tabelle nicht existiert)
- Lädt `backend/schema.sql` (Basis-Schema)
3. **Migrations-System** (`run_migrations()`)
- Erstellt `schema_migrations` Tabelle (falls nicht vorhanden)
- Scannt `backend/migrations/` nach `.sql` Dateien
- Filtert nur nummerierte Dateien: `\d{3}_*.sql` (z.B. `001_feature.sql`)
- Sortiert alphabetisch (aufsteigende Reihenfolge)
- Wendet nur noch nicht angewendete Migrationen an
- Trackt jede erfolgreich angewendete Migration
4. **SQLite-zu-PostgreSQL Migration** (falls vorhanden)
## Datei-Konventionen
### Naming-Pattern
**Format:** `XXX_descriptive_name.sql`
- `XXX` = Dreistellige Nummer (001, 002, 003, ...)
- Unterstrich `_` als Trennzeichen
- Kleinbuchstaben, keine Leerzeichen
- `.sql` Extension
**Beispiele:**
```
✅ 001_subscription_system.sql
✅ 002_fix_features.sql
✅ 003_add_email_verification.sql
❌ v9c_subscription_system.sql # Keine Nummer
❌ check_features.sql # Keine Nummer
❌ 1_feature.sql # Nur eine Ziffer
❌ 001-feature.sql # Bindestrich statt Unterstrich
```
### Datei-Struktur
Jede Migration sollte folgende Struktur haben:
```sql
-- ================================================================
-- Migration XXX: Beschreibung
-- Version: vX.X
-- Date: YYYY-MM-DD
-- ================================================================
-- Beschreibung der Änderung
ALTER TABLE table_name ...
-- Weitere SQL-Statements
-- Kommentare für Dokumentation
COMMENT ON COLUMN table.column IS 'Beschreibung';
```
### SQL-Einschränkungen
**Erlaubt:**
- Standard SQL DDL (CREATE, ALTER, DROP)
- Standard SQL DML (INSERT, UPDATE, DELETE)
- CREATE INDEX, CREATE FUNCTION, etc.
- Multi-Statement-Scripts (durch `;` getrennt)
**Nicht erlaubt:**
- psql Meta-Kommandos (`\echo`, `\set`, `\connect`, etc.)
- Interactive Commands (`\i`, `\include`)
- Transaktions-Kontrolle (automatisch gehandhabt)
## Anwendung
### Automatisch (Production/Dev)
Migrationen werden **automatisch** beim Container-Start angewendet:
```bash
# Container startet
docker compose up -d
# db_init.py wird ausgeführt:
# 1. PostgreSQL ready check
# 2. Schema initialisiert (falls nötig)
# 3. Migrationen ausgeführt
# 4. SQLite-Migration (falls nötig)
```
**Log-Output:**
```
═══════════════════════════════════════════════════════════
MITAI JINKENDO - Database Initialization (v9c)
═══════════════════════════════════════════════════════════
Checking PostgreSQL connection...
✓ PostgreSQL ready
Checking database schema...
✓ Schema already exists
Running database migrations...
Found 2 pending migration(s)...
✓ Applied: 001_subscription_system.sql
✓ Applied: 003_add_email_verification.sql
✓ Database initialization complete
```
### Manuell (Entwicklung)
Für Testing während der Entwicklung:
```bash
# Im laufenden Container
docker exec -it dev-mitai-api python3 /app/db_init.py
# Oder direkt mit psql (für einzelne Migrationen)
docker exec -it dev-mitai-db psql -U mitai_dev -d mitai_dev \
-f /path/to/migration.sql
```
## Migration erstellen
### Schritt 1: Datei erstellen
```bash
# Nächste freie Nummer ermitteln
ls backend/migrations/ | grep -E '^\d{3}_' | sort | tail -1
# → 003_add_email_verification.sql
# Neue Migration mit Nummer 004
touch backend/migrations/004_add_new_feature.sql
```
### Schritt 2: SQL schreiben
```sql
-- ================================================================
-- Migration 004: Add New Feature
-- Version: v9d
-- Date: 2026-03-22
-- ================================================================
-- Add new column
ALTER TABLE profiles
ADD COLUMN IF NOT EXISTS new_feature_enabled BOOLEAN DEFAULT TRUE;
-- Create index if needed
CREATE INDEX IF NOT EXISTS idx_profiles_new_feature
ON profiles(new_feature_enabled)
WHERE new_feature_enabled = TRUE;
-- Update existing data if needed
UPDATE profiles
SET new_feature_enabled = TRUE
WHERE tier = 'premium';
COMMENT ON COLUMN profiles.new_feature_enabled IS 'Feature flag for new feature';
```
### Schritt 3: Testen
```bash
# Lokal testen (Dev-Container)
git add backend/migrations/004_add_new_feature.sql
git commit -m "feat: add migration for new feature"
git push origin develop
# Container wird neu gebaut und Migration automatisch angewendet
```
### Schritt 4: Verifizieren
```bash
# Prüfen ob Migration angewendet wurde
docker exec -it dev-mitai-db psql -U mitai_dev -d mitai_dev \
-c "SELECT * FROM schema_migrations ORDER BY applied_at DESC LIMIT 5;"
# Output:
# id | filename | applied_at
# ---+------------------------------+------------------------
# 4 | 004_add_new_feature.sql | 2026-03-22 10:30:15+00
# 3 | 003_add_email_verification.sql| 2026-03-21 15:20:10+00
# 2 | 002_fix_features.sql | 2026-03-20 12:10:05+00
# 1 | 001_subscription_system.sql | 2026-03-20 12:10:00+00
```
## Rollback-Strategie
**Automatischer Rollback:** Nicht implementiert
**Manueller Rollback:**
1. **Identifizieren der problematischen Migration:**
```bash
docker logs dev-mitai-api | grep "Failed to apply"
```
2. **Migration aus Tracking entfernen:**
```sql
DELETE FROM schema_migrations
WHERE filename = '004_broken_migration.sql';
```
3. **Änderungen manuell rückgängig machen:**
```sql
-- Beispiel: Spalte entfernen
ALTER TABLE profiles DROP COLUMN new_feature_enabled;
```
4. **Migration-Datei korrigieren**
```bash
vim backend/migrations/004_broken_migration.sql
```
5. **Container neu starten** (Migration wird erneut ausgeführt)
```bash
docker compose restart api
```
## Best Practices
### ✅ DO
- **Immer `IF NOT EXISTS` / `IF EXISTS` verwenden:**
```sql
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS email_verified BOOLEAN;
CREATE INDEX IF NOT EXISTS idx_profiles_email ON profiles(email);
```
- **Idempotente Migrationen schreiben:** Migration kann mehrfach ausgeführt werden ohne Fehler
- **Daten-Migrationen mit Bedacht:**
```sql
UPDATE profiles
SET email_verified = TRUE
WHERE email IS NOT NULL AND email_verified IS NULL;
```
- **Kommentare für Dokumentation:**
```sql
COMMENT ON COLUMN profiles.email_verified IS 'Whether email has been verified';
```
- **Indices für Performance:**
```sql
CREATE INDEX IF NOT EXISTS idx_profiles_verification_token
ON profiles(verification_token)
WHERE verification_token IS NOT NULL; -- Partial index
```
### ❌ DON'T
- **Keine psql Meta-Kommandos:**
```sql
\echo "Starting migration" -- ❌ Funktioniert nicht
SELECT 'Starting migration'; -- ✅ Funktioniert
```
- **Keine Breaking Changes ohne Staging:**
```sql
ALTER TABLE profiles DROP COLUMN tier; -- ❌ App wird brechen
```
- **Keine Hardcoded Values für produktive Daten:**
```sql
INSERT INTO profiles (id, email, ...) VALUES (1, 'admin@example.com', ...); -- ❌
```
- **Keine Foreign Keys ohne Fallback:**
```sql
-- ❌ Ohne ON DELETE Behavior
ALTER TABLE subscriptions
ADD CONSTRAINT fk_profile FOREIGN KEY (profile_id) REFERENCES profiles(id);
-- ✅ Mit Cascade
ALTER TABLE subscriptions
ADD CONSTRAINT fk_profile FOREIGN KEY (profile_id)
REFERENCES profiles(id) ON DELETE CASCADE;
```
## Troubleshooting
### Migration schlägt fehl
**Symptom:** Container startet nicht, Logs zeigen `✗ Failed to apply XXX.sql`
**Lösung:**
1. Logs prüfen: `docker logs dev-mitai-api | tail -50`
2. Fehlerhafte Migration identifizieren
3. Aus Tracking entfernen + Schema manuell korrigieren
4. Migration-Datei fixen
5. Container neu starten
### Migration wurde nicht angewendet
**Symptom:** Neue Migration-Datei wird ignoriert
**Ursachen:**
- Datei entspricht nicht dem Pattern `\d{3}_*.sql`
- Datei wurde bereits in `schema_migrations` getrackt
- Datei ist nicht im Container (`backend/migrations/` Volume gemountet?)
**Lösung:**
```bash
# Prüfen ob Datei gemountet ist
docker exec -it dev-mitai-api ls -la /app/migrations/
# Prüfen ob bereits getrackt
docker exec -it dev-mitai-db psql -U mitai_dev -d mitai_dev \
-c "SELECT * FROM schema_migrations WHERE filename = '004_feature.sql';"
# Falls fälschlich getrackt, entfernen
docker exec -it dev-mitai-db psql -U mitai_dev -d mitai_dev \
-c "DELETE FROM schema_migrations WHERE filename = '004_feature.sql';"
# Container neu starten
docker compose restart api
```
### Datenbank-Schema inkonsistent
**Symptom:** `schema_migrations` zeigt Migration als angewendet, aber Änderungen fehlen
**Ursachen:**
- Migration wurde manuell ausgeführt, aber Tracking war kaputt
- Datenbank wurde zurückgesetzt, aber Tracking-Tabelle nicht
**Lösung:**
```bash
# Schema neu aufbauen (ACHTUNG: Datenverlust!)
docker compose down -v # Löscht Volumes
docker compose up -d # Baut alles neu auf
# ODER: Tracking-Tabelle manuell korrigieren
docker exec -it dev-mitai-db psql -U mitai_dev -d mitai_dev \
-c "TRUNCATE schema_migrations; -- Alle Tracking-Einträge löschen"
# Container neu starten → Alle Migrationen werden erneut angewendet
docker compose restart api
```
## Migrations-Historie
| Nr. | Datei | Version | Datum | Beschreibung |
|-----|-------|---------|-------|--------------|
| 003 | `003_add_email_verification.sql` | v9c | 2026-03-21 | Email-Verifizierung (verification_token, email_verified, verification_expires) |
| 002 | `002_fix_features.sql` (manuell) | v9c | 2026-03-20 | Feature-System Fixes |
| 001 | `001_subscription_system.sql` (manuell) | v9c | 2026-03-20 | Membership-System (tiers, subscriptions, coupons, access_grants) |
**Hinweis:** Migrationen 001 und 002 wurden vor Einführung des automatischen Systems manuell angewendet und sind nicht nummeriert. Ab Migration 003 läuft alles automatisch.
---
## Referenzen
- **Code:** `backend/db_init.py` (Zeilen 94-200)
- **Migrations-Ordner:** `backend/migrations/`
- **Tracking-Tabelle:** `schema_migrations`
- **Startup-Script:** `backend/startup.sh` (ruft `db_init.py` auf)
- **Dokumentation:** `.claude/docs/technical/MIGRATIONS.md` (diese Datei)
---
**Dokumentiert:** 2026-03-21
**Letzte Änderung:** 2026-03-21

View File

@ -0,0 +1,799 @@
# Placeholder Development Guide
**Version:** 1.0
**Erstellt:** 28. März 2026
**Zielgruppe:** Entwickler, Claude Code
---
## Überblick
Dieses Dokument beschreibt, wie neue KI-Platzhalter hinzugefügt, getestet und dokumentiert werden.
**Wichtig für Phase 0c:** Nach dem Refactoring zu Multi-Layer Architecture nutzen alle Platzhalter das Data Layer. Dieser Guide beschreibt beide Architekturen.
---
## Phase 0b Architektur (Aktuell - bis Phase 0c)
### Anatomie eines Platzhalters
```python
# backend/placeholder_resolver.py
def resolve_weight_28d_trend_slope(profile_id: str) -> str:
"""
Returns kg/week slope for 28-day weight trend.
This function:
1. Retrieves data from database
2. Performs calculation
3. Formats result for KI consumption
Args:
profile_id: User profile ID
Returns:
Formatted string (e.g., "0.23 kg/Woche")
or "Nicht genug Daten" if insufficient data
"""
with get_db() as conn:
cur = get_cursor(conn)
# 1. DATA RETRIEVAL
cur.execute("""
SELECT date, weight
FROM weight_log
WHERE profile_id = %s
AND date >= NOW() - INTERVAL '28 days'
ORDER BY date
""", (profile_id,))
rows = cur.fetchall()
# 2. VALIDATION
if len(rows) < 18: # Confidence threshold
return "Nicht genug Daten"
# 3. CALCULATION
x = [(row[0] - rows[0][0]).days for row in rows]
y = [row[1] for row in rows]
# Linear regression
n = len(x)
sum_x = sum(x)
sum_y = sum(y)
sum_xy = sum(xi * yi for xi, yi in zip(x, y))
sum_x2 = sum(xi ** 2 for xi in x)
slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)
slope_per_week = slope * 7
# 4. FORMATTING
return f"{slope_per_week:.2f} kg/Woche"
```
### Schritte zum Hinzufügen eines neuen Platzhalters (Phase 0b)
#### 1. Funktion implementieren
**Datei:** `backend/placeholder_resolver.py`
**Namenskonvention:**
- `resolve_<placeholder_name>(profile_id: str) -> str`
- Snake_case
- Immer `profile_id` als Parameter
- Immer `str` als Return-Type
**Template:**
```python
def resolve_my_new_metric(profile_id: str) -> str:
"""
[Beschreibung was der Platzhalter zurückgibt]
Args:
profile_id: User profile ID
Returns:
[Beschreibung des Return-Formats]
"""
with get_db() as conn:
cur = get_cursor(conn)
# 1. DATA RETRIEVAL
cur.execute("""
SELECT ...
FROM ...
WHERE profile_id = %s
""", (profile_id,))
# 2. VALIDATION
if <insufficient_data_condition>:
return "Nicht genug Daten"
# 3. CALCULATION
result = ...
# 4. FORMATTING
return f"{result}"
```
#### 2. In Mapping registrieren
**Datei:** `backend/placeholder_resolver.py`
**Finde `PLACEHOLDER_FUNCTIONS` Dictionary:**
```python
PLACEHOLDER_FUNCTIONS = {
# ... existing placeholders ...
# Add your new placeholder:
"my_new_metric": resolve_my_new_metric,
}
```
**Naming:**
- Key = Platzhalter-Name (snake_case)
- Value = Funktions-Referenz (ohne Klammern!)
#### 3. In Katalog dokumentieren
**Datei:** `backend/placeholder_resolver.py`
**Finde `get_placeholder_catalog()` Funktion:**
```python
def get_placeholder_catalog(profile_id: str) -> Dict[str, List[Dict[str, str]]]:
placeholders = {
'Körper': [
# ... existing ...
('my_new_metric', 'Beschreibung des Platzhalters'),
],
# ...
}
```
**Kategorien:**
- `Profil`
- `Körper`
- `Ernährung`
- `Training`
- `Schlaf & Erholung`
- `Vitalwerte`
- `Scores (Phase 0b)`
- `Focus Areas`
- `Zeitraum`
#### 4. Testen
**Manueller Test:**
```python
# In Python REPL oder test script:
from placeholder_resolver import resolve_my_new_metric
result = resolve_my_new_metric("test_profile_id")
print(result) # Should return formatted string
```
**Integration Test:**
```python
# Test in actual prompt
from placeholder_resolver import resolve_placeholders
template = "Dein {{my_new_metric}} ist ..."
result = resolve_placeholders(template, "test_profile_id")
print(result) # Should have placeholder replaced
```
---
## Phase 0c Architektur (Nach Refactoring)
### Anatomie eines Platzhalters (3-Layer)
```python
# Layer 1: DATA LAYER
# backend/data_layer/body_metrics.py
def get_weight_trend_data(profile_id: str, days: int = 90) -> dict:
"""
Returns weight trend data with slopes and projections.
This is pure data retrieval and calculation.
NO FORMATTING. NO STRINGS.
Args:
profile_id: User profile ID
days: Analysis window
Returns:
{
"raw_values": [(date, weight), ...],
"rolling_median_7d": [(date, value), ...],
"slope_7d": float,
"slope_28d": float,
"slope_90d": float,
"confidence": str,
...
}
"""
with get_db() as conn:
cur = get_cursor(conn)
# DATA RETRIEVAL
cur.execute("""...""", (profile_id, days))
rows = cur.fetchall()
# VALIDATION + CONFIDENCE
from data_layer.utils import calculate_confidence
confidence = calculate_confidence(len(rows), days, "trend")
if confidence == 'insufficient':
return {
"confidence": "insufficient",
"slope_28d": 0.0,
# ... minimal data
}
# CALCULATION
# ... (same logic as before)
# RETURN STRUCTURED DATA (not formatted!)
return {
"raw_values": rows,
"slope_7d": slope_7d,
"slope_28d": slope_28d,
"confidence": confidence,
# ... all data as dict/list/float
}
# Layer 2a: KI LAYER
# backend/placeholder_resolver.py
from data_layer.body_metrics import get_weight_trend_data
def resolve_weight_28d_trend_slope(profile_id: str) -> str:
"""
Formats weight trend slope for KI consumption.
This function is now THIN - just calls data layer and formats.
"""
data = get_weight_trend_data(profile_id, days=28)
if data['confidence'] == 'insufficient':
return "Nicht genug Daten"
return f"{data['slope_28d']:.2f} kg/Woche"
```
### Schritte zum Hinzufügen eines neuen Platzhalters (Phase 0c)
#### 1. Data Layer Funktion implementieren
**Datei:** Passendes Modul in `backend/data_layer/`
- Body metrics → `body_metrics.py`
- Nutrition → `nutrition_metrics.py`
- Activity → `activity_metrics.py`
- Recovery → `recovery_metrics.py`
- Health → `health_metrics.py`
- Goals → `goals.py`
- Correlations → `correlations.py`
**Template:**
```python
# backend/data_layer/<module>.py
def get_<metric>_data(
profile_id: str,
days: int = 28,
**kwargs
) -> dict:
"""
[Beschreibung der Daten]
Args:
profile_id: User profile ID
days: Analysis window
**kwargs: Additional parameters
Returns:
{
"<field>": <value>,
"confidence": str, # ALWAYS include!
"data_points": int, # ALWAYS include!
}
"""
with get_db() as conn:
cur = get_cursor(conn)
# 1. DATA RETRIEVAL
cur.execute("""...""", (profile_id,))
rows = cur.fetchall()
# 2. CONFIDENCE CALCULATION
from data_layer.utils import calculate_confidence
confidence = calculate_confidence(
len(rows),
days,
"general" # or "correlation" or "trend"
)
# 3. VALIDATION
if confidence == 'insufficient':
return {
"confidence": "insufficient",
"data_points": len(rows),
# Return minimal safe data
}
# 4. CALCULATION
# ... your logic here ...
# 5. RETURN STRUCTURED DATA
return {
# All data as primitives: dict, list, float, int, str, bool
# NO FORMATTING (no "0.23 kg/Woche" - just 0.23)
"result": result_value,
"confidence": confidence,
"data_points": len(rows),
}
```
**WICHTIG:**
- ❌ Keine Strings mit Einheiten: `"0.23 kg/Woche"`
- ✅ Nur Zahlen: `0.23`
- ❌ Keine Formatierung für Menschen
- ✅ Strukturierte Daten für Maschinen
#### 2. KI Layer Wrapper erstellen
**Datei:** `backend/placeholder_resolver.py`
```python
from data_layer.<module> import get_<metric>_data
def resolve_<placeholder_name>(profile_id: str) -> str:
"""
[Beschreibung was zurückgegeben wird]
Phase 0c: Uses data_layer.<module>.get_<metric>_data()
"""
data = get_<metric>_data(profile_id)
if data['confidence'] == 'insufficient':
return "Nicht genug Daten"
# FORMAT for KI consumption
return f"{data['<field>']:.2f} <unit>"
```
#### 3. In Mapping registrieren
**UNVERÄNDERT - gleich wie Phase 0b:**
```python
PLACEHOLDER_FUNCTIONS = {
"my_new_metric": resolve_my_new_metric,
}
```
#### 4. In Katalog dokumentieren
**UNVERÄNDERT - gleich wie Phase 0b:**
```python
def get_placeholder_catalog(profile_id: str):
placeholders = {
'Körper': [
('my_new_metric', 'Beschreibung'),
],
}
```
#### 5. Testen
**Unit Test für Data Layer:**
```python
# backend/tests/test_data_layer.py
def test_get_metric_data_sufficient():
data = get_<metric>_data("test_profile_1", days=28)
assert data['confidence'] in ['high', 'medium', 'low', 'insufficient']
assert 'data_points' in data
assert isinstance(data['<field>'], float)
def test_get_metric_data_insufficient():
data = get_<metric>_data("profile_no_data", days=28)
assert data['confidence'] == 'insufficient'
```
**Integration Test für KI Layer:**
```python
# backend/tests/test_placeholders.py
def test_resolve_placeholder():
result = resolve_<placeholder_name>("test_profile_1")
assert isinstance(result, str)
assert result != "Nicht genug Daten"
```
---
## Best Practices
### 1. Confidence Scoring
**IMMER `calculate_confidence()` verwenden:**
```python
from data_layer.utils import calculate_confidence
confidence = calculate_confidence(
data_points=len(rows),
days_requested=days,
metric_type="general" # or "correlation" or "trend"
)
```
**Confidence Thresholds:**
- General (28d): high >= 18, medium >= 12, low >= 8
- Correlation: high >= 28, medium >= 21, low >= 14
- Trend: high >= (days * 0.7), medium >= (days * 0.5)
### 2. Decimal → Float Conversion
**PostgreSQL gibt Decimal zurück - immer zu float konvertieren:**
```python
# ❌ WRONG:
value = row['column']
# ✅ CORRECT:
value = float(row['column']) if row['column'] else 0.0
```
### 3. Safe Dict Access
**Nie direkter Key-Zugriff ohne Fallback:**
```python
# ❌ WRONG:
value = data['key'] # KeyError if missing
# ✅ CORRECT:
value = data.get('key', default_value)
```
### 4. Date Serialization
**Python date objects sind nicht JSON-serializable:**
```python
from data_layer.utils import serialize_dates
data = {
"date": date(2026, 3, 28),
"values": [...]
}
# Serialize before returning from API
return serialize_dates(data)
```
### 5. SQL Parameter Binding
**IMMER Parameter-Binding, NIE String-Concatenation:**
```python
# ✅ CORRECT:
cur.execute("SELECT * FROM t WHERE id = %s", (id,))
# ❌ WRONG (SQL Injection Risk):
cur.execute(f"SELECT * FROM t WHERE id = {id}")
```
### 6. Column Name Consistency
**Prüfe Schema BEVOR du Column-Namen verwendest:**
```python
# ❌ WRONG (assumed name):
SELECT bf_jpl FROM caliper_log
# ✅ CORRECT (check schema first):
SELECT body_fat_pct FROM caliper_log
```
**Schema prüfen:**
```sql
\d caliper_log -- in psql
-- oder
SELECT column_name FROM information_schema.columns
WHERE table_name = 'caliper_log';
```
---
## Fehler-Handling
### 1. Insufficient Data
**Return-Value bei zu wenig Daten:**
```python
# Data Layer:
return {
"confidence": "insufficient",
"data_points": 0,
# Alle anderen Felder mit safe defaults (0.0, [], etc.)
}
# KI Layer:
if data['confidence'] == 'insufficient':
return "Nicht genug Daten"
```
### 2. Missing Optional Data
**Wenn optionale Daten fehlen (z.B. keine Vitals):**
```python
# Data Layer:
return {
"hrv": None, # or 0.0, depending on semantic
"confidence": "low", # downgrade confidence
}
# KI Layer:
if data['hrv'] is None:
return "Keine HRV-Daten verfügbar"
```
### 3. Calculation Errors
**Bei Math-Errors (Division by Zero, etc.):**
```python
try:
result = numerator / denominator
except ZeroDivisionError:
result = 0.0 # or None, depending on semantic
```
---
## Dokumentations-Pflicht
### 1. Docstring
**Jede Funktion braucht Docstring:**
```python
def get_metric_data(profile_id: str, days: int = 28) -> dict:
"""
[Eine Zeile Zusammenfassung]
[Ausführliche Beschreibung wenn nötig]
Args:
profile_id: User profile ID
days: Analysis window (default 28)
Returns:
{
"field": value,
"confidence": str,
"data_points": int
}
Confidence Rules:
- high: >= X points
- medium: >= Y points
- low: >= Z points
- insufficient: < Z points
"""
```
### 2. Inline Comments
**Nur bei nicht-offensichtlicher Logik:**
```python
# Calculate trimmed mean (remove top/bottom 10%)
sorted_values = sorted(values)
trim_count = len(values) // 10
trimmed = sorted_values[trim_count:-trim_count]
result = sum(trimmed) / len(trimmed)
```
### 3. Type Hints
**IMMER Type Hints verwenden:**
```python
from typing import Optional, List, Dict, Tuple
def get_data(
profile_id: str,
days: int = 28,
include_raw: bool = False
) -> Dict[str, any]:
...
```
---
## Testing-Strategie
### 1. Unit Tests (Data Layer)
**Teste jede Data Layer Funktion isoliert:**
```python
# backend/tests/test_data_layer.py
import pytest
from data_layer.body_metrics import get_weight_trend_data
@pytest.fixture
def test_profile():
# Setup test data in database
...
yield profile_id
# Teardown
...
def test_weight_trend_sufficient_data(test_profile):
data = get_weight_trend_data(test_profile, days=28)
assert data['confidence'] in ['high', 'medium']
assert data['slope_28d'] != 0.0
assert len(data['raw_values']) >= 18
def test_weight_trend_insufficient_data():
data = get_weight_trend_data("no_data_profile", days=28)
assert data['confidence'] == 'insufficient'
```
### 2. Integration Tests (KI Layer)
**Teste Placeholder-Resolution:**
```python
# backend/tests/test_placeholders.py
def test_placeholder_resolution(test_profile):
result = resolve_weight_28d_trend_slope(test_profile)
assert isinstance(result, str)
assert "kg/Woche" in result or "Nicht genug Daten" in result
def test_placeholder_in_template(test_profile):
template = "Trend: {{weight_28d_trend_slope}}"
result = resolve_placeholders(template, test_profile)
assert "{{" not in result # All placeholders resolved
assert result.startswith("Trend:")
```
### 3. Manual Testing Checklist
```
[ ] Funktion mit verschiedenen days-Parametern testen
[ ] Mit vollständigen Daten testen
[ ] Mit unvollständigen Daten testen
[ ] Mit NO DATA testen
[ ] Edge Cases: Extreme Werte, Outliers
[ ] Performance: < 500ms für typische Queries
[ ] Memory: Kein Leak bei großen Datasets
```
---
## Checkliste: Neuer Platzhalter
### Phase 0b (Aktuell):
```
[ ] Funktion in placeholder_resolver.py implementiert
[ ] resolve_<name>(profile_id: str) -> str Signatur
[ ] Docstring vollständig
[ ] Confidence-Check implementiert
[ ] In PLACEHOLDER_FUNCTIONS registriert
[ ] In get_placeholder_catalog() dokumentiert
[ ] Manuell getestet
[ ] In echtem Prompt getestet
```
### Phase 0c (Nach Refactoring):
```
[ ] Data Layer Funktion implementiert
[ ] Richtiges Modul gewählt
[ ] get_<metric>_data(profile_id, ...) -> dict Signatur
[ ] Returns structured data (dict/list/primitives)
[ ] NO formatting, NO strings with units
[ ] Confidence calculation included
[ ] Docstring vollständig
[ ] KI Layer Wrapper implementiert
[ ] resolve_<name>(profile_id: str) -> str Signatur
[ ] Calls data_layer function
[ ] Formats result for KI
[ ] In PLACEHOLDER_FUNCTIONS registriert
[ ] In get_placeholder_catalog() dokumentiert
[ ] Unit Test für Data Layer geschrieben
[ ] Integration Test für KI Layer geschrieben
[ ] Manual Testing durchgeführt
```
---
## Häufige Fehler (Learnings from Phase 0b)
### 1. Vergessen float() Conversion
```python
# SYMPTOM: "Object of type Decimal is not JSON serializable"
# FIX:
value = float(row['column']) if row['column'] else 0.0
```
### 2. Hardcoded Column Names
```python
# SYMPTOM: "column bf_jpl does not exist"
# FIX: Check schema first
SELECT column_name FROM information_schema.columns
WHERE table_name = 'caliper_log';
```
### 3. KeyError bei fehlenden Daten
```python
# SYMPTOM: "KeyError: 'hrv'"
# FIX: Use .get() with default
hrv = data.get('hrv', 0.0)
```
### 4. Confidence nicht berechnet
```python
# SYMPTOM: Platzhalter liefert Daten bei <3 Punkten
# FIX: calculate_confidence() verwenden
from data_layer.utils import calculate_confidence
confidence = calculate_confidence(len(rows), days, "general")
```
### 5. Date nicht serialized
```python
# SYMPTOM: "Object of type date is not JSON serializable"
# FIX:
from data_layer.utils import serialize_dates
return serialize_dates(data)
```
### 6. SQL Injection Risk
```python
# SYMPTOM: Security Scanner warnt
# FIX: ALWAYS use parameter binding
cur.execute("SELECT * FROM t WHERE id = %s", (id,))
```
---
## Nächste Schritte
### Nach Implementierung eines neuen Platzhalters:
1. **Commit Message:**
```
feat: add {{my_new_metric}} placeholder
- Implements resolve_my_new_metric() in placeholder_resolver.py
- Adds entry to PLACEHOLDER_FUNCTIONS
- Documents in get_placeholder_catalog()
- Tested with profile XYZ
Category: <Körper/Ernährung/Training/etc.>
Returns: <description>
```
2. **Dokumentation aktualisieren:**
- `CLAUDE.md` - Neue Platzhalter auflisten
- `docs/api/PLACEHOLDERS.md` - API-Dokumentation
3. **Testing:**
- Mindestens 1 manueller Test mit echtem Profil
- Optional: Unit Test hinzufügen
4. **Review:**
- Prüfe ob Platzhalter in Prompt-Bibliothek sinnvoll
- Teste mit verschiedenen Prompts
- Performance-Check (< 500ms)
---
**Autor:** Claude Sonnet 4.5
**Version:** 1.0
**Letzte Aktualisierung:** 28. März 2026

View File

@ -0,0 +1,498 @@
# Placeholder Registry Framework - Verbindliche Dokumentation
**Status:** VERBINDLICH (ab 2026-04-02)
**Version:** 1.0
**Geltungsbereich:** Alle Placeholder/Metrics im System
---
## 1. Zweck
Das **Placeholder Registry Framework** ist die zentrale, verbindliche Metadaten-Verwaltung für alle Placeholder und Metrics im System.
**Kernprinzip:** Single Source of Truth
**Ziele:**
1. Einheitliche Metadaten-Struktur für alle Placeholder
2. Vermeidung von Duplikation und Inkonsistenzen
3. Zentrale Verwaltung für alle Konsumenten
4. Evidence-basierte Transparenz
5. Erweiterbarkeit und Wartbarkeit
---
## 2. Verbindlichkeit
### 2.1 Pflicht zur Nutzung
**ALLE neuen Placeholder/Metrics MÜSSEN über das Registry Framework registriert werden.**
Keine Ausnahmen ohne explizite technische Begründung und Freigabe.
### 2.2 Betroffene Systeme
Folgende Systeme MÜSSEN die Registry als Single Source of Truth nutzen:
1. **Backend Prompt-Injektion** (Layer 2a)
- Placeholder-Resolver
- Prompt-Template-Engine
2. **GUI Auswahllisten**
- Placeholder-Picker
- Kategorie-Filter
- Metadata-Anzeige
3. **Extended Export**
- `/api/prompts/placeholders/export-values-extended`
- Catalog-Generierung
- ZIP-Export
4. **Validierung** (zukünftig)
- Metadata-Completeness-Checks
- Evidence-Quality-Assurance
- Compliance-Reports
5. **Diagramm-Zuordnung** (zukünftig)
- Chart-Metadata-Mapping
- Layer-2b-Integration
### 2.3 Verbotene Praktiken
**VERBOTEN:**
- Hardcoded Metadaten außerhalb der Registry
- Duplizierte Metadaten-Definitionen
- Placeholder ohne Registry-Registrierung
- Direkte Manipulation von Metadaten im Export-Code
- Inkonsistente Metadaten zwischen Systemen
---
## 3. Framework-Architektur
### 3.1 Kernkomponenten
**Modul:** `backend/placeholder_registry.py`
**Klassen:**
- `PlaceholderMetadata` - Metadata-Dataclass (22 Pflichtfelder)
- `MissingValuePolicy` - Strukturierte Missing-Value-Behandlung
- `PlaceholderRegistry` - Zentrale Registry (Singleton)
- `EvidenceType` - Enum für Evidenz-Tagging
- `OutputType` - Enum für Output-Typen
- `PlaceholderType` - Enum für Placeholder-Typen
**Singleton-Instanz:**
```python
from placeholder_registry import get_registry
registry = get_registry()
```
### 3.2 Registrierungs-Package
**Package:** `backend/placeholder_registrations/`
**Struktur:** Vollständige Cluster-Module (u. a. Ernährung, Körper, Aktivität, Schlaf,
Vitalwerte, Profil/Zeitraum, Phase-0b-Ziele, Korrelationen); siehe `__init__.py` für die
Import-Liste. **Anzahl:** 114 Platzhalter, identisch zu `PLACEHOLDER_MAP` in
`placeholder_resolver.py`.
**Auto-Registration:**
- Import des Package triggert automatische Registrierung aller Placeholder
- Keine manuelle Registrierung erforderlich
### 3.3 Export-Integration
**Modul:** `backend/placeholder_registry_export.py`
**Funktionen:**
- `get_registry_metadata_for_export()` - Metadata aus Registry
- `merge_registry_with_legacy_export()` - Backward-Compatibility
- `get_enhanced_export_with_registry()` - Vollständiger Export
**Endpoint-Integration:**
```python
# backend/routers/prompts.py
import placeholder_registrations # Auto-registers
from placeholder_registry_export import get_registry_metadata_for_export
registry_data = get_registry_metadata_for_export(profile_id)
export_data['registry_metadata'] = registry_data
```
---
## 4. Metadata-Schema
### 4.1 Pflichtfelder (22 Felder)
**Core Identification (3):**
- `key` - Placeholder-Schlüssel (z.B. "kcal_avg")
- `category` - Kategorie (z.B. "Ernährung")
- `description` - Kurzbeschreibung
**Technical (6):**
- `resolver_module` - Modul-Pfad des Resolvers
- `resolver_function` - Funktionsname des Resolvers
- `data_layer_module` - Data Layer Modul (optional)
- `data_layer_function` - Data Layer Funktion (optional)
- `source_tables` - Liste der Quelltabellen
- `_resolver_func` - Runtime-Resolver (nicht exportiert)
**Semantic (8):**
- `semantic_contract` - Semantische Definition
- `business_meaning` - Fachliche Bedeutung
- `unit` - Einheit (z.B. "kcal/day")
- `time_window` - Zeitfenster (z.B. "30d")
- `output_type` - Output-Typ (Enum)
- `placeholder_type` - Placeholder-Typ (Enum)
- `format_hint` - Format-Information
- `example_output` - Beispiel-Ausgabe
**Quality (5):**
- `minimum_data_requirements` - Mindestanforderungen (optional)
- `quality_filter_policy` - Qualitätsfilter (optional)
- `confidence_logic` - Confidence-Berechnung (optional)
- `missing_value_policy` - Missing-Value-Handling
- `known_limitations` - Bekannte Einschränkungen (optional)
**Architecture (5):**
- `layer_1_decision` - Layer-1-Zuordnung (optional)
- `layer_2a_decision` - Layer-2a-Zuordnung (optional)
- `layer_2b_reuse_possible` - Chart-Reuse möglich (optional)
- `architecture_alignment` - Architektur-Konformität (optional)
- `issue_53_alignment` - Issue #53 Konformität (optional)
**Evidence Tracking (1):**
- `evidence` - Dict mapping Feldname → EvidenceType
### 4.2 Evidence-Typen
**Enum:** `EvidenceType`
**Werte:**
- `CODE_DERIVED` - Aus Code belegt (z.B. aus Import-Statement, SQL-Query)
- `DRAFT_DERIVED` - Aus Canonical Requirements Draft übernommen
- `MIXED` - Teilweise Code, teilweise Draft/abgeleitet
- `UNRESOLVED` - Nicht explizit dokumentiert, offen
- `TO_VERIFY` - Behauptung, muss noch verifiziert werden
**Verwendung:**
```python
metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
metadata.set_evidence("semantic_contract", EvidenceType.DRAFT_DERIVED)
metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.TO_VERIFY)
```
---
## 5. Registrierungs-Workflow
### 5.1 Neuen Placeholder registrieren
**Schritt 1: Metadata-Objekt erstellen**
```python
# backend/placeholder_registrations/my_cluster.py
from placeholder_registry import (
PlaceholderMetadata,
MissingValuePolicy,
EvidenceType,
OutputType,
PlaceholderType,
register_placeholder
)
metadata = PlaceholderMetadata(
key="my_placeholder",
category="Meine Kategorie",
description="Kurzbeschreibung",
# Technical (CODE_DERIVED)
resolver_module="backend/placeholder_resolver.py",
resolver_function="get_my_placeholder",
data_layer_module="backend/data_layer/my_metrics.py",
data_layer_function="get_my_data",
source_tables=["my_table"],
# Semantic
semantic_contract="Was liefert dieser Placeholder?",
business_meaning="Fachliche Bedeutung",
unit="einheit",
time_window="30d",
output_type=OutputType.NUMERIC,
placeholder_type=PlaceholderType.INTERPRETED,
format_hint="Ganzzahl",
example_output="42",
# Quality
confidence_logic="Wie wird Verlässlichkeit berechnet?",
missing_value_policy=MissingValuePolicy(
available=False,
value_raw=None,
missing_reason="insufficient_data",
legacy_display="nicht genug Daten"
),
known_limitations="Einschränkungen dokumentieren",
# Architecture
layer_1_decision="Data Layer (my_metrics.get_my_data)",
layer_2a_decision="Placeholder Resolver (formatting only)",
architecture_alignment="Phase 0c conform"
)
```
**Schritt 2: Evidence setzen**
```python
# Code-derived Felder
metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED)
metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED)
metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED)
metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED)
# Draft-derived Felder
metadata.set_evidence("semantic_contract", EvidenceType.DRAFT_DERIVED)
metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
metadata.set_evidence("known_limitations", EvidenceType.DRAFT_DERIVED)
# Unresolved Felder
metadata.set_evidence("minimum_data_requirements", EvidenceType.UNRESOLVED)
```
**Schritt 3: Registrieren**
```python
register_placeholder(metadata)
```
**Schritt 4: Auto-Import sicherstellen**
```python
# backend/placeholder_registrations/__init__.py
from . import my_cluster
__all__ = ['nutrition_part_a', 'my_cluster']
```
### 5.2 Resolver-Funktion bereitstellen (optional)
Wenn der Placeholder runtime-resolved werden soll:
```python
from placeholder_resolver import get_my_placeholder
register_placeholder(
metadata,
resolver_func=lambda pid: get_my_placeholder(pid)
)
```
---
## 6. API-Nutzung
### 6.1 Metadata abrufen
```python
from placeholder_registry import get_registry
registry = get_registry()
# Einzelner Placeholder
meta = registry.get("kcal_avg")
print(meta.unit) # "kcal/day"
print(meta.time_window) # "30d"
# Alle Placeholder
all_metadata = registry.get_all() # Dict[str, PlaceholderMetadata]
# Nach Kategorie
ernaehrung = registry.get_by_category("Ernährung") # List[PlaceholderMetadata]
```
### 6.2 Export
```python
# Für Extended Export
export_data = registry.get_all_for_export() # List[Dict]
# Mit Runtime-Werten
from placeholder_registry_export import get_registry_metadata_for_export
registry_data = get_registry_metadata_for_export(profile_id)
# Returns: {flat, by_category, evidence_report, validation_report}
```
### 6.3 Validierung
```python
# Alle Placeholder validieren
issues = registry.validate_all() # Dict[str, List[str]]
if issues:
for key, problems in issues.items():
print(f"{key}: {problems}")
```
### 6.4 QA / Evidence-Tracking
```python
# Placeholder mit unresolved Fields finden
unresolved = registry.get_by_evidence_type(EvidenceType.UNRESOLVED)
# Returns: Dict[placeholder_key, List[field_names]]
# Placeholder die verifiziert werden müssen
to_verify = registry.get_by_evidence_type(EvidenceType.TO_VERIFY)
```
---
## 7. Best Practices
### 7.1 Evidence-Tagging
**DO:**
- Jedes Feld mit Evidence-Tag versehen
- `CODE_DERIVED` nur wenn direkt aus Code ableitbar
- `TO_VERIFY` für Behauptungen, die noch geprüft werden müssen
- `UNRESOLVED` für fehlende/unklare Informationen
**DON'T:**
- Felder ohne Evidence lassen
- Evidence halluzinieren (wenn nicht belegt, `UNRESOLVED` nutzen)
- `CODE_DERIVED` für Draft-Informationen nutzen
### 7.2 Metadata-Vollständigkeit
**Minimum Required:**
- `key`, `category`, `description`
- `resolver_module`, `resolver_function`
- `semantic_contract`
- `unit`, `time_window`
- `output_type`, `placeholder_type`
**Optional but Recommended:**
- `data_layer_module`, `data_layer_function`
- `source_tables`
- `confidence_logic`, `missing_value_policy`
- `layer_1_decision`, `layer_2a_decision`
### 7.3 Modularisierung
**Registrations nach Cluster gruppieren:**
- `nutrition_part_a.py` - Nutrition Basis (4 Placeholder)
- `nutrition_part_b.py` - Nutrition Protein (5 Placeholder)
- `body_metrics.py` - Körper-Metriken (N Placeholder)
**Nicht:**
- Alle Placeholder in eine riesige Datei
- Placeholder ohne thematische Gruppierung
### 7.4 Backward-Compatibility
**Export-Endpoint MUSS:**
- Legacy-Export beibehalten (`export_data['legacy']`)
- Graceful degradation bei Registry-Fehler
- Registry-Metadata als separate Sektion (`export_data['registry_metadata']`)
---
## 8. Migration bestehender Placeholder
### 8.1 Priorität
**Part A (erledigt):** Nutrition Basis (kcal_avg, protein_avg, carb_avg, fat_avg)
**Nächste Priorität:**
1. Part B - Nutrition Protein (5 Placeholder)
2. Part C - Nutrition Balance (4 Placeholder)
3. Part D - Nutrition Meta (1 Placeholder)
4. Body Metrics (ca. 15 Placeholder)
5. Activity Metrics (ca. 20 Placeholder)
### 8.2 Migration-Workflow
**Für jeden Placeholder:**
1. Code inspizieren (Resolver, Data Layer, SQL)
2. Evidence ableiten (was ist code-derived, was draft-derived?)
3. Metadata-Objekt erstellen
4. Registrieren
5. Export testen
6. Werte-Identität bestätigen
**Keine Logikänderung während Migration!**
---
## 9. Compliance & Enforcement
### 9.1 Code-Review-Checkliste
**Für neue Placeholder:**
- [ ] Registry-Registrierung vorhanden?
- [ ] Evidence-Tags gesetzt?
- [ ] Metadata-Vollständigkeit (minimum required)?
- [ ] Auto-Import in `__init__.py`?
- [ ] Export getestet?
### 9.2 CI/CD-Integration (zukünftig)
**Geplante Checks:**
- Alle Placeholder in PLACEHOLDER_MAP sind in Registry registriert
- Keine Placeholder ohne Evidence-Tags
- Keine doppelten Registrierungen
- Metadata-Vollständigkeit für production-ready Placeholder
---
## 10. Support & Weiterentwicklung
### 10.1 Fragen & Issues
**Bei Unklarheiten:**
1. Diese Dokumentation prüfen
2. Bestehende Registrations als Vorlage nutzen (`nutrition_part_a.py`)
3. Code-Review anfragen
### 10.2 Framework-Erweiterungen
**Geplante Features:**
- GUI-Integration (Placeholder-Picker mit Registry-Metadata)
- Validation-Dashboard (QA-Monitoring)
- Evidence-Report-Endpoint (Metadata-Qualität)
- Resolver-Test-Framework (Automatisierte Werteänderungs-Detektion)
- Chart-Metadata-Mapping (Layer-2b-Integration)
### 10.3 Versions-History
**v1.0 (2026-04-02):**
- Initial Release
- Part A Implementation (4 Nutrition Placeholders)
- Core Framework + Export-Integration
---
## 11. Referenzen
**Code:**
- `backend/placeholder_registry.py` - Core Framework
- `backend/placeholder_registrations/nutrition_part_a.py` - Part A Implementation
- `backend/placeholder_registry_export.py` - Export-Integration
- `backend/routers/prompts.py` - Export-Endpoint
**Dokumentation:**
- `.claude/task/rework_0b_placeholder/NUTRITION_PART_A_CHANGE_PLAN.md`
- `.claude/task/rework_0b_placeholder/NUTRITION_PART_A_IMPLEMENTATION_REPORT.md`
**Beispiel-Export:**
```bash
curl "https://dev.mitai.jinkendo.de/api/prompts/placeholders/export-values-extended?token=XXX"
```
---
**Ende Verbindliche Dokumentation**

View File

@ -0,0 +1,53 @@
# Persönliche Referenzwerte (Profil)
## Überblick
Nutzer-spezifische, **historische** Kennwerte (z. B. HF-Schwellen, Trainingshäufigkeit), die **nicht** zur Admin-/Focus-Area-Konfiguration gehören, sondern zum **aktiven Profil** wie Größe oder Ziele.
## Tabellen
| Tabelle | Zweck |
|--------|--------|
| `reference_value_types` | System-seedete Typdefinitionen: stabiler `key`, Anzeige-`label`, optional `default_unit`, `sort_order`, `active`, `metadata` (JSONB). |
| `profile_reference_values` | Historische Einträge: `profile_id`, `reference_value_type_id`, `effective_date`, `value_numeric` und/oder `value_text`, `unit`, optionale Felder `source`, `confidence`, `method`, `notes`, `extra` (JSONB). |
**Kein** Überschreiben eines einzelnen „aktuellen“ Werts: jede Messung ist eine eigene Zeile.
## Seed-Typen (Migration 037)
- `max_heart_rate` (bpm)
- `resting_heart_rate` (bpm)
- `anaerobic_threshold_hr` (bpm)
- `aerobic_threshold_hr` (bpm)
- `training_frequency_weekly` (Sessions/Woche)
- `fitness_level` (Stufe)
Es werden **keine** Benutzerwerte automatisch angelegt.
## Admin (nur Rolle `admin`)
- `GET/POST/PUT/DELETE /api/admin/reference-value-types` — vollständiger CRUD auf `reference_value_types` (inkl. inaktiver Typen).
- Löschen nur, wenn keine Zeilen in `profile_reference_values` zu diesem Typ existieren (sonst HTTP 409).
- UI: **Admin → Ziele & Fokus → Referenz-Kennwerte** (`/admin/reference-value-types`).
## API (Prefix `/api`)
- `GET /reference-value-types` — aktive Typen (dynamische UI)
- `GET /profile-reference-values?type_key=…` — Liste pro Typ, neueste zuerst
- `POST /profile-reference-values` — neuer Eintrag
- `PUT /profile-reference-values/{id}` — Aktualisierung
- `DELETE /profile-reference-values/{id}` — Löschen
Authentifizierung wie üblich; Profil über `X-Profile-Id` / `get_pid` wie andere Module.
## UI
**Einstellungen → Karte „Referenzwerte“ → „Referenzwerte verwalten“** (`/settings/reference-values`).
Typauswahl per Dropdown (aus API); Verlauf als Tabelle mit Bearbeiten/Löschen; Formular für neue Einträge bzw. Bearbeitung.
## Erweiterbarkeit
- Neue Messgrößen: nur **INSERT** in `reference_value_types` (Migration oder Admin-Skript), kein Schema-Wechsel für Nutzerdaten.
- Zusatzmetadaten: Spalten `source`, `confidence`, `method`, `notes`, `extra` bereits vorhanden; UI kann später erweitert werden.
- Platzierung **profilorientiert**, damit klar ist: Nutzerdaten, keine systemweite Semantik wie Focus Areas.

View File

@ -0,0 +1,56 @@
# Berichtsprofile & PDF (technisch)
**Stand:** 2026-04-29
## Begriffe
| Begriff | Bedeutung |
|--------|-----------|
| **Layout-Snapshot** | PDF aus gerasteter DOM-Übersicht (`html2canvas` + `jspdf`), optional Widget `report_export`. |
| **Strukturierter Bericht** | Profil mit Blöcken (`section`, `chart`, `ai_insight`), PDF serverseitig via Data Layer + Matplotlib + ReportLab. |
Die beiden Wege sind bewusst getrennt, damit das Dashboard nicht die einzige „Wahrheit“ für Dokumente wird.
## Datenbank
- Tabelle `report_profiles` (Migration `060_report_profiles.sql`): `profile_id` PK → `profiles`, `payload` JSONB, `updated_at`.
Ohne Zeile gilt ein **Code-Standard** (`default_report_profile_dict` in `report_profile_schema.py`).
## API (`/api/reports`)
| Methode | Pfad | Zweck |
|--------|------|--------|
| GET | `/catalog` | Diagramm-Katalog + Blocktypen für UI |
| GET | `/profile` | `{ stored, profile }` |
| PUT | `/profile` | Vollständiges Profil-JSON (Pydantic-validiert) |
| DELETE | `/profile` | DB-Zeile löschen → wieder Standard |
| POST | `/generate-pdf` | PDF-Download; `data_export`-Kontingent + `increment_feature_usage` |
## Schema v1 (`report_profile_schema.py`)
- `version`: nur `1`
- `document_title`: optional
- `blocks`: Liste mit Union:
- `section`: `title`
- `chart`: `chart_id``ALLOWED_CHART_IDS`, `window_days` 7365
- `ai_insight`: optional `insight_id` (UUID, `ai_insights.id`), optional `title`
## Diagrammdaten
`report_chart_fetch.fetch_chart_payload` ruft dieselben Bausteine auf wie `/api/charts` (ohne HTTP). Erweiterung: Eintrag in `ALLOWED_CHART_IDS`, Fetcher in `_CHART_FETCHERS`, Zeile in `CHART_CATALOG_FOR_API`.
## PDF-Rendering
`report_pdf_render.build_structured_report_pdf`: ReportLab-Flowable-Kette, Diagramme als PNG aus Chart-Payload (Matplotlib, Agg-Backend).
## Frontend
- **Einstellungen:** Karte „PDF-Bericht (strukturiert)“ — Blöcke bearbeiten, speichern, Standard, PDF erzeugen.
- **Dashboard:** Widget bleibt optionaler **Schnappschuss**; Hinweis verweist auf Einstellungen.
## Nächste sinnvolle Erweiterungen
- Dashboard-Layout → Berichtsprofil **einmalig importieren** (Mapping-Tabelle Widget-ID → chart_id).
- KI: Insights-Auswahl in der UI statt manueller UUID.
- Weitere `chart_id`-Werte / multipage Feintuning (Seitenumbrüche pro Block).

View File

@ -0,0 +1,148 @@
# Training Profile Resolver (Layer 1) — technisches Scaffold
**Stand:** 2026-04-06
**Zweck:** Erweiterbare technische Basis für spätere trainingsprofil-basierte Auswertungen, ohne freie Formel-/Skript-Engine und ohne Kopplung an KI oder Charts.
---
## 1. Einordnung in Layer 1
| Aspekt | Beschreibung |
|--------|----------------|
| Ort | `backend/data_layer/training_profile/` |
| Rolle | Reine Orchestrierung: Templates → registrierte Built-in-Algorithmen → strukturiertes Ergebnis inkl. Focus-Area-Beiträge |
| Single Source of Truth | Berechnungslogik der Algorithmen lebt in Python-Modulen; Templates wählen nur **Algorithmus-ID + Parameter + Dimensionen + FA-Mapping** |
| Rückwärtskompatibel | Keine Änderungen an bestehenden Data-Layer-Metriken, Placeholdern oder Chart-Routern |
---
## 2. Modulübersicht
| Pfad | Inhalt |
|------|--------|
| `models.py` | `CalculationTemplate`, `DimensionSpec`, `FocusAreaMapping`, `TrainingBaseProfile`, `TrainingEvaluationResult`, `AlgorithmRunResult` |
| `resolver.py` | `resolve_training_evaluation()`, `resolve_for_base_profile()` |
| `algorithms/registry.py` | `register_algorithm`, `get_algorithm`, `list_algorithm_ids` |
| `algorithms/builtin/threshold_band.py` | Beispiel: Schwellen-Bänder → Score 01 |
| `algorithms/builtin/linear_range.py` | Beispiel: lineare Abbildung [min,max] → [0,1] |
| `templates/registry.py` | Beispiel-Templates (deklarativ, in-code) |
| `profiles/registry.py` | Beispiel-Trainings-Basisprofile (Default-Template, optionale Dimensions-Whitelist) |
---
## 3. Built-in-Algorithmen
- Algorithmen sind **fest im Code** implementiert und über eine **ID** referenzierbar.
- Neue Algorithmen: Funktion mit Signatur `(*, inputs, params) -> AlgorithmRunResult` und `register_algorithm(id, fn)` (Start-up-Registrierung in `registry.py` oder Import eines Moduls, das registriert).
- **Nicht** vorgesehen: Nutzerdefinierte Ausdrücke, DSL, `eval`, externe Skripte.
Implementiert (Beispiele):
- `threshold_band``params.value_key`, `params.bands` (Liste mit `max` / `score`)
- `linear_range``params.value_key`, `min_value`, `max_value`, optional `invert`
---
## 4. Templates (deklarativ)
Ein `CalculationTemplate` besteht aus:
- `id`, `version`, `label`
- `dimensions`: Liste von `DimensionSpec` mit:
- `key` — Dimensionsname
- `algorithm_id` — referenziert registrierten Algorithmus
- `inputs` — erwartete Schlüssel im flachen `activity_inputs`-Dict des Aufrufers
- `params` — JSON-serialisierbare Parameter für den Algorithmus
- `maps_to` — Tupel `(focus_area_key, weight)` — gewichteter Anteil der **normalisierten** Dimension am jeweiligen Focus Area
Aggregation: Pro Dimension wird `normalized_score * weight` pro Focus Area addiert (`focus_area_contributions`).
---
## 5. Trainings-Basisprofile (Scaffold)
`TrainingBaseProfile`:
- `key`, `label`
- `default_template_id` — verweist auf ein `CalculationTemplate`
- optional `allowed_dimension_keys` — nur diese Dimensionen aus dem Template werden ausgeführt (Filter)
Aktuell **nur In-Code-Registry**; später denkbar: DB-Verknüpfung Trainingstyp → Profil-Key.
---
## 6. Ergebnisstruktur (`TrainingEvaluationResult`)
- `template_id`, `template_version`, `base_profile_key`
- `dimension_results[]` — pro Dimension: Scores, fehlende Inputs, Evidence
- `focus_area_contributions``dict[str, float]` (Focus-Area-Key → aggregierter Beitrag)
- `confidence``high` | `medium` | `low` | `insufficient` (heuristisch aus fehlenden Pflicht-Inputs)
- `evidence` — Metadaten (z. B. Anzahl Dimensionen, Input-Keys)
- optional `trace` — bei `include_trace=True` für Debugging
`to_serializable()` liefert ein JSON-taugliches Dict für APIs/Persistenz.
---
## 7. Öffentliche API (Import)
```python
from data_layer.training_profile import (
resolve_training_evaluation,
resolve_for_base_profile,
TrainingEvaluationResult,
CalculationTemplate,
)
```
Registries:
```python
from data_layer.training_profile.templates.registry import get_calculation_template
from data_layer.training_profile.profiles.registry import get_training_base_profile
from data_layer.training_profile.algorithms.registry import get_algorithm, list_algorithm_ids
```
---
## 8. Erweiterungspunkte (für spätere Produktlogik)
1. **Neue Algorithmen** — neue Datei unter `algorithms/builtin/`, in `registry.py` registrieren.
2. **Templates** — weitere `CalculationTemplate`-Instanzen in `templates/registry.py` oder später aus DB laden (Loader baut dieselben Dataclasses).
3. **Profile** — weitere `TrainingBaseProfile`-Einträge; Anbindung an `training_types` / Aktivität.
4. **Confidence/Evidence** — feinere Regeln (Datenqualität, Mindestkriterien) im Resolver oder in den Algorithmen.
5. **Normalisierung der FA-Beiträge** — optional globale Skalierung/Cap (aktuell rein additive Gewichtung).
---
## 9. Was absichtlich offen ist
- Finale Domänenregeln (welche Dimensionen für welchen Sport)
- Vollständige Liste Basisprofile und Templates
- Persistenz von Evaluationsergebnissen
- Integration in Placeholder-Resolver, Charts, Admin-UI
- Validierung gegen `focus_area_definitions` (DB-Keys)
---
## 10. Kritische Einschätzung
| Bereich | Bewertung |
|---------|-----------|
| Registry + Algorithmus-Schnittstelle | Robust, testbar, erweiterbar |
| Template-Modelle (frozen dataclasses) | Stabil, typsicher, serialisierbar |
| Beispiel-Algorithmen | Minimal, nur zur Demonstration der Pipeline |
| Confidence | Heuristik — für Produktion noch abzustimmen |
| Focus-Area-Gewichte | Additiv, nicht normiert — Domänenentscheidung für später |
---
## 11. Tests
`backend/tests/test_training_profile_resolver.py` — Registry, Resolver, Profil-Filter, Serialisierung, unbekannter Algorithmus.
Ausführen (aus `backend/`):
```bash
python -m pytest tests/test_training_profile_resolver.py -v
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
# Universal CSV Import Agent-Leitfaden
**Stand:** 2026-04-09 · **Kontext:** Issue #21 (Universeller CSV-Parser), Prod-Migrationen u. a. 051053.
Dieses Dokument ist **normativ für Agenten**, die ein neues Import-Zielmodul anlegen oder bestehende Import-Pfade (Executor, Vorlagen, DB) ändern.
---
## 1. Architektur (Kurz)
| Komponente | Pfad / Rolle |
|------------|----------------|
| Modul-Definitionen | `backend/csv_parser/module_registry.py` (`MODULE_DEFINITIONS`) |
| Typ-/Einheiten-Konvertierung | `backend/csv_parser/type_converter.py`, `field_units.py` |
| Zeilen-Aggregation (z. B. Ernährung pro Tag) | `backend/csv_parser/import_row_processing.py` |
| Import-Ausführung | `backend/csv_parser/executor.py` |
| Fehlertexte / Transaktions-Hinweise | `backend/csv_parser/import_errors.py` (`enrich_row_error`) |
| Admin-Systemvorlagen | `backend/routers/admin_csv_templates.py` |
| Nutzer-Import (Profil-Mappings) | `backend/routers/csv_import.py` |
| Vorlagen-Validierung (strukturell + Sample) | `backend/csv_parser/template_validator.py` (`validate_csv_template`) |
| Effektives Listentrennzeichen | `backend/csv_parser/core.py` (`resolve_effective_csv_delimiter`) — Datei kann `;` (z.B. Apple DE) haben, Vorlage `,` (EN); Import/Diagnose **nicht** nur das gespeicherte Trennzeichen blind nutzen. |
**Single Source of Truth** für erlaubte Zielfelder, Typen und Duplikat-Keys ist **`module_registry.py`**. Keine parallele Feldliste in Routern duplizieren.
---
## 2. Checkliste: Neues Zielmodul
1. **`MODULE_DEFINITIONS`** um Eintrag erweitern: `table`, `fields` (Typen `date` / `datetime` / `float` / `int` / `string`), `duplicate_key`, `duplicate_strategy`, ggf. `derive_date_from_datetime_field`, `import_mode` (Spezialpfade wie Schlaf).
2. **DB:** Migration nur nach Projektregel (`backend/migrations/NNN_*.sql`). Spaltenbreiten/Typen so wählen, dass importierte Werte (z. B. kJ→kcal, große Energiebeträge) **keinen NUMERIC-Overflow** verursachen.
3. **`source` / CHECK-Constraints:** Wenn die Zieltabelle `source` hat, muss der Wert **`csv`** (oder der vereinbarte Import-Tag) in der DB erlaubt sein (Migration anpassen, nicht nur App-Code).
4. **Executor:** Einfügen/Aktualisieren in `executor.py` nur über bestehende Muster (ein Cursor, **kein** verschachteltes `get_db()` im gleichen Request). Bei mehreren Zeilen pro Transaktion: bei **Zeilenfehlern** SAVEPOINT pro Zeile nutzen (siehe Activity-Pattern), damit die Transaktion nicht dauerhaft abgebrochen ist.
5. **Trainingstyp / FK-Auflösung:** DB-Zugriffe für abhängige Entitäten (z. B. `get_training_type_for_activity_with_cursor`) **mit dem gleichen Cursor** wie der Import keine zweite Connection aus dem Importpfad.
6. **Vorlagen:** System-Templates in Migration/Seed pflegen (`csv_field_mappings`, `is_system=true`). `type_conversions` und `source_unit` dort setzen, wo Einheiten aus Exporten abweichen (z. B. Apple kJ).
7. **Validierung:** Neue/angepasste Admin-Vorlagen müssen **`validate_csv_template`** passieren (Create/Update liefert bei Fehlern **422** mit `validation`). Tests für Randfälle ergänzen (`tests/test_template_validator.py` o. ä.).
8. **API / Frontend:** Neue Admin-Endpunkte in `main.py` registrieren; Frontend **nur** über `api.js`. Bei strukturierten FastAPI-Fehlern (`detail` als Objekt/Liste) bestehende Hilfen (`formatFastApiDetail`) nutzen.
---
## 3. Checkliste: Bestehendes Modul ändern
- Schema-Änderung: Migration + ggf. **`module_registry`**-Felder anpassen.
- Neue Spalte im Import: Executor-Mapping, optional `type_conversions` / Validator.
- Änderung an Duplikatlogik: `duplicate_key` / `ON CONFLICT`-Pfad im Executor prüfen.
- Datums-/Zeit-Parsing: **`type_converter`** ISO-Daten `YYYY-MM-DD` konsistent (**`dayfirst=False`**), Zeiten `HH:MM` ohne Sekunden unterstützen wo nötig.
---
## 4. Bekannte Einschränkungen (Follow-up in Gitea)
- Admin **„Format prüfen“** kann `import_row_processing` derzeit weglassen; volle Parität mit dem gespeicherten Template erst beim Speichern / echten Import.
- Nutzer-Mappings (Copy aus Systemvorlage) laufen nicht automatisch durch **`validate_csv_template`** Tracking: **Gitea #71** (http://192.168.2.144:3000/Lars/mitai-jinkendo/issues/71).
---
## 5. Verwandte Regeln
- `.claude/rules/ARCHITECTURE.md` Router, DB, `source`-Tracking
- `.claude/rules/CODING_RULES.md` Kurzverweis Universal CSV
- `.claude/rules/DOCUMENTATION.md` Ablage technischer Specs
---
**Version:** 1.0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More