# Техническое задание: Браузерное расширение для записи сессий операторов
## Фаза 1 — Локальная запись + экспорт архива
 
---
 
## 1. Контекст и цель
 
Операторы работают в браузере и периодически совершают ошибки, причины которых сложно диагностировать.
Цель Фазы 1 — незаметно для оператора вести непрерывную запись его сессии,
а по нажатию кнопки — сохранять архив с данными сессии в папку «Загрузки» для передачи в поддержку.
 
---
 
## 2. Стек
 
| Компонент | Технология |
|---|---|
| Тип расширения | Chrome Extension, Manifest V3 |
| Service Worker | Background script (Manifest V3) |
| Захват экрана | `chrome.tabCapture` API |
| Захват DOM | `rrweb` (npm: rrweb) |
| Лог событий | Content Script |
| Упаковка архива | `JSZip` (npm: jszip) |
| Сохранение файла | `chrome.downloads` API |
| Хранение буфера | In-memory (Service Worker + Content Script) |
 
---
 
## 3. Структура расширения
 
```
extension/
├── manifest.json
├── background/
│   └── service-worker.js      # координатор, буфер видео, упаковка архива
├── content/
│   ├── recorder.js             # rrweb + лог событий
│   └── inject.js               # инжектируется на каждую страницу
├── popup/
│   ├── popup.html              # кнопка «Сохранить архив»
│   └── popup.js
└── libs/
    ├── rrweb.min.js
    └── jszip.min.js
```
 
---
 
## 4. Что записывается
 
### 4.1 Кольцевой видеобуфер (последние 30 секунд)
 
- Захват активной вкладки через `chrome.tabCapture.capture()`
- Кодек: `video/webm; codecs=vp9`
- Битрейт: `400 000 bps` (~3 МБ/мин)
- `MediaRecorder` пишет чанки каждые `2000 мс`
- Буфер хранится в памяти Service Worker как массив `{ data: Blob, timestamp: number }`
- Чанки старше 30 секунд удаляются автоматически после каждого нового чанка
- Первый чанк (WebM-заголовок) **никогда не удаляется** — он нужен для корректного воспроизведения файла
**Ожидаемый размер в памяти:** ~1.5–2 МБ постоянно
 
### 4.2 DOM-снимки через rrweb (последние 10 минут)
 
- `rrweb.record()` пишет события в массив
- Хранится в Content Script, передаётся в Service Worker по запросу
- События старше 10 минут удаляются по таймеру каждые 60 секунд
- Маскирование чувствительных полей: все `input[type=password]` и поля с `data-sensitive="true"` маскируются через `rrweb` опцию `maskInputSelector`
**Ожидаемый размер в памяти:** ~1–3 МБ
 
### 4.3 Лог действий пользователя (последние 10 минут)
 
Каждая запись лога:
```json
{
  "timestamp": 1716800000000,
  "type": "click | input | navigation | error | network",
  "target": "CSS-селектор элемента",
  "value": "текст/значение (маскируется для паролей)",
  "url": "текущий URL",
  "meta": {}
}
```
 
Перехватываемые события:
- `click` — клик по любому элементу (фиксируется `target`, текст элемента)
- `input` — изменение значения поля (без паролей)
- `navigation` — `popstate`, `hashchange`, переходы по страницам
- `js_error` — `window.onerror`, `window.onunhandledrejection`
- `network_error` — `fetch` / `XMLHttpRequest` с кодом ответа `>= 400`
**Ожидаемый размер в памяти:** ~100–300 КБ
 
### 4.4 Скриншот текущего состояния
 
- Делается в момент нажатия кнопки «Сохранить архив»
- Через `chrome.tabs.captureVisibleTab()`
- Формат: PNG, сохраняется как `screenshot.png` в архив
---
 
## 5. Кнопка «Сохранить архив» (Popup)
 
### UI
- Минималистичный popup: одна кнопка **«Сохранить отчёт об ошибке»**
- Под кнопкой: серый текст «Последние 30 сек видео + 10 мин лога»
- Состояния кнопки: `idle` → `Сохраняю...` → `Готово! ✓` → `idle` (через 3 сек)
### Поведение при нажатии
1. Сделать скриншот активной вкладки
2. Запросить у Service Worker: видеобуфер + лог событий
3. Запросить у Content Script: rrweb-снимки
4. Собрать архив (см. раздел 6)
5. Скачать архив через `chrome.downloads.download()`
6. Показать статус «Готово! ✓»
---
 
## 6. Структура архива
 
Имя файла: `session_report_YYYY-MM-DD_HH-MM-SS.zip`
 
```
session_report_2025-05-15_14-32-10.zip
├── video/
│   └── last_30sec.webm         # склеенные чанки видеобуфера
├── rrweb/
│   └── session.json            # массив DOM-событий rrweb
├── logs/
│   └── events.json             # лог действий пользователя
├── screenshot.png              # скриншот в момент сохранения
└── meta.json                   # метаданные сессии
```
 
Содержимое `meta.json`:
```json
{
  "timestamp": "2025-05-15T14:32:10Z",
  "url": "https://...",
  "userAgent": "Chrome/...",
  "extensionVersion": "1.0.0",
  "videoBufferSeconds": 30,
  "logDurationMinutes": 10,
  "totalEvents": 143
}
```
 
---
 
## 7. Разрешения в manifest.json
 
```json
{
  "permissions": [
    "tabCapture",
    "activeTab",
    "downloads",
    "scripting",
    "storage"
  ],
  "host_permissions": [
    "<all_urls>"
  ]
}
```
 
> **Примечание:** `tabCapture` требует жеста пользователя при первом запуске.
> При первой установке расширение запрашивает разрешение явно.
 
---
 
## 8. Важные ограничения и решения
 
| Проблема | Решение |
|---|---|
| WebM без заголовка не воспроизводится | Первый чанк (header) хранится всегда, не удаляется из буфера |
| Service Worker выгружается через 30 сек простоя | Keepalive через `chrome.alarms` каждые 20 сек |
| `tabCapture` только для активной вкладки | Фиксируется при активации расширения; при смене вкладки — переподключение |
| Большой объём rrweb-данных | Лимит буфера: 5 000 событий; при превышении удаляются самые старые |
| Пароли и чувствительные данные | `maskInputSelector` в rrweb + фильтр в логгере событий |
 
---
 
## 9. Что НЕ входит в Фазу 1
 
- Отправка данных на сервер
- AI-диагностика
- Автоматическое создание тикетов
- Аналитический дашборд
- Запись звука
Эти функции — Фаза 2.
 
---
 
## 10. Критерии приёмки Фазы 1
 
- [ ] Расширение устанавливается в Chrome без ошибок
- [ ] Видеобуфер непрерывно работает на любой вкладке
- [ ] В буфере всегда есть не более 30 секунд видео
- [ ] rrweb пишет DOM-события без ошибок на типовых страницах (формы, таблицы, модальные окна)
- [ ] Лог событий фиксирует клики, навигацию и сетевые ошибки
- [ ] При нажатии кнопки архив скачивается в «Загрузки» за < 5 секунд
- [ ] Архив открывается, `last_30sec.webm` воспроизводится в браузере
- [ ] Пароли не попадают в лог и rrweb-снимки
- [ ] RAM-потребление расширения не превышает 50 МБ в фоне