Перейти к содержанию

Коммуникационная платформа Ruxeo: Assignments + Chat#

Тип документа: L3 архитектурный артефакт. Описывает замысел, текущее состояние реализации и roadmap. Source: ветка sansay365, 2026-05-17. Backend в modules/ruxeo-base-core + modules/ruxeo-base-studio, UI там же (web-resources). Mobile-клиент — в отдельном репо /home/ssay/Project/ruxeo-ai-services/mobile/, вне scope этого документа.

§1 Замысел#

Коммуникации в Ruxeo строятся вокруг двух связанных сущностей, доступных пользователю на каждой точке платформы:

  1. Assignment — universal-носитель Задачи. Универсальный case-management контейнер: исполнитель + соисполнители, deadline, иерархия подзадач, привязка к workflow или агенту, встроенный чат. Базовый doctype в ruxeo-base-studio, доопределяется функциональными модулями (DocFlow, КЭДО, …) под свои случаи.
  2. Chat — каналы общения с тремя самостоятельными режимами:
  3. DIRECT — 1:1 переписка между двумя пользователями;
  4. GROUP — мульти-участник чат без анкера на документ;
  5. DOCUMENT / WORKFLOW / ASSIGNMENT — встроенный чат, привязанный к конкретному объекту, ACL независим от объекта.

Эти две сущности образуют четыре сценария коммуникации, доступные пользователю:

Сценарий Носитель Точка входа
«Поговорить с коллегой» DIRECT chat Drawer «Чаты»
«Обсудить в команде» GROUP chat Drawer «Чаты»
«Спросить по документу» DOCUMENT chat Метаданные документа (раскрывающаяся панель)
«Дать поручение» Assignment + ASSIGNMENT chat UI «Поручить» (внутри чата или контекстного меню)

Пользователю не нужно выбирать модуль — каналы коммуникации одинаково доступны на любой странице платформы. Drawer «Чаты» виден всем authenticated users; chat-панель — на любом документе с facet-ом Chattable.

§2 Архитектура#

§2.1 Assignment — universal case container#

Doctype: Assignment (modules/ruxeo-base-studio/src/main/resources/OSGI-INF/rxbm-document-types.xml:454).

  • Extends File.
  • Facets: Folderish, Versionable, Commentable, NXTag, Registration, TitleInfo, Recurring, Chattable.
  • Schema: rxbm_assignment (префикс asm).

Поля схемы (rxbm_assignment.xsd):

Поле Тип Назначение
asmKind enum Тип Задачи: free (свободная), from_workflow (порождённая WF), from_agent (порождённая AI-агентом), from_chat (созданная из чата)
asmAssignee user-ref Основной исполнитель
asmCoExecutors user-list Соисполнители (см. §2.1.1)
asmInitiator user-ref Постановщик
asmTitle, asmDescription string, html Содержание задачи
asmDueDate, asmPriority, asmStatus date, enum, enum SLA + статус (см. SLA.md)
asmHierarchyLevel, asmParentRef int, doc-ref Иерархия подзадач
asmWorkflowInstanceId string Backlink на запустившую WF-инстанцию (если есть)
asmChatRoomRef doc-ref Backlink на встроенный chat-room (lazy-created)

Lifecycle: assignment_lifecycle (определён в ruxeo-docflow-studio/.../rxdf-lifecycles.xml, шаги: draft → linked_to_wf_step | agent_generated | onExecution → onReview → completed | cancelled | archived).

Physical location: хранится в AssignmentsFolder под путём БЕ (resolution через RxasmAssignmentService.resolveAssignmentsFolder(buCode)).

§2.1.1 Co-executors как набор#

asmCoExecutorsstringList имён пользователей. Operations (RxasmAddCoExecutor, RxasmRemoveCoExecutor, RxasmUpdateCoExecutor) поддерживают diff-операции. ACL Assignment-а наследует прав на запись для всех co-executors через ComputedGroups (см. EMPLOYEE_DELEGATION.md §2.1).

§2.1.2 Sub-assignments#

Folderish + asmParentRef + asmHierarchyLevel. Operation RxasmCreateSubAssignment (assignment-operations.xml:43) создаёт child-Assignment внутри parent-а. Используется для декомпозиции крупных задач.

