""" FastAPI application with integrated FileWatcher for document processing. This module provides the main FastAPI application with: - JWT authentication - User management APIs - Real-time file monitoring via FileWatcher - Document processing via Celery tasks """ import logging from contextlib import asynccontextmanager from typing import AsyncGenerator from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.api.routes.auth import router as auth_router from app.api.routes.users import router as users_router from app.config import settings from app.database.connection import get_database from app.file_watcher import create_file_watcher, FileWatcher from app.services.document_service import DocumentService from app.services.init_service import InitializationService from app.services.job_service import JobService from app.services.user_service import UserService # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Global file watcher instance file_watcher: FileWatcher = None @asynccontextmanager async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: """ FastAPI lifespan context manager. Handles application startup and shutdown events including: - Database connection - Default admin user creation - FileWatcher startup/shutdown """ global file_watcher # Startup logger.info("Starting MyDocManager application...") try: # Initialize database connection database = get_database() logger.info("Database connection established") document_service = DocumentService(database=database, objects_folder=settings.get_objects_folder()) job_service = JobService(database=database) user_service = UserService(database=database) logger.info("Service created") # Create default admin user init_service = InitializationService(user_service) init_service.initialize_application() logger.info("Default admin user initialization completed") # Create and start file watcher file_watcher = create_file_watcher( watch_directory=settings.get_watch_folder(), document_service=document_service, job_service=job_service ) file_watcher.start() logger.info(f"FileWatcher started for directory: {settings.get_watch_folder()}") logger.info("Application startup completed successfully") yield except Exception as e: logger.error(f"Application startup failed: {str(e)}") raise finally: # Shutdown logger.info("Shutting down MyDocManager application...") if file_watcher and file_watcher.is_running(): file_watcher.stop() logger.info("FileWatcher stopped") logger.info("Application shutdown completed") # Create FastAPI application app = FastAPI( title="MyDocManager", description="Real-time document processing application with authentication", version="0.1.0", lifespan=lifespan ) # Configure CORS app.add_middleware( CORSMiddleware, allow_origins=["http://localhost:5173", "http://localhost:5174"], # React frontend allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Include routers app.include_router(auth_router, prefix="/auth", tags=["Authentication"]) app.include_router(users_router, prefix="/users", tags=["User Management"]) # app.include_router(documents_router, prefix="/documents", tags=["Documents"]) # app.include_router(jobs_router, prefix="/jobs", tags=["Processing Jobs"]) @app.get("/health") async def health_check(): """ Health check endpoint. Returns: Dictionary containing application health status """ return { "status": "healthy", "service": "MyDocManager", "version": "1.0.0", "file_watcher_running": file_watcher.is_running() if file_watcher else False } @app.get("/") async def root(): """ Root endpoint with basic application information. Returns: Dictionary containing welcome message and available endpoints """ return { "message": "Welcome to MyDocManager", "description": "Real-time document processing application", "docs": "/docs", "health": "/health" } @app.get("/watcher/status") async def watcher_status(): """ Get file watcher status. Returns: Dictionary containing file watcher status information """ if not file_watcher: return { "status": "not_initialized", "running": False } return { "status": "initialized", "running": file_watcher.is_running(), "watch_directory": str(file_watcher.watch_directory), "recursive": file_watcher.recursive }