# Архитектура onGuard24 (для разработки и доработок) Цель продукта: **модульный монолит** в духе IRM — ядро + подключаемые области (дежурства, контакты, «светофор» по сервисам). Текущая версия — **каркас v1**: HTTP, БД, ingress Grafana, проверки интеграций. ## Дерево пакетов ``` onGuard24/ ├── onguard24/ │ ├── main.py # FastAPI app, lifespan, маршруты верхнего уровня │ ├── config.py # Settings: .env из корня репозитория (не от cwd) │ ├── db.py # asyncpg pool, миграция ingress_events │ ├── status_snapshot.py # Единый сборщик JSON для /api/v1/status │ ├── root_html.py # HTML главной страницы со статусами │ ├── vaultcheck.py # Vault /v1/sys/health │ ├── ingress/grafana.py # POST webhook Grafana → INSERT ingress_events │ ├── integrations/ │ │ ├── grafana_api.py # Grafana HTTP API (Bearer SA) │ │ └── forgejo_api.py # Forgejo/Gitea API (token + probe/fallback) │ └── modules/ # Заглушки: schedules, contacts, statusboard ├── web/ # Vite + React (опционально) ├── pyproject.toml ├── CHANGELOG.md └── docs/ ``` ## Поток данных (сейчас) 1. **Grafana** (отдельно настроенный contact point) шлёт **POST** на `/api/v1/ingress/grafana` → тело JSON пишется в **`ingress_events`**. 2. **Параллельно** Grafana может слать в Mattermost — это вне этого репозитория (конфиг Grafana). 3. **Статус страницы** не ходит в Grafana за алертами — только **проверка доступности API** (токен SA). ## Куда класть новый функционал | Задача | Место | |--------|--------| | Новый HTTP-роут модуля | `onguard24/modules/.py` + `include_router` в `main.py` | | Общая логика инцидентов / событий | позже: `onguard24/core/` или сервисный слой + события из БД | | Новая таблица БД | пока: SQL в `db.py` (MIGRATION_00N); позже: Alembic | | Новая внешняя интеграция | `onguard24/integrations/.py`, вызов из `status_snapshot` при необходимости | ## Конфигурация Все секреты только через **переменные окружения** / `.env` (файл **не в git**). Список ключей — `.env.example`. ## Зависимости между компонентами - `status_snapshot.build(request)` читает `request.app.state.pool` и `request.app.state.settings` (устанавливаются в `lifespan`). - Модули **не** зависят друг от друга; общий контракт позже можно ввести через **таблицы БД** и **внутренние события** (ещё не реализовано). ## Известные ограничения v1 - Нет единой модели «инцидент» в БД — только сырой ingest в `ingress_events`. - Нет очереди/воркеров для эскалаций. - Нет auth на GET `/api/v1/status` (только для внутренней сети / за reverse proxy с ограничением).