Client backoffice development¶
Technical conventions for frontend/client-backoffice: package boundaries, workspace
selection, and Config Studio routing for path-rooted workspaces.
Shared imports and domain contracts¶
The monorepo-wide shared package boundary model applies here. In client-backoffice specifically:
- Use scoped shared entrypoints only:
@inboundx/shared/config,@inboundx/shared/platform,@inboundx/shared/types, and@inboundx/shared/ui. - Keep
@/local to client-backoffice (src/). - Put service and domain contracts in
src/domain/*instead of importing types from UI components.
cd frontend && just lint includes the import-boundary checker that blocks new
shared-internal imports from app packages.
Which workspace key a screen uses¶
useWorkspace() exposes three keys. Two workspaces on one host share selectedDomain,
so picking the wrong one reads or edits the sibling.
| Key | Use for |
|---|---|
selectedWorkspaceId |
Data a workspace owns (knowledge, FAQs, datasets, and other workspace-scoped tables). |
selectedConfigKey |
Rows in config.client_configs for the active workspace. Always go through useResolvedConfig / useSaveConfigSection, which own the key: a workspace under a path inherits its host's rows and stores only its differences (frontend/client-backoffice/src/config/workspaceConfig.ts). Never pass a hostname to a config save. |
selectedDomain |
The registered domain for hostname-keyed readers (analytics, tracking, the admin API). Never a URL to fetch and never the identity of form state. |
Conversation screens are host-scoped: they list every workspace on the selected host. Code that
acts on one conversation (support tickets, deep links) takes its workspace from the turn's
messages.resolved_workspace.site_id, never from useWorkspace(). Turns from before routing
have none; fall back to the domain alone.
Config resolution and saves are documented in the unified config system.
Path-rooted workspaces and Config Studio¶
A studio screen may open for a workspace under a path only once everything it touches is keyed by workspace. Until then, restrict access or keep the route on the host workspace.
When a screen is ready, add its route to isPathWorkspaceConfigRoute in
frontend/client-backoffice/src/components/layout/AppLayout.tsx.
AppLayout remounts the page on workspace switch because several screens still use
selectedDomain as form identity while two workspaces on one host share that value.
Schema-driven sections (ConfigSection) say under their title which workspaces follow the
root workspace and which have their own version, and reset a path workspace to the root's
values (useWorkspaceInheritance). Custom setup screens (CTAs, suggested questions, brand)
do not show this yet.
After changing workspace keying or the selector, run the workspace non-regression checks.