Part 3 — Delivery and Reference

N Implementing the ERP: People, Process and Change

Every chapter before this taught you to build the thing. This one is about whether anyone will use it. The longest-running published research is blunt: roughly one IT project in five is written off entirely, and about half arrive late, over budget or missing what was promised. The causes are almost never the code. They are scope, data, governance and people.

In this chapter15 sections · about 74 min
  1. What you need to know first
  2. Why ERP implementations fail
  3. Build versus buy versus configure
  4. Requirements gathering that works
  5. Scoping and phasing: the minimum viable ERP
  6. Data migration: the thing that actually sinks projects
  7. Project governance: who decides what
  8. Testing with real users
  9. Cutover: the plan for the actual night
  10. Training and adoption
  11. Hypercare and stabilization
  12. Change management, honestly
  13. Measuring success
  14. Vendor and consultant management
  15. What this means for your ERP

What you need to know first

First, the three letters on the cover. ERP stands for enterprise resource planning. It is an unhelpful name for a simple idea: one system that holds your products, your customers, your stock, your orders and your money, so that everyone in the company is looking at the same numbers. That is all it means.

An ERP implementation is the project that takes that software and turns it into the way your company actually works. It is not the same as writing the software. You can have perfect code and a failed implementation. You can have mediocre software and a wildly successful implementation. The two are separate problems. This chapter is about the second one.

Go-live, cutover and scope, defined

Some vocabulary you will hear constantly, defined from zero.

Go-live is the moment the new system becomes the real system. Before it, the old way is the truth. After it, the new way is. Cutover is the set of activities that gets you across that line: the last export from the old system, the final data load, the stock count, the switch-flip. It works like moving house. Go-live is the night you sleep in the new place. Cutover is the moving van and the meter readings.

  • Scope is the list of things the project promises to deliver.
  • Scope creep is that list quietly growing while the deadline does not.
  • Phasing means splitting scope into releases, so that phase one is small enough to survive.
  • Big bang means everything goes live at once.
  • Phased means going live in slices.
  • Parallel running means operating both systems at once and comparing the answers.

We will price all three out later.

Requirements are statements of what the system must do. Process mapping is drawing out how work flows today — who touches an order, in what order, using what document — before deciding what tomorrow should look like.

The people: sponsor, product owner, SMEs

Now the people:

  • The executive sponsor owns the outcome, settles arguments, and can tell a department head "no, we are doing it the new way." Usually the founder or the chief operating officer.
  • The product owner decides day to day what gets built and in what order. They are the single owner of scope.
  • A subject matter expert, or SME, knows how a particular job is really done: the warehouse supervisor who knows why cartons get restacked, the customer service lead who knows which shops pay less than they were invoiced.
  • A super-user is an ordinary employee trained deeply enough to help colleagues, so that not every question routes to you.
  • The steering committee meets on a fixed schedule to approve scope, budget and the decision to go live.

Testing, go-live and change-management words

Testing vocabulary. A conference room pilot, or CRP, is a structured walkthrough where real users drive the configured system through real situations, early, to find out whether the design is even right. User acceptance testing, or UAT, is the later, formal round where users work through written scripts and sign off. A CRP asks "is this the right system?" UAT asks "does this system work?" One does not replace the other.

Go-live vocabulary:

  • Opening balances are the starting numbers you carry in: how much of each product you hold, what each customer owes you, what you owe suppliers, what the accounts say.
  • Go/no-go criteria are conditions, written in advance, that must all be true before you may proceed.
  • Hypercare is the period of extra-heavy support straight after go-live.
  • Change management, sometimes called organizational change management or OCM, is the deliberate work of preparing people to work differently: communication, training, incentives, reinforcement. Almost everyone skips it.
  • Benefits realization means writing down beforehand what improvement you expect, capturing the current number, then checking later whether you got it.

The apparel words, in plain English

This book assumes you know nothing about the clothing trade, so here are the terms this chapter uses. Read the table once. Every one of them reappears below.

TermWhat it actually means
SKU"Stock keeping unit." One exact sellable thing. Not "the black shirt" but "the black shirt, size medium." A brand with 50 designs can easily have 2,000 SKUs.
StyleOne design, before you split it by color and size. "Style 220, the poplin shirt."
UPCThe barcode number printed on a garment's label. Unlike your own internal SKU code, it is globally unique, which makes it the one identifier your warehouse and your retailers can both agree on.
ColorwayOne color version of a style. The same shirt in black, in white and in navy is three colorways.
Size runThe set of sizes a style is made in — say XS to XL. "Ordering a size run" means ordering one of each.
Size curveHow many of each size you expect to sell. Most brands sell far more mediums than extra-smalls. The curve is that pattern, written down.
PrepackA pre-mixed carton, e.g. 2 small, 3 medium, 3 large, 2 extra-large. Shops buy the box rather than picking sizes.
SeasonThe block of time a collection is designed, sold and shipped for. Spring/Summer and Autumn/Winter are the classic two.
Market (or market week)The few weeks each season when shops come to view the new collection and place orders. Often built around trade shows.
LinesheetThe sales document listing every style, color, size, price and delivery date. Usually a PDF or a spreadsheet.
DropA batch of product released on a particular date, rather than a whole season at once.
Delivery windowThe agreed range of dates a shop will accept the goods. Ship outside it and they can refuse or fine you.
Order bookEvery order you have taken but not yet shipped. It is your best view of future revenue.
ATS (available-to-sell)How many units you can still promise to somebody. Not the same as what is on the shelf: it is stock on hand, minus what is already promised to other orders, plus what is arriving soon.
AllocationReserving specific stock for a specific order, so nobody else can sell it.
Short-shipSending fewer units than were ordered, because you do not have them.
Fill rateThe percentage of what was ordered that you actually shipped. 24 of 24 units is 100%. 19 of 24 is 79%.
BackorderThe unshipped remainder of an order, still owed to the customer.
ChargebackA fine a retailer deducts from your invoice when you break one of their rules — late delivery, wrong label, wrong carton. You do not get an invoice for it. They simply pay you less.
Short-payWhen a customer pays less than the invoice, for any reason, and you have to work out why.
Sell-throughThe percentage of the units a shop bought that the shop has since sold to real people. High sell-through is why they reorder.
3PL"Third-party logistics." An outside company that stores your stock and ships your orders. Your warehouse, run by somebody else.
EDI"Electronic data interchange." A rigid, decades-old file format that large retailers use to send orders and receive invoices automatically. Big accounts often make it mandatory.
ASN"Advance ship notice." An electronic message sent before a delivery arrives, telling the retailer exactly what is in each carton. Usually part of an EDI arrangement.
Cost sheetThe costing for one style: fabric, trims, labor, freight. It tells you the true unit cost and therefore the margin.
Landed costWhat a unit really costs you once it is in your warehouse: factory price plus freight, plus import duty (the tax charged when goods cross a border), plus handling.
Tech packThe instruction manual you send a factory: measurements, materials, stitching, labels. Enough for someone who has never seen the garment to make it.
GradingScaling one sample size up and down into the full size run.
PLM"Product lifecycle management." Software for the design-and-development side — tech packs, samples, fit comments — as opposed to the selling-and-shipping side.
Net 30 / net 60Payment terms. "Net 30" means the invoice is due 30 days after it is issued.
AR / AP"Accounts receivable" is money customers owe you. "Accounts payable" is money you owe suppliers.
AgingA report grouping unpaid invoices by how overdue they are: current, 30 days, 60 days, 90+.
General ledger (GL)The master accounting record. Every financial event in the business eventually lands here.
Trial balanceA summary listing the closing figure of every accounting category. The starting point when you switch accounting systems.
Cycle countCounting a small slice of the warehouse regularly, instead of counting everything once a year.

Finally, the shape of the business, because it drives the testing and cutover sections. A wholesale brand runs on seasons. You show a collection at market, take orders from shop buyers months ahead, place production orders on factories against that order book, receive the goods, then ship inside a delivery window agreed with each retailer.

An order written in February can ship in August. That gap is what makes apparel harder than most industries: the cycle is six to twelve months long, and you cannot wait a year to find out whether your system handles it.

Core principle

The software is the easy half. An implementation is a negotiation with people who already have a way of working that got the company this far. Treat that way of working with curiosity and you will find the twenty percent of it that is genuinely load-bearing. Treat it with contempt and they will keep using it, in a spreadsheet, where you cannot see it.

Why ERP implementations fail

Start with the numbers, because the numbers set your expectations.

The longest-running dataset is the Standish Group's CHAOS research, which has tracked IT project outcomes since the 1990s. In January 2026 the PM World Journal published a follow-up study by Giuseppe Arcidiacono that set the 2015–2017 CHAOS figures beside the 2020–2024 ones.

The comparison shows near-total stagnation:

  • Success — on time, on budget, in scope — moved from about 29% to 31%.
  • "Challenged" projects, meaning late, over budget or missing function, moved from about 52% to 50%.
  • Outright failure, meaning canceled or never used, sat at about 19% in both periods and did not move at all.

That flat line covers a decade in which most of the industry switched to Agile — a way of working that delivers software in short repeated cycles instead of one long push. Roughly one project in five is still a write-off.

The averages hide the real danger. Bent Flyvbjerg and Alexander Budzier studied 1,471 IT projects and reported in Harvard Business Review in 2011 that the average cost overrun was 27%, which is survivable. One project in six, though, was what they called a "black swan" — a rare outcome at the far extreme of the range, in this case averaging a 200% cost overrun and a schedule overrun of almost 70%.

Most projects are a bit late and a bit expensive. A meaningful minority are company-threatening. Plan against that tail rather than against the average. The 2026 review returns to the same point, borrowing Flyvbjerg and Gardner's idea of "fat tail" risk: a software project can overrun by a multiple rather than by a percentage, because scope creep stays invisible until it is already expensive.

Where the causes of failure are shifting

