from contextlib import asynccontextmanager from fastapi import Depends, FastAPI from fastapi.middleware.cors import CORSMiddleware from sqlalchemy import select, text from sqlalchemy.orm import Session from .config import settings from .database import Base, engine, get_db from .auth import current_user from .models import ActivityEvent, UserAccount from .routes_admin import router as admin_router from .routes_api_keys import router as api_keys_router from .routes_auth import router as auth_router from .routes_compliance import router as compliance_router from .routes_dlt import router as dlt_router from .routes_kyc import router as kyc_router from .routes_analytics import router as analytics_router from .routes_logs import router as logs_router from .routes_otp import router as otp_router from .routes_messages import router as messages_router from .routes_messaging import router as messaging_router from .routes_campaigns import router as campaigns_router from .routes_integrations import router as integrations_router from .routes_numbers import router as numbers_router from .routes_urmiotp import router as urmiotp_router from .routes_voice import router as voice_router from .routes_whatsapp import router as whatsapp_router from .routes_meta import router as meta_router from .routes_agent_templates import router as agent_templates_router from .routes_agent_messages import router as agent_messages_router from .routes_urmiport import router as urmiport_router from .routes_urmiport_api import router as urmiport_api_router from .agent_templates_seed import seed_agent_message_templates @asynccontextmanager async def lifespan(_: FastAPI): Base.metadata.create_all(bind=engine) with Session(engine) as db: seed_agent_message_templates(db) with engine.begin() as conn: conn.execute( text( "ALTER TABLE urmiotp_projects " "ADD COLUMN IF NOT EXISTS message_label VARCHAR(20) NOT NULL DEFAULT 'URMI'" ) ) conn.execute( text( "ALTER TABLE phone_numbers " "ADD COLUMN IF NOT EXISTS monthly_number_price NUMERIC(10,2) NOT NULL DEFAULT 0" ) ) conn.execute( text( "ALTER TABLE phone_numbers " "ADD COLUMN IF NOT EXISTS monthly_inbound_price NUMERIC(10,2) NOT NULL DEFAULT 0" ) ) conn.execute( text( "ALTER TABLE phone_numbers " "ADD COLUMN IF NOT EXISTS monthly_outbound_price NUMERIC(10,2) NOT NULL DEFAULT 0" ) ) conn.execute( text( "ALTER TABLE whatsapp_phone_assets " "ADD COLUMN IF NOT EXISTS two_step_pin VARCHAR(6)" ) ) conn.execute(text("ALTER TABLE whatsapp_messages ADD COLUMN IF NOT EXISTS user_id UUID")) conn.execute(text("ALTER TABLE whatsapp_messages ADD COLUMN IF NOT EXISTS phone_number_id VARCHAR(64)")) conn.execute(text("ALTER TABLE whatsapp_messages ADD COLUMN IF NOT EXISTS contact_name VARCHAR(200)")) conn.execute(text("ALTER TABLE whatsapp_meta_connections ADD COLUMN IF NOT EXISTS meta_app_id VARCHAR(64)")) conn.execute(text("ALTER TABLE whatsapp_meta_connections ADD COLUMN IF NOT EXISTS meta_app_secret TEXT")) conn.execute(text("CREATE INDEX IF NOT EXISTS ix_whatsapp_messages_user_id ON whatsapp_messages (user_id)")) conn.execute(text("CREATE INDEX IF NOT EXISTS ix_whatsapp_messages_phone_number_id ON whatsapp_messages (phone_number_id)")) yield app = FastAPI( title=settings.app_name, version="0.1.0", lifespan=lifespan, docs_url="/docs", ) app.add_middleware( CORSMiddleware, allow_origins=settings.cors_allowed_origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(auth_router) app.include_router(kyc_router) app.include_router(dlt_router) app.include_router(compliance_router) app.include_router(messaging_router) app.include_router(api_keys_router) app.include_router(messages_router) app.include_router(otp_router) app.include_router(logs_router) app.include_router(analytics_router) app.include_router(urmiotp_router) app.include_router(campaigns_router) app.include_router(numbers_router) app.include_router(integrations_router) app.include_router(voice_router) app.include_router(whatsapp_router) app.include_router(meta_router) app.include_router(agent_templates_router) app.include_router(agent_messages_router) app.include_router(urmiport_router) app.include_router(urmiport_api_router) app.include_router(admin_router) @app.get("/health") def health(db: Session = Depends(get_db)) -> dict[str, str]: db.execute(text("SELECT 1")) return {"status": "healthy", "service": settings.app_name} @app.get("/api/v1/dashboard") def dashboard( db: Session = Depends(get_db), _: UserAccount = Depends(current_user), ) -> dict: events = db.scalars( select(ActivityEvent).order_by(ActivityEvent.occurred_at.desc()).limit(8) ).all() return { "metrics": { "voice_calls": 1243, "messages_sent": 45231, "delivery_rate": 98.7, "api_requests": 1_200_000, "balance": 24820, }, "activity": [ { "id": str(event.id), "type": event.event_type, "title": event.title, "detail": event.detail, "status": event.status, "occurred_at": event.occurred_at, } for event in events ], }