Connect by JBRH Open Connect

One implementation, two audiences

Connect serves an operator's own workspace and its customers' workspaces from one implementation. Every capability is available to both, over the same code; the difference is commercial, not functional — a customer's use is bounded by their plan's allowances. Behaviour lives in a module both routers call, and each router adds only its route. Parity is then enumerated from the running application rather than asserted.

Status
Available What this means
Audience
both, developer
Last verified
Product version
6.3.2

What one feature set means, precisely#

There is no operator-only feature and no customer-only feature. The same mailbox handling, the same phone behaviour, the same relationships, the same Voice Lab. What differs is the commercial frame: a customer's workspace has a plan with allowances, and the operator's has neither.

AspectOperatorCustomer
Sessioncustomer_mode falsecustomer_mode true
WorkspaceThe operator's ownOne tenant workspace
API pathsThe operator paths, called directly/api/customer/ui/…, reached by rewriting the path
LimitsNo plan, no allowance gatesThe plan decides the allowance
Vocabularyrelationships, knowledge-bankpeople, knowledge-sources — recorded as aliases

Three capabilities are correctly reachable only by the operator, and they are not features being withheld: verifying customer payments, the operator's own pricing, and website enquiries addressed to the operator, which live in a control-plane table outside every workspace. Those are the platform being run rather than Connect being used.

The seam that keeps it one implementation#

New behaviour goes into a module both routers call — mailbox_console for mail, workspace_console for screen data, relationship_console for one relationship, the voice configuration and preview endpoints, the supervisor panel. The operator's router and the customer's router add a route and nothing else.

  • No second implementation for the other audience. When the operator's own mail handlers were consolidated, they were rewired onto the shared console rather than left running in parallel.
  • No reduced view unless the omission is deliberate and written down. A customer-facing function that renders a subset is a decision that needs a reason recorded, not a default.
  • A rename is an alias, not a fork. The customer surface calls relationships *people*; that is a vocabulary difference registered in one place, and the code behind both names is the same.
  • Storage may still differ where moving it would be worse. Mailbox rows live in two tables; merging them would move live customer credentials and is not required for the capability. One console over one policy module was.

What drift looks like when it happens#

It does not announce itself. The operator's workspace had no way to connect a Google account while every customer did — the capability existed with nothing on screen calling it. Nothing failed, no test complained, and the gap was in the audience whose screen nobody had open.

That is the general shape: a copy stops keeping up rather than breaking, and the difference is discovered by whoever needs the missing half. It is also why the same report from either direction — "this works on the tenant and not on the operator" and its reverse — is treated as one class of defect rather than two unrelated ones.

Enumeration, and what one implementation costs#

The rule is checked rather than restated: the parity suite reads the flattened route table out of the running application and compares every operator capability with every customer one, with aliases registered and known gaps listed with reasons — a list that may shrink and must never grow. The mechanism, and how to read a 403 against it, is in a tenant facade that fails closed.

  • A defect in shared code reaches both audiences at once. That is the deliberate trade against silent divergence, and it raises the value of checking a change on both surfaces before it ships.
  • Every new operator path is a two-part change: the capability, and its customer mapping or a written reason for not having one.
  • Screens have to be looked at as each audience, in a browser, because several of these differences are invisible in source — the cases in defects invisible in the source.
  • Shared modules grow. A console serving two routers accumulates the union of both surfaces' needs, and keeping it coherent is ongoing work rather than a one-off consolidation.

Questions#

Do customers get a cut-down version of the product?

No. The same implementation serves both, and there is no customer-only or operator-only feature. What a plan bounds is volume — allowances — not which capabilities exist.

Why are payments and pricing operator-only?

Because they are the platform being run rather than Connect being used: verifying a customer's payment and setting the operator's own prices are not capabilities a tenant is missing. Website enquiries addressed to the operator sit outside every workspace for the same reason.

Why do the two surfaces use different words for the same thing?

Because the customer-facing vocabulary is chosen for a business rather than for an operator. The renames are registered as aliases so the parity comparison treats them as the same capability, which is what stops a vocabulary decision reading as a missing feature.