Build Hive CPQ
KINDAback to the verdict
Configure, price and quote for manufactured products, where the core is a constraint solver over option rules that must explain why something is unavailable, and the discipline is that a quote is a priced snapshot that cannot silently change after it is sent.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the server, the solver and the document renderer.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - installfree locally
Why Versioned rules, price lists and immutable quotes want real constraints.
Get it Docker or your package manager. open ↗
Verify
psql connects and an insert-only table can be enforced - installfree
Why Percentage discounts over rounded line items produce arithmetic a customer will dispute.
Get it Any well-tested decimal library for your runtime.
Verify
Line items sum exactly to a discounted total - have readyfree, and it takes a conversation with whoever knows the product
Why Contradiction detection, explanation quality and solver performance are all uninteresting below a few dozen rules and become the whole problem above a hundred.
Get it Take a real configurable product and write out its rules, including the ones the sales team keep in their heads.
Verify
Fifty rules exist, including at least one pair that turns out to contradict - decidefree
Why Where rounding happens and whether discounts apply per line or to the total are decisions that change the number, and reconstructing them later from disputed quotes is worse.
Get it Decide the rounding point, the discount order and the approval threshold, and write them down before pricing anything.
Verify
A written note states the rounding point, discount order and approval threshold
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- products(id, name, active_from, active_to) - options(id, product_id, group_id, code, name, active) - rules(id, product_id, version, kind, expression_json, message) · kind is requires, excludes, implies or constrains - rule_versions(product_id, version, published_at, published_by) - price_lists(id, product_id, version, currency, valid_from, valid_to) - prices(price_list_id, option_id, amount_minor, kind) · kind is base, per_unit or surcharge - quotes(id, customer_ref, product_id, rule_version, price_list_id, configuration_json, total_minor, currency, valid_until, status, sent_at) - A quote pins the rule version and price list it was built from, because both will have changed by the time the customer replies.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DATABASE_URLsecret | required | postgres://localhost:5432/cpq | Rules, prices and customer quotes. |
ROUNDING_POINT | required | line_item | Where rounding happens. Applied once, stated on the quote. |
DISCOUNT_APPROVAL_THRESHOLD_BPS | required | 1000 | Above this a quote needs approval before sending. |
QUOTE_VALIDITY_DAYS | required | 30 | How long a quote holds its price. Pinned data makes this enforceable. |
SOLVER_TIMEOUT_MS | required | 200 | Configuration must stay interactive. A slow solver is an abandoned configurator. |
ALLOW_EDIT_SENT_QUOTES | required | never | Present as a constant so the answer is visible. Revisions, not edits. |
The build, in order
Rules as data, not code
Option constraints are declarative and can be changed without deploying.
Four kinds cover most of it. Code means every change is a deployment.
Files
src/rules.tsBefore a customer finds them, which is the alternative.
Files
src/analyse.tssrc/analyse.test.tsAn option nothing can select is a rule mistake, not a product decision.
Files
src/analyse.ts
done when · tick each as it passeswatch out- Expressing configuration rules as conditional code means every catalogue change is a deployment, and after two hundred rules nobody can tell whether a new one contradicts an existing one. Keep them as data, and check the rule set for contradictions and unreachable options when it is published.
Saying why an option is unavailable
Every disabled option can explain which choice disabled it.
Not afterwards. A separate explanation path drifts from the real one.
Files
src/evaluate.tsBoth. The rule alone does not tell the user what to change.
Files
src/explain.tsAnd make applying it actually work.
Files
src/suggest.ts
done when · tick each as it passeswatch out- Greying out an option without a reason is the single most common complaint about configurators, because the user cannot tell whether it is genuinely unavailable or whether they made a wrong choice three steps earlier. Track the excluding rules during evaluation rather than recomputing an explanation afterwards, since the second version drifts from the first.
Pricing a configuration exactly
A configured product prices correctly including the awkward parts.
Percentages on rounded lines produce arithmetic customers dispute.
Files
src/money.tsThe threshold itself is where off-by-one pricing lives.
Files
src/pricing.test.tsAnd assert lines sum exactly to the total.
Files
src/pricing.ts
done when · tick each as it passeswatch out- Applying a percentage discount to a total computed from rounded line items gives a different answer from discounting each line, and a customer checking your arithmetic will find the discrepancy. Decide where rounding happens, apply it once, and state the rule.
Quotes that do not change after sending
What the customer received is what you can still see months later.
At creation. Referencing current means the quote changes itself.
Files
src/quotes.tsRevisions, not edits. The customer has a copy.
Files
src/quotes.tstests/immutable.test.tsAn expired quote accepted at the old price is a loss you chose by accident.
Files
src/validity.ts
done when · tick each as it passeswatch out- A quote that references the current price list rather than a pinned one reprices itself when the catalogue is updated, and the customer accepts a figure that no longer matches what you sent. Pin everything at creation, and make a sent quote a snapshot rather than a view.
Documents, approvals and handing off to productionproduct builder
A quote becomes a document, an approval and something the factory can build.
The document a customer holds must be reproducible exactly.
Files
src/document.tsAbove a threshold, recorded, before sending.
Files
src/approvals.tsA separate derivation diverges and the factory builds the wrong thing.
Files
src/bom.tstests/bom-agreement.test.ts
done when · tick each as it passeswatch out- A bill of materials derived separately from the configuration will diverge from what was quoted, and the factory builds something the customer did not buy. Derive it from the same configuration and rule version the quote was priced from, and assert the two agree.
That is the whole plan for Hive CPQ. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Manufacturing and resource planning integration.
- Three-dimensional product visualisation.
- Dealer portals with per-partner pricing.
- Tax, shipping and cross-border compliance.
- ERP and CRM integrations, so accepted quotes become copy-paste work
- A dealer or reseller portal with per-account price lists, discount tiers and order history
- Visual product previews, 3D or otherwise, which is often the thing that closes the sale
- Anyone but you maintaining the rule engine when the catalog changes
- Version control on quotes and catalogs, audit trails, and the boring guarantees a buyer expects when a quote is contractual
- Guided selling that orders questions by what constrains most, which shortens configuration
- Quote comparison for a customer weighing two configurations
- Rule change impact analysis, showing which existing quotes a new rule would invalidate
Need the files? The project pack on the verdict page hands your agent the whole brief · more sales outreach.