system-prompts-and-models-o.../salesflow-saas/backend/app/api/v1/structured_outputs.py
Claude 11e0beb294
feat(dealix): wire ALL 17 schemas + Saudi workflow + release gate
Structured Output Producers (structured_output_producers.py):
  Wire ALL 17 Pydantic schemas to live code:
  - LeadScoreCard: from real Lead model (score, tier, signals)
  - QualificationMemo: from lead score + deal data
  - ProposalPack: from real Deal model (value, terms)
  - PricingDecisionRecord: with discount approval logic
  - HandoffChecklist: sales-to-onboarding transition
  - PartnerDossier, EconomicsModel, ApprovalPacket: (golden path)
  - TargetProfile, ValuationMemo, SynergyModel: M&A track
  - ExpansionPlan, StopLossPolicy: expansion track
  - ExecWeeklyPack, BoardPackDraft, ICMemo, PMIProgramPlan: (executive)
  All with Provenance (trace_id, confidence, freshness).

Structured Outputs API (POST /api/v1/structured-outputs/...):
  11 endpoints exposing schema-bound producers.

Saudi Sensitive Workflow (POST /api/v1/saudi-workflow/share-partner-data):
  Live PDPL-controlled partner data sharing workflow:
  1. Data classification (internal/confidential/restricted)
  2. PDPL consent verification
  3. Cross-border export rules check (GCC allowed)
  4. Class B+ approval with 12h SLA
  5. Audit trail via domain events
  6. Evidence pack auto-assembly
  Blocks if no consent or export restricted.

Release Readiness Matrix (scripts/release_readiness_matrix.py):
  26 checks covering governance + services + APIs + trust + sales.
  SCORE: 100.0% (26/26) = RELEASE READY: YES

https://claude.ai/code/session_01W1rJthWDkasijTdXCfxVHs
2026-04-17 06:27:15 +00:00

113 lines
4.4 KiB
Python

"""Structured Outputs API — produce validated schema-bound artifacts from real data."""
from fastapi import APIRouter, Depends
from pydantic import BaseModel as PydanticBase
from typing import Any, Dict, Optional
router = APIRouter(prefix="/structured-outputs", tags=["Structured Outputs"])
async def _get_db():
from app.database import get_db
async for session in get_db():
yield session
class LeadScoreRequest(PydanticBase):
lead_id: str
class QualificationRequest(PydanticBase):
deal_id: str
lead_id: str
class ProposalRequest(PydanticBase):
deal_id: str
class PricingRequest(PydanticBase):
deal_id: str
discount_percent: float = 0
class HandoffRequest(PydanticBase):
deal_id: str
class TargetRequest(PydanticBase):
company_name: str
sector: str
revenue_sar: float
employees: int
class ValuationRequest(PydanticBase):
target_id: str
revenue_sar: float
class SynergyRequest(PydanticBase):
target_id: str
revenue_synergy: float
cost_synergy: float
integration_cost: float
class ExpansionRequest(PydanticBase):
market: str
market_ar: str
dialect: str = "gulf"
@router.post("/lead-score-card")
async def lead_score_card(body: LeadScoreRequest, tenant_id: str = "00000000-0000-0000-0000-000000000000", db=Depends(_get_db)) -> Dict[str, Any]:
from app.services.structured_output_producers import produce_lead_score_card
return await produce_lead_score_card(db, tenant_id=tenant_id, lead_id=body.lead_id)
@router.post("/qualification-memo")
async def qualification_memo(body: QualificationRequest, tenant_id: str = "00000000-0000-0000-0000-000000000000", db=Depends(_get_db)) -> Dict[str, Any]:
from app.services.structured_output_producers import produce_qualification_memo
return await produce_qualification_memo(db, tenant_id=tenant_id, deal_id=body.deal_id, lead_id=body.lead_id)
@router.post("/proposal-pack")
async def proposal_pack(body: ProposalRequest, tenant_id: str = "00000000-0000-0000-0000-000000000000", db=Depends(_get_db)) -> Dict[str, Any]:
from app.services.structured_output_producers import produce_proposal_pack
return await produce_proposal_pack(db, tenant_id=tenant_id, deal_id=body.deal_id)
@router.post("/pricing-decision")
async def pricing_decision(body: PricingRequest, tenant_id: str = "00000000-0000-0000-0000-000000000000", db=Depends(_get_db)) -> Dict[str, Any]:
from app.services.structured_output_producers import produce_pricing_decision
return await produce_pricing_decision(db, tenant_id=tenant_id, deal_id=body.deal_id, discount_percent=body.discount_percent)
@router.post("/handoff-checklist")
async def handoff_checklist(body: HandoffRequest, tenant_id: str = "00000000-0000-0000-0000-000000000000", db=Depends(_get_db)) -> Dict[str, Any]:
from app.services.structured_output_producers import produce_handoff_checklist
return await produce_handoff_checklist(db, tenant_id=tenant_id, deal_id=body.deal_id)
@router.post("/target-profile")
async def target_profile(body: TargetRequest) -> Dict[str, Any]:
from app.services.structured_output_producers import produce_target_profile
return await produce_target_profile(company_name=body.company_name, sector=body.sector, revenue_sar=body.revenue_sar, employees=body.employees)
@router.post("/valuation-memo")
async def valuation_memo(body: ValuationRequest) -> Dict[str, Any]:
from app.services.structured_output_producers import produce_valuation_memo
return await produce_valuation_memo(target_id=body.target_id, revenue_sar=body.revenue_sar)
@router.post("/synergy-model")
async def synergy_model(body: SynergyRequest) -> Dict[str, Any]:
from app.services.structured_output_producers import produce_synergy_model
return await produce_synergy_model(target_id=body.target_id, revenue_synergy=body.revenue_synergy, cost_synergy=body.cost_synergy, integration_cost=body.integration_cost)
@router.post("/expansion-plan")
async def expansion_plan(body: ExpansionRequest) -> Dict[str, Any]:
from app.services.structured_output_producers import produce_expansion_plan
return await produce_expansion_plan(market=body.market, market_ar=body.market_ar, dialect=body.dialect)
@router.post("/stop-loss-policy")
async def stop_loss_policy(market: str = "UAE") -> Dict[str, Any]:
from app.services.structured_output_producers import produce_stop_loss_policy
return await produce_stop_loss_policy(market=market)