What is changing is why projects fail. The 2026 review argues that the root causes are moving away from process execution and toward strategic alignment and data governance — the rules about who owns each piece of data, who is allowed to change it, and how you know it is right.

Read its root-cause table carefully, though, because it is narrower than it first appears. That table contrasts traditional IT projects, whose primary failure cause it gives as poor requirements gathering, with artificial-intelligence projects, whose primary failure cause it gives as data immaturity. So the review does not demonstrate that data has already overtaken requirements as the leading cause of ordinary ERP failures, and you should be wary of anyone who claims it does.

What it does establish is a direction of travel, stated plainly in the author's conclusion: weak data governance now amplifies every other problem a project has. That is enough to justify what follows. The migration section below is the longest one in this chapter, and the failures documented later in this section, Birmingham above all, turned on data and governance rather than on code.

How much to trust these numbers

A word of caution about all of these figures, including the ones just quoted. The Standish Group's underlying CHAOS data is proprietary: you cannot download the sample or inspect the method, and researchers have argued for years about how "success" is even defined.

Consultancies also publish annual ERP surveys quoting median project costs and durations, and those medians get repeated everywhere as though they were laws. They come from small self-selected samples, mostly of organizations far larger than a growing apparel brand, and they swing hard from year to year. Treat every number in this section as an indication of direction. Do not plan a budget against any of them. Where this chapter quotes a figure, it comes from a source you can open yourself, listed at the end.

The consistent, uncontroversial lesson across every dataset: small, standard, phased projects mostly land. Large, heavily customized, big-bang projects produce the write-offs. You choose which kind you run.

Named failures and what actually went wrong

Specific disasters teach what abstractions cannot. Five publicly reported cases follow, chosen because each failure mode is available to you at your scale.

Hershey, 1999. The Y2K bug was the fear that older software, which stored the year as two digits, would read the year 2000 as 1900 and start miscalculating. Worried about it, the confectionery company set out in 1996 to replace its systems, and chose three at once: SAP's R/3 for the core, Manugistics for supply chain planning, Siebel for customer relationships.

The vendors recommended a 48-month timeframe. Hershey pushed for 30 months to beat Y2K. The systems went live in July 1999, three months behind schedule, heading into the busiest stretch of its year — Halloween and Christmas. Testing had been cut short.

Order processing broke, and the company could not process more than $100 million of candy orders even though most of the product was sitting in the warehouse. Quarterly profits fell 19%, the share price dropped 8% in a single day, and annual revenue fell about 12% from 1998 to 1999. Every ingredient was a decision made months earlier: too much scope, compressed testing, and a go-live date chosen without looking at the seasonal calendar.

Levi Strauss, 2008. This one should frighten you specifically, because it is an apparel company. Flyvbjerg and Budzier open their Harvard Business Review article with it. An SAP migration initially budgeted at under $5 million ended in a $192.5 million charge against earnings, and the chief information officer resigned.

The company could not fill orders: it took the shipping systems at its three big US distribution centers offline for a full week in April 2008 to fix problems receiving and fulfilling orders. Second-quarter net income fell by about 98%, to roughly $0.7 million. A brand that cannot ship during a delivery window loses far more than that week's revenue. It takes cancellations, chargebacks and reputational damage that cost seasons to repair.

Revlon and Lidl: unfamiliar platform, expensive customization

Revlon, 2018. Revlon completed its acquisition of Elizabeth Arden in September 2016 for $870 million. The two sides ran different systems: Revlon on Microsoft Dynamics AX, Elizabeth Arden on Oracle Fusion. Parts of the combined group — the Colomer business Revlon had bought in 2013, and Arden's Red Door Spas — ran SAP, and SAP is what the merged company chose to standardize on. So the target was a platform that neither main business had been running.

In early February 2018 it went live across much of North America, and the Oxford, North Carolina plant could not record inventory correctly. By March the company disclosed roughly $64 million of net sales it could not fulfill, a $20 million reduction in quarterly net earnings, and about $10 million of unplanned expense.

The stock fell 6.9% within a day, shareholder class actions followed, and the company disclosed weaknesses in its internal controls. The theme: a big-bang go-live onto an unfamiliar platform, on top of an unfinished acquisition, with no fallback.

Lidl, 2011–2018. The German discount grocer spent roughly €500 million over about seven years on an SAP-based program, abandoned it in 2018, and went back to its legacy systems. The core failure was inventory valuation.

Lidl valued stock using its own long-established logic; SAP Retail's standard used a different basis; and Lidl chose to customize the software rather than change the business practice, for fear of losing a competitive edge. Every customization added complexity and removed the benefit of buying standard software in the first place. Lidl's own summary was that the original strategic goals could not be achieved with reasonable effort. It is the canonical example of the most expensive mistake in enterprise software: paying for a standard product, then paying again to make it non-standard.

Birmingham City Council: governance that silenced bad news

Birmingham City Council, 2020–2026. The most instructive recent case, because the post-mortems are public and free to read. The council set out to replace a heavily customized SAP system with Oracle Cloud on a budget of about £19 million, plus £1 million of contingency. It went live in April 2022.

A Grant Thornton audit later reported the cost passing £90 million once re-implementation was counted, with full functionality not expected before 2026 — four years late. It has since gotten worse. By January 2026 the forecast total cost through the 2027/28 financial year had reached £144.4 million, the re-implementation had slipped again, and the system still was not doing the job.

The council had adopted an explicit "adopt not adapt" principle and then broke it, accepting extensive customizations to preserve processes inherited from the old system, and accepting significant change requests late in the build.

The bank reconciliation process — the routine check that the money the system thinks you have matches the money the bank says you have — has never worked properly. Posting errors were identified in April 2022, and by April 2024 the manual workarounds were estimated to be costing the council around £250,000 a month. It has since spent over £5 million on that manual labor and bought a separate third-party product to do the job.

Internal audit did not review the program until shortly before go-live, and when that review did identify key issues, the findings were not acted on. Auditors described a culture in which "either bad news was not welcome, or officers felt uncomfortable to communicate bad news," and found risks set out in the detail of reports rather than in the headline messages anyone would actually read. The council issued a section 114 notice, the local-government equivalent of declaring itself unable to balance its books, in September 2023.

CaseYearHeadline damagePrimary failure modeAvailable to you?
Hershey1999$100M+ of orders unprocessedCompressed testing; big bang into peak seasonYes
Levi Strauss2008$192.5M charge from a <$5M budgetDistribution cutover with no fallbackYes
Revlon2018~$64M of sales unfulfilledBig bang onto an unfamiliar platform mid-mergerPartly
Lidl2018~€500M written offCustomized standard software to fit an old processYes
Birmingham CC2022£19M budget; £144M forecast by Jan 2026Broke own "adopt not adapt" rule; governance silenceYes

Read the last column carefully. Four of the five failure modes are fully reproducible by a twelve-person apparel brand with a Next.js repository. You do not need a nine-figure budget to compress testing, to go live in the middle of a delivery window, to bend the system to fit a habit, or to create a culture where nobody wants to tell the founder the data is not ready.

The recurring root causes

Strip the cases and the surveys down and the same short list appears.

Scope too large for the organization to absorb. Hershey ran three systems at once. Every big-bang case is on this list.

Data. The reported causes of failure are shifting steadily toward data quality and data governance, and every case above involved data that nobody clearly owned. Treating data as a technical chore for the end of the project is the mistake. It is the longest-lead item you have, and most of the work is human judgment rather than code.

Customizing instead of adapting. Lidl and Birmingham both destroyed themselves this way, deliberately, to preserve a process somebody was attached to.

Governance that suppresses bad news. If the only acceptable project status is green, you get green right up until the day the accounts do not balance. Birmingham is the textbook case, and it is free to read.

No change management. Prosci, whose research on this is the most widely cited practitioner dataset, reports that 88% of participants with excellent change management met or exceeded their objectives, against 13% of those with poor change management. That gap is where the widely quoted "seven times more likely to succeed" comes from: 88 divided by 13 is a little under seven. Treat the multiplier as directional, because this is practitioners grading their own projects in a survey rather than an independent audit. The direction itself is not disputed anywhere.

Timing against the business calendar. Hershey went live before Halloween. Your equivalent is going live in the middle of a delivery window, or during market week.

The failure you are most likely to have

Your project will most likely fail quietly. It goes live 80% right, with no spare capacity to fix the other 20%, and the team rebuilds the missing pieces in Google Sheets. Six months later the ERP holds stale data, nobody trusts the availability numbers, and you are paying to run two systems. That ordinary failure is far more common than the dramatic ones, and it is what most of this chapter is designed to prevent.

Build versus buy versus configure

You are reading a book about building an ERP, so you might expect this section to tell you to build one. It will not. Most apparel brands should buy. You should understand exactly why, and what would make you the exception.

First, understand the market you would be opting out of. The industry loosely sorts enterprise software into tiers by the size of customer it targets:

  • Tier I products aim at the largest global companies: SAP S/4HANA, Oracle Fusion, Infor CloudSuite.
  • Tier II covers the broad middle, from Microsoft Dynamics 365, IFS, Sage X3 and Epicor Kinetic at the upper end down to NetSuite, SYSPRO, Acumatica and Rootstock.
  • Tier III is hundreds of niche and industry-specific products.

The revenue boundaries between these tiers are informal, differ by whoever is drawing them, and shift year to year, so do not treat them as precise. A wholesale apparel brand doing $5–40 million sits at the lower end of the middle tier, or in the apparel-specific niche.

That niche matters, because generic ERP handles apparel badly. A generic system wants a product to be a thing with a quantity. Apparel wants a style, in colorways, in a size run, bought as a prepack or against a size curve, tied to a season, with a delivery window, a cost sheet listing fabric and trim, and history you can compare against the same week last year.

Apparel-native products model all of that out of the box. The rest make you fake it with generic attribute fields, and then cannot give you a size-curve report.

What the vendors publish, as of July 2026

