# Copyright (c) 2026 Krzysztof Rudnicki. MIT licence. """The management application, assembled. A second process rather than more routes on the bot's own app. Two reasons, and both are about blast radius: this one can rewrite ``.env``, and the bot's port already serves ``/_selftest``, which posts for real into a real group. Keeping them apart means the surface that can reconfigure the bot is only listening while somebody has the page open. Order is load-bearing. The guard goes on first so it sees every request; the API routers are registered next; the static catch-all is registered last, because ``/{path:path}`` would otherwise shadow every route after it. """ from __future__ import annotations from typing import TYPE_CHECKING from fastapi import FastAPI from signal_bot.manage import ( assets, guard, routes_actions, routes_album, routes_aliases, routes_analytics, routes_commands, routes_env, routes_status, routes_suggestions, ) if TYPE_CHECKING: from signal_bot.manage.deps import ManageDeps DEFAULT_CONTAINER = "signal-api" def build_app(deps: ManageDeps, *, container: str = DEFAULT_CONTAINER) -> FastAPI: """The whole page, bound to one bot and one album. Args: deps: Everything the app is pointed at. container: The docker container signal-cli runs in. Returns: An application ready for uvicorn, or for a test client. """ app = FastAPI(title="signal-bot", docs_url=None, redoc_url=None, openapi_url=None) guard.install(app, deps.port) app.include_router(routes_status.router(deps)) app.include_router(routes_env.router(deps)) app.include_router(routes_actions.router(deps, container)) app.include_router(routes_album.router(deps)) app.include_router(routes_suggestions.router(deps)) app.include_router(routes_analytics.router(deps)) app.include_router(routes_commands.router(deps)) app.include_router(routes_aliases.router(deps)) assets.install(app, deps.dist_dir) return app