Дизайн: широковещательное оповещение веб-приложений из 1С
Контекст
В конфигурации УИТ используются HTML-формы со встроенными SPA-приложениями (канбан, база знаний Доксинум, ассистент). Приложения общаются с 1С через протокол onec — JS-код кликает по якорной ссылке onec://<callbackId>?request=<json>, 1C перехватывает клик в обработчике ПолеФормы.ПриНажатии и отдаёт ответ обратно через document.callback(...).
Команды, доступные только на уровне конкретной формы 1С (без серверного REST-эндпоинта), по соглашению имеют суффикс -form — например upload-file-form, set-current-page-form. API-методы без суффикса (/v2/projects, /v2/tasks и т.д.) обрабатываются серверным модулем APIВебСервисыВызовСервера.
Проблема. Связь web -> 1C -> web работает только как «запрос–ответ». Сценариев обратного направления (1С сигнализирует вебу «обновись») в протоколе нет. Это рождает типовые задачи без решения:
- Пользователь изменил фон канбан-доски или переименовал проект в 1С — канбан в соседнем окне не знает и не перерисовывается.
- После массовой правки задач в списке нужно уведомить канбан и ассистент, что связанные сущности изменились.
- Веб-компоненты начинают строить с обственные таймеры polling, что дорого и не согласовано между приложениями.
Цели
- Дать 1С универсальный API для публикации событий в любые открытые веб-компоненты текущего клиентского сеанса.
- Не ломать существующий контракт
onecи не менять веб-код в рамках этого тикета. Новый механизм — опциональный на стороне веба. - Реализовать конкретное применение: форма списка документа
Заданиесможет инициировать перерисовку канбан-доски. - Задокументировать протокол Onec в
.docs/— зафиксировать соглашение «API по умолчанию, onec с суффиксом-formтолько для специфики 1С».
Не-цели
- Кросс-сеансовые оповещения (User A изменил — User B увидел). Это потребует WebSocket / long-polling / push через серверный websocket и выходит за рамки тикета.
- Переписывание существующих Onec-методов.
- Измен ение веб-кода (клиентская подписка
document.onecBroadcast— отдельный тикет в web_monorepo).
Архитектура
Поток «1С публикует событие»
Код формы 1С
└─ ПротоколOnecКлиент.ОповеститьВеб(ИмяСобытия, Данные)
└─ Оповестить("OnecBroadcast", Структура("event", ..., "data", ...))
├─ Форма списка Задание.ОбработкаОповещения
│ └─ ПротоколOnecКлиент.ПередатьСобытиеВБраузер(Элементы.КанбанДоска, ...)
│ └─ Браузер.document.onecBroadcast(event, dataJson)
│ └─ JS-подписчик в kanban SPA
├─ Форма Доксинум.ОбработкаОповещения
│ └─ ПротоколOnecКлиент.ПередатьСобытиеВБраузер(Элементы.ВебИнтерфейс, ...)
└─ ...другие формы с браузером
Механика:
- Инициатор вызывает
ПротоколOnecКлиент.ОповеститьВеб. Это обёртка надОповестить("OnecBroadcast", <параметр>). Параметр — структура с двумя полями:event(строка, имя события) иdata(структура c любыми JSON-совместимыми данными, обычно{"id": "ref_<type>_<guid>"}). - Все открытые формы текущего клиентского сеанса получают оповещение в
ОбработкаОповещения. - Формы, содержащие браузер и желающие транслировать события в веб, вызывают
ПротоколOnecКлиент.ПередатьСобытиеВБраузер(Браузер, ИмяСобытия, Параметр). Функция:- возвращает
Ложь, еслиИмяСобытия <> "OnecBroadcast"(дальше форма обрабатывает оповещение сама); - десериализует
dataв JSON, вызываетБраузер.document.onecBroadcast(event, dataJson); - ловит исключение, если
document.onecBroadcastне определён (веб ещё не подписался) — тихий no-op; - возвращает
Истинапри успешной передаче.
- возвращает
Контракт JS со стороны веба (для будущей реализации)
// В каждом SPA при старте:
declare global {
interface Document {
onecBroadcast?: (eventName: string, jsonPayload: string) => void;
}
}
document.onecBroadcast = (eventName, jsonPayload) => {
const data = JSON.parse(jsonPayload);
busBroadcast.emit(eventName, data); // event bus / zustand / redux — как удобнее
};
Веб не обязан регистрировать onecBroadcast — 1С будет молча игнорировать отсутствие функции. Это даёт безболезненную постепенную миграцию.
Имена событий и форма payload
Соглашение имен — snake_case, без суффиксов (в отличие от onec-методов):
| Событие | Когда публикуется | Ожидаемый data |
|---|---|---|
project_update | Изменились реквизиты проекта или фон канбана | {"id": "ref_projects_<guid>"} |
task_update | Изменилось задание (статус, ис полнитель, ...) | {"id": "ref_tasks_<guid>"} |
kanban_reload | Нужна полная перезагрузка канбан-доски | {"id": "ref_projects_<guid>"} |
knowledge_update | Изменилась страница базы знаний | {"id": "ref_knowledge-base_<guid>"} |
Соглашение закрепляется в документации .docs/reference/onec-protocol.md. Конкретные имена событий добавляются по мере необходимости; 1С не валидирует их по белому списку — это открытый протокол.
Компоненты
1. CommonModule.ПротоколOnecКлиент (расширение)
Две новые экспортные процедуры/функции:
Процедура ОповеститьВеб(ИмяСобытия, Данные = Неопределено) Экспорт
Функция ПередатьСобытиеВБраузер(Браузер, ИмяСобытия, Параметр) Экспорт
Данные = Неопределено— payload может быть пустым (есть события без контекста, напримерui_theme_changed).- Сериализация — через существующий
ЗаписьJSONВСтруктуру.
2. Document.Задание.Forms.ФормаСписка
- Добавить команду
ОбновитьКанбанДоску(на форме): публикуетkanban_reloadс текущим проектом. - Расширить существующий
ОбработкаОповещения— вызовПротоколOnecКлиент.ПередатьСобытиеВБраузер(Элементы.КанбанДоска, ИмяСобытия, Параметр)в начале процедуры (до обработки собственных оповещений формы, чтобы не пропускать их). - В существующих местах формы, где после записи данных уже вызывается
Оповестить("ОбновитьФормуСпискаЗаданий"), дополнительно публиковатьtask_update/project_updateпо смыслу. В рамках этого тикета реализуется только команда обновления канбана — остальные точки оставляются как TODO (отдельный тикет), чтобы не раздувать изменения.