Below is published pricing, read directly from each vendor's own pricing page in July 2026. Software prices change often, so treat every figure in this table as "as of July 2026" and open the vendor's page before you rely on it. These are list prices, useful for planning. What you actually pay after negotiation is usually different.

ProductPublished entry pricePublished higher tierNotes
Zedonk (apparel ERP/PLM)$225/mo — Studio Design Suite$425/mo Core Operations Hub; $500/mo Studio Operations Suite; $650/mo Commerce Operations HubPaid annually. The vendor states the bundles are examples and can be customized.
ApparelMagic (apparel ERP)$337/mo — Professional: 3 users, 3 integrations, 3 warehouses$655/mo — Enterprise: 5 users, 5 integrations, 5 warehousesPaid annually; monthly billing on an annual commitment costs slightly more. "Ultimate" tier (10+ users) is quote-only.
Cin7 Core (inventory-led, not apparel-native)$349/mo — Standard: 5 users, 6,000 orders/yr$599/mo — Pro: 10 users, 24,000 orders/yr; $999/mo — Advanced: 15 users, 120,000 orders/yrStrong ecommerce integrations. Cin7 Omni is quote-only.
NetSuiteNo published list priceQuote-only. Priced as a base platform plus per-user seats plus modules; implementation is a separate cost.
Aptean Apparel ERPNo published list priceQuote-only, and one edition states a 15-user minimum. Aimed at larger brands than the published-price products above.
BlueCherry (CGS)No published list priceQuote-only. A separate vendor from Aptean, despite the two often being listed together. Also aimed at larger brands.

What that tells you, as of July 2026. Multiply the entry prices by twelve and a credible apparel-native system publishes at roughly $2,700 to $4,200 a year: Zedonk's $225 a month is $2,700, ApparelMagic's $337 is $4,044, Cin7 Core's $349 is $4,188. Move up to five or ten users and multiple warehouses and the published tiers run to roughly $7,800 to $12,000 a year — $655 a month is $7,860, and $999 a month is $11,988.

Above that, vendors stop publishing and start quoting, which is itself informative: quote-only pricing generally means bigger deals and a required implementation project. Ask every vendor, in writing, what implementation, data migration and training cost on top of the license. For anything above the entry tier those services frequently cost more than the first year of software.

The honest comparison

One term before the table. SaaS stands for "software as a service": you rent the software by the month, the vendor runs it on their own computers, and updates arrive automatically. You never install anything on a server of your own. Almost every product in the pricing table above is sold this way.

DimensionBuy (apparel SaaS)Configure (generic ERP + partner)Build (this book)
Time to first useful output4–12 weeks4–9 months6–18 months
Year-one cash cost~$3k–15k on published tiers; more if quote-onlyVaries enormously — tens of thousands to low six figures, dominated by implementation labor, not licenseYour time, plus roughly $1k–5k of hosting and services
Ongoing costLicense grows with users and order volumeLicense plus a partner retainerYour engineering time, forever
Apparel model (size runs, seasons)NativeBolted on or absentExactly what you build
The odd workflow you actually needOften impossibleExpensive customizationTrivial
Key-person riskLowMediumExtreme — you are the vendor
Compliance and audit trailComes with the productComes with the productYou must build it and defend it
Who fixes it at 2am in peak seasonVendor support, under a service level agreementThe partner, if you have retained themYou

A service level agreement, or SLA, is the contractual promise about how fast a vendor will respond and how much downtime is acceptable. It is the row that decides this table for most people. Buying transfers operational risk to somebody whose business is absorbing it. Building keeps it. A brand with one technical founder who also does everything else is buying a permanent second job with no holiday cover.

When building is genuinely the right call

Build if at least three of these are true. (1) Your core operating model differs materially from every product you have demoed, and that difference is a competitive advantage rather than a habit. (2) You have durable engineering capacity — not one founder, but a person whose job this still is next year. (3) Your integration surface is unusual enough that you would end up building half of it anyway. (4) Products that actually fit would cost more than a developer over three years. (5) There is a specific, dated business event that a bought system provably cannot support. If fewer than three hold, buy — then build the small custom layer around it.

The hybrid deserves naming: buy the boring parts, build the sharp ones. Never build accounting, warehouse management or shipping labels. But the order-book view, the availability calculation your reps quote from, and the size-curve analysis that tells you what to cut are places where a brand can genuinely beat its competitors, and they are small enough to build well.

Requirements gathering that works

Most requirements documents are useless, because they are feature lists collected by asking people what they want. People are bad at that question. They describe software they have used, the workaround they built, or whatever annoyed them last week.

Map the current state first

Before writing a single requirement, follow real work through the business. Watch it happen rather than asking people to describe it.

Pick one customer order and trace it end to end. Watch what the person opens, types, looks up, prints, emails and checks twice. Write down every artifact: the PDF the rep sends, the price-list spreadsheet, the sticky note about the customer who is not allowed to order until they pay. Then do it again for a production order to a factory, a goods receipt, a shipment and an invoice.

CURRENT STATE: wholesale order, from rep to cash
=================================================

 1. Rep writes order at market  ......  paper/iPad, brand form
 2. Rep emails order to CS       ......  PDF attachment, 1-3 days
 3. CS keys into QuickBooks      ......  ~8 min/order, retypes SKUs
 4. CS checks stock              ......  opens "MASTER STOCK v7.xlsx"
     ^ spreadsheet updated manually, Mondays only
 5. CS checks credit             ......  emails finance, waits
 6. Finance approves / holds     ......  no record of the decision
 7. Order confirmed to buyer     ......  CS retypes into email body
 8. Warehouse picks              ......  printed pick list, pen marks
 9. Short-ship happens           ......  warehouse writes on the sheet
10. CS amends invoice            ......  finds out at invoicing, not pick
11. Invoice raised               ......  QuickBooks, manual carton count
12. Retailer short-pays          ......  reason unknown for ~6 weeks

HANDOFFS: 7    RE-KEYING EVENTS: 4    SYSTEMS OF RECORD: 3
LONGEST DELAY: step 5-6 (credit), median 2 days, max 9

Read that block like this. "CS" is customer service. Four points in the flow have a human retyping data that already exists in digital form — those are marked as re-keying events, and each one is a place where errors enter. Three competing systems of record means there is no single truth about how much stock you have.

The credit check is the longest delay and leaves no written trace, so nobody can later answer "why was this order held?" And the short-ship surfaces at invoicing rather than at picking, which is exactly why the retailer pays you less six weeks later. Those four observations are your real requirements, and not one of them would have appeared on a wishlist.

Genuine requirement or habit?

The hardest judgment in requirements work is separating a rule the business genuinely depends on from a habit that exists because of a limitation nobody has revisited. Both are defended with equal passion. Use a simple test: What breaks if we do not do this? Who outside this room notices? When did we start doing it, and why?

A genuine requirement survives all three. "We must be able to reserve stock for a specific customer before it arrives" — that breaks our ability to confirm a delivery window to a key account, the buyer notices immediately, and we started doing it because we sold the same units twice in 2023. Encode it.

A habit fails at least one. "The pick list must be sorted alphabetically by style name" — that breaks nothing, nobody outside the warehouse notices, and we started because the old system could not sort by shelf location. That is scar tissue from a previous system, and building it makes picking slower forever.

The "we do it differently" trap

Every business believes its process is unusual. Almost none are. When somebody says "we do it differently here," ask them to describe the difference in terms of what the customer experiences. Usually the answer is an internal step, not a customer-visible outcome, and internal steps are negotiable. Genuine differences do exist — a brand that licenses its name and must report royalties by territory, or one that sells the same style to a department store and an independent boutique at different prices and with different return rights. They are few, specific and worth building for. The imagined ones are many and vague. Lidl spent about €500 million honoring one.

Write requirements as scenarios

A feature list is untestable. "The system shall support partial shipments" tells you nothing about what happens to the unshipped balance, whether the delivery window still applies, or whether the invoice covers what shipped or what was ordered. Write scenarios instead: a person, a situation, the action, and the observable outcome — including the money.

SCENARIO: SO-14  Short-ship discovered at pick
----------------------------------------------
Persona:  Marcus, warehouse supervisor
Given:    Order 4471, Nordstrom, ship window 01-15 Aug
          Line 3: STYLE-220 / Black / size run 24 units
          Physical stock on hand: 19 units
When:     Marcus picks and confirms 19 of 24
Then:     - Shipment records 19; 5 remain on the order
          - Order line status = PARTIALLY_SHIPPED
          - Invoice is raised for 19 units only
          - CS sees the shortage the same day, not at
            invoicing
          - Buyer notification is generated with the
            5-unit balance and a revised date option
          - Ledger shows -19 from the pick bin, and the
            5 stay reserved, not released to ATS
Money:    Invoice = 19 x $42.00 = $798.00
          Backorder value $210.00 stays in the order book
Fails if: ATS increases by 5 at the moment of shipment
Owner:    Marcus (ops) + Priya (CS) both sign off

Look at what that does which a feature list cannot. It names two owners who must both agree, so ambiguity gets resolved by humans rather than by a developer guessing at midnight. It states the money, so finance can check it.

Its "fails if" line captures the specific wrong behavior the team fears: the five unshipped units quietly going back into available-to-sell, where a rep sells them to somebody else and you short two customers instead of one.

And because it describes an observable outcome, it is directly executable as a user acceptance test script, so your requirements document and your test plan are the same artifact. Write forty to sixty of these and you have specified a wholesale apparel ERP.

Scoping and phasing: the minimum viable ERP

Big-bang scope is the most reliable predictor of failure in the case studies above. Your scope decision moves the outcome more than any other decision you will make, and you make it before you write any code.

Ask one question of every candidate for phase one: what is the smallest set of capabilities that lets us stop using the old system for one complete, self-contained flow? "What would be nice" is the wrong test. And if phase one leaves people running both systems for the same task, you have doubled the work rather than phased it.

