Files
k1nq d582f15681 feat: add tests for import polling, login page, money utilities, and query keys
- Implemented tests for import polling functionality, ensuring correct behavior for active and terminal import statuses.
- Created tests for the login page, validating user interactions and error handling.
- Added unit tests for money utility functions, covering parsing, formatting, and summation of monetary values.
- Developed tests for query keys, ensuring proper scoping and invalidation roots.

chore: setup testing environment and configuration

- Added setup file for testing with Vitest and Testing Library.
- Configured TypeScript and Vite for the frontend project.
- Created Docker and Nginx configurations for local development and production environments.
- Established a PostgreSQL initialization script for setting up application roles.

docs: add README and environment configuration for infra

- Included README for the infra directory, detailing local development setup and service descriptions.
- Created an example environment configuration file for local development with placeholders for sensitive information.
2026-09-14 09:26:33 +05:00

80 lines
2.4 KiB
Python

from collections.abc import Awaitable, Callable
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from sqlalchemy import text
from sqlalchemy.orm.exc import StaleDataError
from app.analytics.router import router as analytics_router
from app.budgeting.router import router as budgeting_router
from app.db.session import get_engine
from app.errors import AppError
from app.exports.router import router as exports_router
from app.identity.router import router as identity_router
from app.imports.router import router as imports_router
from app.ledger.router import router as ledger_router
from app.spaces.router import router as spaces_router
app = FastAPI(
title="Finance Tracker API",
version="0.1.0",
docs_url="/api/docs",
openapi_url="/api/v1/openapi.json",
)
@app.exception_handler(AppError)
async def app_error_handler(_request: Request, exc: AppError) -> JSONResponse:
return JSONResponse(
status_code=exc.status_code,
content={"error": {"code": exc.code, "message": exc.message, "details": exc.details}},
)
@app.exception_handler(StaleDataError)
async def stale_data_handler(_request: Request, _exc: StaleDataError) -> JSONResponse:
return JSONResponse(
status_code=409,
content={"error": {"code": "VERSION_CONFLICT", "message": "Resource changed"}},
)
@app.middleware("http")
async def security_headers(request: Request, call_next: Callable[[Request], Awaitable]):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["Referrer-Policy"] = "no-referrer"
response.headers["Permissions-Policy"] = "camera=(), microphone=(), geolocation=()"
response.headers["Content-Security-Policy"] = "default-src 'none'; frame-ancestors 'none'"
return response
@app.get("/health")
def health() -> dict:
return {"status": "ok"}
@app.get("/healthz", include_in_schema=False)
def healthz() -> dict:
return health()
@app.get("/ready")
def readiness() -> dict:
with get_engine().connect() as connection:
connection.execute(text("select 1"))
return {"status": "ready"}
for api_router in (
identity_router,
spaces_router,
ledger_router,
budgeting_router,
imports_router,
analytics_router,
exports_router,
):
app.include_router(api_router, prefix="/api/v1")