One customer. One opportunity. One go-live date. That model feels perfectly reasonable until the customer buys a second rollout, the first rollout slips, and someone asks which date was originally promised.

Now the opportunity has three delivery dates, two project owners, and a notes field doing the work of a database. The dashboard still loads. The answers have become negotiable.

A Salesforce data model that can survive growth starts with a clear definition of what each record represents. We need separate records when the business has separate things to track, not whenever someone requests another dropdown.

Let's work through a hypothetical B2B company that sells a service and delivers it in multiple deployments. The names, amounts, and dates below are illustrative, not client results.

Start with the question your current model can't answer

Our example customer, Northstar, signs a $60,000 expansion covering East and West deployments. East goes live in October. West is planned for November and has a different delivery owner.

The sales team needs one commercial opportunity. Delivery needs two work records. Finance wants to count the $60,000 once. Leadership wants to know whether each deployment met its original commitment.

Putting everything on Opportunity forces those needs to compete. A single status can't describe both deployments. Adding East Status and West Status fields might survive this deal, but the third deployment will arrive with a feature request attached.

Before changing the schema, write four sentences:

  • An Account represents a customer organization under our agreed account hierarchy.

  • A Contact represents a person, with the appropriate relationship to that organization.

  • An Opportunity represents a commercial sale, with an agreed definition of amount and stage.

  • A Deployment represents one delivery episode with its own owner, status, and dates.

That last sentence is the reason to consider a separate object. "We ran out of space on the page layout" isn't.

Reuse the model you have before extending it

Keep the standard Account, Contact, and Opportunity concepts where they fit. Inspect existing objects, installed products, integrations, and reports before proposing Deployment__c. An existing project or delivery object may already represent the same thing.

For this example, assume it doesn't. A small custom Deployment object is reasonable because delivery episodes repeat and change independently of the sale.

Give it a name, delivery owner, status, original committed date, current target date, actual completion date, and a relationship to the source Opportunity. Agree which fields are required at creation and which become required as work progresses. A completion date shouldn't be fabricated just to save a newly planned deployment.

Use the Opportunity's Account relationship as the customer path unless there's a real need for a separate relationship. If deployments can serve a different account from the buying account, name those roles explicitly. Two unlabeled "customer" fields will eventually disagree.

This is the kind of decision revenue systems architecture should settle before automation turns an ambiguous definition into a repeatable mistake.

Choose the relationship by lifecycle and access

Lookup and master-detail relationships aren't interchangeable implementation shortcuts. Salesforce documents that master-detail ties important detail-record behavior to the master, including visibility and deletion. Deleting the master deletes its detail records. A lookup provides a looser relationship. Salesforce's object relationship guide explains those differences.

In our example, delivery staff need their own ownership and access rules, and deleting a sales record must not quietly remove delivery history. That points us toward evaluating a lookup to Opportunity, with deliberate required-field and deletion behavior.

The lookup alone doesn't implement that policy. Configure and test the relevant permissions, sharing, validation, and deletion restrictions in the actual org. Confirm what happens to existing deployments if someone tries to delete or change their source opportunity.

Don't select a relationship because it makes one total easier to calculate. First decide who should see the record, whether it can exist independently, and what must happen when its parent changes or disappears.

Keep sales totals at the sales level

Our example now contains one $60,000 opportunity and two deployments. A report that repeats the opportunity amount on each deployment row can display $120,000 if someone sums those rows.

Nothing was duplicated in the database. The report counted the same sale twice.

Define the report's grain, the thing each row represents, before choosing its columns:

  • Bookings report: one row per qualifying opportunity; Northstar contributes $60,000.

  • Delivery workload report: one row per deployment; Northstar contributes two deployments.

  • Deployment timeliness report: one row per deployment with an original commitment and actual completion date.

If the business needs revenue allocated by deployment, define a separate allocation rule and reconcile the allocations to the commercial total. Don't imply that repeating the parent amount performs an allocation.

The same discipline applies to opportunity stages people can trust: a field's label doesn't tell us what belongs in the metric. Its business definition does.

Preserve the promise as well as the latest plan

Suppose East was originally committed for October 15, then rescheduled to October 29. Overwriting the only target date makes the current plan look tidy while erasing the original promise.

Use separate meanings:

  • Original committed date: the approved baseline, with controlled correction rules.

  • Current target date: the team's latest forecast.

  • Actual completion date: when the defined completion event happened.

Agree what "complete" means. Technical configuration finished, customer acceptance received, and first production use are different milestones.

If every deployment needs a variable number of independently assigned milestones, evaluate related milestone records. If the business only needs one completion event, don't build an entire project-management system to hold it.

Historical reporting also needs a retention decision. Decide which changes need an audit trail or snapshots, who can amend the baseline, and how long evidence must remain available. Then verify that your chosen Salesforce configuration or reporting system supports those requirements. Three date fields are a useful start, not a complete audit strategy. For the sales-side version of this problem, see how close-date slippage can undermine a forecast even when the data looks clean.

Give repeat imports a stable identity

Names are for people. Integration keys are for matching records reliably.

For our hypothetical delivery system, use a stable key such as delivery:DEP-1042. Document how it's formed, whether case matters, and what happens when source systems merge or migrate. A renamed deployment should retain its identity.

Salesforce REST upsert can create or update a record based on an external ID. Its documentation distinguishes an External ID field from a field also marked Unique; selecting External ID alone doesn't enforce uniqueness. Multiple matching records cause an error rather than a successful update. See the REST upsert reference.

For this design, enforce the agreed unique deployment key and test the same import twice. The expected result is two deployments both times, with permitted updates applied, not four deployments with familiar names.

Prove the model with a small acceptance test

Before moving production data, create the Northstar example in a sandbox and ask sales, delivery, reporting, and integration owners to demonstrate these outcomes:

  1. Add a third deployment without adding another set of fields to Opportunity.

  2. Move East's target date without changing West or erasing East's original commitment.

  3. Show $60,000 in the bookings report and three records in the deployment report.

  4. Sign in as the actual delivery persona and confirm intended access, including fields they must not see.

  5. Run the same import twice and verify stable record counts and relationships.

  6. Attempt the prohibited parent deletion and confirm the agreed protection works.

Then test realistic scale and distribution. Include your largest customer, busiest owner, bulk updates, and reporting workloads, not just evenly distributed sample records. Record observed failures and resolve them before rollout.

Migration needs its own reconciliation: source counts, rejected rows, unmatched parents, duplicate keys, and before-and-after report totals. Keep a recoverable source export and agree the cutover and rollback process. Retire old fields only after their consumers have moved and the results reconcile.

Put definitions, ownership, and change review into a lightweight CRM governance framework. Otherwise the next urgent request will rebuild the ambiguity you just removed.

About CRM Hacker

We help teams connect record definitions, reporting and migration decisions through our revenue systems architecture work.

If one sale now spans several deliveries and your reports double-count the revenue, let's untangle your Salesforce data model. The initial conversation is free; detailed assessment, migration and implementation work are scoped and priced separately.