system-prompts-and-models-o.../dealix/api/main.py
Dealix Builder 4e969131c7 feat(platform+intelligence): Growth Control Tower + Growth Neural Network — 20 modules + 25 endpoints + 60 tests
Platform Services Layer (10 modules) — برج التحكم بالنمو
- event_bus: 27 typed events (whatsapp/email/calendar/lead/payment/review/social/partner/sheet/crm/action)
- identity_resolution: cross-channel merge (phone+email+CRM+social) with confidence scoring
- channel_registry: 11 channels (WA, Gmail, Calendar, Moyasar, LinkedIn, X, IG, GBP, Sheets, CRM, Forms) with capabilities/risk/PDPL notes
- action_policy: 9 rules (block_cold_whatsapp, block_payment_no_confirm, block_secrets, external_send_needs_approval, calendar_insert_needs_approval, social_dm_needs_explicit, unknown_source_review, high_value_deal_review, draft_only_safe)
- tool_gateway: single execution chokepoint, env-flag-gated live actions (default OFF)
- unified_inbox: 8 card types, ≤3 buttons enforced, Arabic
- action_ledger: requested→approved→executed audit trail
- proof_ledger: leads/meetings/drafts/sends/payments/revenue/risks_blocked/time_saved per channel
- service_catalog: 12 sellable services
- router api/routers/platform_services.py — 13 endpoints under /api/v1/platform/

Intelligence Layer (10 modules) — الشبكة العصبية للنمو
- growth_brain: per-customer Brain + is_ready_for_autopilot() (≥30 signals + ≥40% accept)
- command_feed: 9 daily card types (opportunity/revenue_leak/partner_suggestion/meeting_prep/review_response/competitive_move/customer_reactivation/ai_visibility_alert/action_required)
- action_graph: 10 typed edges (signal→action→outcome) with what_works_summary
- mission_engine: 7 missions, KILL FEATURE first_10_opportunities (10 فرص في 10 دقائق)
- decision_memory: learns from accept/skip/edit/block, returns preferences (channels, tones, sectors, rejected actions, accept_rate)
- trust_score: composite 0-100 (source+opt_in+channel+content+freq+approval) → safe/needs_review/blocked
- revenue_dna: best_channel/segment/angle + common_objection + avg_cycle_days
- opportunity_simulator: 9 Saudi sectors, expected_replies/meetings/deals/pipeline_sar + risk_score
- competitive_moves: 8 move types with Arabic recommended_action_ar
- board_brief: weekly Founder Shadow Board (3 decisions + 3 opportunities + 3 risks + relationship + experiment + metric)
- router api/routers/intelligence_layer.py — 12 endpoints under /api/v1/intelligence/

Tests
- tests/unit/test_platform_services.py — 31 tests covering catalog/channels/events/policy/gateway/identity/inbox/ledger/proof
- tests/unit/test_intelligence_layer.py — 29 tests covering brain/feed/graph/missions/memory/trust/dna/simulator/competitive/brief
- 60/60 new tests pass; full suite 587 passed, 2 skipped

Docs
- docs/PLATFORM_SERVICES_STRATEGY.md (Arabic)
- docs/INTELLIGENCE_LAYER_STRATEGY.md (Arabic)
- docs/DEALIX_100_PERCENT_LAUNCH_PLAN.md — added §32 Platform Services + §33 Intelligence Layer

Safety
- No live send by default (all WA/Gmail/Calendar/Moyasar guarded by env flags, all OFF)
- All external actions go through Tool Gateway → Action Policy → draft/approval_required
- No secrets allowed in payloads (block_secrets policy)
- PDPL-aware: cold WhatsApp without consent is hard-blocked
- Existing 477+ tests untouched (no breaking changes)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 16:05:12 +03:00

190 lines
5.6 KiB
Python

