1System Inventory
Each system is the system of record for a defined set of business capabilities. A requirement is placed by matching what it does to the domain below — not by where it is easiest to build.
| System | Designated Domain | Native Mechanisms |
| SALESFORCE — CRM |
Leads, opportunities, sales activity, quote-stage negotiation, forecast, pre-sale communications |
Flows, validation rules, approval processes, quote templates |
| NETSUITE — ERP |
Customers (billing entities), items, pricing, sales orders, credit & AR, inventory quantities, billing, revenue, GL |
Price levels & pricing groups, SuiteFlow, user event scripts, saved searches, approval routing, invoicing & rev rec |
| 3PL — WAREHOUSE |
Physical fulfillment execution: pick, pack, ship, carrier selection, shipment confirmation, warehouse exceptions |
Warehouse rules (wave, cartonization, carrier rate shop), shipment webhooks |
2Data Ownership Map
For every core entity, exactly one system holds the authoritative copy. Every other system is a consumer of a synced, read-only projection. Logic that creates or changes an entity runs in the owner.
| Entity | Owner | Consumers | Notes |
| Lead / Opportunity | SALESFORCE | — | Never synced to NetSuite; pre-sale only |
| Quote | SALESFORCE | NetSuite (converted copy) | Becomes a Sales Order at Closed-Won |
| Customer | SPLIT BY STAGE | — | Salesforce owns the prospect record; NetSuite owns the billing entity from first order onward. Salesforce consumes NetSuite entityid, terms, credit status after conversion. |
| Item / Product | NETSUITE | Salesforce, 3PL | Item master syncs outbound only |
| Price & Discount rules | NETSUITE | Salesforce | Price levels / pricing groups; CRM displays, never computes |
| Sales Order | NETSUITE | Salesforce (status), 3PL (fulfillment request) | Created at conversion; all mutations in NetSuite |
| Inventory quantity | NETSUITE | Salesforce, 3PL | 3PL reports physical events; NetSuite ledger is authoritative |
| Shipment | 3PL | NetSuite (Item Fulfillment), Salesforce (status) | Tracking numbers, carrier, ship date originate here |
| Invoice / Payment / GL | NETSUITE | Salesforce (balance summary) | No financial data is authored outside NetSuite |
3Boundary Events
Responsibility passes between systems only at these four transitions. Logic is placed by asking: does it execute before or after the nearest boundary event? Integrations that bypass these events are flagged for remediation.
B1 · Closed-Won → OrderSalesforce → NetSuite
Quote becomes Sales Order. Contract: account ref, line items, negotiated prices, PO#.
B2 · Order Released → FulfillmentNetSuite → 3PL
Approved, credit-cleared order sent as fulfillment request. Contract: SO#, lines, ship-to, service level.
B3 · Shipment Confirmed3PL → NetSuite
Ship confirm creates/updates Item Fulfillment. Contract: SO#, quantities shipped, tracking, ship date.
B4 · Fulfillment BilledNetSuite internal
Item Fulfillment drives Invoice and revenue. No external system participates.
4Classification Rules
Applied in order. The first rule that resolves the item decides placement; when rules disagree, the lower number wins and the conflict is noted.
R1System of RecordLogic that creates or mutates an entity belongs in the system that owns that entity.
R2Process StageLogic belongs in the system responsible for the stage at which it executes, per the boundary events.
R3Data LocalityMulti-system inputs → place with the majority of the data; pass the remainder via the boundary contract.
R4Single PlacementNo rule set is implemented twice. One system is authoritative; the others consume its output.
5Worked Classifications
Six real-shape requirements run through the procedure. Each entry shows the verdict, the rule that decided it, and the concrete NetSuite / Salesforce / 3PL mechanism to use.
SALESFORCENETSUITE3PLSPLITVIOLATION FOUND
#1 — "Sales reps need customer-specific discount pricing on quotes."
Requested by: Sales Ops · Proposed build: discount formula fields in Salesforce CPQ-style config
NETSUITE
- Rule applied
- R1 — price rules mutate the Price entity; NetSuite owns pricing.
- Entities
- Reads: Customer, Item, Price (all NetSuite-owned). Writes: quoted line price.
- Stage
- Quote (before B1) — but stage does not override entity ownership.
- Placement
- NetSuite price levels + pricing groups on the item and customer records; customer-specific rates via the customer's Pricing sublist.
Data contract (consumption)
NetSuite → Salesforce nightly + on-change sync of effective price per (customer, item). Salesforce quote lines display the synced price read-only. Trigger: item/customer price change. Method: middleware upsert to a Salesforce price object.
R4 check Rebuilding the discount matrix in Salesforce would duplicate a rule set that already exists in NetSuite — two sources of truth that drift after the first price change. Salesforce displays; NetSuite decides.
#2 — "Hold orders from customers who are over their credit limit."
Requested by: Finance · Proposed build: block quote submission in Salesforce
NETSUITE
- Rule applied
- R1 — credit limit and AR balance are attributes of the NetSuite-owned Customer (billing entity).
- Entities
- Reads: Customer credit limit, open AR. Writes: Sales Order hold status.
- Stage
- Order processing (after B1, before B2).
- Placement
- NetSuite native credit hold (
creditholdoverride / customer credit limit) so held orders never reach boundary B2; the fulfillment request to the 3PL is simply not sent.
Data contract (consumption)
NetSuite → Salesforce sync of credit status + available credit to the Account, so reps see a warning at quote stage. The warning is informational; enforcement stays in NetSuite.
#3 — "Email the customer with tracking when their order ships."
Requested by: Customer Service · Proposed build: 3PL sends the email
NETSUITE
- Rule applied
- R3 — inputs are customer email, order details, brand template (NetSuite) + tracking number (3PL). Majority of inputs live in NetSuite.
- Entities
- Reads: Item Fulfillment, Customer, Shipment tracking. Writes: outbound communication log.
- Stage
- Immediately after boundary B3 (shipment confirmed).
- Placement
- NetSuite user event / workflow on Item Fulfillment status = Shipped, using an email template; tracking number arrives on the fulfillment via the B3 contract.
R4 check If the 3PL also sends its own notification, the customer gets two emails with different branding and no suppression logic. One sender: NetSuite.
#4 — "Reps need live inventory availability while quoting."
Requested by: Sales · Current state: reps keep a shared spreadsheet updated weekly
NETSUITE
- Rule applied
- R1 — inventory quantity is a NetSuite-owned entity; the spreadsheet is an unauthorized second copy.
- Entities
- Reads: item quantity available. Writes: none (display only).
- Stage
- Quote (before B1).
- Placement
- NetSuite remains the source; expose
quantityavailable per item/location via the item sync.
Data contract (consumption)
NetSuite → Salesforce: item availability snapshot every 15 minutes (or on-demand callout for high-value quotes). Field is read-only in Salesforce and labeled with sync timestamp so reps know its freshness.
Remediation Retire the spreadsheet. It is a manually-maintained duplicate of a NetSuite entity and will disagree with the ledger by construction.
#5 — "Discounts over 20% require a manager sign-off; orders over $50k require a CFO sign-off."
Requested by: Controller · One requirement, two approvals
SPLIT
- Rule applied
- R2 — two different process stages, so the requirement splits at boundary B1.
- Segment A
- SALESFORCE Discount approval executes at quote stage (before B1): Salesforce approval process on the quote, threshold sourced from the synced NetSuite price so "20%" is measured off the authoritative base price.
- Segment B
- NETSUITE Order-value approval executes at order stage (after B1): SuiteFlow approval routing on the Sales Order (
orderstatus Pending Approval → Pending Fulfillment) before it can reach boundary B2.
Data contract (at B1)
Quote → Sales Order carries: approved discount %, approver identity, approval timestamp (custom fields). NetSuite trusts the quote-stage approval and does not re-approve the discount; it only evaluates the $50k order rule. Each threshold is enforced exactly once (R4).
#6 — "When an item is out of stock, the warehouse substitutes an equivalent SKU so the order ships complete."
Found during review · Currently live as a 3PL warehouse rule
VIOLATION FOUND
- Rule violated
- R1 — substitution mutates Sales Order lines, a NetSuite-owned entity, from inside the 3PL. It also bypasses boundary B3's contract: the ship confirm reports SKUs that were never on the order.
- Observed impact
- Item Fulfillments fail to match SO lines; inventory is decremented on the wrong SKU; invoices bill the original item while the customer received another.
- Correct owner
- NETSUITE
Remediation design
Move substitution upstream of boundary B2: NetSuite evaluates availability at order release; a substitution rule (item-level related/substitute item plus a SuiteFlow or scheduled script) swaps the SO line before the fulfillment request is generated. The 3PL ships exactly what the request says — no discretion. B3 then reconciles cleanly, and billing, inventory, and the customer record all agree.
6Decision Checklist
The short form of the method — apply top to bottom to any new requirement before build planning.
- What does it write? The system that owns that entity is the default owner (R1).
- When does it run? Locate it against boundaries B1–B4; the stage's system takes it if R1 didn't resolve (R2).
- What does it read? If inputs span systems, place with the majority and add the minority to the boundary contract (R3).
- Does this logic already exist anywhere? If yes, consume it — never re-implement it (R4).
- Is a Split verdict clean? A valid split names the boundary event, the fields carried across, the direction, the trigger, and the sync method. If any of those five can't be named, the split isn't ready to build.
- Can't classify? List the missing facts and stop. A guessed placement costs more to remove than a delayed one costs to wait for.