§2.1.3 Связка с Workflow#

asmWorkflowInstanceId хранит referrer на запустившую DocumentRoute. При завершении WF-step-а (workflowTaskCompleted) listener (TBD) обновляет asmStatus и пишет событие в встроенный chat. Деталь — см. DYNAMIC_APPROVAL_WORKFLOW.md.

§2.1.4 Связка с AI-агентом#

asmKind="from_agent" помечает Assignment-ы, порождённые ruxeo-ai-services/agent/. Агент создаёт Assignment через operation RxasmAssignment.CreateFromChat с source=AGENT (см. §2.2.5).

§2.2 Chat — RuxeoChatRoom#

Doctype: RuxeoChatRoom (rxbm-document-types.xml:257).

  • Extends Document (lightweight, не Folderish).
  • Schema: ruxeo_chat_room (префикс rcr).
  • Comments как messages (Nuxeo native, doctype Comment).

Поля схемы:

Поле Тип Назначение
rcrKind enum DIRECT / GROUP / DOCUMENT / WORKFLOW / ASSIGNMENT
rcrContextType, rcrContextId string, string Слабая ссылка на объект (для DOCUMENT/WORKFLOW/ASSIGNMENT) — НЕ parent в дереве, чтобы ACL не наследовался
rcrParticipants string-list Список user-id participants
rcrLastMessageId, rcrLastMessageDate string, date Для сортировки и preview
rcrCreatedBy, rcrCreated string, date Audit
rcrTitle string Только для GROUP и для context-aware (autocomputed для DIRECT/DOCUMENT)

Message doctype — обычный Nuxeo Comment, parent-document = ChatRoom. Поле rcm:reactions (расширение Comment-а) хранит JSON-карту {emoji: [userIds]} для реакций.

§2.2.1 Пять kind-ов с одним кодом#

В отличие от типичного «отдельный doctype под каждый use-case», RuxeoChatRoom универсальный — поле rcrKind разграничивает UX:

  • DIRECTparticipants.size() == 2, contextType == null. UI: автогенерируемый title из имени собеседника. Поиск/создание идемпотентно через Ruxeo.Chat.GetOrCreateDirectRoom(userA, userB).
  • GROUPparticipants.size() > 2, contextType == null. UI: editable title, add/remove participants.
  • DOCUMENTcontextType = "Document", contextId = <uuid>. Lazy-created при первом разворачивании rxat-chat-panel на документе. Participants seed-ятся из ACL документа в момент создания (см. §2.2.4).
  • WORKFLOWcontextType = "DocumentRoute", contextId = <wf-instance-uuid>. Создаётся при старте WF-инстанции, participants — все assignees всех узлов.
  • ASSIGNMENTcontextType = "Assignment", contextId = <asm-uuid>. Создаётся одновременно с Assignment, participants — asmAssignee + asmCoExecutors + asmInitiator.

UI-компонент ruxeo-chat-room.js рендерит один и тот же интерфейс для всех kind-ов, отличаясь только header-section (avatar/title/subtitle, см. rxbm-chats-page.html:329-340).

§2.2.2 Lazy-create и идемпотентность#

Operation Ruxeo.Chat.CreateDocumentChat(docId) (используется из rxat-chat-panel): 1. Ищет существующий chat-room с contextType="Document" AND contextId=docId. 2. Если найден — возвращает его. 3. Если нет — создаёт, заполняет participants из ACL документа (текущие пользователи с Read). 4. Возвращает ChatRoom.

Аналогично для WORKFLOW (Ruxeo.Chat.GetOrCreateWorkflowRoom) и ASSIGNMENT-чатов.

§2.2.3 ACL decoupling#

Ключевая особенность — ACL чата независим от ACL объекта-контекста.

Реализация (RuxeoChatServiceImpl.java:158-180, setupChatRoomACL): - При создании ChatRoom-а вызывается acp.removeACL("inherited") + setUseInheritedAcl(false). - Затем ACE для каждого participant-а явно прописываются (Read + Write). - Документ-контекст в дереве — НЕ parent ChatRoom-а (ChatRoom живёт в /management/chats/, не как child documenta).

