from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from sqlalchemy import select from app.config import settings, validate_security_settings from app.database import engine, async_session from app.api import router as api_router from app.api import auth, users, customers, visits, work_plans, mini_business, mini_business_logs, key_visits from app.api import dashboard, upload, export, import_data, wecom, daily_notes, ai_summary, system_config, leaves, audit from app.models.system_config import SystemConfig from app.services.holidays import refresh_holidays from app.services.scheduler_manager import start_scheduler, shutdown_scheduler @asynccontextmanager async def lifespan(app: FastAPI): validate_security_settings() # Read notification_time from DB (or use default 17:30) notification_hour, notification_minute = 17, 30 async with async_session() as db: row = await db.get(SystemConfig, "notification_time") if row and row.value: try: parts = row.value.strip().split(":") notification_hour, notification_minute = int(parts[0]), int(parts[1]) except (ValueError, IndexError): pass # Auto-refresh Chinese holiday data from API on startup try: await refresh_holidays(db) except Exception: pass # Use cached data if API unavailable # Start daily reporting scheduler start_scheduler(notification_hour, notification_minute) yield # Shutdown shutdown_scheduler() await engine.dispose() app = FastAPI( title=settings.APP_NAME, version="0.1.0", lifespan=lifespan, ) # CORS app.add_middleware( CORSMiddleware, allow_origins=settings.CORS_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Mount all routers app.include_router(auth.router, prefix="/api") app.include_router(users.router, prefix="/api") app.include_router(customers.router, prefix="/api") app.include_router(visits.router, prefix="/api") app.include_router(work_plans.router, prefix="/api") app.include_router(mini_business.router, prefix="/api") app.include_router(mini_business_logs.router, prefix="/api") app.include_router(key_visits.router, prefix="/api") app.include_router(dashboard.router, prefix="/api") app.include_router(leaves.router, prefix="/api") app.include_router(upload.router, prefix="/api") app.include_router(export.router, prefix="/api") app.include_router(import_data.router, prefix="/api") app.include_router(wecom.router, prefix="/api") app.include_router(daily_notes.router, prefix="/api") app.include_router(ai_summary.router, prefix="/api") app.include_router(system_config.router, prefix="/api") app.include_router(audit.router, prefix="/api") @app.get("/health") async def health_check(): return {"status": "ok", "app": settings.APP_NAME}