v1.5.0: IRM — инциденты, задачи, эскалации

- docs/IRM.md; Alembic 002: incidents, tasks, escalation_policies
- Модули incidents/tasks/escalations: API, UI, register_events(bus, pool)
- Авто-инцидент из alert.received; тесты test_irm_modules.py

Made-with: Cursor
This commit is contained in:
Alexandr
2026-04-03 09:03:16 +03:00
parent 0787745098
commit 89b5983526
20 changed files with 772 additions and 16 deletions

View File

@ -5,6 +5,7 @@
from __future__ import annotations
import asyncpg
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
@ -12,10 +13,18 @@ from fastapi import APIRouter
from starlette.requests import Request
from onguard24.domain.events import EventBus
from onguard24.modules import contacts, schedules, statusboard
from onguard24.modules import (
contacts,
escalations,
incidents,
schedules,
statusboard,
tasks,
)
# async (Request) -> str — фрагмент HTML для главной страницы (опционально)
HomeFragment = Callable[[Request], Awaitable[str]]
RegisterEvents = Callable[[EventBus, asyncpg.Pool | None], None]
@dataclass(frozen=True)
@ -24,7 +33,7 @@ class ModuleMount:
router: APIRouter
url_prefix: str
register_events: Callable[[EventBus], None]
register_events: RegisterEvents
slug: str
title: str
ui_router: APIRouter | None = None
@ -33,6 +42,33 @@ class ModuleMount:
def _mounts() -> list[ModuleMount]:
return [
ModuleMount(
router=incidents.router,
url_prefix="/api/v1/modules/incidents",
register_events=incidents.register_events,
slug="incidents",
title="Инциденты",
ui_router=incidents.ui_router,
render_home_fragment=incidents.render_home_fragment,
),
ModuleMount(
router=tasks.router,
url_prefix="/api/v1/modules/tasks",
register_events=tasks.register_events,
slug="tasks",
title="Задачи",
ui_router=tasks.ui_router,
render_home_fragment=tasks.render_home_fragment,
),
ModuleMount(
router=escalations.router,
url_prefix="/api/v1/modules/escalations",
register_events=escalations.register_events,
slug="escalations",
title="Эскалации",
ui_router=escalations.ui_router,
render_home_fragment=escalations.render_home_fragment,
),
ModuleMount(
router=schedules.router,
url_prefix="/api/v1/modules/schedules",
@ -66,6 +102,6 @@ def _mounts() -> list[ModuleMount]:
MODULE_MOUNTS: list[ModuleMount] = _mounts()
def register_module_events(bus: EventBus) -> None:
def register_module_events(bus: EventBus, pool: asyncpg.Pool | None = None) -> None:
for m in MODULE_MOUNTS:
m.register_events(bus)
m.register_events(bus, pool)