Следствие: - Можно пригласить в DOCUMENT-чат внешнего эксперта, не давая ему доступа к самому документу. - Удаление пользователя из ACL документа не удаляет его из чата (пока не вызвать explicit remove-participant). - Закрытие WF-инстанции не закрывает WORKFLOW-чат — он остаётся как history.

§2.3 Транспорт — PubSub + SSE#

Двухуровневая схема для real-time доставки.

§2.3.1 SSE endpoint#

modules/ruxeo-base-core/src/main/java/ru/ruxeo/base/chat/sse/RuxeoChatSSEResource.java:51:

@WebObject(type = "RuxeoChatSSE")
@Path("/chat/sse")
public class RuxeoChatSSEResource {
    @GET
    @Path("/room/{roomId}")
    @Produces(MediaType.SERVER_SENT_EVENTS)
    public EventOutput streamRoom(@PathParam("roomId") String roomId) { ... }
}

WebEngine module: MANIFEST.MFNuxeo-WebModule: …;name=ruxeo-chat-sse;extends=base;package=ru/ruxeo/base/chat/sse;headless=true.

RuxeoChatSSEEventManager (in-memory registry на узле) держит per-room список открытых SSE-sinks. При получении события от PubSub bridge — fan-out на локальные sinks.

§2.3.2 PubSub bridge (кластер-fanout)#

ChatPubSubBridge (rxbm-chat-pubsub.xml): - Topic: chat.events. - Envelope: {roomId, eventType, data} (JSON). - На каждом узле — subscriber, который при получении envelope-а распределяет на RuxeoChatSSEEventManager своего узла. - Backend — Nuxeo PubSubService (Redis/JGroups по platform config).

Producer pattern (RuxeoChatServiceImpl.java):

bridge.publish(chatId, "message_added", payload);

§2.3.3 Типы событий#

Event Publisher Subscriber action
message_added RuxeoChatCommentEventListener на commentAdded UI добавляет message в feed
message_updated listener на commentUpdated UI обновляет content (включая reactions snapshot)
message_deleted listener на commentDeleted UI скрывает message
chat_read markRead() UI снимает unread badge у других participants
typing_started ruxeo-chat-input.js debounce UI отображает «X пишет…» (см. §2.5.4)
participant_added / _removed RuxeoChatServiceImpl.{addParticipant,removeParticipant} UI обновляет список + ACL
reaction_added / _removed RxbmReactToChatMessageOperation UI обновляет message reactions

Cluster-safety: события dispatch-ятся через PubSub, локальный SSE-manager — только для presence-tracking. Reconnect клиента — клиент сам refetch-ает state через REST (нет persistent message-queue в SSE).

§2.4 Read-state + Mute#

§2.4.1 RuxeoChatReadState doctype#

Отдельный lightweight-doctype (ruxeo-chat-read-state-types-contrib.xml:31): - Schema: ruxeo_chat_read_state (префикс rcs). - Хранится в директории /management/chat-read-states/.

Поля: | Поле | Тип | Назначение | |---|---|---| | rcsUserId | string | User-ключ | | rcsChatId | string | Chat-ключ | | rcsLastReadMessageId | string | UUID последнего прочитанного message-а | | rcsLastReadDate | date | Timestamp | | rcsMuteLevel | enum | ALL (все нотификации) / MENTIONS (только при упоминании) / NONE (полная тишина) |

Один entry на пару (user, chat). Lazy-created при первом markRead.

§2.4.2 Unread computation#

Operation Ruxeo.Chat.GetUnreadInfo([roomIds]) возвращает per-chat:

{ "chatId": { "total": 7, "mentions": 2, "muteLevel": "ALL", "lastReadMessageId": "..." } }

Используется: - rxat-chat-panel для бейджа на свёрнутой панели (§3.1.1). - rxbm-chats-page для бейджа per-chat в списке + total-pill в drawer header. - Mobile/portal-web — через тот же REST-операцией.

§2.4.3 Mute UX#