CapabilityPhase 1Phase 2Later / never
Customer and supplier master recordsYes
Products: style, color, size, seasonsYes
Stock ledger and on-hand by locationYes
Sales orders, allocation and available-to-sellYes
Pick, pack, ship, invoiceYes
Purchase orders (POs) to factories, goods receiptYes
Accounting integration (push invoices out)Yes
Self-service ordering portal for shop buyersYes
EDI with the big retail accountsYes
Landed cost: duty and freight spread over unitsYes
Full PLM: tech packs, fit history, gradingYes
Demand forecasting and auto-replenishmentYes
Sales commission calculation engineYes
Warehouse shelf-layout optimizationYes

Where the phase-one line sits

The line between phase 1 and phase 2 sits at one place: everything needed to take an order, know what you have, ship it and get paid. That sequence is called order-to-cash, and it is self-contained. You can switch it on and turn the old system off for that flow entirely. EDI and the buyer portal are valuable but additive — the business functions without them, on email and PDFs, exactly as it does today.

Notice the "later or never" column too. Full PLM is a separate product category with its own vendors — Centric, Bamboo Rose, Backbone, PTC FlexPLM, Lectra, BeProduct, and pulling tech-pack management into phase one is how brands end up two years late.

Forecasting needs clean sales history that you will not have for a year. And commission engines are politically explosive, because the moment you automate a rep's pay you are auditing it.

The discipline of saying no

Every request arrives with a plausible story and a person who will be disappointed. You need a response that is neither "no" nor "yes": "That is a real need. It goes in the backlog with a written scenario, scheduled for phase two. If it must be in phase one, tell me which phase-one item it replaces." The backlog there is just the ordered list of everything you have agreed to build but have not built yet. Forcing a trade instead of an addition is what makes the answer work. It converts an argument with you into an argument with the person whose item would be cut, and those resolve honestly.

One more piece of discipline: fix the phase-one go-live date first, then work backward to see what fits. Do not fix the scope and then estimate a date. The first method produces a project. The second produces Hershey.

Data migration: the thing that actually sinks projects

This is the section people skim and then regret. Remember where the 2026 review said the causes of failure are heading: toward data quality and data governance. Chapter 7 covered the mechanics of spreadsheet imports — parsing, column mapping, validation, error reporting. This section is about the project work surrounding those mechanics, and it is mostly not engineering.

Data archaeology

Your data does not live where you think it does. In a typical apparel brand of $5–30 million it is spread across:

  • an accounting package
  • spreadsheets the operations lead maintains and quietly guards
  • a warehouse system or 3PL portal
  • an ecommerce platform with its own idea of what a SKU code looks like
  • a shared drive full of PDF linesheets
  • and email threads containing agreed terms that exist nowhere else.

Inventory these before you design anything. For each source, record who owns it, how many rows it has, how far back it goes, what it is keyed on, and, above all, where it disagrees with the others.

DATA SOURCE INVENTORY  (fill this in before you build)
======================================================
Source           Entity      Rows   Owner    Trust  Keyed by
---------------  ----------  -----  -------  -----  ----------
QuickBooks       Customers   1,240  Finance  HIGH   Display name
QuickBooks       Invoices   18,600  Finance  HIGH   Doc number
MASTER_STOCK.xls Inventory   4,900  Ops      LOW    Style-Colour
Shopify          Products    3,100  Ecomm    MED    Shopify SKU
3PL portal       Inventory   4,400  3PL      HIGH   Barcode/UPC
Linesheet PDFs   Prices        n/a  Sales    MED    Style name
Email threads    Terms         n/a  Founder  ???    (none)

KNOWN CONFLICTS
- Customer "Nordstrom" exists 4x in QuickBooks:
  "Nordstrom", "Nordstrom Inc", "NORDSTROM #402", "Nordstrom.com"
  -> 4 separate balances, 1 real trading relationship
- Shopify SKU format differs from warehouse barcode
  Shopify: TW-220-BLK-M    3PL: 0810234002201
  -> no mapping table exists anywhere
- MASTER_STOCK.xls disagrees with 3PL on 380 SKUs
  -> nobody knows which is right; 3PL probably is

A couple of terms in that block. "UPC" is the barcode number printed on the garment's label. "Keyed by" means the field that source uses to identify a row uniquely, and the whole problem is visible in that column, because no two sources use the same one.

Every line there is a decision you will otherwise end up making accidentally at 2am during cutover. The "Trust" column matters most, and it must be assigned by a human with authority rather than inferred by a script.

Note the pattern in the conflicts: the same real-world thing has four names in one system and no shared key across systems. That is completely normal, it is the largest single source of migration effort, and it is not a coding problem. Somebody must decide that "NORDSTROM #402" is the same trading partner as "Nordstrom Inc" and that their balances merge.

Cleansing and deduplication

Clean the data in the old system, not in the import pipeline. If you clean during the load, the old system stays dirty and every rehearsal reintroduces the same mess. Clean it in the source and the fix is permanent, so each rehearsal starts cleaner than the last.

Sequence it. Dedupe customers first, because everything else hangs off them. Then products. Then open transactions. Give each entity a named owner who signs off — finance owns customers and suppliers, operations owns products and stock. "Nobody owns the data" is how it stays broken.

For deduplication, do not be clever. Automated fuzzy name matching will eventually merge two genuinely distinct boutiques with similar names, and that error is far worse than a missed merge: you cannot easily unpick two customers' order histories once they are one record. Generate candidate pairs automatically, have a human confirm each one, and record the decision permanently so the next rehearsal does not ask again.

How much history to bring

This argument will consume more meeting time than it deserves. The default below is defensible. One term first: master data, or master records, means the reference lists a business keeps standing — customers, suppliers, products, locations. They describe things that exist. Transactions, by contrast, describe things that happened: an order, a shipment, an invoice. The two need different migration rules, which is why the table below separates them.

DataBring into the ERPWhy
Customers, suppliers, productsAll active, plus anything that traded in the last 24 monthsMaster records; cheap to carry, painful to miss
Open sales ordersAll open, in fullThis is your order book; the business runs on it
Open purchase ordersAll open, in fullStock arriving that you must receive against
Stock on handPhysically counted, as at cutover onlyNever migrate a running balance — count it
Unpaid customer and supplier invoices (AR/AP)Open items only, invoice by invoiceYou must chase these and pay those
Closed sales history24–36 months, summarized by month, style and customerEnough for "same week last year" comparisons
Closed invoices, line by lineLeave in the old system; keep read-only accessMigration cost exceeds the value; auditors accept an archive
General ledger detailOpening trial balance onlyThe detail stays with the accounting system of record

The rule underneath that table: migrate what you must transact against, summarize what you must analyze, and archive the rest with a documented way to retrieve it. The instinct to bring "everything, just in case" multiplies migration effort and buys almost nothing. Nobody queries seven-year-old invoice lines, and on the rare day somebody does, they can open the old system.

Never migrate a stock balance

Every other opening balance can be carried over from a trustworthy source. Stock cannot, because your spreadsheet is wrong and you do not know by how much. You must physically count it. If you migrate a stock figure you did not count, you have permanently poisoned the one number the entire business will judge the system by, and every discrepancy for the next year will be blamed on the software rather than on the bad starting figure. Count it, get it signed off, and post it as an explicit opening entry in the ledger.

Rehearsal: run the migration repeatedly

A migration you have run once is a migration that will fail. Large programs run several full practice cycles before the real cutover for exactly this reason. Yours should too, and at your scale each one is cheap.

MIGRATION REHEARSAL SCHEDULE
=============================
Run 1   T-10 weeks  Load everything, expect chaos.
                    Goal: discover unknown data, not pass.
                    Output: defect list + rules to add.

Run 2   T-7 weeks   Cleansing has started in source.
                    Goal: every entity loads; errors < 5%.
                    Output: reject reasons categorised.

Run 3   T-4 weeks   Full dress rehearsal, timed.
                    Goal: errors < 0.5%; record wall-clock
                    duration of every step.
                    Output: the cutover runbook timings.

Run 4   T-2 weeks   Repeat run 3 on a fresher extract.
                    Goal: reconcile to the penny on AR/AP.
                    Output: sign-off sheet dry run.

Run 5   Cutover     The real one. No new code. No new
                    mappings. Only a rerun of run 4.

RULE: the cutover run must contain ZERO steps that have
      not been executed successfully at least twice.

"T-10 weeks" simply means ten weeks before go-live. A runbook, mentioned under run 3, is a written list of every step in an operation, in order, with an owner and an expected duration against each one.

That schedule does three jobs:

  • It converts unknown data problems into a known defect list early, while there is still time to fix them at source.
  • It measures how long each step actually takes, which is the only honest input to your hour-by-hour cutover plan.
  • And by run 4 it has turned migration from an engineering event into a boring repeat of something the team has already done four times, which is exactly the state you want everyone in on the night.

The rule at the bottom is what saves you: any step performed for the first time during cutover is an unexploded bomb.

This connects straight back to chapter 7. The importer you built there — column mapping, row-level validation, rejection report — is the engine. What this section adds is that it must be re-runnable without side effects, because you will run it five times against a database that must end up identical each time.

Engineers call that property idempotency: running the same operation twice leaves the same result as running it once. In practice it means every migrated record carries the name of the system it came from and its identifier in that system, and loading performs an upsert on that pair — update the row if it already exists, insert it if it does not — rather than a blind insert. Chapter 3's idempotency machinery is what makes rehearsal possible at all.

Project governance: who decides what

Governance sounds like corporate theater, and it earns its place anyway. It answers a question that arises twice a week: two people disagree, who decides, and how do we remember what was decided?

The executive sponsor

The sponsor owns the business outcome. Attending meetings is the smallest part of the job. The role is three things:

  • protecting the project's resources when other priorities appear
  • settling disputes between departments
  • and being visibly committed enough that everyone understands the new system is compulsory.

