Перейти к основному содержимому

Дизайн: широковещательное оповещение веб-приложений из 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. Дать 1С универсальный API для публикации событий в любые открытые веб-компоненты текущего клиентского сеанса.
  2. Не ломать существующий контракт onec и не менять веб-код в рамках этого тикета. Новый механизм — опциональный на стороне веба.
  3. Реализовать конкретное применение: форма списка документа Задание сможет инициировать перерисовку канбан-доски.
  4. Задокументировать протокол 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Клиент.ПередатьСобытиеВБраузер(Элементы.ВебИнтерфейс, ...)
└─ ...другие формы с браузером

Механика:

  1. Инициатор вызывает ПротоколOnecКлиент.ОповеститьВеб. Это обёртка над Оповестить("OnecBroadcast", <параметр>). Параметр — структура с двумя полями: event (строка, имя события) и data (структура c любыми JSON-совместимыми данными, обычно {"id": "ref_<type>_<guid>"}).
  2. Все открытые формы текущего клиентского сеанса получают оповещение в ОбработкаОповещения.
  3. Формы, содержащие браузер и желающие транслировать события в веб, вызывают Протокол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 (отдельный тикет), чтобы не раздувать изменения.

3. DataProcessor.Доксинум.Forms.Форма

  • Добавить процедуру ОбработкаОповещения (сейчас её нет) с единственной строкой — вызов ПротоколOnecКлиент.ПередатьСобытиеВБраузер(Элементы.ВебИнтерфейс, ИмяСобытия, Параметр). Это обеспечит приём будущих событий knowledge_update, project_update.

4. Документация

  • Новый файл .docs/reference/onec-protocol.md с разделами:
    • Обзор протокола Onec (модель document.callback / document.get).
    • Правило выбора: «API-эндпоинт по умолчанию, onec с суффиксом -form только для client-only операций формы».
    • Реестр ПараметрыOnec() в форме, схема запрос/ответ.
    • Broadcast: ОповеститьВеб, ПередатьСобытиеВБраузер, JS-контракт document.onecBroadcast.
  • Обновить .docs/reference/INDEX.md — добавить строку со ссылкой.
  • Проверить остальные главы .docs/: если есть устаревшие упоминания Onec — актуализировать.

Инварианты

  • ПротоколOnecКлиент не зависит от клиентских SSL-методов сервера — процедура и функция остаются &НаКлиенте, не дёргают сервер.
  • ОповеститьВеб не бросает исключений при отсутствии подписчиков (Оповестить всегда ок).
  • ПередатьСобытиеВБраузер не бросает исключений при отсутствии document.onecBroadcast — событие теряется молча, это ожидаемое поведение на старых версиях веба.
  • Имя события OnecBroadcast в 1С-пространстве оповещений зарезервировано за этим механизмом; конфликт со старыми оповещениями исключён (поиском не обнаружено).
  • Формат параметра Оповестить("OnecBroadcast", …) фиксирован: Структура("event" : Строка, "data" : Структура|Неопределено). Изменение формата требует согласованной правки всех форм-приёмников.

Тестирование

  • BSL-ошибки: mcp__edt-mcp__get_project_errors после правок.
  • Ручной сценарий: открыть форму списка Задание, нажать команду «Обновить канбан-доску» — в консоли браузера в SPA должен появиться console.log при условии, что к моменту тестирования веб будет обновлён и зарегистрирует document.onecBroadcast. На текущем вебе — no-op без ошибок.
  • Регрессия: существующие onec-методы (upload-file-form, set-current-page-form и др.) должны работать без изменений.

Риски

  • Веб не обновлён. Вызовы document.onecBroadcast молча теряются. Это ок для транзитного периода.
  • Много открытых форм. Оповестить доставит событие в каждую форму с браузером. В теории можно получить шторм вызовов document.onecBroadcast в одном SPA. На практике число одновременно открытых форм невелико; дебаунс — на стороне веба (если понадобится).
  • Конфликт имени оповещения. Имя OnecBroadcast уникально в репозитории (проверено rg). Дублей нет.

План реализации (краткий)

  1. Расширение CommonModule.ПротоколOnecКлиент (две процедуры).
  2. Правка Document.Задание.Forms.ФормаСписка.Module.bsl + Form.form (команда, кнопка, ОбработкаОповещения).
  3. Правка DataProcessor.Доксинум.Forms.Форма.Module.bsl — добавить ОбработкаОповещения.
  4. Документация .docs/reference/onec-protocol.md + обновление INDEX.md.
  5. Валидация через mcp__edt-mcp__get_project_errors.