В ruxeo-chat-room.js:407-886 toggle между тремя уровнями. Иконки: - ALLcommunication:notifications - MENTIONScommunication:notifications-active
- NONEcommunication:notifications-off

Mute не влияет на доставку (SSE приходят всегда), но: - MENTIONS — push/email только при упоминании user-а в message-е. - NONE — push/email подавляются полностью, бейдж не растёт.

§2.5 Богатый функционал сообщений#

§2.5.1 Mentions#

ChatNotificationEventListener.java:53 — regex MENTION_PATTERN парсит @username в content message-а. Каждое упоминание: - Расширяет recipients для notification до конкретного user-а (даже если у него mute=ALL). - Инкрементит mentions counter в GetUnreadInfo.

§2.5.2 Reactions#

RxbmReactToChatMessageOperation.java: - Properties: messageId, emoji, action (add/remove). - Хранит JSON-карту {emoji: [userIds]} в rcm:reactions. - При update эмитится message_updated event с полным snapshot реакций (idempotent).

UI: ruxeo-chat-room.js:753, 767-778_toggleReaction(). Полный emoji-picker не реализован, только +1//?.

§2.5.3 Participants management#

ruxeo-chat-participants.html — отдельный side-panel с list + add/remove buttons (только для GROUP и ASSIGNMENT-чатов). API: - Ruxeo.Chat.AddParticipant(chatId, userId) — добавляет в rcrParticipants + дополняет ACL. - Ruxeo.Chat.RemoveParticipant(chatId, userId) — обратное, исключает ACE.

§2.5.4 Typing indicator#

ruxeo-chat-input.js:1025-1047 — debounced typing events (typing-start / typing-stop через PubSub). Backend (RuxeoChatSSEResource.java:49) пробрасывает event.

UI-отображение «X пишет…» — в коде помечено как Future (ruxeo-chat-input.js:1007). Sprint неизвестен.

§2.6 Notification digest#

Backend-механизм (см. отдельную NOTIFICATION_DIGEST.md) интегрирован с Chat:

  • ChatNotificationEventListener (ruxeo-chat-notification-listeners.xml) — слушает commentAdded/commentUpdated, фильтрует по rcsMuteLevel.
  • Templates: chatNotificationTemplate.ftl, chatMentionNotificationTemplate.ftl, workflowChatNotificationTemplate.ftl (ruxeo-chat-notification-templates.xml).
  • Feature flag: rxbm.notifications.chat.enabled (default true).
  • Digest агрегирует chat-сообщения в почасовой/дневной отчёт по адресату.

UI для per-user digest preferences (frequency, opt-out per-chat) — не реализован (см. §6).

§3 UI слой#

§3.1 Встроенный чат на документе#

§3.1.1 rxat-chat-panel behavior#

modules/ruxeo-attributes-studio/src/main/resources/web/nuxeo.war/ui/elements/rxat-chat-panel.html.

  • Lazy: ChatRoom создаётся/загружается только при первом разворачивании панели (:240-250).
  • Persisted UI state в localStorage per (user, doc)-паре (:162-184).
  • Unread badge на свёрнутой панели через Ruxeo.Chat.GetUnreadInfo (:200-222).
  • Embedded <ruxeo-chat-room> + SSE subscriptions при разворачивании (:131).
  • Height: 480px (:81).

§3.1.2 Интеграция в rxat-metadata-layout#

rxat-metadata-layout.html:160 — chat-panel зашит как «Discussion» card в metadata-layout, доступна на всех doctype-ах с facet Chattable.

Все основные business-doctype Ruxeo (Contract, IncomingDocument, OutgoingDocument, Invoice, Assignment, …) имеют facet Chattable через rxbm-document-types.xml.

§3.2 Глобальная страница «Чаты»#

§3.2.1 Routes + Drawer#

  • Drawer entry: rxbm-drawer-slots.html:53-69 — icon communication:chat, order 40, без user-filter (виден всем authenticated).
  • Drawer component: rxbm-chats-drawer.html — header с total-unread-pill, menu-item на /chats.
  • Route: /chats (rxbm-pages-routes-slots.html:33-37).

§3.2.2 Two-pane layout#

rxbm-chats-page.html: - Sidebar 320px: room-list, search, kind-filter, mute-icons (:165-167, 300-317), unread-pill per room (:90-104). - Main: открытый <ruxeo-chat-room> с full message-feed. - Subtitle per room показывает kind: DOCUMENT, WORKFLOW, ASSIGNMENT, DIRECT, GROUP (:329-340).

§3.3 Home chat widget#

ruxeo-home-chat-widget.html — two-column виджет на главной странице (nuxeo-home.html): - Left: список contacts (DIRECT-чаты last-active). - Right: открытый chat-room. - Поддерживает гибрид: ruxeo-agent-chat-room (для AI-чатов) + ruxeo-chat-room (обычные).

§3.4 Assignment UI#

modules/ruxeo-base-studio/src/main/resources/web/nuxeo.war/ui/document/assignment/: - nuxeo-assignment-view-layout.html — табы: Main / Sub-Assignments / Execution / History. - nuxeo-assignment-metadata-layout.html, nuxeo-assignment-create-layout.html, nuxeo-assignment-edit-layout.html. - Отчёты: - rxbm-my-assignments-report.html — мои поручения. - rxbm-management-assignments-report.html — администрирование (для руководителей).

Dedicated /assignments page + drawer entry — не реализованы (см. §6).

§3.5 Mobile#

Mobile-клиент (React Native) живёт в /home/ssay/Project/ruxeo-ai-services/mobile/. Использует те же REST/SSE endpoints. Вне scope этого документа.

§4 Extension model для модулей#

§4.1 Текущая модель — naked Assignment + facet#

Сейчас функциональные модули не наследуют Assignment в своих doctype-ах, а используют его «голым»:

<!-- ruxeo-docflow-studio/.../rxdf-document-types.xml -->
<doctype name="AssignmentsFolder" extends="Folder">
  <subtypes>
    <type>Assignment</type>
  </subtypes>
</doctype>

DocFlow позволяет создавать Assignment внутри AssignmentsFolder, но Assignment остаётся базовым doctype-ом. Дополнительные поля DocFlow-специфичных задач сейчас не выделены — используется generic-схема.

§4.2 Возможные точки расширения#

Архитектурно поддержано следующее (но не используется массово):

Вариант А — facet over Assignment. Модуль создаёт свой facet с дополнительными схемами, навешивается на Assignment контрибуцией. Пример (гипотетический):

<facet name="DocflowSpecificAssignment">
  <schema name="rxdf_assignment_extras"/>
</facet>

Вариант Б — subtype через extends. Модуль объявляет свой doctype extends="Assignment":

<doctype name="RxsmRequest" extends="Assignment">
  <schema name="rxsm_request_extras"/>
</doctype>

Текущий сканер grep по extends="Assignment" не находит ни одного case — модули используют Assignment напрямую. Это сознательное решение или roadmap-обещание — нужно зафиксировать (см. §6.6).

§4.3 ChatSource enum#

RxasmAssignmentService.createFromChat() принимает ChatSource: - FREE — пользователь создал task вручную в free-standing GROUP/DIRECT чате. - WORKFLOW — task порождён workflow-узлом. - AGENT — task порождён AI-агентом.

Это расширяемая точка для extension model — модули могут добавлять свои enum-значения для discrimination origin-а.

§5 Текущее состояние реализации#

§5.1 Матрица capabilities#

Capability Backend UI Web UI Mobile Notes
DIRECT chat 1:1 /chats 🔵 Idempotent GetOrCreateDirectRoom
GROUP chat /chats 🔵 Editable title, participants management
DOCUMENT chat rxat-chat-panel 🔵 Lazy на любом Chattable doctype
WORKFLOW chat rxat-chat-panel 🔵 Auto-created при старте WF
ASSIGNMENT chat rxat-chat-panel 🔵 Auto-created вместе с Assignment
ACL decoupling 🔵 setupChatRoomACL explicit ACE
SSE real-time 🔵 /chat/sse/room/{roomId}
PubSub cluster fanout n/a n/a Topic chat.events
Mentions 🔵 Regex pattern + notification escalation
Reactions ⚠️ (only +1/✓/?) 🔵 Full emoji picker не реализован
Participants management 🔵 Add/Remove + ACL sync
Read-state + badges ✅ Sprint 6.2 🔵 Per-room + total-pill
Mute (ALL/MENTIONS/NONE) ✅ Sprint 6.4 🔵 Toggle в ruxeo-chat-room.js
Typing indicator (events) ✅ debounce 🔵 Display «X пишет…» — TODO
Notification digest 🚧 нет preferences UI 🔵 Backend готов, UI частично
Assignment co-executors 🔵 Add/Remove/Update operations
Sub-assignments ✅ tab 🔵 Folderish + asmParentRef
Launch WF on Assignment 🔵 Через стандартный workflow start UI
Embedded chat in Assignment ✅ rxat-chat-panel 🔵 Через facet Chattable
Create Assignment from Chat ✅ operation ❌ нет UI 🔵 RxasmAssignment.CreateFromChat без UI button
Assignment cover-page + drawer entry n/a ❌ нет 🔵 Layout-ы есть, entry-point — нет

Легенда: ✅ реализовано · ⚠️ частично · 🚧 backend есть, UI неполный · ❌ не реализовано · 🔵 mobile out-of-scope.

§5.2 Что готово к продакшну#

  • Все 5 kind-ов чатов с UI на web.
  • Real-time через SSE + cluster-safe PubSub.
  • Read-state, бейджи, mute.
  • Mentions, reactions (минимальный набор), participants.
  • Assignment как полноценный case-объект с co-executors, sub-assignments, workflow-link, embedded chat.

§5.3 Что в работе или backlog#

  • UI кнопка «Создать поручение из чата» (operation готов).
  • Dedicated /assignments страница и drawer entry для свободных задач.
  • Display typing indicator («X пишет…»).
  • Полноценный emoji picker для reactions.
  • Per-user digest preferences UI.
  • Расширение модулей через subtype/facet (есть гипотетически, нет в проде).

§6 Gaps и roadmap#

§6.1 🟡 P2 — Нет UI-кнопки «Создать поручение из чата»#

Backend operation RxasmAssignment.CreateFromChat готов (params: roomId, task, executorId, deadline, source), включая публикацию card-сообщения обратно в чат. Но кнопки в context-menu чата или slash-command /поручить (упомянутого в CHAT_TOBE_SPECIFICATION.md §5.5) нет в коде.

Целевая реализация: кнопка в header-action-bar ruxeo-chat-room.js с dialog-ом выбора assignee + deadline + title. Slash-command /поручить в ruxeo-chat-input.js с inline-syntax parsing.

Срок: до GA-внедрения чата как «Communications Platform».

§6.2 🟡 P2 — Нет dedicated /assignments страницы#

Layouts (view/create/edit) для Assignment есть, отчёты «Мои поручения» / «Администрирование поручений» — есть. Но единой точки входа «Все мои Assignment-ы (всех источников: WF/Agent/Free/from-chat)» — нет. Drawer entry для Assignment-ов также отсутствует.

В rxbm-drawer-slots.html:36-37 есть комментарий: «Tasks & Reports drawer entry removed (sansay270). Reports are now surfaced via the Home Page «Отчёты» tab.» — отчёты перенесены, но универсального entry для assignments как сущности нет.

Целевая реализация: новый drawer-entry «Поручения» + /assignments page с: - табы по kind-ам: Свободные / Из workflow / От агента / Из чатов; - группировка: активные / на ревью / завершённые; - быстрое создание свободной задачи.

Срок: связан с § «Assignment как universal task carrier» в roadmap-е (UNIVERSAL_TASK_SPECIFICATION.md, см. §6.6).

§6.3 🟡 P2 — UNIVERSAL_TASK_SPECIFICATION.md упомянут как блокер, но не существует#

CHAT_TOBE_SPECIFICATION.md §5.5 ссылается на SPECS/BASEMODULE/UNIVERSAL_TASK_SPECIFICATION.md как блокер для drawer-entry / consolidation отчётов. Файл не существует в репо.

