ADR-006: WebSocket-сповіщення
- Статус: прийнято
- Дата: 2026-04-16
- Автор: CTO Agent (KALA-133)
Контекст
AgentCore уже мав WebSocket-інфраструктуру для прогресу agent-tasks. Новим потокам продукту знадобились live-сповіщення користувачам: схвалення, згадки, готові документи. Команда мала обрати: розширити існуючий WebSocket-плагін, додати server-sent events або обмежитись REST-опитуванням.
Рішення
Додаємо /ws/notifications до існуючого Fastify WebSocket-плагіна.
Канал сповіщень:
- автентифікується за тією ж JWT-моделлю, що й REST;
- підтримує query-token або first-message auth;
- підписується на notification-події для автентифікованого
userId; - відправляє
notification.created-події, коли продюсери викликаютьemitNotification(); - тримає довготривалий стан у таблиці
notifications.
Розглянуті альтернативи
Тільки REST-поллінг
Відхилено. Поллінг простий, але додає ack-latency до approval- та document-ready-воркфлоу і збільшує обсяг запитів для активних дашбордів.
Окремий SSE-ендпоінт
Поки відхилено. SSE підходить для server-to-server подій, але в застосунку вже є автентифікована WebSocket-система та тести. Додавати ще один транспорт — значить дублювати auth і lifecycle-логіку.
Розширити /ws/agent-tasks
Відхилено. Прогрес agent-task scope-обмежений по namespace/task. Сповіщення — це per-user inbox. Окремі шляхи не плутають subscription-семантику.
Наслідки
Позитивні
- Перевикористовує існуючий WebSocket-плагін і JWT-шлях валідації.
- Доставка сповіщень прибита до поточного користувача.
- REST-inbox лишається source of truth після reconnect.
- Тести можуть перевіряти сокет тими самими WebSocket-хелперами, які вже є.
Негативні
- Поточний broadcast через EventEmitter локальний для процесу.
- Багаторепліковий прод потребує Redis pub/sub або іншої shared event bus.
- Клієнтам все одно треба REST-resync для подій, пропущених під час дисконекту.
Нотатки про реалізацію
src/lib/notifications.tsволодієemitNotification()іsubscribeUserNotifications().src/plugins/websocket.tsреєструє/ws/notifications.- Продюсери мають спочатку створити DB-рядок, а потім емітити подію.
- Сокет закривається кодом
4001при auth-таймауті або невалідному токені.