Skip to content

Replace Cloud tiered pricing with the v3 single-plan model - #87

Merged
roncodes merged 1 commit into
mainfrom
feature/v3-pricing
Aug 9, 2026
Merged

Replace Cloud tiered pricing with the v3 single-plan model#87
roncodes merged 1 commit into
mainfrom
feature/v3-pricing

Conversation

@roncodes

@roncodes roncodes commented Aug 8, 2026

Copy link
Copy Markdown
Member

Replaces the 13 tiered "resource unit" Cloud plans with the v3 single-plan model across the whole site, rebuilds /pricing around it, and replaces the order-volume calculator.

Numbers are taken from the billing implementation, not from the brief's prose: packages/billing/server/src/Support/V3Statement.php and config/plans.phpplans_v3. I checked every figure against those files and they agree.

Important

Do not merge/deploy before the product cutover. plans_v3 currently ships with 'is_visible' => false, with a comment saying Phase 6 flips it in the same release as the console build. So this pricing is not live in the product yet. See Open questions below.


The pricing page

Rebuilt around one plan, reusing the existing design system rather than inventing a new one. The "Which one are you?" chooser, self-hosted/professional-services cards, support tiers and commercial-licence callout are structurally unchanged.

Section What it does now
Hero The price plainly: $29 a month, plus $5 per driver or vehicle, with the per-delivery point as the supporting line
Billing toggle Monthly / Annual with the 20% saving shown; one piece of state, rendered both above the plan card and inside the calculator so they can't disagree
Plan card The four approved bullets verbatim from plans_v3highlight_features, plus an "Unlimited, at no cost" chip list
Calculator Line-by-line estimate — given real prominence directly under the plan
Usage rates The three meters and their free allowances, shown on the page rather than behind a disclosure
FAQ Rewritten: do I pay per order, what counts as a driver/vehicle, what if I remove a vehicle, what is a gateway-paid invoice, will I be charged for API usage, monthly vs annual, what happens when the trial ends

Removed: all 13 tiers, "Most Popular", "Show all 13 plans", the overage and top-up pack tables, and the "How resource units work" disclosure.

Deliberately not built: the competitor comparison table. The brief made it optional and required date-stamped, signed-off, publicly published competitor pricing. I had no way to verify current Onfleet/Tookan/Route4Me pricing, and inventing numbers is exactly the published-wrong-number risk the brief warns about. The existing per-competitor comparison pages already carry their own competitor figures — see Open questions.

How the calculator works

src/lib/pricing/v3.ts is a direct port of V3Statement.phpmeteredAmount(), licensedAmount() and build(), with the plans_v3 rate table. All arithmetic is in cents, formatted only for display.

resources           = drivers + vehicles
billableStorefronts = max(0, storefronts - 1)      // first storefront free

monthly: base 2900,  resource 500,  storefront 500
annual:  base 27840, resource 4800, storefront 4800    // 20% off recurring

ledger  = invoices     * 10                        // every invoice, no allowance
api     = floor(apiCalls     / 100000) * 25        // round DOWN, first block free
webhook = floor(webhookSends / 100000) * 25        // round DOWN, first block free
  • Inputs: drivers (5), vehicles (3), storefronts (0), billing interval. The three usage inputs sit behind a collapsed "Estimate usage fees" disclosure — the headline estimate is correct and complete without them.
  • Orders input: included and priced at $0.00 — orders are always free, however many you run. It demonstrates the Onfleet contrast far better than a sentence does.
  • Annual: usage meters are fed annual volumes (monthly input × 12) because meters are period-to-date; the rates themselves are identical on both intervals.
  • Output: a statement, not a number — each line with quantity, unit rate and amount, then a recurring subtotal, a usage subtotal and the estimated total. Zero-value usage lines still render so the reader can see the meter exists and is costing nothing. The storefront line appears only when storefronts > 0 and reads 3 storefronts, first included · 2 × $5.00.

Verified

