Files
AFFAANhandClaude Opus 5 f6a54d6f93 Initial commit: Maskan CRM backend
Independent FastAPI backend for Maskan CRM.

Owns contacts, organizations, leads, pipelines, activities, products,
quotes, users, permissions, audit records and first-party integration
credentials, with Alembic migrations against PostgreSQL.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 10:28:41 +05:30

108 lines
2.7 KiB
Python

from uuid import uuid4
from fastapi import FastAPI, HTTPException, Request
from fastapi.exceptions import RequestValidationError
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from sqlalchemy import text
from app.api.router import api_router
from app.core.config import get_settings
from app.core.database import SessionLocal
settings = get_settings()
app = FastAPI(
title="Maskan CRM API",
version="0.1.0",
docs_url="/api/docs",
openapi_url="/api/openapi.json",
)
app.add_middleware(
CORSMiddleware,
allow_origins=settings.cors_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
def error_response(
*,
request: Request,
status_code: int,
code: str,
message: str,
details: object | None = None,
) -> JSONResponse:
request_id = getattr(request.state, "request_id", str(uuid4()))
return JSONResponse(
status_code=status_code,
content={
"error": {
"code": code,
"message": message,
"details": details,
"request_id": request_id,
},
},
headers={"X-Request-ID": request_id},
)
@app.middleware("http")
async def request_id_middleware(request: Request, call_next):
request.state.request_id = request.headers.get("X-Request-ID") or str(uuid4())
response = await call_next(request)
response.headers["X-Request-ID"] = request.state.request_id
return response
@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse:
return error_response(
request=request,
status_code=exc.status_code,
code=f"HTTP_{exc.status_code}",
message=str(exc.detail),
)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(
request: Request,
exc: RequestValidationError,
) -> JSONResponse:
return error_response(
request=request,
status_code=422,
code="VALIDATION_ERROR",
message="One or more fields are invalid.",
details=exc.errors(),
)
@app.get("/health/live", tags=["Health"])
def live() -> dict[str, str]:
return {"status": "ok", "service": "maskan-crm-api"}
@app.get("/health/ready", tags=["Health"])
def ready() -> dict[str, str]:
with SessionLocal() as db:
db.execute(text("SELECT 1"))
return {"status": "ready", "database": "connected"}
@app.get("/api/v1/status", tags=["Health"])
def status() -> dict[str, str]:
return {
"product": "Maskan CRM",
"mode": settings.mode,
"environment": settings.environment,
}
app.include_router(api_router)