Prosci's survey data puts real weight behind the role. Among its respondents, 79% of those with extremely effective sponsors met or exceeded their objectives, against 27% of those with extremely ineffective sponsors. Again, that is practitioners reporting on their own projects, so read it as a strong signal rather than as a measurement.

Without one, this is what happens. The warehouse supervisor is needed for user acceptance testing. The warehouse is busy. Their manager keeps them on the floor. Testing slips, and nobody has the standing to say the project matters more this week. Multiply that by every department. Nobody ever cancels the project. It simply starves.

In a founder-led brand the sponsor is usually the founder, and there is one failure mode to avoid: the founder who is also the developer, the product owner and the sponsor. Those roles conflict by design. The developer wants to build the elegant thing. The product owner must cut scope. The sponsor must tell the developer that their scope is too big. Nobody holds that argument honestly with themselves. If that is you, name somebody else to sign the go/no-go decision, and give them real authority to say no to you.

The internal product owner and the SMEs

The product owner is the single person who prioritizes. They own the backlog, they accept or defer requests, and they are accountable for phase one being small. They must be internal. If a consultant holds this role, scope decisions are being made by somebody who gets paid more when scope grows and who will not be there to live with the result.

Your subject matter experts are your named domain authorities: one each for sales, warehouse, finance and production. Each owes the project a bounded amount of time, negotiated with their manager in hours per week, in writing. "We'll need Priya sometimes" leaves everything to chance. "Priya, six hours a week, Tuesday and Thursday mornings, through go-live" is something a manager can actually plan around, and something you can tell has been broken.

Steering cadence and the decision log

Keep it light and frequent. Weekly, thirty minutes, four items: what shipped, what is blocked, what decisions are needed, and whether the date is still credible. Monthly, a longer session on budget, scope and risk.

The most valuable artifact in the project is the decision log. Every non-trivial decision goes in it with the date, the question, the options considered, the decision, who made it, and whether it can be undone.

DECISION LOG  (extract)
=======================
D-011  2026-03-04
Q:  Do we allow stock on hand to go negative?
Opt: (a) block; (b) allow with warning; (c) allow silently
Dec: (a) block. Picks against zero stock are rejected.
By:  Sponsor (founder) after ops/finance disagreement
Why: Negative stock is always a data error here; the
     3PL confirms counts daily. Blocking surfaces it
     same-day rather than at month end.
Rev: Reversible - config flag, not schema.
Revisit: after 2 peak weeks live.

D-014  2026-03-11
Q:  Migrate 7 years of invoice line detail?
Opt: (a) all 7y; (b) 3y detail + summary; (c) 2y summary
Dec: (b) 3 years detail, older summarised by month.
By:  Product owner, finance SME concurring
Why: Accountant confirmed archive access to legacy
     system satisfies audit. 7y triples load time.
Rev: NOT reversible after legacy decommission (2027-01).
Revisit: no.

Two things make that valuable rather than bureaucratic. The "reversible" field separates cheap decisions from expensive ones, so you spend your deliberation where it counts — D-011 is a configuration flag somebody can flip back in a minute, while D-014 permanently determines what data will exist.

And "revisit" gives the people who lost the argument a legitimate future hearing, which closes the discussion without leaving anyone feeling steamrollered. Six months later, when somebody insists "we never agreed to block negative stock," you have the date, the reasoning and the name.

One ritual is worth mandating, given Birmingham. At every steering meeting, ask each subject matter expert directly for the one thing most likely to go wrong, and thank them visibly for saying it. If the answer is ever "nothing," your reporting is broken, not your project.

Testing with real users

Developer testing proves the code does what the developer meant. It cannot prove the system does what the business needs, because the developer does not know what the business needs. You need two distinct rounds with real people.

Conference room pilot

A conference room pilot is early and exploratory. Put your subject matter experts in a room with the configured system and walk real situations end to end. Give them a task, in their own words: "here is an actual order from last season, process it." Never a script of button presses. The purpose is discovering design errors while they are still cheap to fix. Run at least two rounds: one when core order-to-cash roughly works, and another after the fixes.

Run it properly. Use real data, never "Test Customer 1." Nobody spots a wrong result on fake data, but they will instantly notice that Nordstrom's payment terms are showing as net 30 when they are net 60. Have somebody whose only job is recording every hesitation, because a hesitation is a usability defect that the user will never report as one. And resist fixing anything in the room, or you will get through two situations instead of twenty.

User acceptance testing

User acceptance testing is later and formal. Users execute the SO-14 style scenarios written during requirements, and record pass or fail with evidence.

Two rules make it meaningful instead of theater. First, whoever wrote the code does not run the test. Second, a test passes only when the business outcome is right. An invoice that generates successfully for the wrong amount has failed, and recording it as a pass with a note attached is how wrong amounts reach customers.

Define your exit criteria in advance and in business terms:

  • every critical scenario passes
  • no open defect carries revenue or compliance impact
  • and every accepted workaround has a named owner and an end date.

The seasonal problem

Apparel has a peculiarity that makes it harder than most industries, and that almost no generic implementation guide addresses.

Your business cycle is six to twelve months long. An order taken at market in February ships in August. A production order placed with a factory in March lands in July. A chargeback for a late delivery arrives in September and is deducted from a payment in October.

If you test only what happens this month, you have validated perhaps a fifth of your system, and the untested four fifths includes everything about seasons, delivery windows, aging order books and cancellation dates.

You cannot wait a year to find out. So you must simulate a compressed season. This is an engineering requirement that flows directly from a business fact, and it has to be designed in from the start.

COMPRESSED SEASON TEST  (run over 5 working days)
==================================================
Day 1  = simulated February: MARKET
  - Load a real prior-season linesheet
  - Enter 40 real orders from last year's order book
  - Two orders with special terms, one on credit hold
  - CHECK: order book totals match last year's actuals

Day 2  = simulated March: PRODUCTION
  - Generate production POs from the order book
  - One factory confirms short, one confirms late
  - CHECK: order book vs on-order coverage report

Day 3  = simulated July: RECEIVING
  - Receive POs; one arrives 400 units short
  - One arrives with a substituted colourway
  - CHECK: allocation re-runs; ATS updates; the
    short creates a visible exposure, not silence

Day 4  = simulated August: SHIPPING WINDOW
  - Pick/pack/ship 40 orders inside their windows
  - Force 3 short-ships and 1 window miss
  - CHECK: cancellations, backorder handling,
    invoice amounts, EDI/ASN content if in scope

Day 5  = simulated Oct: CASH, CLAIMS, CLOSE
  - Apply payments incl. 2 short-payments
  - Enter 1 chargeback for the late window
  - Run month-end; reconcile to opening balances
  - CHECK: AR ageing, margin by style, sell-through

REQUIREMENT: the system must accept a configurable
"business date" outside production, so that windows,
ageing and season logic can be exercised out of
real time. Without it this test is impossible.

The last paragraph of that block is easy to skim past, and it is the important one. To run a whole season in a week, your test environments need a business date you can set by hand. That means every piece of date logic reads the current date from one small service you control, rather than each function calling the database's now() or current_date directly.

Hardcode the real clock into your allocation and aging logic and this test becomes impossible. You will then discover your delivery-window bugs in production, in August, with a Nordstrom order on the line. Design that clock abstraction on day one. It costs almost nothing then, and it cannot be retrofitted cheaply.

The rest of the schedule is deliberately full of unhappy paths: a short delivery from the factory, a substituted colorway, a missed window, a short payment, a chargeback. Happy-path testing is nearly worthless, because the happy path is precisely what the developer already tested. Every expensive apparel ERP defect lives in the exception handling.

Cutover: the plan for the actual night

Cutover is a logistics exercise, and it benefits enormously from being boring.

Choosing a strategy

StrategyHow it worksCostRiskVerdict for a small brand
Big bangEverything switches over one weekendLowest effortHighest; no fallback once trading resumesOnly if your business genuinely stops for a period
Phased by functionOrder-to-cash first, then purchasing, then EDIMedium; needs temporary bridges between systemsContained; each phase is smallDefault choice
Phased by entityOne warehouse or one brand at a timeMediumContained, but split stock is painful to manageOnly with genuinely separate stock pools
Parallel runningBoth systems, same transactions, results comparedVery high; doubles data entryLowest system risk, highest human burnoutFinancial close only, for one cycle

Parallel running deserves a specific warning. It sounds safe, but it requires people to enter every transaction twice, for weeks, while they are already learning a new system. In a small team that is the fastest available way to destroy goodwill and guarantee the new system gets blamed for the exhaustion. The compromise that works: run parallel for one financial close only, on accounting outputs, not on daily operations.

The hour-by-hour plan

Large implementations orchestrate hundreds of cutover tasks. Yours will have thirty to sixty. It still needs owners, dependencies, and timings taken from rehearsal run 3 rather than from optimism.

CUTOVER RUNBOOK - PHASE 1 ORDER-TO-CASH
Window: Fri 18:00 - Mon 06:00   Owner: Product Owner
=====================================================
T      Task                            Owner   Est  Rollback
-----  ------------------------------  ------  ---  --------
FRIDAY
18:00  Stop order entry in legacy      Priya   -    n/a
18:15  Announce freeze to reps + 3PL   Priya   15m  n/a
18:30  Final legacy extract: cust,     Dev     45m  rerun
       supp, products, open SO/PO
19:15  Extract AR/AP open items        Finance 30m  rerun
19:45  RECONCILE extracts vs legacy    Finance 60m  STOP
       reports. Variance must be 0.
SATURDAY
08:00  Physical stock count starts     Marcus  6h   n/a
       (full count, all locations)
14:00  Count entry + second count on   Marcus  3h   recount
       any SKU with >2% variance
17:00  Stock count sign-off (signed)   Sponsor 30m  STOP
SUNDAY
09:00  Load master data (run 5)        Dev     90m  restore
10:30  Load open SO / PO               Dev     60m  restore
11:30  Post opening stock ledger       Dev     30m  restore
12:00  Post opening AR / AP balances   Dev     30m  restore
12:30  RECONCILE all opening balances  Finance 2h   STOP
       to signed sheets. Zero variance.
