Kairo-Jinkendo/backend/routers/steering.py
Lars d3bf3c36e0
Some checks failed
Deploy Development / deploy (push) Successful in 46s
Test Suite / pytest-backend (push) Failing after 3m17s
Test Suite / k6 /api/health Baseline (push) Has been skipped
Test Suite / playwright-smoke (push) Has been skipped
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
AP2.4: Steuerungselement-Registry und Methoden-Vertrag.
MethodDefinition traegt steering_elements/ui_features/graph_profile; operating-context und FE-Registry ohne Archetyp-Ifs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-25 11:27:59 +02:00

124 lines
4.2 KiB
Python

"""Steering API — methods, profiles and context (AP1.1 / AP2.0 / AP2.4)."""
from __future__ import annotations
from typing import Optional
from capabilities import require_capability
from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel, Field
from entity_archetypes.registry import resolve_default_method_key, resolve_ui_profile
from method_profiles.registry import list_method_profiles
from services import initiatives as initiative_service
from services import steering_context as sc_service
from steering.context import get_steering_context_dto
from steering.methods.registry import (
list_compatible_methods,
list_methods,
method_to_dict,
)
from tenant_context import TenantContext
router = APIRouter(prefix="/api/steering", tags=["steering"])
class SteeringContextUpdateRequest(BaseModel):
method_key: Optional[str] = Field(default=None, min_length=1)
method_profile_key: Optional[str] = Field(default=None, min_length=1)
clear_method_profile: bool = False
def _om_capabilities_for_archetype(archetype_key: str | None) -> frozenset[str] | None:
if not archetype_key:
return None
profile = resolve_ui_profile(archetype_key)
caps = profile.get("omCapabilities") or profile.get("dataSlices") or []
return frozenset(caps)
@router.get("/methods")
def list_steering_methods(
archetype_key: Optional[str] = Query(default=None),
ctx: TenantContext = Depends(require_capability("kairo.initiative.read")),
):
_ = ctx
om_caps = _om_capabilities_for_archetype(archetype_key)
if archetype_key:
methods = list_compatible_methods(archetype_key, om_capabilities=om_caps)
default_key = resolve_default_method_key(archetype_key)
else:
methods = list_methods()
default_key = None
return [
{
**method_to_dict(m),
"is_default": m.key == default_key if default_key else False,
}
for m in methods
]
@router.get("/method-profiles")
def list_steering_method_profiles(
initiative_archetype_key: Optional[str] = Query(default=None),
ctx: TenantContext = Depends(require_capability("kairo.initiative.read")),
):
_ = ctx
return [
{
"key": p["key"],
"label": p["label"],
"description": p["description"],
"initiative_archetype_key": p["initiative_archetype_key"],
"method_key": p["method_key"],
}
for p in list_method_profiles(initiative_archetype_key=initiative_archetype_key)
]
@router.patch("/initiatives/{initiative_id}/context")
def patch_initiative_steering_context(
initiative_id: str,
body: SteeringContextUpdateRequest,
ctx: TenantContext = Depends(require_capability("kairo.initiative.manage")),
):
initiative = initiative_service.get_initiative(
tenant_id=ctx.tenant_id, initiative_id=initiative_id
)
if not initiative:
raise HTTPException(status_code=404, detail="Vorhaben nicht gefunden")
if not body.method_key and not body.method_profile_key and not body.clear_method_profile:
raise HTTPException(
status_code=400,
detail="method_key, method_profile_key oder clear_method_profile erforderlich",
)
try:
if body.clear_method_profile:
sc_service.update_method_profile_key(
tenant_id=ctx.tenant_id,
initiative_id=initiative_id,
method_profile_key=None,
user_id=ctx.user_id,
)
elif body.method_profile_key:
sc_service.update_method_profile_key(
tenant_id=ctx.tenant_id,
initiative_id=initiative_id,
method_profile_key=body.method_profile_key,
user_id=ctx.user_id,
)
elif body.method_key:
sc_service.update_method_key(
tenant_id=ctx.tenant_id,
initiative_id=initiative_id,
method_key=body.method_key,
user_id=ctx.user_id,
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return get_steering_context_dto(ctx, initiative_id=initiative_id)