diff --git a/docs/agent-integration.md b/docs/agent-integration.md
index 06bc061..f2fda55 100644
--- a/docs/agent-integration.md
+++ b/docs/agent-integration.md
@@ -191,6 +191,15 @@ Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Telegram у ssh/RDP использует ту же подпись, что и `display_name`, когда параметр задан.
+### Версии агентов (единый номер)
+
+| Репозиторий | Источник версии | SAC `product_version` |
+|-------------|-----------------|------------------------|
+| **ssh-monitor** | `SSH_MONITOR_VERSION` в `ssh-monitor` + `version.txt` | из `SSH_MONITOR_VERSION` |
+| **RDP-login-monitor** | `$ScriptVersion` в `Login_Monitor.ps1` + `version.txt` | из `$ScriptVersion` |
+
+Не задавайте разные номера для «скрипта» и «SAC-модуля» — в UI **Хосты** отображается одна версия с ingest.
+
---
## 4. Поля `dedup_key` (рекомендации)
diff --git a/docs/testing-e2e-checklist.md b/docs/testing-e2e-checklist.md
new file mode 100644
index 0000000..9a192bc
--- /dev/null
+++ b/docs/testing-e2e-checklist.md
@@ -0,0 +1,55 @@
+# E2E и нагрузочное тестирование SAC + агенты
+
+Чеклист после freeze MVP (`work-plan.md`). Отмечайте дату и хост.
+
+## Дни 1–2: функциональный E2E
+
+### Linux (ssh-monitor, `UseSAC=dual` или `exclusive`)
+
+- [ ] `ssh-monitor --check-sac` → HTTP 201/202, событие `agent.test` в UI
+- [ ] Успешный SSH login → `ssh.login.success` в SAC + Telegram (dual)
+- [ ] Неудачный SSH → `ssh.login.failed`
+- [ ] `SERVER_DISPLAY_NAME` задан → в SAC **Хосты** отображается display name
+- [ ] Heartbeat → `agent.heartbeat`, хост не `stale` в пределах `SAC_HEARTBEAT_STALE_MINUTES`
+- [ ] Daily report → `report.daily.ssh` (если включён)
+
+### Windows (RDP-login-monitor, `UseSAC=dual`)
+
+- [ ] `-CheckSac` → ingest OK
+- [ ] Старт монитора → `agent.lifecycle` в SAC (HTTP 201), Telegram «ЗАПУЩЕН»
+- [ ] Версия в UI **Хосты** = `$ScriptVersion` после деплоя
+- [ ] `$ServerDisplayName` → display name в SAC
+- [ ] 4624/4625 (тестовый вход) → `rdp.login.*` при наличии событий
+- [ ] Dashboard: новое событие появляется в «Последние события» без F5 (~5 с)
+
+### SAC UI
+
+- [ ] Problems: open → ack → resolve
+- [ ] Дубликат `event_id` → HTTP 409, одна строка в БД
+- [ ] Правило brute-force (порог событий) → Problem
+
+## Дни 3–4: нагрузка и устойчивость
+
+- [ ] Пакет 50+ `ssh.login.failed` с одного IP → агрегация/Problem, без зависания UI
+- [ ] Повтор ingest с тем же `event_id` → 409
+- [ ] Остановка SAC API → spool на агенте, восстановление после `/health`
+- [ ] Flapping heartbeat: stale → warning в health / хостах
+
+## День 5: регресс
+
+- [ ] Обновление RDP через Deploy: одна версия в `deployed_version.txt`, ingest после 1.2.14+ JSON
+- [ ] `sac-retention.timer` active; ручной `systemctl start sac-retention.service` — exit 0
+- [ ] Известные issues занесены в issue tracker / `known-issues.md`
+
+## Дни 6–7: soak
+
+- [ ] 48–72 ч dual mode: нет роста spool без причины, диск БД в норме
+- [ ] Только bugfix по результатам выше
+
+## Версии на момент чеклиста
+
+| Компонент | Версия |
+|-----------|--------|
+| ssh-monitor | 1.2.6-SAC |
+| RDP-login-monitor | 1.2.15-SAC |
+| security-alert-center | см. `backend/app/version.py` |
diff --git a/docs/work-plan.md b/docs/work-plan.md
index 6df1303..effaca6 100644
--- a/docs/work-plan.md
+++ b/docs/work-plan.md
@@ -126,6 +126,8 @@
### Неделя после freeze (только тестирование)
+Чеклист: [testing-e2e-checklist.md](testing-e2e-checklist.md)
+
- [ ] `дни 1–2` функциональные E2E (`RDP + SSH + mixed load`)
- [ ] `дни 3–4` нагрузка, дубликаты, флаппинг heartbeat
- [ ] `день 5` регресс + known issues
diff --git a/frontend/src/style.css b/frontend/src/style.css
index c9d4ce6..0c7a211 100644
--- a/frontend/src/style.css
+++ b/frontend/src/style.css
@@ -18,9 +18,10 @@ a {
}
.layout {
- max-width: 1200px;
- margin: 0 auto;
- padding: 1rem 1.25rem 2rem;
+ width: 100%;
+ max-width: none;
+ margin: 0;
+ padding: 1rem 1rem 2rem;
}
nav {
@@ -59,6 +60,15 @@ th {
font-weight: 600;
}
+.th-sort {
+ background: transparent;
+ border: 0;
+ color: inherit;
+ padding: 0;
+ cursor: pointer;
+ font-weight: 600;
+}
+
.sev-critical,
.sev-high {
color: #ff6b6b;
diff --git a/frontend/src/views/EventDetailView.vue b/frontend/src/views/EventDetailView.vue
index adc266e..c717395 100644
--- a/frontend/src/views/EventDetailView.vue
+++ b/frontend/src/views/EventDetailView.vue
@@ -1,86 +1,177 @@
-
-
- {{ error }} Загрузка… {{ event.summary }}
+
+ {{ error }} Загрузка… {{ event.summary }}{{ event.title }}
-
-
-
- Отчёт
- details (JSON)
- {{ JSON.stringify(event.details, null, 2) }}
- details (JSON)
- {{ JSON.stringify(event.details, null, 2) }}
- payload (JSON)
- {{ JSON.stringify(event.payload, null, 2) }}
- {{ event.title }}
+
+
+
+
+
+
+
+ Отчёт
+
+ details (JSON)
+
+ {{ JSON.stringify(event.details, null, 2) }}
+
+ details (JSON)
+
+ {{ JSON.stringify(event.details, null, 2) }}
+
+ payload (JSON)
+
+ {{ JSON.stringify(event.payload, null, 2) }}
+
+
| ID | -Имя | -Hostname | -Product | -OS | -IPv4 | ++ | + | + | + | + | Агент | Heartbeat | -Отчёт | -Last seen | -Events | ++ | + | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {{ h.id }} | {{ h.display_name || "—" }} | {{ h.hostname }} | @@ -55,13 +55,25 @@