Целевая реализация: написать спецификацию (содержание см. §6.2 + §6.6 этого документа) и зафиксировать как договорённость. Может быть переименовано в ASSIGNMENT_AS_UNIVERSAL_TASK_CARRIER.md чтобы не путать с Nuxeo Task doctype-ом.

Срок: до §6.2 (предшествует UI implementation).

§6.4 🟢 P3 — Display typing indicator не реализован#

Backend events (typing_started/typing_stopped) идут через PubSub, debounce на input-е работает. Но отображение «Иванов И. пишет…» под чатом в ruxeo-chat-room.js:1007 помечено Future.

Целевая реализация: subscribe на typing_started события + список «typing users» с auto-clear через 5 секунд без update-а.

Срок: low-priority, при следующем UX-rework чата.

§6.5 🟢 P3 — Reactions без полного emoji picker#

UI поддерживает только +1//? reactions. Backend гибче — rcm:reactions хранит любую emoji-строку как key.

Целевая реализация: emoji picker (например, <emoji-picker-element>) с поиском. Можно ограничить набор «корпоративных» reactions.

Срок: при пользовательском запросе, не блокер.

§6.6 🟢 P3 — Extension model для модулей не документирован и не использован#

Архитектурно есть два пути расширения Assignment (facet over / subtype extends), но: - Ни одного case в текущем коде. - Нет SPEC-документа «как расширять Assignment в новом модуле». - В консерватории не очевидно, какой вариант предпочтителен.

Целевая реализация: SPEC ASSIGNMENT_EXTENSION_GUIDE.md + один пилотный case (например, RxsmRequest extends Assignment в Service Management) для демонстрации.

Срок: при добавлении специфики Assignment в любом из модулей.

§6.7 🟢 P3 — Per-user digest preferences UI отсутствует#

Backend digest-service работает по global config (rxbm.notifications.chat.enabled). У пользователя нет способа: - выбрать частоту (immediate / hourly / daily / weekly); - отписаться от digest-ов конкретного чата (не муть, а именно digest); - настроить часы тишины (do-not-disturb hours).

Целевая реализация: страница /preferences/notifications с tab-ом «Чат-сообщения», persistent в rxbm_user_preferences directory.

Срок: после accumulated user feedback по noise level.

§6.8 🟢 P3 — Cluster-safety PubSub backend не верифицирован#

PubSubService платформенный, поддерживает Redis/JGroups. В nuxeo.conf на стенде QA backend не выставлен явно — работает на default (in-memory). На production требуется явная конфигурация.

Целевая реализация: dev/QA stand документация + monitoring «PubSub backend type» в Admin Center.

Срок: при первом production deployment.

§6.9 ✅ Sprint 6 — закрыт полностью#

Memory note про Sprint 6 (sansay284, заморожена) — частично устарела. На текущей ветке sprint 6.1 (tx audit), 6.2 (read-state + бейджи + разделитель), 6.4 (mute UI), 6.5 (digest backend) — реализованы. 6.3 (статусы доставки сообщений типа «прочитано/доставлено») — не подтверждено в коде, нужна отдельная проверка при возврате к chat backlog-у.

§7 Связанные документы#

Внутри DOCS/#

Внутри SPECS/#

  • SPECS/BASEMODULE/CHAT_TOBE_SPECIFICATION.md (черновик 2026-04-29, sansay280) — forward-looking, частично реализован.
  • SPECS/BASEMODULE/UNIVERSAL_TASK_SPECIFICATION.mdотсутствует (см. §6.3).

Внешние#

  • /home/ssay/Project/ruxeo-ai-services/mobile/ — React Native mobile-клиент (вне scope).
  • /home/ssay/Project/ruxeo-ai-services/orchestrator/ — orchestrator, через который агент создаёт Assignment-ы.

Memory#

  • [[project-chat-tobe]] — initiative, sprint roadmap.
  • [[project-chat-sprint6-status]] — Sprint 6 in-progress notes (нужно обновить — см. §6.9).
  • [[project-assignments-chat-case-management]] — концепция от user-а, this document её формализует.
  • [[feedback-nuxeo-workflow-task-event-api]]ctx.getProperty("taskInstance") для WF-task events (применимо к WORKFLOW-чату).