V3StatementTest.php is ported case for case into src/lib/pricing/v3.test.ts, plus assertions pinning the claims the page makes. npm test (node's built-in runner, no new dependencies) — 12 passing.

I also drove the deployed calculator in a browser rather than trusting the unit tests alone:

Case Expected Live UI
25 drivers, 5 vehicles, 2 storefronts, 6 invoices, monthly recurring $184.00 · usage $0.60 · $184.60 ✅ exact
99,999 API calls $0.00
100,000 API calls $0.25
1 storefront adds $0.00 ✅ (line shown, labelled)
Annual, same inputs exactly 20% off recurring ✅ $1,718.40 vs $179.00 × 12 × 0.8

Everything else touched

Pricing model copy

  • compare/ (index, vs-onfleet, vs-tookan, vs-route4me) — resource-unit framing → the per-delivery contrast; vs-onfleet's Fleetbase pricing card $25/100 units → $29 + $5; three stale $50/mo "Pricing Model" rows (the old Lite tier) corrected
  • platform/fleetops (page + content + JSON-LD Offer), platform/storefront (commission FAQ), solutions/trucking, solutions/roles/executives, partners, company/investors
  • contact/sales, developers — trial "capped at 50 resource units" removed; API FAQ now states the real 100k free allowance and $0.25/100k rate
  • components/sections/deployment-options — "From $25/mo" → "$29/mo + $5 per driver or vehicle"
  • content/docs/community/faq.mdx — Cloud pricing answer and the self-hosted/Cloud comparison table

Now-false claims removed. "No per-seat pricing" is still true (users are unlimited and free) and was left alone, but "no per-driver fees" is now false — drivers are $5. Corrected to "never a per-delivery fee" on the homepage metadata/OG, sections/hero, sections/seo-content, and the Fleet-Ops page.

SEO / structured data

  • seo/json-ld.tsxSoftwareApplicationSchema default price 2529, with an Offer.description covering the per-resource lines so a single number isn't presented as the whole price. No page overrode the default, so every stale Offer on the site moved with it.
  • /pricing metadata, OG and Twitter descriptions rewritten; OG image subtitle regenerated. Added an explicit SoftwareApplicationSchema to /pricing.
  • URL-encoded OG subtitles (no%20per-driver%20fees) were carrying the old claim past plain-text greps — fixed.

Legal — needs review. Terms §1 and §6 defined and priced Resource Units, so leaving them would have published a contract for a billing model that no longer exists. Rewritten factually in terms of Billable Resources and Metered Usage, keeping the existing structure and register; §5's "20% discount (equivalent to two months free)" corrected to ~ten months' charges for twelve months. Privacy's "Resource Unit consumption" → metered usage and billable resource counts. I am not a lawyer — please have these reviewed.

Fleet-Ops rename. 28 display strings in src/, 88 in content/docs/. Code is untouched: fenced code blocks, inline code spans, Fleetbase\FleetOps\… namespaces, the fleetbase/fleetops repo slug, getModelPackage('FleetOps') and component identifiers all stay. Applied with a script that skips code contexts, then hand-checked the 32 remaining occurrences — all genuinely code.

Verification

  • npm test — 12/12
  • ✅ No resource unit / overage / top-up / Micro / Starter / Scale remains as Cloud plan pricing (remaining "overage" hits are the substring in "coverage"; $200/mo hits are the installation Maintenance Plan, a separate product, left alone)
  • tsc --noEmit0 errors in changed files. 48 pre-existing errors remain, all PageData in the docs/[[...slug]] route templates
  • ✅ Renders correctly at 390 / 834 / 1440. Confirmed via DOM measurement that the page does not scroll horizontally at 375px; the usage-rates table scrolls inside its own overflow-x-auto container by design
  • ✅ Signup links unchanged and still resolve to console.fleetbase.io/onboard
  • ⚠️ Lint: 83 files fail — but main fails on the same 83. Diffed both: this branch introduces zero new violations. Mostly simple-import-sort and unescaped entities; worth a separate autofix PR
  • ⚠️ Build: compiles successfully, then fails collecting page data for /blog/[slug]Ghost Content API request failed with status 402. I built main in a clean worktree and it fails identically, so this is a pre-existing expired/unpaid Ghost credential, not this change

Two unrelated things in the working tree were left uncommitted: the modified vendor/postman submodule pointer, and an untracked pnpm-workspace.yaml. That file makes every pnpm run script fail with ERROR packages field missing or empty, which is why verification here used npm.

Open questions — please confirm before this ships

  1. Launch timing. plans_v3 is is_visible => false pending the Phase 6 console build. What is the cutover date, and should this PR be held or merged-but-not-deployed?
  2. Existing customers. Nothing on the page says current customers are already on this model, but nothing addresses them either. Do you want a "what this means for existing customers" note, and what does migration actually look like?
  3. Self-hosted ($2,500 one-time) and the four support tiers are untouched, as instructed. They sit below the single plan and read fine — please confirm that's still correct.
  4. Competitor numbers. I built no new comparison. But the existing pages still carry unverified, undated competitor pricing — Onfleet "$550/mo Launch plan, 2,000 tasks", plus "Per-driver"/"Per-agent"/"Per-route" model claims for Onfleet, Bringg, Spoke, Tookan, Detrack and Route4Me. Those now sit next to a freshly-updated Fleetbase column, which makes them more load-bearing than before. They need sign-off and date-stamping, or removal.
  5. Trial length. The site says 7 days, matching the billing.trial-duration default. That setting is operator-editable and plans.php explicitly warns against copying it into plan config — so this figure can go stale. Worth confirming, or softening to "free trial" with no number.
  6. Pallet. Per the accuracy guardrails I kept Pallet out of the pricing page's included-modules line and off the vs-onfleet module list. It is still named as a shipped module on /platform/pallet, solutions/roles/warehouse-managers and a vs-route4me row ("Pallet WMS included"). Rewriting those is well outside this change — flagging it since Pallet is not released.
  7. Naming. content/docs/contributing/translations/glossary.mdx previously declared the opposite convention — that FleetOps is canonical and "hyphenated Fleet-Ops may appear in older copy". I flipped it to match the brief and noted that code keeps the unhyphenated form. Please confirm that's the intended direction.

Screenshots

Before/after of /pricing, captured full-page via CDP at identical device metrics from main and this branch.

(Attaching below — desktop 1440px, tablet 834px, mobile 390px.)

The 13 tiered plans metered in "resource units" are gone. Cloud is now one
plan: a $29 platform fee plus $5 per driver, vehicle and storefront beyond the
first, with three genuinely usage-based meters on top. No tiers, no
allowances, no overages, no top-up packs.

Rebuilds /pricing around the single plan and replaces the order-volume
calculator, whose premise — that price scales with orders — is now false.

- src/lib/pricing/v3.ts ports meteredAmount/licensedAmount/build from
  packages/billing V3Statement.php, with the plans_v3 rate table. Amounts in
  cents; API and webhook blocks round DOWN, so the first 100,000 of each per
  period are free and the site never quotes more than we charge.
- src/lib/pricing/v3.test.ts ports V3StatementTest.php case for case and adds
  assertions for the claims the page makes (first storefront free, annual
  exactly 20% off recurring, identical usage rates on both intervals, no order
  line on the statement at all). `npm test` runs them on node:test.
- The calculator shows a line-by-line statement rather than one number, with
  the three usage inputs behind a collapsed disclosure and an orders input
  that is priced at $0.00 to make the per-delivery contrast concrete.
- Plan bullets are the four strings from plans_v3 highlight_features verbatim,
  so site and checkout cannot disagree.

Site-wide sweep beyond /pricing: removed resource-unit, overage and top-up
copy from the compare, platform, solutions, developers, contact and docs FAQ
pages; corrected "no per-driver fees" (now false — drivers are $5) to "never a
per-delivery fee" on the homepage, hero, OG images and Fleet-Ops page;
refreshed JSON-LD Offer pricing from $25 to $29 with a description covering
the per-resource lines; and rewrote the Terms billing clauses and the Privacy
usage-data sentence in terms of billable resources and metered usage.

Also renames FleetOps to Fleet-Ops in display text across the marketing pages
and docs, leaving code identifiers, namespaces, package names and repo slugs
untouched, and updates the contributor glossary that declared the opposite
convention.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
fleetbase-io Ready Ready Preview Aug 8, 2026 9:00am

Request Review

@roncodes
roncodes merged commit 1957842 into main Aug 9, 2026
2 checks passed
@roncodes
roncodes deleted the feature/v3-pricing branch August 9, 2026 06:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant