"""Единая точка регистрации модулей: API, веб-UI и подписки на события. Новый модуль: файл в `onguard24/modules/`, запись в `MODULE_MOUNTS` — см. docs/MODULES.md. """ from __future__ import annotations from collections.abc import Awaitable, Callable from dataclasses import dataclass from fastapi import APIRouter from starlette.requests import Request from onguard24.domain.events import EventBus from onguard24.modules import contacts, schedules, statusboard # async (Request) -> str — фрагмент HTML для главной страницы (опционально) HomeFragment = Callable[[Request], Awaitable[str]] @dataclass(frozen=True) class ModuleMount: """Один модуль: API под url_prefix, UI под /ui/modules/{slug}.""" router: APIRouter url_prefix: str register_events: Callable[[EventBus], None] slug: str title: str ui_router: APIRouter | None = None render_home_fragment: HomeFragment | None = None def _mounts() -> list[ModuleMount]: return [ ModuleMount( router=schedules.router, url_prefix="/api/v1/modules/schedules", register_events=schedules.register_events, slug="schedules", title="Календарь дежурств", ui_router=schedules.ui_router, render_home_fragment=schedules.render_home_fragment, ), ModuleMount( router=contacts.router, url_prefix="/api/v1/modules/contacts", register_events=contacts.register_events, slug="contacts", title="Контакты", ui_router=contacts.ui_router, render_home_fragment=contacts.render_home_fragment, ), ModuleMount( router=statusboard.router, url_prefix="/api/v1/modules/statusboard", register_events=statusboard.register_events, slug="statusboard", title="Светофор", ui_router=statusboard.ui_router, render_home_fragment=statusboard.render_home_fragment, ), ] MODULE_MOUNTS: list[ModuleMount] = _mounts() def register_module_events(bus: EventBus) -> None: for m in MODULE_MOUNTS: m.register_events(bus)