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)
124 lines
6.4 KiB
Python
124 lines
6.4 KiB
Python
"""
|
|
Mitai Jinkendo API - Main Application
|
|
|
|
FastAPI backend with modular router structure.
|
|
"""
|
|
import os
|
|
from pathlib import Path
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from slowapi import Limiter, _rate_limit_exceeded_handler
|
|
from slowapi.util import get_remote_address
|
|
from slowapi.errors import RateLimitExceeded
|
|
|
|
from db import init_db
|
|
|
|
# Import routers
|
|
from routers import auth, profiles, weight, circumference, caliper
|
|
from routers import activity, nutrition, photos, insights, prompts
|
|
from routers import admin, stats, exportdata, importdata
|
|
from routers import subscription, coupons, features, tiers_mgmt, tier_limits
|
|
from routers import user_restrictions, access_grants, training_types, admin_training_types
|
|
from routers import admin_activity_mappings, sleep, rest_days
|
|
from routers import vitals_baseline, blood_pressure # v9d Phase 2d Refactored
|
|
from routers import evaluation # v9d/v9e Training Type Profiles (#15)
|
|
from routers import goals, focus_areas # v9e/v9g Goal System v2.0 (Dynamic Focus Areas)
|
|
from routers import goal_types, goal_progress, training_phases, fitness_tests # v9h Goal System (Split routers)
|
|
from routers import charts # Phase 0c Multi-Layer Architecture
|
|
from routers import workflow_questions # Phase 1 Workflow Engine - Question Catalog
|
|
from routers import workflows # Phase 2 Workflow Engine - Execution
|
|
|
|
# ── App Configuration ─────────────────────────────────────────────────────────
|
|
DATA_DIR = Path(os.getenv("DATA_DIR", "./data"))
|
|
PHOTOS_DIR = Path(os.getenv("PHOTOS_DIR", "./photos"))
|
|
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
PHOTOS_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
app = FastAPI(title="Mitai Jinkendo API", version="3.0.0")
|
|
|
|
# Rate limiting
|
|
limiter = Limiter(key_func=get_remote_address)
|
|
app.state.limiter = limiter
|
|
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
|
|
|
# CORS
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=os.getenv("ALLOWED_ORIGINS", "*").split(","),
|
|
allow_credentials=True,
|
|
allow_methods=["GET","POST","PUT","DELETE","OPTIONS"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
# ── Startup Event ─────────────────────────────────────────────────────────────
|
|
@app.on_event("startup")
|
|
async def startup_event():
|
|
"""Run database initialization on startup."""
|
|
try:
|
|
init_db()
|
|
except Exception as e:
|
|
print(f"⚠️ init_db() failed (non-fatal): {e}")
|
|
# Don't crash on startup - can be created manually
|
|
|
|
# Apply v9c migration if needed
|
|
try:
|
|
from apply_v9c_migration import apply_migration
|
|
apply_migration()
|
|
except Exception as e:
|
|
print(f"⚠️ v9c migration failed (non-fatal): {e}")
|
|
|
|
# ── Register Routers ──────────────────────────────────────────────────────────
|
|
app.include_router(auth.router) # /api/auth/*
|
|
app.include_router(profiles.router) # /api/profiles/*, /api/profile
|
|
app.include_router(weight.router) # /api/weight/*
|
|
app.include_router(circumference.router) # /api/circumferences/*
|
|
app.include_router(caliper.router) # /api/caliper/*
|
|
app.include_router(activity.router) # /api/activity/*
|
|
app.include_router(nutrition.router) # /api/nutrition/*
|
|
app.include_router(photos.router) # /api/photos/*
|
|
app.include_router(insights.router) # /api/insights/*, /api/ai/*
|
|
app.include_router(prompts.router) # /api/prompts/*
|
|
app.include_router(admin.router) # /api/admin/*
|
|
app.include_router(stats.router) # /api/stats
|
|
app.include_router(exportdata.router) # /api/export/*
|
|
app.include_router(importdata.router) # /api/import/*
|
|
|
|
# v9c Subscription System
|
|
app.include_router(subscription.router) # /api/subscription/*
|
|
app.include_router(coupons.router) # /api/coupons/*
|
|
app.include_router(features.router) # /api/features (admin)
|
|
app.include_router(tiers_mgmt.router) # /api/tiers (admin)
|
|
app.include_router(tier_limits.router) # /api/tier-limits (admin)
|
|
app.include_router(user_restrictions.router) # /api/user-restrictions (admin)
|
|
app.include_router(access_grants.router) # /api/access-grants (admin)
|
|
|
|
# v9d Training Types & Sleep Module & Rest Days & Vitals
|
|
app.include_router(training_types.router) # /api/training-types/*
|
|
app.include_router(admin_training_types.router) # /api/admin/training-types/*
|
|
app.include_router(admin_activity_mappings.router) # /api/admin/activity-mappings/*
|
|
app.include_router(sleep.router) # /api/sleep/* (v9d Phase 2b)
|
|
app.include_router(rest_days.router) # /api/rest-days/* (v9d Phase 2a)
|
|
app.include_router(vitals_baseline.router) # /api/vitals/baseline/* (v9d Phase 2d Refactored)
|
|
app.include_router(blood_pressure.router) # /api/blood-pressure/* (v9d Phase 2d Refactored)
|
|
app.include_router(evaluation.router) # /api/evaluation/* (v9d/v9e Training Profiles #15)
|
|
app.include_router(goals.router) # /api/goals/* (v9h Goal System Core CRUD + Focus Areas)
|
|
app.include_router(goal_types.router) # /api/goals/goal-types/* (v9h Goal Type Definitions)
|
|
app.include_router(goal_progress.router) # /api/goals/{goal_id}/progress/* (v9h Progress Tracking)
|
|
app.include_router(training_phases.router) # /api/goals/phases/* (v9h Training Phases)
|
|
app.include_router(fitness_tests.router) # /api/goals/tests/* (v9h Fitness Tests)
|
|
app.include_router(focus_areas.router) # /api/focus-areas/* (v9g Focus Area System v2.0 - Dynamic)
|
|
|
|
# Phase 0c Multi-Layer Architecture
|
|
app.include_router(charts.router) # /api/charts/* (Phase 0c Charts API)
|
|
|
|
# Phase 1-2 Workflow Engine
|
|
app.include_router(workflow_questions.router) # /api/workflow/questions/* (Phase 1 Question Catalog)
|
|
app.include_router(workflows.router) # /api/workflows/* (Phase 2 Execution)
|
|
|
|
# ── Health Check ──────────────────────────────────────────────────────────────
|
|
@app.get("/")
|
|
def root():
|
|
"""API health check."""
|
|
return {"status": "ok", "service": "mitai-jinkendo", "version": "v9c-dev"}
|