Skip to content

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.