system-prompts-and-models-o.../dealix/api/routers/platform_services.py
Sami Assiri b13cb389cc feat(dealix): sync full Dealix package to repo
- API routers, ACA modules, integrations (draft operators)
- Docs, landing pages, scripts (launch readiness, scorecard)
- Tests and CI workflow updates for Dealix

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-01 21:01:17 +03:00

186 lines
6.7 KiB
Python

"""Platform Services API — Growth Control Tower (no live external sends)."""
from __future__ import annotations
from typing import Any
from fastapi import APIRouter, Body
from auto_client_acquisition.platform_services import (
build_proof_summary,
evaluate_action,
event_to_inbox_card,
execute_tool,
get_action_ledger,
get_service_catalog,
list_channels,
validate_event,
)
from auto_client_acquisition.innovation.proof_ledger import build_demo_proof_ledger
from auto_client_acquisition.platform_services.contact_import_preview import build_import_preview
from auto_client_acquisition.platform_services.identity_resolution import resolve_identity_demo
from auto_client_acquisition.platform_services.inbox_feed import build_inbox_feed
from auto_client_acquisition.platform_services.lead_form_ingest import ingest_lead_form
from auto_client_acquisition.platform_services.proof_overview import build_proof_overview
router = APIRouter(prefix="/api/v1/platform", tags=["platform_services"])
@router.get("/service-catalog")
async def service_catalog() -> dict[str, Any]:
return get_service_catalog()
@router.get("/services/catalog")
async def services_catalog_alias() -> dict[str, Any]:
"""Alias path for product docs compatibility."""
return get_service_catalog()
@router.get("/channels")
async def channels() -> dict[str, Any]:
return list_channels()
@router.post("/events/validate")
async def events_validate(payload: dict[str, Any] = Body(default_factory=dict)) -> dict[str, Any]:
return validate_event(payload or {})
@router.post("/events/ingest")
async def events_ingest(payload: dict[str, Any] = Body(default_factory=dict)) -> dict[str, Any]:
"""Validate normalized event and return inbox card — no persistence."""
v = validate_event(payload or {})
if not v["valid"]:
return {"ok": False, "errors": v["errors"], "approval_required": True}
ev = v.get("normalized") or {}
return {"ok": True, "event": ev, "card": event_to_inbox_card(ev), "approval_required": True}
@router.post("/actions/approve")
async def actions_approve(payload: dict[str, Any] = Body(default_factory=dict)) -> dict[str, Any]:
"""Record human approval/rejection in the in-memory action ledger — no live side effects."""
ledger = get_action_ledger()
action_id = str(payload.get("action_id") or payload.get("request_id") or "unspecified")
actor = str(payload.get("actor") or "operator")
approved = payload.get("approved")
is_approved = True if approved is None else bool(approved)
entry = ledger.append_decision(
tool="human_approval",
outcome="approved" if is_approved else "rejected",
detail={
"action_id": action_id,
"actor": actor,
"notes": payload.get("notes"),
},
)
return {
"ok": True,
"ledger_entry": entry,
"detail_ar": "سُجّل القرار في دفتر MVP — لا يُطلق إرسالاً أو دفعاً تلقائياً من هذا المسار.",
"approval_required": False,
}
@router.post("/actions/evaluate")
async def actions_evaluate_alias(payload: dict[str, Any] = Body(default_factory=dict)) -> dict[str, Any]:
"""Alias of ``POST /policy/evaluate`` for docs that refer to ``actions/evaluate``."""
return evaluate_action(
action=str(payload.get("action") or ""),
channel_id=str(payload.get("channel_id") or ""),
context=payload.get("context") if isinstance(payload.get("context"), dict) else {},
)
@router.post("/inbox/from-event")
async def inbox_from_event(
payload: dict[str, Any] = Body(default_factory=dict),
) -> dict[str, Any]:
event = payload.get("event") if isinstance(payload.get("event"), dict) else payload
merge = bool(payload.get("merge_demo_hint"))
return {"card": event_to_inbox_card(event or {}, merge_demo_hint=merge)}
@router.post("/policy/evaluate")
async def policy_evaluate(payload: dict[str, Any] = Body(default_factory=dict)) -> dict[str, Any]:
return evaluate_action(
action=str(payload.get("action") or ""),
channel_id=str(payload.get("channel_id") or ""),
context=payload.get("context") if isinstance(payload.get("context"), dict) else {},
)
@router.post("/tools/execute")
async def tools_execute(payload: dict[str, Any] = Body(default_factory=dict)) -> dict[str, Any]:
return execute_tool(str(payload.get("tool_name") or ""), payload.get("payload") if isinstance(payload.get("payload"), dict) else {})
@router.get("/proof/summary")
async def proof_summary() -> dict[str, Any]:
return build_proof_summary()
@router.get("/proof-ledger/demo")
async def proof_ledger_demo() -> dict[str, Any]:
"""Demo ledger events — same source as innovation demo."""
return build_demo_proof_ledger()
@router.get("/identity/resolve-demo")
async def identity_resolve_demo(
phone: str | None = None,
email: str | None = None,
company_hint: str | None = None,
) -> dict[str, Any]:
return resolve_identity_demo(phone=phone, email=email, company_hint=company_hint)
@router.get("/proof/overview")
async def proof_overview() -> dict[str, Any]:
return build_proof_overview()
@router.get("/inbox/feed")
async def inbox_feed() -> dict[str, Any]:
return build_inbox_feed()
@router.post("/contacts/import-preview")
async def contacts_import_preview(body: dict[str, Any] = Body(default_factory=dict)) -> dict[str, Any]:
return build_import_preview(body or {})
@router.get("/action-ledger/recent")
async def action_ledger_recent(limit: int = 50) -> dict[str, Any]:
lim = max(1, min(limit, 200))
return {"entries": get_action_ledger().recent(lim)}
@router.post("/ingest/lead-form")
async def ingest_lead_form_route(body: dict[str, Any] = Body(default_factory=dict)) -> dict[str, Any]:
return ingest_lead_form(body or {})
# --- Wave 4: draft payloads only (re-export from aca.integrations) ---
@router.post("/integrations/gmail/draft")
async def gmail_draft(payload: dict[str, Any] = Body(default_factory=dict)) -> dict[str, Any]:
from auto_client_acquisition.integrations.gmail_operator import build_gmail_draft_payload
return build_gmail_draft_payload(payload or {})
@router.post("/integrations/calendar/draft")
async def calendar_draft(payload: dict[str, Any] = Body(default_factory=dict)) -> dict[str, Any]:
from auto_client_acquisition.integrations.calendar_operator import build_calendar_draft_payload
return build_calendar_draft_payload(payload or {})
@router.post("/integrations/moyasar/payment-draft")
async def moyasar_payment_draft(payload: dict[str, Any] = Body(default_factory=dict)) -> dict[str, Any]:
from auto_client_acquisition.integrations.moyasar_draft import build_moyasar_payment_draft
return build_moyasar_payment_draft(payload or {})