e3fac99045
Backend: - GET /api/v1/dashboard?month=YYYY-MM: KPIs, by_category, 6-month trend, budget alerts - GET/POST/PUT/DELETE /api/v1/budgets: budget envelopes with spent_cents/remaining_cents - POST /api/v1/budgets/rollover: copy budgets from M-1 to target month - GET /api/v1/history?year=YYYY: monthly summary for the year - GET /api/v1/export/csv|pdf?month=YYYY-MM: StreamingResponse exports (WeasyPrint PDF) - New schemas: dashboard, budget, history - Services: dashboard_service, budget_service - Routers mounted in main.py Frontend: - DashboardPage: 4 KPI cards, PieChart (expenses by category), BarChart (6-month trend), month navigation, budget alert badges, CSV/PDF export buttons - BudgetsPage: progress bars (green/orange/red), create/edit form, delete, rollover M-1 - HistoryPage: annual table with month click → dashboard, LineChart revenues/expenses - CategoriesPage: list by type with create/edit/delete (was missing from Phase 2) - TransactionsPage: added CSV/PDF export buttons - App.tsx: full routing with ProtectedRoute + Layout for all authenticated pages - New hooks: useDashboard, useBudgets (with mutations), useHistory - API types + client updated for all new endpoints Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
56 lines
1.6 KiB
Python
56 lines
1.6 KiB
Python
from collections.abc import AsyncIterator
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
from app.auth.router import router as auth_router
|
|
from app.config import settings
|
|
from app.database import engine
|
|
from app.routers.budgets import router as budgets_router
|
|
from app.routers.categories import router as categories_router
|
|
from app.routers.dashboard import router as dashboard_router
|
|
from app.routers.export import router as export_router
|
|
from app.routers.history import router as history_router
|
|
from app.routers.transactions import router as transactions_router
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
|
|
yield
|
|
await engine.dispose()
|
|
|
|
|
|
def create_app() -> FastAPI:
|
|
app = FastAPI(
|
|
title="Budget Tracker API",
|
|
version="0.1.0",
|
|
lifespan=lifespan,
|
|
)
|
|
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=settings.CORS_ORIGINS,
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
@app.get("/health")
|
|
async def health_check() -> dict[str, str]:
|
|
return {"status": "ok"}
|
|
|
|
api_prefix = "/api/v1"
|
|
app.include_router(auth_router, prefix=api_prefix)
|
|
app.include_router(transactions_router, prefix=api_prefix)
|
|
app.include_router(categories_router, prefix=api_prefix)
|
|
app.include_router(dashboard_router, prefix=api_prefix)
|
|
app.include_router(budgets_router, prefix=api_prefix)
|
|
app.include_router(history_router, prefix=api_prefix)
|
|
app.include_router(export_router, prefix=api_prefix)
|
|
|
|
return app
|
|
|
|
|
|
app = create_app()
|