Architecture
The widget is a React app mounted in a shadow DOM, talking to the backend (morzebot-backend-v2, the Router) over WebSocket. Below are the key architectural ideas that matter when integrating or extending it.
Custom element & shadow DOM
- The widget registers an
<mz-bot>custom element (insrc/index.js). - The primary widget mounts on
<mz-bot id="__mz-bot">; the overlay on<mz-bot id="__mz-bot-overlay">. - The shadow root is open (
mode: 'open'), which lets the outside read the host's CSS variables. - All styles are inlined into the JS (via
vite-plugin-css-injected-by-js) and injected into the shadow root, and host styles don't break the widget.
Surfaces
The widget can mount several presentations of the same conversation at once. Each surface is its own <mz-bot> host + shadow root + React root, but there's one store and oneWebsocketConnection, so all surfaces stay in sync over a single socket.
| Surface | What it is | Host |
|---|---|---|
| primary | The main mode (static / inline / classic) | #__mz-bot |
| overlay | An optional floating launcher (chat.overlay.enabled) | #__mz-bot-overlay on <body> |
The surface descriptor (id, host, mode, position) is passed via SurfaceContext (src/contexts/SurfaceContext.js). Components read their host/mode from useSurface(), not from getElementById('__mz-bot') and not from globals like config.STATIC/INLINE/CHAT_TYPE.
Per-surface state isolation
Per-surface keys in StaticStore (ChatOpen:<id>, ChatWasOpened:<id>, seen-count) keep surfaces from clobbering each other's state. Overlay visibility lives in a separate external store, src/services/overlayStore.js.
Singletons
A handful of module singletons guarantee one conversation across all surfaces:
| Singleton | File | Role |
|---|---|---|
WebsocketConnection | src/services/WebsocketConnection.js | The single WS connection; carries ws_token in the query for session recovery; reconnects on tab focus / online. |
WebsocketEvents | src/services/WebsocketEvents.js | Incoming-event handler registry; wired up once in bootstrap.js. |
Redux store | src/store.js | All messages and UI state. Reducers: bot, menu, options, notifications, wsEvents. |
StaticStore | src/services/StaticStore.js | In-memory cache: ws-token, operator header state, etc. |
overlayStore | src/services/overlayStore.js | Pub-sub for overlay launcher visibility and open/close (via useSyncExternalStore). |
Bootstrap
One-time socket setup lives in src/bootstrap.js (guarded against re-running):
- Create the WebSocket and handlers (
WebsocketConnection.getInstance(),WebsocketEvents.getInstance()). - Restore the operator header from
sessionStorageif present. - Send a "start" action to the backend (~1s later).
- Attach visibility/online listeners for auto-reconnect.
Message flow
widget ──msg──► Router (morzebot-backend-v2, :9000)
▲ │ routes to the script engine / Messenger
│ event:* over WS ▼
└───────────────────────┘ Router pushes events (typing, caption_after, …) back over WSThis widget's backend is the Router (morzebot-backend-v2), not the support-panel.
src/ structure
src/
index.js # entrypoint: config resolution, surface mounting, installs the MZBOT API
bootstrap.js # one-time socket + handler setup
config.js # the resolved config (generated at startup; gitignored)
theme.js # theme state machine + the global MZBOT API
store.js # Redux store configuration
App.js # root component (mounts per surface via SurfaceContext)
components/ # Main, Header, Logs, Controls, ClosedButton, Messengers, Options, Menu,
# Notification, ResizeWrapper, ReturnToBot, LazyImage, ErrorBoundary
contexts/ # SurfaceContext — the surface descriptor (id, host, mode, position)
services/ # WebsocketConnection, WebsocketEvents, StaticStore, overlayStore, Notification
reducers/ # bot, menu, options, notifications, wsEvents/
actions/ # bot, menu, options, notification, types
helpers/ # commonHelper (sendAction, botElement, userUuid), soundHelper, scrollLock,
# bitrixHelper, fileHelper, messageHelper, cookieHelper, …
hooks/ # usePrevious, animateOpacity, openToggleRoot
assets/ # styles (theme-runtime.scss), svg, fonts, imgSee also Build — how this becomes a single bundle.