from __future__ import annotations from fastapi import APIRouter from govoplan_core.core.lifecycle import ModuleLifecycleManager from govoplan_core.core.module_management import load_startup_enabled_modules, startup_candidate_module_ids from govoplan_core.db.session import configure_database from govoplan_core.server.config import GovoplanServerConfig, load_server_config from govoplan_core.server.fastapi import create_govoplan_app from govoplan_core.server.platform import create_platform_router from govoplan_core.server.credentials import router as credential_router from govoplan_core.server.registry import available_module_manifests, build_platform_registry from govoplan_core.server.route_validation import validate_no_route_collisions def create_app(config: GovoplanServerConfig | str | None = None): server_config = _server_config(config) _configure_app_database(server_config) registry, available_modules = _server_module_registry(server_config) api_router = _server_api_router(server_config, registry) lifecycle = _server_lifecycle(server_config, registry=registry, available_modules=available_modules) lifecycle.configure_runtime() app = create_govoplan_app( title=server_config.title, version=server_config.version, registry=registry, api_router=api_router, lifespan=server_config.lifespan, cors_origins=server_config.cors_origins, ) lifecycle.attach_app(app) lifecycle.apply_enabled_modules(tuple(manifest.id for manifest in registry.manifests()), migrate=False) for configurator in server_config.app_configurators: configurator(app, registry, server_config.settings) return app def _server_config(config: GovoplanServerConfig | str | None) -> GovoplanServerConfig: if isinstance(config, str) or config is None: return load_server_config(config) return config def _configure_app_database(server_config: GovoplanServerConfig) -> None: database_url = getattr(server_config.settings, "database_url", None) if server_config.settings is not None else None if database_url: dispose_previous = getattr(server_config.settings, "app_env", None) == "test" configure_database(str(database_url), dispose_previous=dispose_previous) def _server_module_registry(server_config: GovoplanServerConfig): raw_enabled_modules = load_startup_enabled_modules(server_config.enabled_modules) candidate_modules = startup_candidate_module_ids(server_config.enabled_modules, raw_enabled_modules) startup_available_modules = available_module_manifests( server_config.manifest_factories, enabled_modules=candidate_modules, ignore_load_errors=True, ) available_modules = available_module_manifests(server_config.manifest_factories, ignore_load_errors=True) enabled_modules = load_startup_enabled_modules(server_config.enabled_modules, available=startup_available_modules) registry = build_platform_registry(enabled_modules, manifest_factories=server_config.manifest_factories) return registry, available_modules def _server_api_router(server_config: GovoplanServerConfig, registry) -> APIRouter: api_router = APIRouter(prefix=server_config.api_prefix) for router in server_config.base_routers: api_router.include_router(router) api_router.include_router(create_platform_router(settings=server_config.settings)) api_router.include_router(credential_router) for router in server_config.post_module_routers: api_router.include_router(router) for contribution in server_config.extra_routers: if contribution.should_include(server_config.settings, registry): api_router.include_router(contribution.router) validate_no_route_collisions(api_router, owner="server startup routes") return api_router def _server_lifecycle( server_config: GovoplanServerConfig, *, registry, available_modules, ) -> ModuleLifecycleManager: return ModuleLifecycleManager( registry=registry, available_modules=available_modules, settings=server_config.settings, api_prefix=server_config.api_prefix, manifest_factories=tuple(server_config.manifest_factories), module_context_data=server_config.module_context_data, ) app = create_app()