from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from contextlib import asynccontextmanager from apscheduler.schedulers.asyncio import AsyncIOScheduler from app.database import engine from app.routers import auth, todos, events, calendars, reminders, projects, people, locations, settings as settings_router, dashboard, weather, event_templates from app.jobs.notifications import run_notification_dispatch @asynccontextmanager async def lifespan(app: FastAPI): scheduler = AsyncIOScheduler() scheduler.add_job( run_notification_dispatch, "interval", minutes=1, id="ntfy_dispatch", max_instances=1, # prevent overlap if a run takes longer than 60s ) scheduler.start() yield scheduler.shutdown(wait=False) await engine.dispose() app = FastAPI( title="UMBRA API", description="Backend API for UMBRA application", version="1.0.0", lifespan=lifespan ) # CORS configuration for development app.add_middleware( CORSMiddleware, allow_origins=["http://localhost:5173"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Include routers with /api prefix app.include_router(auth.router, prefix="/api/auth", tags=["Authentication"]) app.include_router(todos.router, prefix="/api/todos", tags=["Todos"]) app.include_router(events.router, prefix="/api/events", tags=["Calendar Events"]) app.include_router(calendars.router, prefix="/api/calendars", tags=["Calendars"]) app.include_router(reminders.router, prefix="/api/reminders", tags=["Reminders"]) app.include_router(projects.router, prefix="/api/projects", tags=["Projects"]) app.include_router(people.router, prefix="/api/people", tags=["People"]) app.include_router(locations.router, prefix="/api/locations", tags=["Locations"]) app.include_router(settings_router.router, prefix="/api/settings", tags=["Settings"]) app.include_router(dashboard.router, prefix="/api", tags=["Dashboard"]) app.include_router(weather.router, prefix="/api/weather", tags=["Weather"]) app.include_router(event_templates.router, prefix="/api/event-templates", tags=["Event Templates"]) @app.get("/") async def root(): return {"message": "UMBRA API is running"} @app.get("/health") async def health_check(): return {"status": "healthy"}