feat(admin): ingest аудита из apps и users 1:1 с Sheet журнала
Добавлен POST /api/v1/ingest/audit, фильтры source_app/user_id, last_login_at; таблица пользователей по solution-users-1 с журналом в Sheet. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
# Audit ingest — интеграция приложений с Auth Portal
|
||||
|
||||
Центральный журнал: `GET /api/v1/admin/audit` (только admin).
|
||||
Приложения пишут **локально** и дублируют события в portal.
|
||||
|
||||
## Endpoint
|
||||
|
||||
```
|
||||
POST /api/v1/ingest/audit
|
||||
Authorization: Bearer <AUDIT_INGEST_SECRET>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
### Body
|
||||
|
||||
```json
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"event_id": "uuid-unique-per-event",
|
||||
"source_app": "vps",
|
||||
"action": "vps.vps.create",
|
||||
"severity": "info",
|
||||
"actor_user_id": "…",
|
||||
"actor_email": "[email protected]",
|
||||
"actor_name": "Name",
|
||||
"target_type": "app_resource",
|
||||
"target_id": "entity-id",
|
||||
"summary": "Человекочитаемое описание",
|
||||
"details": { "entity": "vps", "diff": {} },
|
||||
"ip": "1.2.3.4",
|
||||
"created_at": "2026-07-21T00:00:00.000Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- `events`: 1–50 за запрос
|
||||
- `source_app`: `vps` | `cfdm` | `bgp` | `fw` (не `portal`)
|
||||
- `event_id`: идемпотентность (дубликаты → `duplicates++`)
|
||||
- Ответ: `{ "accepted": N, "duplicates": M }`
|
||||
|
||||
## Env
|
||||
|
||||
| Где | Переменная |
|
||||
|-----|------------|
|
||||
| auth-portal | `AUDIT_INGEST_SECRET` |
|
||||
| apps (vps / cfdm / bgp / fw) | `AUTH_PORTAL_URL` + `AUTH_AUDIT_INGEST_SECRET` (тот же секрет) |
|
||||
|
||||
Dev default secret: `dev-audit-ingest-secret`.
|
||||
|
||||
## Dual-write
|
||||
|
||||
1. Записать в локальный `audit_log`
|
||||
2. Fire-and-forget `POST` в portal (timeout ~2s)
|
||||
3. Ошибка push **не** должна ломать CRUD
|
||||
|
||||
## Фильтры admin UI
|
||||
|
||||
- `/admin/audit` — source_app + type tabs + range
|
||||
- Клик по пользователю на `/admin` — Sheet с событиями, где `actor_user_id` или `target_id` = user id
|
||||
|
||||
Preview: [solution-users-1](https://reui.io/preview/base/solution-users-1) · [solution-users-6](https://reui.io/preview/base/solution-users-6)
|
||||
@@ -100,6 +100,10 @@ pnpm --filter web dev
|
||||
|
||||
`CURRENT_APP_ID = cfdm`. Если в JWT есть `apps[]` — в меню только пересечение с каталогом.
|
||||
|
||||
## Audit ingest
|
||||
|
||||
Dual-write локального журнала в portal: [`integrate-audit-ingest.md`](./integrate-audit-ingest.md) (`source_app: cfdm`).
|
||||
|
||||
## UI аккаунта
|
||||
|
||||
SidebarFooter → **NavUser** ([app-shell-1](https://reui.io/preview/base/app-shell-1)): Настройки, Тема, Выйти → `AUTH_PORTAL_URL/logout`.
|
||||
|
||||
@@ -89,6 +89,10 @@ VITE_AUTH_PORTAL_URL=http://localhost:5175
|
||||
|
||||
Очистить локальный JWT → `AUTH_PORTAL_URL/logout` (не `/?return_to=`).
|
||||
|
||||
## Audit ingest
|
||||
|
||||
Dual-write локального журнала в portal: [`integrate-audit-ingest.md`](./integrate-audit-ingest.md) (`source_app: bgp`).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Симптом | Причина |
|
||||
|
||||
@@ -24,3 +24,7 @@ App id: **`fw`**.
|
||||
## App env
|
||||
|
||||
См. EvoFirewall `docs/integrate-auth-portal.md`.
|
||||
|
||||
## Audit ingest
|
||||
|
||||
Dual-write локального журнала в portal: [`integrate-audit-ingest.md`](./integrate-audit-ingest.md) (`source_app: fw`).
|
||||
|
||||
@@ -107,6 +107,10 @@ pnpm --filter web dev # :5173
|
||||
|
||||
`CURRENT_APP_ID = vps`. Фильтр меню по JWT `apps[]` при наличии claims.
|
||||
|
||||
## Audit ingest
|
||||
|
||||
Dual-write локального журнала в portal: [`integrate-audit-ingest.md`](./integrate-audit-ingest.md) (`source_app: vps`).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Симптом | Причина |
|
||||
|
||||
Reference in New Issue
Block a user