"""Cotizador E3 — FastAPI Application REST API for digital marketing quotation management. Optimized for n8n workflows and other integrations. """ from __future__ import annotations from contextlib import asynccontextmanager from datetime import datetime, timezone from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse from app.config import settings from app.database import close_db, init_db @asynccontextmanager async def lifespan(app: FastAPI): await init_db() yield await close_db() app = FastAPI( title="Cotizador E3 API", description=( "API REST para el sistema de cotizaciones de marketing digital de Consultoría E3. " "Optimizada para integración con n8n y otros consumidores. " "Autenticación por X-API-Key o Bearer JWT." ), version="1.0.0", lifespan=lifespan, docs_url="/docs", redoc_url="/redoc", openapi_url="/openapi.json", openapi_tags=[ {"name": "Health", "description": "Health check y información de la API"}, {"name": "Auth", "description": "Autenticación (API Key + JWT)"}, {"name": "Clientes", "description": "Gestión de clientes"}, {"name": "Catálogo", "description": "Catálogo de servicios de marketing digital"}, {"name": "Categorías", "description": "Categorías de servicios"}, {"name": "Cotizaciones", "description": "Cotizaciones — CRUD completo con servicios y plan CRM"}, {"name": "Paquetes", "description": "Paquetes de servicios con fases"}, {"name": "Configuración", "description": "Configuración de la empresa (key-value)"}, {"name": "Bonos", "description": "Bonos disponibles para cotizaciones"}, {"name": "Financiamiento", "description": "Planes y cálculo de financiamiento"}, {"name": "Export", "description": "Exportación de PDF, Excel y CSV"}, {"name": "Import", "description": "Importación masiva de servicios"}, ], ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.exception_handler(Exception) async def global_exception_handler(request: Request, exc: Exception): return JSONResponse( status_code=500, content={"error": "Error interno del servidor", "detail": str(exc)}, ) # Register routers from app.routers import ( auth, bonos, catalogo, categorias, clientes, configuracion, cotizaciones, export_, financiamiento, health, import_, paquetes, ) app.include_router(health.router) app.include_router(auth.router) app.include_router(clientes.router) app.include_router(catalogo.router) app.include_router(categorias.router) app.include_router(cotizaciones.router) app.include_router(paquetes.router) app.include_router(configuracion.router) app.include_router(bonos.router) app.include_router(financiamiento.router) app.include_router(export_.router) app.include_router(import_.router) # El servidor MCP se retiro (2026-07-28). No se estaba usando, su transporte # llevaba tiempo roto (instanciaba un StreamableHTTPServerTransport por peticion, # sin manejo de sesion, y devolvia 500 con credencial valida) y su SDK sin fijar # tumbo el API entero en produccion al saltar a 2.0.0. Si algun dia se retoma, # el codigo esta en el historial: `git show edb500f5:api/app/mcp/server.py`. @app.get("/", include_in_schema=False) async def root(): return { "name": "Cotizador E3 API", "version": "1.0.0", "docs": "/docs", "openapi": "/openapi.json", "health": "/health", } if __name__ == "__main__": import uvicorn uvicorn.run("main:app", host=settings.API_HOST, port=settings.API_PORT, reload=True)