Files
lifetrack/apps/api/app/main.py
T
MeeJayandClaude Opus 5 93f0689c1e Initial import: LifeTrack v1 (santé, vape, finances)
Tracker de vie auto-hébergé : suivi poids/calories/sport avec planning de
pesées, sevrage tabac (vape) avec modèle de coût DIY et économies, et
finances personnelles avec import de relevés bancaires.

Architecture : FastAPI + SQLAlchemy 2.0 + PostgreSQL 16, React 18 + TS +
Vite + Tailwind + ECharts, déploiement Docker Compose. Modules
auto-découverts des deux côtés (pkgutil / import.meta.glob) et framework
de connecteurs à deux voies (importeurs de fichiers + ingestion JSON)
pour brancher de nouvelles sources sans toucher au noyau.

Validé : 292 tests pytest, tsc + vite build, contrat API/web vérifié
contre le schéma OpenAPI, et déploiement Docker réel sur PostgreSQL 16
(28 tables, SPA servie par nginx, wizard de premier démarrage).

Documentation : README.md, docs/GUIDE.md, CONVENTIONS.md, et les
documents de conception et de recherche dans docs/.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 10:48:57 +02:00

64 lines
1.9 KiB
Python

from contextlib import asynccontextmanager
from typing import Any
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from app.core.config import get_settings
from app.core.database import Base, engine
from app.core.errors import register_error_handlers
from app.core.module_loader import import_side_modules, register_routers
@asynccontextmanager
async def lifespan(app: FastAPI):
# Import every module's models/importers/ingest so that:
# - Base.metadata knows all tables before create_all
# - importer & ingest registries are populated (decorator side effects)
import_side_modules()
# v1 table-creation strategy: create_all on startup (Alembic later).
Base.metadata.create_all(bind=engine)
yield
def create_app() -> FastAPI:
settings = get_settings()
app = FastAPI(
title="LifeTrack API",
version="1.0.0",
docs_url="/api/docs",
redoc_url=None,
openapi_url="/api/openapi.json",
lifespan=lifespan,
)
if settings.cors_origins:
app.add_middleware(
CORSMiddleware,
allow_origins=settings.cors_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
register_error_handlers(app)
register_routers(app) # auto-discovery, see architecture §3.4
@app.get("/api/healthz", include_in_schema=False)
def healthz() -> dict[str, str]:
return {"status": "ok"}
# Bare aliases (no /api prefix) for container/orchestrator probes.
@app.get("/healthz", include_in_schema=False)
def healthz_alias() -> dict[str, str]:
return {"status": "ok"}
@app.get("/openapi.json", include_in_schema=False)
def openapi_alias() -> JSONResponse:
schema: dict[str, Any] = app.openapi()
return JSONResponse(schema)
return app
app = create_app()