# services/sales/app/main.py """ Sales Service Main Application """ from fastapi import FastAPI from sqlalchemy import text from app.core.config import settings from app.core.database import database_manager from shared.service_base import StandardFastAPIService # Import API routers from app.api import sales_records, sales_operations, analytics, internal_demo, audit class SalesService(StandardFastAPIService): """Sales Service with standardized setup""" expected_migration_version = "00001" async def on_startup(self, app): """Custom startup logic including migration verification""" await self.verify_migrations() await super().on_startup(app) async def verify_migrations(self): """Verify database schema matches the latest migrations.""" try: async with self.database_manager.get_session() as session: result = await session.execute(text("SELECT version_num FROM alembic_version")) version = result.scalar() if version != self.expected_migration_version: self.logger.error(f"Migration version mismatch: expected {self.expected_migration_version}, got {version}") raise RuntimeError(f"Migration version mismatch: expected {self.expected_migration_version}, got {version}") self.logger.info(f"Migration verification successful: {version}") except Exception as e: self.logger.error(f"Migration verification failed: {e}") raise def __init__(self): # Define expected database tables for health checks sales_expected_tables = ['sales_data', 'sales_import_jobs'] super().__init__( service_name="sales-service", app_name="Bakery Sales Service", description="Sales data management service for bakery operations", version="1.0.0", log_level=settings.LOG_LEVEL, cors_origins=settings.CORS_ORIGINS, api_prefix="", # Empty because RouteBuilder already includes /api/v1 database_manager=database_manager, expected_tables=sales_expected_tables ) async def on_startup(self, app: FastAPI): """Custom startup logic for sales service""" # Register custom metrics self.register_custom_metrics({ "sales_records_created_total": { "type": "counter", "description": "Total sales records created" }, "sales_records_updated_total": { "type": "counter", "description": "Total sales records updated" }, "sales_queries_total": { "type": "counter", "description": "Sales record queries" }, "product_queries_total": { "type": "counter", "description": "Product catalog queries" }, "import_jobs_total": { "type": "counter", "description": "Data import jobs" }, "export_jobs_total": { "type": "counter", "description": "Data export jobs" }, "sales_create_duration_seconds": { "type": "histogram", "description": "Sales record creation duration" }, "sales_query_duration_seconds": { "type": "histogram", "description": "Sales query duration" }, "import_processing_duration_seconds": { "type": "histogram", "description": "Import processing duration" }, "export_generation_duration_seconds": { "type": "histogram", "description": "Export generation duration" } }) async def on_shutdown(self, app: FastAPI): """Custom shutdown logic for sales service""" # Database cleanup is handled by the base class pass def get_service_features(self): """Return sales-specific features""" return [ "sales_data_management", "product_catalog", "data_import_export", "sales_analytics", "performance_tracking" ] def setup_custom_endpoints(self): """Setup custom endpoints for sales service""" @self.app.get("/") async def root(): """Root endpoint""" return { "service": "Sales Service", "version": "1.0.0", "status": "running", "endpoints": { "health": "/health", "docs": "/docs", "sales": "/api/v1/sales", "products": "/api/v1/products" } } # Create service instance service = SalesService() # Create FastAPI app with standardized setup app = service.create_app() # Setup standard endpoints service.setup_standard_endpoints() # Setup custom endpoints service.setup_custom_endpoints() # Include routers # IMPORTANT: Register audit router FIRST to avoid route matching conflicts service.add_router(audit.router) service.add_router(sales_records.router) service.add_router(sales_operations.router) service.add_router(analytics.router) service.add_router(internal_demo.router)