""" BMC Hub - FastAPI Application Main application entry point """ import logging from pathlib import Path from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi.responses import RedirectResponse from contextlib import asynccontextmanager from app.core.config import settings from app.core.database import init_db def get_version(): """Read version from VERSION file""" try: version_file = Path(__file__).parent / "VERSION" return version_file.read_text().strip() except Exception: return "unknown" # Import Feature Routers from app.customers.backend import router as customers_api from app.customers.backend import views as customers_views from app.customers.backend import bmc_office_router from app.hardware.backend import router as hardware_api from app.billing.backend import router as billing_api from app.billing.frontend import views as billing_views from app.system.backend import router as system_api from app.system.backend import sync_router from app.dashboard.backend import views as dashboard_views from app.prepaid.backend import router as prepaid_api from app.prepaid.backend import views as prepaid_views from app.ticket.backend import router as ticket_api from app.ticket.frontend import views as ticket_views from app.vendors.backend import router as vendors_api from app.vendors.backend import views as vendors_views from app.timetracking.backend import router as timetracking_api from app.timetracking.frontend import views as timetracking_views from app.contacts.backend import views as contacts_views from app.contacts.backend import router_simple as contacts_api from app.tags.backend import router as tags_api from app.tags.backend import views as tags_views from app.emails.backend import router as emails_api from app.emails.frontend import views as emails_views from app.settings.backend import router as settings_api from app.settings.backend import views as settings_views from app.backups.backend.router import router as backups_api from app.backups.frontend import views as backups_views # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.StreamHandler(), logging.FileHandler('logs/app.log') ] ) logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): """Lifecycle management - startup and shutdown""" # Startup logger.info("🚀 Starting BMC Hub...") logger.info(f"Database: {settings.DATABASE_URL}") init_db() logger.info("✅ System initialized successfully") yield # Shutdown logger.info("👋 Shutting down...") # Create FastAPI app app = FastAPI( title="BMC Hub API", description=""" Central management system for BMC Networks. **Key Features:** - Customer management - Hardware tracking - Service management - Billing integration """, version="1.0.0", lifespan=lifespan, docs_url="/api/docs", redoc_url="/api/redoc", openapi_url="/api/openapi.json" ) # CORS middleware - use CORS_ORIGINS if set, otherwise fallback to ALLOWED_ORIGINS cors_origins = settings.CORS_ORIGINS.split(",") if settings.CORS_ORIGINS else settings.ALLOWED_ORIGINS app.add_middleware( CORSMiddleware, allow_origins=cors_origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Include routers app.include_router(customers_api.router, prefix="/api/v1", tags=["Customers"]) app.include_router(bmc_office_router.router, prefix="/api/v1", tags=["BMC Office"]) app.include_router(hardware_api.router, prefix="/api/v1", tags=["Hardware"]) app.include_router(billing_api.router, prefix="/api/v1", tags=["Billing"]) app.include_router(system_api.router, prefix="/api/v1", tags=["System"]) app.include_router(sync_router.router, prefix="/api/v1/system", tags=["System Sync"]) app.include_router(prepaid_api.router, prefix="/api/v1", tags=["Prepaid Cards"]) app.include_router(ticket_api.router, prefix="/api/v1/ticket", tags=["Tickets"]) app.include_router(vendors_api.router, prefix="/api/v1", tags=["Vendors"]) app.include_router(contacts_api.router, prefix="/api/v1", tags=["Contacts"]) app.include_router(timetracking_api, prefix="/api/v1", tags=["Time Tracking"]) app.include_router(tags_api.router, prefix="/api/v1", tags=["Tags"]) app.include_router(emails_api.router, prefix="/api/v1", tags=["Emails"]) app.include_router(settings_api.router, prefix="/api/v1", tags=["Settings"]) app.include_router(backups_api, prefix="/api/v1", tags=["Backups"]) # Frontend Routers app.include_router(dashboard_views.router, tags=["Frontend"]) app.include_router(customers_views.router, tags=["Frontend"]) app.include_router(prepaid_views.router, tags=["Frontend"]) app.include_router(vendors_views.router, tags=["Frontend"]) app.include_router(timetracking_views.router, tags=["Frontend"]) app.include_router(billing_views.router, tags=["Frontend"]) app.include_router(ticket_views.router, prefix="/ticket", tags=["Frontend"]) app.include_router(contacts_views.router, tags=["Frontend"]) app.include_router(tags_views.router, tags=["Frontend"]) app.include_router(settings_views.router, tags=["Frontend"]) app.include_router(emails_views.router, tags=["Frontend"]) app.include_router(backups_views.router, tags=["Frontend"]) # Serve static files (UI) app.mount("/static", StaticFiles(directory="static", html=True), name="static") @app.get("/health") async def health_check(): """Health check endpoint""" return { "status": "healthy", "service": "BMC Hub", "version": get_version() } if __name__ == "__main__": import uvicorn import os # Only enable reload in local development (not in Docker) enable_reload = os.getenv("ENABLE_RELOAD", "false").lower() == "true" if enable_reload: uvicorn.run( "main:app", host="0.0.0.0", port=8000, reload=True, reload_includes=["*.py"], reload_dirs=["app"], reload_excludes=[".git/*", "*.pyc", "__pycache__/*", "logs/*", "uploads/*", "data/*"], log_level="info" ) else: uvicorn.run( "main:app", host="0.0.0.0", port=8000, reload=False )