14:30  Smoke test: 5 scripted orders   SMEs    90m  STOP
       end to end, incl. one short-ship
16:00  GO / NO-GO MEETING              All     30m  ---
       <-- POINT OF NO RETURN
16:30  Enable user logins, publish     Dev     30m  n/a
       ATS feed to reps
17:00  Legacy set to READ-ONLY         Dev     15m  reversible
                                                    until Tue
MONDAY
06:00  Warehouse opens on new system   Marcus  -    -
06:00  Super-users on floor, 2 per     All     -    -
       shift, hypercare bridge open

Two bits of vocabulary in that plan. A smoke test is a quick run of the most important paths through the system to check nothing is obviously on fire. A hypercare bridge is a phone or video call that is left permanently open on go-live day, so anyone stuck can join and ask without raising a ticket first.

Several features of the plan are deliberate. Three tasks are marked STOP: these are the go/no-go gates, where failure halts the cutover rather than triggering a midnight debate about whether a variance is "close enough."

The point of no return sits after the smoke test and before logins are enabled, because until that moment you can abandon the whole thing and reopen the legacy system on Monday having lost only a weekend.

The count gets a full day, plus a rule that anything more than 2% out gets counted again. And the legacy system goes read-only rather than off, so people can check their work without there being two competing versions of the truth.

The stock freeze and count

You cannot count stock that is moving, so stop it moving: no picking, no receiving, no returns processing, from the start of the count until sign-off. If a third-party logistics provider holds your stock, agree this in writing weeks ahead. Their operation does not stop for your project unless it is contractually scheduled to.

Count everything. Sampling is for routine cycle counts, not for establishing an opening balance. Count by location and by full SKU — style, color and size, because a style-level count is useless to an apparel business. Skip the size dimension and you will discover in September that you have plenty of medium and none of small, with no way to work out when that happened.

Post the counted quantities as explicit opening entries in the chapter 1 stock ledger, each with a distinct reason code, a timestamp, and the name of the person who signed it off. Do not seed a bare starting number in a table. Recorded as ledger entries, the opening position is auditable and reconstructible exactly like every other movement, which is the property that makes an append-only ledger worth having in the first place.

Go/no-go criteria, written in advance

Write these well before cutover week, while you are calm, and give the sponsor sole authority to waive any of them — in writing, with a reason, recorded in the decision log.

GO / NO-GO CHECKLIST  (all must be YES)
========================================
[ ] Migration run 4 completed with <0.5% rejects,
    and every reject individually dispositioned
[ ] Opening AR reconciles to legacy: variance $0
[ ] Opening AP reconciles to legacy: variance $0
[ ] Stock count signed by sponsor + ops lead
[ ] All open sales orders present; count matches
    legacy open-order report exactly
[ ] All critical UAT scenarios PASS
[ ] Zero open defects rated "revenue impacting"
[ ] Accounting integration posts a test invoice
    and it appears correctly in the ledger
[ ] Every user has a login and has completed
    role-based training, verified by super-user
[ ] Super-user roster staffed for 10 working days
[ ] Rollback tested: we have restored the pre-load
    database snapshot at least once, successfully
[ ] No conflicting business event in the next
    14 days (market week, peak ship window,
    trade show, physical audit, month-end close)

WAIVER: sponsor only, written, logged. Any waiver
of the last item is almost always a mistake.

"Dispositioned" simply means somebody looked at each rejected row and decided what happens to it.

The final criterion is the Hershey clause: the cheapest item on the list to satisfy, and the most expensive to ignore. Find the quiet window in your season calendar — for most northern-hemisphere wholesale brands, after one season's shipping has largely finished and before the next market. Going live two weeks before a delivery window closes is taking Hershey's risk voluntarily, for no gain.

Note the rollback item too. Until you have actually restored the database from a snapshot and watched it work, your rollback plan is only a hope written down.

Training and adoption

Adoption is a management problem wearing a software costume. No amount of interface polish will make somebody use a system their manager does not require and their pay does not reward. But training done badly guarantees failure, so do it properly.

How to run the training

Train by role, not by module. The warehouse team does not need to know how invoices post to the general ledger. They need to receive a purchase order, pick an order, record a short-ship and handle a return. Build one session per role that follows that person's actual day in sequence. A customer service session runs: find the customer, check whether they are allowed to order, enter the order, check availability, confirm the delivery window, handle a change, chase a shipment.

Train on your own data. No other training decision pays back as much. Generic data teaches people to click buttons. Your data teaches them to spot what is wrong. Shown a real account, a rep notices that the discount says 40% when it should be 45%, and that noticing is precisely the skill you are trying to build.

Train close to go-live, then again after. Training more than two weeks ahead evaporates. Put the main sessions in the fortnight before, and a shorter round two to three weeks after go-live, when people have accumulated real questions. That second round is where competence actually forms, and it is the one most projects skip.

Appoint super-users. One per functional area, chosen for helpfulness rather than seniority. It is usually the person colleagues already ask. Train them deeper and earlier, involve them in user acceptance testing, and give them explicit permission to spend work time helping others. That needs their manager's agreement in advance, without which the role is nominal.

Write documentation people will actually read. One page per task, in the team's own language, with screenshots of the real system, kept where they work rather than in a shared drive nobody opens. A 60-page PDF manual will sit unread. The format that reliably gets read is a short recipe.

HOW TO: record a short-ship at picking
--------------------------------------
WHEN: you cannot pick the full quantity on a line.

1. Open the pick list. Tap the line.
2. Enter the quantity you ACTUALLY have in the bin.
3. Choose a reason:
     - Not in bin (stock error)   - Damaged
     - Wrong size in carton       - Held for QC
4. Tap Confirm.

WHAT HAPPENS NEXT
- CS sees it on their dashboard within a minute.
- The invoice will bill only what you picked.
- The missing units stay on the order. They do NOT
  go back into available-to-sell.

DO NOT
- Do not pick a different size to make the count up.
- Do not adjust stock to match. Report the variance;
  someone will investigate the bin.

STUCK? Ask Marcus (super-user, warehouse) first.

Notice the structure. It leads with when, so somebody scanning finds the right page in two seconds. The numbered actions carry no explanation or clutter. The "what happens next" section builds a mental model of the system, which is the thing that actually reduces future questions. The prohibitions matter because those two specific items are exactly the workarounds a warehouse person would otherwise invent in good faith, and each one silently corrupts the ledger. And it names a human being. That gets read. A manual does not.

Instrument adoption, do not guess

Measure whether people are using the system; do not assume it. Count:

  • logins per user per week
  • orders entered in the ERP versus orders still arriving by email
  • stock adjustments made with a reason code versus without
  • and the sharpest signal of all: spreadsheet exports per person.

A spike in one person's exports is that person rebuilding their old spreadsheet. Treat it as a diagnostic telling you which report you failed to build, not as a compliance problem to punish.

Hypercare and stabilization

Published guidance on how long hypercare should last is vague on purpose — most of it says "several weeks, depending on complexity" and then declines to be more specific, which is the honest answer. The calendar is the wrong measure. Panorama's own guidance is to exit on metrics instead: transaction accuracy, support volume, backlog reduction, unresolved high-severity issues.

For a phase-one apparel go-live, plan four to six weeks and be ready to extend. Staying in emergency mode for months is its own failure, because it blurs accountability and hides the fact that nothing is improving.

Staff it deliberately. For the first ten working days:

  • a super-user in the warehouse during picking hours
  • somebody available to customer service all day
  • a developer with no other assigned work
  • and a fifteen-minute triage stand-up at a fixed time each day.

That last one matters more than it sounds. A known daily slot stops people escalating everything the instant it happens.

Triage by business impact, not by technical severity, and define the levels in business language.

LevelDefinition in business termsResponseExample
P1We cannot ship, invoice or take an orderImmediate, all hands, workaround within hoursPick confirmation fails for every user
P2Money or a customer commitment is wrongSame dayInvoice prices ignore a customer's discount
P3Slow, ugly or needs a manual step, but correctWithin the weekPick list sorted badly; extra walking
P4Improvement requestBacklog; review at the end of hypercare"Can this column be wider?"

Defining P1 and P2 in terms of shipping, invoicing and money is what stops every ticket being labeled critical. Nobody can argue that a column width is a P1 when P1 is defined as "we cannot ship."

The error inbox as an operational tool

This one habit most distinguishes implementations that stabilize from ones that limp. Chapter 4 built integrations that fail asynchronously — a Shopify order that will not match to a customer record, an EDI order from a retailer with a delivery address you have never seen. What you need operationally is one screen listing every failed thing, each one owned by a named human who has to clear it.

Treat it like the exception bay in a warehouse:

  • reviewed at a fixed time every day
  • every item assigned to somebody
  • nothing left unassigned overnight
  • age visible on screen
  • anything older than 48 hours escalated automatically.

Report the count at the daily stand-up during hypercare, and weekly forever afterward.

This matters because integration failures are silent. People notice a broken screen immediately. Nobody notices that one EDI order failed to import three days ago — until the retailer calls about a missing shipment and issues a chargeback. The error inbox converts a silent failure into a visible queue with an owner's name on it. That is the whole trick.

Knowing when it is over

Hypercare ends when you can honestly say all of the following:

  • no P1 issue in ten working days;
  • open P2s in single figures and falling;
  • the error inbox clears every day;
  • one full month-end close has completed and reconciled;
  • and the questions coming at you have shifted from "how do I" to "can it also."

Announce the end explicitly rather than letting it dribble away, move to normal support, and schedule the phase-two kickoff.

Change management, honestly

People resist change because it reliably threatens something specific, and they are usually right about what it threatens. Difficult personalities have very little to do with it. Your job is to find out what the threat is, person by person, and address it directly.

What each team is actually afraid of