"""
FastAPI application entry point.
نقطة دخول تطبيق FastAPI.
"""
from __future__ import annotations
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from api.middleware import RequestIDMiddleware
from api.routers import (
admin,
agents,
automation,
autonomous,
business,
command_center,
customer_success,
data,
dominance,
drafts,
ecosystem,
email_send,
full_os,
growth_operator,
health,
innovation,
intelligence_layer,
leads,
outreach,
personal_operator,
platform_services,
pricing,
prospect,
public,
revenue,
revenue_os,
sales,
sectors,
v3,
webhooks,
)
from api.security import APIKeyMiddleware, setup_rate_limit
from core.config.settings import get_settings
from core.errors import AICompanyError
from core.logging import configure_logging, get_logger
@asynccontextmanager
async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
"""App startup/shutdown hook."""
configure_logging()
log = get_logger(__name__)
settings = get_settings()
log.info(
"app_startup",
app=settings.app_name,
version=settings.app_version,
env=settings.app_env,
)
# Auto-create tables on boot (additive — safe with SQLAlchemy create_all)
try:
from db.session import init_db
await init_db()
log.info("db_init_complete")
except Exception as exc:
log.warning("db_init_skipped", error=str(exc))
yield
log.info("app_shutdown")
def create_app() -> FastAPI:
"""FastAPI factory."""
settings = get_settings()
app = FastAPI(
title=settings.app_name,
version=settings.app_version,
description=(
"Multi-agent AI platform for the Saudi Arabian market.\n\n"
"**Phase 8**: Auto Client Acquisition — intake, ICP match, "
"pain extraction, qualification, CRM sync, booking, proposals.\n\n"
"**Phase 9**: Autonomous Growth — sector intel, content, distribution, "
"enrichment, competitor analysis, market research.\n\n"
"**Phase 10 / v3**: Autonomous Saudi Revenue OS — revenue memory, "
"safe agent runtime, market radar, compliance OS, revenue science, "
"and Sami Personal Strategic Operator."
),
docs_url="/docs",
redoc_url="/redoc",
openapi_url="/openapi.json",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=settings.cors_origin_list,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.add_middleware(RequestIDMiddleware)
app.add_middleware(APIKeyMiddleware)
setup_rate_limit(app)
try:
from dealix.observability import instrument_fastapi, setup_sentry, setup_tracing
setup_sentry()
setup_tracing(service_name=settings.app_name, version=settings.app_version)
instrument_fastapi(app)
except Exception: # pragma: no cover
pass
@app.exception_handler(AICompanyError)
async def ai_company_error_handler(_: Request, exc: AICompanyError) -> JSONResponse:
return JSONResponse(
status_code=400,
content={"error": exc.__class__.__name__, "detail": str(exc)},
)
app.include_router(health.router)
app.include_router(leads.router)
app.include_router(sales.router)
app.include_router(sectors.router)
app.include_router(agents.router)
app.include_router(webhooks.router)
app.include_router(pricing.router)
app.include_router(prospect.router)
app.include_router(autonomous.router)
app.include_router(data.router)
app.include_router(outreach.router)
app.include_router(revenue.router)
app.include_router(automation.router)
app.include_router(email_send.router)
app.include_router(drafts.router)
app.include_router(dominance.router)
app.include_router(full_os.router)
app.include_router(customer_success.router)
app.include_router(ecosystem.router)
app.include_router(command_center.router)
app.include_router(revenue_os.router)
app.include_router(v3.router)
app.include_router(innovation.router)
app.include_router(business.router)
app.include_router(personal_operator.router)
app.include_router(growth_operator.router)
app.include_router(platform_services.router)
app.include_router(intelligence_layer.router)
app.include_router(public.router)
app.include_router(admin.router)
@app.get("/", tags=["root"])
async def root() -> dict[str, object]:
return {
"name": settings.app_name,
"version": settings.app_version,
"status": "operational",
"env": settings.app_env,
"docs": "/docs",
"health": "/health",
"v3_command_center": "/api/v1/v3/command-center/snapshot",
"personal_operator_daily_brief": "/api/v1/personal-operator/daily-brief",
"personal_operator_launch_report": "/api/v1/personal-operator/launch-report",
"business_pricing": "/api/v1/business/pricing",
"innovation_command_feed_demo": "/api/v1/innovation/command-feed/demo",
}
return app
app = create_app()
if __name__ == "__main__":
import uvicorn
settings = get_settings()
uvicorn.run(
"api.main:app",
host=settings.app_host,
port=settings.app_port,
reload=settings.is_development,
)