feat(admin): ingest аудита из apps и users 1:1 с Sheet журнала
Build and Push Auth Portal Docker Image / build-and-push (push) Successful in 1m46s
Build and Push Auth Portal Docker Image / create-release (push) Skipped

Добавлен 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:
Denozordec
2026-07-21 13:24:28 +07:00
co-authored by Cursor
parent 26fc8253c3
commit 57e34ff5e9
27 changed files with 1983 additions and 639 deletions
+63
View File
@@ -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`: 150 за запрос
- `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)
+4
View File
@@ -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`.
+4
View File
@@ -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
| Симптом | Причина |
+4
View File
@@ -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`).
+4
View File
@@ -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
| Симптом | Причина |