# Разработка функционала через модули Цель: **новые возможности добавляются в `onguard24/modules/`**, без правок «размазанных» по `main.py`, с явной подпиской на события и **своим веб-UI** (HTML и API в одном файле пакета). ## Что уже есть в ядре | Механизм | Назначение | |----------|------------| | **`modules/registry.py`** | Список `MODULE_MOUNTS`: API, метаданные UI, `register_events`. | | **`modules/ui_support.py`** | `safe_fragment` — безопасный вызов фрагмента главной: ошибка **одного** модуля не роняет `/`. | | **`app.state.event_bus`** | `InMemoryEventBus` — публикация после сохранения ingress (`alert.received`). | | **`domain/events.py`** | Имена событий, `AlertReceived`. | | **Ingress** | `INSERT … RETURNING id` → `publish_alert_received`. | ## Веб-UI: главная и полные страницы - **Главная `/`** автоматически подтягивает карточки из `MODULE_MOUNTS`: заголовок, превью (`render_home_fragment`), ссылка на полный UI. - **Правое меню («Разделы»)** строится из того же реестра: пункт **«Главная»** и по одному пункту на каждый модуль с **`ui_router`** (текст пункта = поле **`title`** в `ModuleMount`). Новый модуль с UI появляется в меню без правок шаблона — только запись в реестре. - **Полный интерфейс модуля** — **`/ui/modules//`**, страница собирается через **`wrap_module_html_page`** (`ui_support.py`): тот же каркас и правое меню, активный пункт подсвечивается (`current_slug`). - Всё, что относится к модулю (JSON API, HTML, события), живёт **в одном файле модуля** + строка в реестре. ### Изоляция сбоев - Ошибка в **`render_home_fragment`** перехватывается в **`safe_fragment`**: на главной показывается блок с классом `module-err`, остальные модули и таблица статусов отображаются. - Ошибка в обработчике **полной страницы** `/ui/modules/...` даёт 500 **только для этого запроса**; процесс и остальные маршруты продолжают работать. - Рекомендуется не полагаться на глобальное состояние между модулями; общение — через БД и `event_bus`. Фронт в **`web/`** (Vite) остаётся опциональным; серверный HTML — основной путь для встроенного UI. ## Добавить новый модуль (чеклист) 1. **Файл** `onguard24/modules/<имя>.py`: - `router` — JSON API под `/api/v1/modules/<имя>/`. - Опционально **`ui_router`** — `APIRouter(include_in_schema=False)`, маршруты полных HTML-страниц (корень `/` → `/ui/modules//`). - Опционально **`async def render_home_fragment(request) -> str`** — HTML-фрагмент (без ``) для карточки на главной. - **`register_events(_bus)`** — подписки на шину. 2. **Регистрация** в **`onguard24/modules/registry.py`** — объект **`ModuleMount`**: - `router`, `url_prefix`, `register_events`, **`slug`**, **`title`**, опционально **`ui_router`**, **`render_home_fragment`**. 3. **Миграции** — если нужны таблицы: `alembic revision`, `alembic upgrade head`. 4. **Тесты** — API, при необходимости GET `/` и `/ui/modules//`. `main.py` **не** меняется — только реестр. ## События - Из ingress публикуется **`alert.received`** (`AlertReceived`). - Обработчик: `async def h(event: DomainEvent) -> None`; удобно `isinstance(event, AlertReceived)`. ## Ограничения - Шина **in-process**; несколько воркеров — позже общая очередь. - Auth на модули пока нет — сеть / reverse proxy. См. [DOMAIN.md](DOMAIN.md), [ARCHITECTURE.md](ARCHITECTURE.md).