Реестр MODULE_MOUNTS: API, ui_router, фрагменты главной, EventBus. Главная и страницы модулей с правой навигацией из реестра; wrap_module_html_page. Ingress: публикация alert.received после сохранения в БД. Документация MODULES.md; pytest покрывает API, UI и навигацию. Made-with: Cursor
58 lines
4.6 KiB
Markdown
58 lines
4.6 KiB
Markdown
# Разработка функционала через модули
|
||
|
||
Цель: **новые возможности добавляются в `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/<slug>/`**, страница собирается через **`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/<slug>/`).
|
||
- Опционально **`async def render_home_fragment(request) -> str`** — HTML-фрагмент (без `<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/<slug>/`.
|
||
|
||
`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).
|