Complete Phase 1 implementation: Backend (FastAPI + MongoDB + Celery): - Core: config, DB with indexes, JWT security, API key auth middleware - Models: org hierarchy (workspace/team/project), user mirror, pricing, usage events/rollups, budgets, alert log, audit log - Services: pricing engine (LiteLLM/YAML/override priority), budget check with preflight, email alerts at 50/80/100%, analytics aggregations, audit logger - API routes: public (preflight/record/upsert), admin CRUD, pricing management, budget management, analytics (summary/timeseries/breakdown/pivot), Microsoft SSO auth - Celery tasks: daily LiteLLM price sync with change notifications, daily rollup aggregation, 5-minute alert evaluator - Pricing catalogue: ElevenLabs + Google Cloud TTS in models.yaml SDK (oliver-cost-tracker Python package): - CostTracker client with httpx + exponential backoff (3 retries) - SQLite outbox with 30s background flusher (never blocks AI pipeline) - Estimators: token/char estimation per provider - BudgetExceeded / CostTrackerUnavailable exceptions Frontend (React 18 + Vite + TypeScript): - Dashboard with KPI cards, daily cost timeseries, top-model/top-user charts - Pivot Explorer with multi-dim row/col selection + stacked bar chart + table - Admin pages: Workspaces, Pricing (with LiteLLM sync + override), Budgets (with live spend bar), API Keys (show-once), Users (mirror), Audit Log - Microsoft SSO login flow Infra: docker-compose.yml (mongo + redis + api + celery worker + beat + frontend) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
57 lines
1.8 KiB
Python
57 lines
1.8 KiB
Python
"""FastAPI application entry-point."""
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
from .core.config import settings
|
|
from .core.database import connect_db, create_indexes, disconnect_db, get_db_instance
|
|
from .core.logging import get_logger
|
|
from .services.pricing_engine import load_yaml_prices
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
# Startup
|
|
logger.info("Connecting to MongoDB…")
|
|
await connect_db()
|
|
db = get_db_instance()
|
|
await create_indexes(db)
|
|
logger.info("Creating indexes… done")
|
|
loaded = await load_yaml_prices(db)
|
|
logger.info(f"YAML prices loaded: {loaded} new records")
|
|
yield
|
|
# Shutdown
|
|
await disconnect_db()
|
|
logger.info("MongoDB disconnected")
|
|
|
|
|
|
app = FastAPI(
|
|
title="Oliver AI Cost Tracker",
|
|
version="1.0.0",
|
|
lifespan=lifespan,
|
|
)
|
|
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=[o.strip() for o in settings.cors_origins.split(",")],
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
from .api.v1.routes_public import router as public_router
|
|
from .api.v1.routes_admin import router as admin_router
|
|
from .api.v1.routes_pricing import router as pricing_router
|
|
from .api.v1.routes_budgets import router as budgets_router
|
|
from .api.v1.routes_analytics import router as analytics_router
|
|
from .api.v1.routes_auth import router as auth_router
|
|
|
|
app.include_router(public_router, prefix="/v1", tags=["public"])
|
|
app.include_router(auth_router, prefix="/v1", tags=["auth"])
|
|
app.include_router(admin_router, prefix="/admin", tags=["admin"])
|
|
app.include_router(pricing_router, prefix="/admin", tags=["pricing"])
|
|
app.include_router(budgets_router, prefix="/admin", tags=["budgets"])
|
|
app.include_router(analytics_router, prefix="/admin", tags=["analytics"])
|