What the warehouse team actually fears. Being measured, rather than the technology itself. The old paper process was slow but opaque: if a pick took eleven minutes nobody knew, and a short-ship written on a sheet was untraceable. A scanned, timestamped system makes their work legible for the first time in their careers.

If they suspect that legibility will be used to discipline them, they will resist absolutely, and they will win, because they control the physical goods. State early and in writing what the data will and will not be used for, then honor it. Break that promise once and you lose the warehouse for years.

What sales reps actually fear. Two things. First, that their customer relationships become company property. A rep whose accounts, terms and history live in their own head has job security, and a shared system evaporates it.

Second, and more legitimately, looking stupid in front of a buyer. A rep at market who cannot answer "when can I get this?" has suffered real professional damage. That fear is rational, and it is why reps abandon systems faster than anyone else.

Make their path genuinely better: availability figures that are right, fast, work on a phone, and keep working when the venue wifi does not. Chapter 6 on offline sync exists for this reason, and chapter 8 on availability caching exists because a rep will not wait four seconds for a number.

What the finance person fears. That the numbers will not tie out and they will be the one explaining it to the accountant. Give them the reconciliation reports before go-live, not after. A finance lead who has personally reconciled the opening balances becomes the project's most powerful advocate, because they have already staked their own credibility on it.

Follow the incentives

Incentives. If sales commission is calculated from a spreadsheet the rep maintains, they will maintain that spreadsheet forever, regardless of what you build. Trace every incentive in the company and ask which system computes it. Move that calculation into the ERP — even if it is the only thing you move at first, and behavior follows the money. This is the most underused lever in adoption.

The person who keeps their own spreadsheet

There is always one. Forbidding it fails: the spreadsheet just goes underground and you lose visibility of it. Instead, assume it contains something real — almost always a calculation your system does not do, a view it does not offer, or knowledge that lives nowhere else. Find out which, build that thing, and tell them you built it because of them. Then agree an explicit end date for the spreadsheet and check on it. Treat the spreadsheet as a bug report, filed by somebody who did not know how else to file one.

Finally, communicate the why, far more often than feels necessary. "We are changing systems" produces anxiety. "We are changing systems because we shorted Nordstrom twice last season, took $18,000 of chargebacks and nearly lost the account, and the new system will tell us before we ship, not after" produces cooperation. People will accept significant disruption for a reason they believe, and will refuse mild disruption for no stated reason at all.

Measuring success

Benefits that come from the software itself tend to arrive on their own. Benefits that require people to work differently do not arrive unless somebody actively manages the change. That is the pattern behind every "we implemented it but nothing improved" story, and it is why the efficiency gains usually show up while the "we finally have one version of the truth across departments" gains usually do not.

What makes any of it measurable is entirely within your control, and it must happen before go-live: capture the baseline. Once the old system is switched off, every claim about improvement becomes an argument about memory.

MetricHow to capture the baselineWhen improvement typically shows
Order entry time per orderTime 20 real orders with a stopwatchWeeks 6–12 (worse before better)
Order-to-ship lead timeMedian days across the last 200 shipped ordersMonth 2–4
Stock accuracy (count vs system)The cutover count is your baselineMonth 3+, via cycle counts
Short-ship ratePercentage of order lines shipped short, last 2 seasonsNext full season
Chargebacks and deductionsTotal value and count, trailing 12 monthsNext full season
Days to invoice after shippingMedian from dispatch date to invoice dateMonth 1–2 (usually a fast win)
Time to produce the order book reportAsk who makes it; time them onceImmediately
Month-end close durationWorking days, across the last 6 closesMonth 4–6

Be realistic, and say it out loud before go-live: most metrics get worse for four to eight weeks. People are slower on a new system than on the one they have used for six years. That dip is normal and is not evidence of failure. But if you have not warned the sponsor in advance, the bottom of that dip is exactly when the project gets declared a disaster. Show them the expected shape of the curve, and agree that no judgment is passed before week eight.

Note the right-hand column too. Seasonal metrics — short-ship rate, chargebacks — genuinely cannot be evaluated for a full season, because the events that produce them only happen once a season. Do not promise improved chargebacks by month three. You will not have the data, and promising numbers you cannot produce is how good projects lose credibility.

Vendor and consultant management

If you use outside help — an implementation partner, a contract developer, a fractional operations consultant, meaning an experienced person you hire for a day or two a week instead of employing full time — the contract shapes their behavior far more than any conversation will.

The statement of work. A statement of work, or SOW, is the document that defines what will be delivered, by when, for how much, and how you will know it is done. Vague statements of work are the root of nearly every consulting dispute.

Insist on four things:

  • Deliverables described as outcomes rather than activities: "order-to-cash live for one warehouse with user acceptance testing signed off," not "provide implementation services."
  • Named individuals, because agencies substitute staff and the person who sold you the work is often not the person who does it.
  • Explicit acceptance criteria for each deliverable.
  • And a written change-order process, so that scope changes are visible events rather than silent ones.
Contract typeFixed priceTime and materials
Optimizes forCost certaintyFlexibility
Who carries the overrun riskThe vendorYou
What it incentivises the vendor to doThe minimum that passes acceptanceStay longer
What it needs to workA genuinely fixed, detailed scope up frontTrust, and tight scope control on your side
Typical failureChange-order war; every question becomes billableQuiet drift; six months in, still no go-live date
Best used forWell-defined discrete pieces: a data migration, an EDI connectionOngoing advisory, discovery, hypercare support

Neither model is safer. They fail in opposite directions. Fixed price fails when the scope was not really fixed, because the vendor then has a direct financial incentive to resist every clarification you ask for. Time and materials fails when nobody is watching the spend.

The strongest structure for a small brand is a hybrid: fixed price for discovery and for genuinely discrete deliverables, time and materials with a not-to-exceed cap for the messy middle, and payments tied to milestones you can verify rather than to calendar months. A not-to-exceed cap is a hard ceiling written into the contract: the vendor bills by the hour, and stops billing at an agreed total unless you approve more in writing.

Knowledge transfer. Small brands get hurt here, and the contract is what prevents it. Make it a deliverable with acceptance criteria of its own:

  • documented configuration decisions with the reasoning behind them
  • a written runbook for every recurring task
  • credentials and infrastructure held in your accounts
  • all code in your repository from day one
  • and, the one everybody forgets, a shadowing period in which your super-user performs the tasks while the consultant watches, rather than the other way round.

Hold back ten to twenty percent of the fee against acceptance of that deliverable. If a consultant objects to the clause, you have learned something useful early and cheaply.

Never let the consultant own the product owner role

In March 2017 MillerCoors sued its implementation partner, HCL Technologies, for $100 million, alleging the firm had inadequately staffed a unified SAP rollout; HCL countersued in June 2017, blaming MillerCoors' own management, and the two settled in December 2018. Notice that both large companies could afford to fight. At your scale you cannot: litigation would cost more than your entire project, so a contract dispute is a loss even when you win it. Your only real protection is retaining the decisions in-house. A consultant may recommend scope; only your product owner accepts it. A consultant may propose a date; only your sponsor approves go-live. Outsource the labor, never the judgment.

What this means for your ERP

Everything above is a management argument. What it demands of the software is concrete: tables, constraints, screens, reports, and the connections back to the engineering chapters.

Migration must be a first-class, repeatable subsystem

Because you will run the migration five times, it cannot be a folder of one-off scripts. It needs its own schema.

-- Every migration run is recorded and reconcilable.
create table migration_batch (
  id              uuid primary key default gen_random_uuid(),
  tenant_id       uuid not null references tenant(id),
  source_system   text not null,     -- 'quickbooks','shopify','3pl'
  entity_type     text not null,      -- 'customer','product','open_so'
  run_number      int  not null,      -- 1..5 rehearsals
  is_rehearsal    boolean not null default true,
  started_at      timestamptz not null default now(),
  completed_at    timestamptz,
  rows_in_source  int not null default 0,
  rows_loaded     int not null default 0,
  rows_rejected   int not null default 0,
  source_checksum text,
  signed_off_by   uuid references app_user(id),
  signed_off_at   timestamptz,
  constraint rows_balance
    check (rows_in_source = rows_loaded + rows_rejected)
);

-- Every rejected row is kept, categorised and dispositioned.
create table migration_rejection (
  id             uuid primary key default gen_random_uuid(),
  batch_id       uuid not null references migration_batch(id),
  source_row_key text not null,
  raw_payload    jsonb not null,
  error_code     text not null,   -- 'DUP_CUSTOMER','NO_SKU_MATCH', ...
  error_detail   text,
  disposition    text,            -- 'fixed_in_source','excluded'
  dispositioned_by uuid references app_user(id),
  dispositioned_at timestamptz
);

-- EVERY migrated business table carries provenance.
alter table customer
  add column legacy_system text,
  add column legacy_id     text,
  add column migration_batch_id uuid references migration_batch(id);

-- This is what makes re-running safe (see chapter 3).
create unique index customer_legacy_key
  on customer (tenant_id, legacy_system, legacy_id)
  where legacy_id is not null;

First, the shape of it. Those are two new database tables and one alteration to an existing one, written in SQL, the language used to talk to a database.

The words after each column name are its data type:

  • text holds words
  • int holds whole numbers
  • boolean holds true or false
  • timestamptz holds a date and time with its time zone
  • uuid holds a long random identifier
  • and jsonb holds a whole structured document in one column.

Provenance, in the comment above the alter table, means the record of where a row originally came from.

Three load-bearing ideas there. The rows_balance check makes it impossible to record a run in which rows silently vanished: the rows you read must equal the rows you loaded plus the rows you rejected, or the database refuses the record. Without it, forty customers can disappear in February and nobody notices until March.

The migration_rejection table keeps every failed row along with its original raw content, so "0.5% rejects" becomes a worklist somebody can clear rather than a statistic somebody can wave away.

And the unique index across the tenant, the source system name and the source identifier turns the loader into an upsert: run it five times and you get the same rows, not five copies of them. That is chapter 3's idempotency applied to migration, and without it rehearsal is impossible.

