""" Authentication 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 app.api import auth_operations, users, onboarding_progress, consent, data_export, account_deletion from app.services.messaging import setup_messaging, cleanup_messaging from shared.service_base import StandardFastAPIService class AuthService(StandardFastAPIService): """Authentication Service with standardized setup""" 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: # Check if alembic_version table exists result = await session.execute(text(""" SELECT EXISTS ( SELECT FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'alembic_version' ) """)) table_exists = result.scalar() if table_exists: # If table exists, check the version result = await session.execute(text("SELECT version_num FROM alembic_version")) version = result.scalar() self.logger.info(f"Migration verification successful: {version}") else: # If table doesn't exist, migrations might not have run yet # This is OK - the migration job should create it self.logger.warning("alembic_version table does not exist yet - migrations may not have run") except Exception as e: self.logger.warning(f"Migration verification failed (this may be expected during initial setup): {e}") def __init__(self): # Define expected database tables for health checks auth_expected_tables = [ 'users', 'refresh_tokens', 'user_onboarding_progress', 'user_onboarding_summary', 'login_attempts', 'user_consents', 'consent_history', 'audit_logs' ] # Define custom metrics for auth service auth_custom_metrics = { "registration_total": { "type": "counter", "description": "Total user registrations by status", "labels": ["status"] }, "login_success_total": { "type": "counter", "description": "Total successful user logins" }, "login_failure_total": { "type": "counter", "description": "Total failed user logins by reason", "labels": ["reason"] }, "token_refresh_total": { "type": "counter", "description": "Total token refreshes by status", "labels": ["status"] }, "token_verify_total": { "type": "counter", "description": "Total token verifications by status", "labels": ["status"] }, "logout_total": { "type": "counter", "description": "Total user logouts by status", "labels": ["status"] }, "registration_duration_seconds": { "type": "histogram", "description": "Registration request duration" }, "login_duration_seconds": { "type": "histogram", "description": "Login request duration" }, "token_refresh_duration_seconds": { "type": "histogram", "description": "Token refresh duration" } } super().__init__( service_name="auth-service", app_name="Authentication Service", description="Handles user authentication and authorization for bakery forecasting platform", version="1.0.0", log_level=settings.LOG_LEVEL, api_prefix="", # Empty because RouteBuilder already includes /api/v1 database_manager=database_manager, expected_tables=auth_expected_tables, enable_messaging=True, custom_metrics=auth_custom_metrics ) async def _setup_messaging(self): """Setup messaging for auth service""" await setup_messaging() self.logger.info("Messaging setup complete") async def _cleanup_messaging(self): """Cleanup messaging for auth service""" await cleanup_messaging() async def on_shutdown(self, app: FastAPI): """Custom shutdown logic for auth service""" self.logger.info("Authentication Service shutdown complete") def get_service_features(self): """Return auth-specific features""" return [ "user_authentication", "token_management", "user_onboarding", "role_based_access", "messaging_integration" ] # Create service instance service = AuthService() # Create FastAPI app with standardized setup app = service.create_app( docs_url="/docs", redoc_url="/redoc" ) # Setup standard endpoints service.setup_standard_endpoints() # Include routers with specific configurations # Note: Routes now use RouteBuilder which includes full paths, so no prefix needed service.add_router(auth_operations.router, tags=["authentication"]) service.add_router(users.router, tags=["users"]) service.add_router(onboarding_progress.router, tags=["onboarding"]) service.add_router(consent.router, tags=["gdpr", "consent"]) service.add_router(data_export.router, tags=["gdpr", "data-export"]) service.add_router(account_deletion.router, tags=["gdpr", "account-deletion"])