Multi-Connection Organizations & Document Routing
Organizations in Ordermatic can connect to multiple ERP systems or facilities (e.g. multiple Great Plains, Prophet21, or WhereFour instances). This document outlines the data model, routing decision engine, review UX, and feature flag conventions governing multi-connection organizations.
Data Model & Default Connection
Section titled “Data Model & Default Connection”Historically, an organization could hold at most one active ERP connection, enforced by a unique partial index. The multi-connection architecture relaxes this constraint:
-
Explicit Default (
is_default):erp_connections.is_defaultdesignates the fallback connection for the organization.- Enforced by a partial unique index
erp_connections_default_org_uniqueensuring at most one active default connection per organization. - Deactivating or deleting a default connection is rejected; another active connection must be designated as default first.
- Resolvers (
getOrganizationDefaultERPConnection) queryWHERE active = true ORDER BY is_default DESC, created_at DESC.
-
Short Facility Codes (
short_label):erp_connections.short_labelholds a 2–4 character uppercase identifier (e.g.OH,TX,DAL) displayed on inbox chips, badges, and pickers.- Unique per active connection within an organization via a case-insensitive unique index.
-
Per-Document Binding & Effective Connection:
- Document routing is bound on
pdf_documents.erp_connection_id. - Work items query effective connection via
COALESCE(pdf_documents.erp_connection_id, email_aliases.erp_connection_id)so document binding takes precedence over the mailbox alias.
- Document routing is bound on
Routing Decisions & Audit Trail
Section titled “Routing Decisions & Audit Trail”Every routing decision is recorded in erp_routing_decisions:
- Fields:
id: UUID primary keypdf_document_id: Target PDF document (FK)from_connection_id: Source ERP connection (nullable for initial binding)to_connection_id: Destination ERP connectionsource: Routing reason:upload: Manual upload pickeralias: Inbound mailbox alias bindingprior_decision: Historical human routing decision for the same sender domain / customer key (Flywheel)rule: Matching intake routing rule (inbox_routing_rules)default: Fallback to organization default connectionhuman: Reviewer confirmed or changed the destination in the review workbench
rule_id: FK toinbox_routing_rules(whensource = 'rule')sender_domain&customer_key: Extracted signals indexed alongsideclerk_organization_idfor $O(1)$ flywheel lookupssignals: JSONB metadata (extracted customer name, ship-to state, broker flags)actor_id&actor_email: Identity of human router (for manual decisions)
Review Workbench & Submit Gates
Section titled “Review Workbench & Submit Gates”The review-v2 workbench displays ReviewRoutingCard when an organization has multiple active connections:
- Destination Derivation:
- Derived from the connections of all matched lines (
extracted_order_items.erp_connection_id). - If all lines belong to one connection, that connection is the derived destination.
- If lines belong to multiple connections, split routing is required.
- Derived from the connections of all matched lines (
- Human Confirmation:
- CSR can confirm the derived destination or choose another facility.
- Re-picks customer matching if switching destination facilities.
- Submit Gates:
ROUTING_UNCONFIRMED: Blocks submission if an order’s latest decision was fromsource = 'default'and has not been confirmed by a human router.SPLIT_REQUIRED: Blocks submission if matched line items belong to multiple ERP connections (directs user to Quote Split).- Legacy documents without decision rows pass automatically.
Intake Routing Rules & Prior Decision Flywheel
Section titled “Intake Routing Rules & Prior Decision Flywheel”When erp_connection_routing_rules_v1 is enabled:
- Prior Decision Flywheel: Before evaluating rules, intake inspects recent human routing decisions matching
(clerk_organization_id, sender_domain, customer_key). If found, routes withsource = 'prior_decision'. - Intake Routing Rules: Evaluates active
inbox_routing_ruleswithaction_type = 'route_to_connection'ordered by priority:- Supports
customer_name_match,customer_name_in, andsender_domain_intriggers. - If matched, routes with
source = 'rule'.
- Supports
Cross-Site Catalog Search
Section titled “Cross-Site Catalog Search”In the review workbench item search modal (ERPSearchModal):
- Single-connection organizations search only their local catalog.
- Multi-connection organizations can check “Search all locations”.
/api/erp/parts?scope=orgqueries Typesense usingconnection_id IN [...], ranking items from the local connection first and labelling foreign items with their facility short label.- Selecting an item from another facility prompts for confirmation and binds the line to that facility.
Feature Flags & Segment Architecture
Section titled “Feature Flags & Segment Architecture”| Flag | Scope | Purpose |
|---|---|---|
erp_multi_connection_v1 |
Organization (getFlagForOrganization) |
Gates multiple active connections, inbox chips, connection pickers, and submit gates |
erp_connection_routing_rules_v1 |
Organization (getFlagForOrganization) |
Gates intake routing sweep (flywheel and route_to_connection rules) |
Flag Evaluation Convention (Plan D5/D9)
Section titled “Flag Evaluation Convention (Plan D5/D9)”- Document-bound surfaces (review cards, extraction, matching, pricing, ERP writes) evaluate on the connection identity (
getFlagForConnection). - Org-level surfaces (inbox list, backlog lists, chips, team, analytics, settings) evaluate on the organization identity (
getFlagForOrganization), never on the default connection. - Cross-Reference Test: Every
conn_*segment ininfrastructure/flagsmith/configs/segments.jsonmust have a correspondingorg_*sibling segment, enforced bytest_flagsmith_config_cross_references.py.