Your chapter 7 importer needs two additions as well. First, a dry-run mode that validates everything and writes nothing, so you can test a mapping without polluting the database. Second, a per-batch reconciliation report, counts and totals by entity, that your finance lead can compare against a report from the old system without needing you to interpret it.

And you need a tested restore path: a snapshot taken immediately before the load, and a restore you have genuinely executed at least once, because the "rollback" column in that cutover runbook must not be fiction. A snapshot is a complete copy of the database saved at one moment, which you can put back later to return everything to how it was.

Opening balances must be explicit, signed and auditable

Do not write starting balances straight into a totals table. Post them through the same code path as normal transactions, so that chapter 1's ledger remains the single explanation for every unit of stock you own.

-- Opening stock enters through the normal ledger,
-- with a reason code that makes it queryable forever.
insert into inventory_ledger
  (tenant_id, sku_id, location_id, qty_delta, reason,
   reference_type, reference_id, occurred_at, created_by)
select :tenant, c.sku_id, c.location_id, c.counted_qty,
       'opening_balance', 'stock_count', c.count_id,
       :cutover_ts, :counter_user
from stock_count_line c
where c.count_id = :count_id;

-- The sign-off is a record, not an email.
create table opening_balance_signoff (
  id              uuid primary key default gen_random_uuid(),
  tenant_id       uuid not null references tenant(id),
  domain          text not null,   -- 'inventory','ar','ap','gl'
  as_of           timestamptz not null,
  legacy_value    numeric(14,2) not null,
  erp_value       numeric(14,2) not null,
  variance        numeric(14,2)
    generated always as (erp_value - legacy_value) stored,
  tolerance       numeric(14,2) not null default 0,
  approved_by     uuid not null references app_user(id),
  approved_at     timestamptz not null default now(),
  evidence_uri    text,            -- scan of the signed sheet
  constraint within_tolerance
    check (abs(erp_value - legacy_value) <= tolerance)
);

The first statement copies each counted line into the stock ledger as a normal movement, tagged with the reason opening_balance and pointing back at the count it came from. A year later you can still ask "where did this number come from?" and get an answer.

In the second table, variance is a generated column: the phrase generated always as ... stored tells the database to work the value out itself, every time, by subtracting the legacy figure from the ERP figure. Nobody can type a flattering number into it.

The within_tolerance constraint does the real work: it makes it physically impossible to record a sign-off that does not reconcile, which converts a go/no-go gate from a promise into a rule the database enforces. Set tolerance to zero for accounts receivable and payable, and to a small agreed figure for stock valuation only where rounding genuinely cannot be avoided.

evidence_uri holds the scanned count sheet, because when somebody asks in a year why opening stock was 480 units, you want the document, not a recollection.

Governance artifacts belong in the system, not in a folder

Decision logs die in shared drives. Put them where the work happens.

create table decision_log (
  id             text primary key,          -- 'D-011'
  decided_on     date not null,
  question       text not null,
  options        jsonb not null,
  decision       text not null,
  rationale      text not null,
  decided_by     uuid not null references app_user(id),
  is_reversible  boolean not null,
  revisit_by     date,
  superseded_by  text references decision_log(id)
);

create table cutover_task (
  id                 int primary key,
  runbook_id         uuid not null,
  seq                int not null,
  name               text not null,
  owner_id           uuid not null references app_user(id),
  depends_on         int[] not null default '{}',
  planned_start      timestamptz not null,
  estimated_minutes  int not null,      -- from rehearsal, not guessed
  actual_start       timestamptz,
  actual_end         timestamptz,
  status             text not null default 'pending',
  is_gate            boolean not null default false,  -- a STOP task
  is_point_of_no_return boolean not null default false,
  rollback_action    text
);

The is_gate and is_point_of_no_return flags let the runbook screen physically block the next task until a gate has been passed, which is discipline you cannot rely on people having at 3am. Populate estimated_minutes from what rehearsal run 3 actually took, so the plan rests on measurement rather than optimism. depends_on records which tasks must finish first, so nobody starts the load before the extract has reconciled. And superseded_by means a reversed decision leaves a visible trail instead of quietly overwriting history.

Testing needs a business date you can set by hand

This requirement comes straight out of the seasonal cycle, and it is architectural, so decide it early. Never call now() or current_date inside allocation, availability, aging, delivery-window or cancellation logic. Route every one of those through a single clock accessor that reads an overridable value outside production, stored per environment and per session, and guarded by an environment check so that it can never be set on the live system. Without this, the compressed season test simply cannot be run.

Model your UAT scenarios as data rather than as a document, so each one is executable and its result is recorded. Something like uat_scenario(id, business_process, persona, given, when_action, then_expected, money_expected, fails_if, season_phase, criticality), joined to uat_run(scenario_id, run_at, tested_by, status, evidence_uri, defect_id). The go/no-go question "have all critical scenarios passed?" then becomes a database query rather than somebody's assertion in a meeting.

Adoption and hypercare need instrumentation

You cannot manage adoption you cannot see. Three things must be real features, not afterthoughts.

An error inbox screen. One list of every asynchronous failure across every integration, filterable by source and by age. Fields: source, entity_type, entity_ref, severity, first_seen_at, last_seen_at, occurrence_count, assigned_to, status, resolution_note. Collapse repeated failures of the same thing onto one row with a counter, because an inbox nobody can ever clear is an inbox nobody reads. This screen is the operational face of chapter 4's integrations and chapter 9's monitoring.

A usage log. Per user, per day: logins, records created by type, reports run, spreadsheet exports. This is what detects the shadow spreadsheet, and what finds the person who quietly stopped using the system three weeks before it becomes a crisis.

Keep it deliberately coarse, so that it reads as a management signal and never as surveillance. That distinction is the promise you made to the warehouse team, and the schema is where you keep it: if the table cannot record how long an individual took on each pick, the promise cannot be broken later by a different manager.

A defect queue with business-language severities. Enforce the P1–P4 definitions above as a constrained set of values, and require a business_impact field on anything rated P1 or P2. If somebody cannot articulate the revenue or customer impact in a sentence, it is not a P1.

The reports people will demand in week one

Build these before go-live. Each one exists because somebody had it before, and they will judge the entire new system by whether it survived the move.

ReportWho demands itWhy it must be in phase one
Order book by season, delivery month and customerFounder, salesIt is the forward-revenue view; the company plans against it
Available-to-sell, by style, color and sizeSales repsEvery quote to a buyer depends on it; see chapter 8
Open purchase orders and expected arrival datesOps, productionAnswers "when can I promise this?"
Shipped but not yet invoicedFinanceA direct cash leak if nobody watches it daily
AR aging by customerFinanceCredit decisions stop dead without it
Short-ship and fill rate, by order and customerOps, salesPredicts chargebacks before they arrive
Stock variance since the opening balanceOps, sponsorThe trust metric for the whole system
Sales this week vs the same week last yearFounderThe entire reason you migrated 24 months of history

Access, tenancy and the consultant problem

Tenancy is the idea behind the tenant_id column you keep seeing in the SQL above. A tenant is one separate business whose data lives in the database, and stamping every row with its tenant means one company's records can never leak into another's.

If an outside consultant touches your data, chapter 5's row-level security, the database feature that restricts which rows a given user is allowed to see, acquires a specific extra requirement: time-bounded access. Add an access_expires_at column to your role assignment table, enforce it inside the security policy itself rather than in application code, and default consultant accounts to a 90-day expiry that somebody must actively renew.

Log access by non-employees separately. When the engagement ends, expiry then happens automatically instead of depending on somebody remembering to revoke a login.

Every credential, cloud account, domain and code repository must also be created under your organization from day one. That single administrative habit is the difference between a consultant leaving and a consultant holding your business hostage.

Where this connects

  • Chapter 1's ledger is what makes the opening stock balance auditable.
  • Chapter 2's Postgres work gives you the check constraints that turn go/no-go gates into rules the database enforces.
  • Chapter 3's idempotency is the precondition for running the migration five times.
  • Chapter 4's integrations feed the error inbox.
  • Chapter 5's row-level security enforces consultant access expiry.
  • Chapter 6's offline sync exists because a rep at market with bad wifi is the single adoption risk most likely to end the project.
  • Chapter 7's importers are the migration engine.
  • Chapter 8's availability caching is why a rep gets a number fast enough to trust it.
  • Chapter 9's testing and operations work gives you the rollback you must have executed before you are allowed to cut over.

In one sentence: ship a small phase one, on a quiet week in the season calendar, onto data you have loaded five times and counted by hand, with a named sponsor who is allowed to say no — then stay in the room for six weeks. Everything else in this chapter hangs off that sentence.

Field notes & further reading

Exercise

1. Map one real order and price the alternative. Take an actual order from your last season, with all its real messiness. Walk it end to end and produce the current-state diagram in this chapter's format: every step, every handoff, every re-keying event, every system of record, plus the median and maximum delay at the slowest step. Then, using the published pricing linked above, work out the three-year total cost of the cheapest commercial product that would handle that order — license at your real user count, plus a realistic implementation figure that you have asked a vendor for in writing. Write one paragraph arguing honestly in favor of buying it. If you cannot write that paragraph convincingly, you have your answer either way.

2. Write your season-compressed test and your go/no-go list. Build the five-day compressed season script for your brand: your market timing, your production lead times, your delivery windows, your three most awkward accounts. Include at least four unhappy paths — a short delivery from a factory, a substituted colorway, a missed delivery window, a short payment. Then write your go/no-go checklist, and identify the fourteen-day window in your own calendar where a go-live would not collide with market week, a shipping window, or month-end close.

What you should have when you finish: a current-state diagram with counted handoffs, a defensible three-year build-versus-buy number, an executable five-day test script covering a full seasonal cycle including its exceptions, and a dated go-live window with written go/no-go criteria. Those four artifacts are the minimum viable project plan, and between them they address most of the failure modes in this chapter.