| | """ |
| | FastAPI application main entry point. |
| | |
| | Configures the FastAPI app with CORS middleware, routes, and middleware. |
| | """ |
| | from contextlib import asynccontextmanager |
| | from typing import AsyncGenerator |
| |
|
| | from fastapi import FastAPI, Request |
| | from fastapi.middleware.cors import CORSMiddleware |
| | from fastapi.responses import JSONResponse |
| |
|
| | from src.core.config import settings |
| | from src.core.database import DatabaseManager, init_db |
| |
|
| |
|
| | @asynccontextmanager |
| | async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: |
| | """ |
| | Lifespan context manager for FastAPI app. |
| | |
| | Handles startup and shutdown events. |
| | """ |
| | |
| | scheduler = None |
| |
|
| | |
| | print(f"Starting Todo App API") |
| | print(f"Environment: {settings.env}") |
| | print(f"Database: {settings.database_url.split('@')[-1]}") |
| |
|
| | |
| | |
| | if settings.is_development: |
| | init_db() |
| | print("Database initialized") |
| |
|
| | |
| | if settings.gmail_email and settings.gmail_app_password: |
| | try: |
| | from apscheduler.schedulers.asyncio import AsyncIOScheduler |
| | from src.services.reminder_service import check_and_send_reminders |
| | from src.core.database import get_session |
| |
|
| | scheduler = AsyncIOScheduler() |
| |
|
| | |
| | def run_reminder_check(): |
| | """Wrapper to get fresh session for each check.""" |
| | session = next(get_session()) |
| | try: |
| | check_and_send_reminders(session) |
| | finally: |
| | session.close() |
| |
|
| | scheduler.add_job( |
| | run_reminder_check, |
| | 'interval', |
| | hours=1, |
| | id='reminder_checker', |
| | name='Check and send task reminders' |
| | ) |
| | scheduler.start() |
| | print("✅ Reminder scheduler started (runs every hour)") |
| | except Exception as e: |
| | print(f"⚠️ Failed to start reminder scheduler: {e}") |
| | else: |
| | print("⚠️ Reminder scheduler disabled (Gmail not configured)") |
| |
|
| | yield |
| |
|
| | |
| | if scheduler: |
| | scheduler.shutdown() |
| | print("Reminder scheduler stopped") |
| | print("Shutting down Todo App API") |
| |
|
| |
|
| | |
| | app = FastAPI( |
| | title='Todo App API', |
| | description='Premium Todo SaaS Application API', |
| | version='0.1.0', |
| | docs_url='/docs', |
| | redoc_url='/redoc', |
| | lifespan=lifespan, |
| | ) |
| |
|
| |
|
| | |
| | app.add_middleware( |
| | CORSMiddleware, |
| | allow_origins=settings.cors_origins, |
| | allow_credentials=True, |
| | allow_methods=['*'], |
| | allow_headers=['*'], |
| | ) |
| |
|
| |
|
| | |
| | @app.exception_handler(Exception) |
| | async def global_exception_handler(request: Request, exc: Exception): |
| | """Handle all unhandled exceptions.""" |
| | print(f"Unhandled exception: {exc}") |
| | return JSONResponse( |
| | status_code=500, |
| | content={ |
| | 'detail': 'Internal server error', |
| | 'message': str(exc) if settings.is_development else 'An error occurred', |
| | }, |
| | ) |
| |
|
| |
|
| | |
| | @app.get('/health', tags=['Health']) |
| | async def health_check(): |
| | """ |
| | Health check endpoint. |
| | |
| | Returns API status and database connection status. |
| | """ |
| | db_connected = DatabaseManager.check_connection() |
| |
|
| | return { |
| | 'status': 'healthy', |
| | 'api': 'Todo App API', |
| | 'version': '0.1.0', |
| | 'environment': settings.env, |
| | 'database': 'connected' if db_connected else 'disconnected', |
| | } |
| |
|
| |
|
| | |
| | @app.get('/', tags=['Root']) |
| | async def root(): |
| | """ |
| | Root endpoint with API information. |
| | """ |
| | return { |
| | 'message': 'Welcome to Todo App API', |
| | 'version': '0.1.0', |
| | 'docs': '/docs', |
| | 'health': '/health', |
| | } |
| |
|
| |
|
| | |
| | from src.api import auth, todos, users, ai, chat |
| |
|
| | app.include_router(auth.router, prefix='/api/auth', tags=['Authentication']) |
| | app.include_router(todos.router, prefix='/api/todos', tags=['Todos']) |
| | app.include_router(users.router, prefix='/api/users', tags=['Users']) |
| | app.include_router(ai.router, prefix='/api/ai', tags=['AI']) |
| | |
| | app.include_router(chat.router, tags=['AI Chat']) |
| |
|
| |
|
| | if __name__ == '__main__': |
| | import uvicorn |
| |
|
| | uvicorn.run( |
| | 'src.main:app', |
| | host='0.0.0.0', |
| | port=settings.port, |
| | reload=settings.is_development, |
| | ) |
| |
|