import asyncio from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from config import settings from shared.firebase import init_firebase, firebase_initialized from auth.router import router as auth_router from melodies.router import router as melodies_router from devices.router import router as devices_router from settings.router import router as settings_router from users.router import router as users_router from mqtt.router import router as mqtt_router from mqtt.auth import router as mqtt_auth_router from equipment.router import router as equipment_router from staff.router import router as staff_router from helpdesk.router import router as helpdesk_router from builder.router import router as builder_router from manufacturing.router import router as manufacturing_router from firmware.router import router as firmware_router from admin.router import router as admin_router from crm.router import router as crm_products_router from crm.customers_router import router as crm_customers_router from crm.orders_router import router as crm_orders_router from crm.comms_router import router as crm_comms_router from crm.media_router import router as crm_media_router from crm.nextcloud_router import router as crm_nextcloud_router from crm.quotations_router import router as crm_quotations_router from crm.nextcloud import close_client as close_nextcloud_client, keepalive_ping as nextcloud_keepalive from crm.mail_accounts import get_mail_accounts from mqtt.client import mqtt_manager from mqtt import database as mqtt_db from melodies import service as melody_service app = FastAPI( title="BellSystems Admin Panel", version="0.1.0", docs_url="/api/docs", openapi_url="/api/openapi.json", ) app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(auth_router) app.include_router(melodies_router) app.include_router(devices_router) app.include_router(settings_router) app.include_router(users_router) app.include_router(mqtt_router) app.include_router(mqtt_auth_router) app.include_router(equipment_router) app.include_router(helpdesk_router) app.include_router(staff_router) app.include_router(builder_router) app.include_router(manufacturing_router) app.include_router(firmware_router) app.include_router(admin_router) app.include_router(crm_products_router) app.include_router(crm_customers_router) app.include_router(crm_orders_router) app.include_router(crm_comms_router) app.include_router(crm_media_router) app.include_router(crm_nextcloud_router) app.include_router(crm_quotations_router) async def nextcloud_keepalive_loop(): await nextcloud_keepalive() # eager warmup on startup while True: await asyncio.sleep(45) await nextcloud_keepalive() async def email_sync_loop(): while True: await asyncio.sleep(settings.email_sync_interval_minutes * 60) try: from crm.email_sync import sync_emails await sync_emails() except Exception as e: print(f"[EMAIL SYNC] Error: {e}") @app.on_event("startup") async def startup(): init_firebase() await mqtt_db.init_db() await melody_service.migrate_from_firestore() mqtt_manager.start(asyncio.get_event_loop()) asyncio.create_task(mqtt_db.purge_loop()) asyncio.create_task(nextcloud_keepalive_loop()) sync_accounts = [a for a in get_mail_accounts() if a.get("sync_inbound") and a.get("imap_host")] if sync_accounts: print(f"[EMAIL SYNC] IMAP configured for {len(sync_accounts)} account(s) - starting sync loop") asyncio.create_task(email_sync_loop()) else: print("[EMAIL SYNC] IMAP not configured - sync loop disabled") @app.on_event("shutdown") async def shutdown(): mqtt_manager.stop() await mqtt_db.close_db() await close_nextcloud_client() @app.get("/api/health") async def health_check(): return { "status": "ok", "firebase": firebase_initialized, "mqtt": mqtt_manager.connected, }