Skip to content

feat(pricing): v3 model — orders & drivers free, interactive calculator#17

Open
roncodes wants to merge 2 commits into
mainfrom
feature/pricing-v3-and-calculator
Open

feat(pricing): v3 model — orders & drivers free, interactive calculator#17
roncodes wants to merge 2 commits into
mainfrom
feature/pricing-v3-and-calculator

Conversation

@roncodes
Copy link
Copy Markdown
Member

Summary

Companion to fleetbase/billing#32. Updates the public pricing page to reflect the v3 resource-unit model and ships an interactive calculator that lets visitors plug in their own numbers and see the recommended plan plus a side-by-side comparison against per-driver competitors.

Headline: One price for your whole fleet. Not per driver. — drivers and orders are free, allocations expanded ~1.5–2× per plan, prices unchanged.

What changes

Hero & narrative

  • New headline and badge — "Drivers and orders are free — always".
  • Body copy reframes competitive position: "Most TMS platforms charge $29–$99 per driver per month. Fleetbase charges $0."
  • Trial cap updated everywhere: 50 → 100 resource units (matches TRIAL_RESOURCE_LIMIT in the billing PR).
  • New FAQ entry comparing Fleetbase to Onfleet / Detrack / Routific directly, plus a reworked Resource Units explainer FAQ.

Plan cards

  • Same prices, same overage rates — only the included-unit values change to match config/plans.php in the billing module:
Plan v2 units v3 units
Micro 100 150
Lite 180 300
Essential 240 450
Starter 300 600
(…) (…) (…)
Enterprise Plus 7,500 12,000
  • Each featured card now shows a "Fits: …" hint (e.g. "5 drivers, ~200 orders/mo") derived from the v3 unit math.

Resource Units explainer

  • Orders and Drivers render with a green FREE badge instead of a unit count.
  • Adds a "Free — never billable" legend alongside the existing resets and rolling legend.
  • Section heading rewritten — "One plan covers everything you do".

New: Interactive pricing calculator (pricing-calculator.tsx)

  • Two-panel layout: inputs left, live output right.
  • Primary inputs always visible: drivers, orders/month, vehicles, dispatchers. Drivers and orders are tagged FREE — sliding them does not affect the bill (proves the claim live in front of the prospect).
  • Advanced section expands to expose contacts, places, vendors, service rates, service areas, zones, webhooks, API keys.
  • Output:
    1. Live usage breakdown — Vehicle ×5 → 5 units, Contact ×100 → 100 units, etc., plus a green FREE row for orders and drivers.
    2. Recommended plan — name, price, allocation, headroom calculation, plus CTA.
    3. Compared to a typical per-driver TMS — side-by-side panel showing competitor cost at $35/driver/mo (midpoint of verified Detrack / OptimoRoute / Track-POD range), and the $/mo + $/yr savings.
  • Inherits the page-level monthly/annual billing toggle.
  • Debounced emits the existing pricing_calculator_changed PostHog event.
  • Native input type="range" styled with Tailwind + accent-primary — no new dependency.

Refactor: shared pricing-data.ts

  • Lifts CLOUD_TIERS, FEATURED_TIERS, RESOURCE_UNITS, OVERAGE_PACKS out of the page component into a shared module.
  • Exports recommendPlan() (cheapest plan that fits) and computeUnits() helpers — single source of truth for the calculator and the page.
  • COMPETITOR_PER_DRIVER_USD = 35 is the documented anchor for the comparison panel.

Rollout coupling

This PR must not ship to production until fleetbase/billing#32 has merged, the billing seeder + sync command have run on production, and the subscription migration command has migrated all active accounts to the v3 Stripe Prices. Otherwise the marketing site advertises prices we are not yet billing.

Recommended sequence:

  1. Merge billing#32, deploy.
  2. Run php artisan db:seed (TrackableResourceSeeder), php artisan billing:sync-plans, then billing:migrate-subscriptions-to-v3 in batches.
  3. Merge this PR after migration is complete.

Test plan

  • Pricing page renders with new hero copy, new plan allocations, and FREE badges on Orders/Drivers.
  • Calculator default state (5 drivers, 5 vehicles, 200 orders, 2 users + a small structural footprint): 220 units → Lite $50/mo with 80-unit headroom. Competitor panel: $175 vs $50, save $125/mo.
  • Set drivers = 100, orders = 5,000: total stays at 220 units; bill stays at $50; competitor panel shows $3,500 vs $50 = $41,400/yr savings. (Proves drivers and orders are free.)
  • Mid-size scenario (15 drivers, 15 vehicles, 1,000 orders + advanced inputs): 848 units → Starter Plus $300/mo with 152-unit headroom.
  • Mobile 375px: no horizontal overflow, calculator grid stacks single-column.
  • Reviewer: try a scenario at >5,000 contacts to confirm overage path renders correctly (calculator falls back to "Talk to sales" when no plan fits).
  • Reviewer: confirm pricing_calculator_changed PostHog event fires once per settle (500ms debounce).

🤖 Generated with Claude Code

Companion to fleetbase/billing#32. Updates the public pricing page to
reflect the v3 resource-unit model and ships an interactive calculator
that lets visitors plug in their own numbers.

Narrative pivot (hero & explainer):
- "One price for your whole fleet. Not per driver."
- "Most TMS platforms charge $29–$99 per driver per month. Fleetbase
  charges $0."
- Reframes Resource Units as a monthly "activity allowance" measured
  against the *structure* of the business (vehicles, contacts, places)
  rather than its activity (orders) or workforce (drivers).
- Adds a comparison FAQ entry against Onfleet, Detrack, Routific.
- Updates trial cap copy from 50 → 100 units.

Plan ladder (CLOUD_TIERS in pricing-data.ts):
- Same prices, same overage rates, same 13 tiers.
- Included units expanded ~1.5–2× per tier to match
  config/plans.php in the billing module.
- Adds a "fits" hint per featured plan (e.g. "5 drivers, ~200 orders/mo")
  derived from the v3 unit math.

Resource units explainer:
- Orders and Drivers now render with a FREE badge instead of a unit count.
- Adds a "Free — never billable" legend alongside the existing
  "resets" and "rolling" legend entries.

Pricing calculator (new — pricing-calculator.tsx):
- Two-panel layout: inputs on the left, live output on the right.
- Primary inputs always visible (drivers, orders/mo, vehicles, users).
  Drivers and orders are tagged FREE — moving the slider does not
  affect the bill (proves the marketing claim live).
- Advanced section expands to expose contacts, places, vendors,
  service rates, service areas, zones, webhooks, API keys.
- Output panels:
  1. Live usage breakdown (Vehicle ×5 → 5 units, etc.).
  2. Recommended plan with headroom calculation.
  3. Side-by-side comparison vs a per-driver TMS at the verified
     $35/driver/mo benchmark (midpoint of Detrack, OptimoRoute,
     Track-POD; range $29–$99). Shows $/mo and $/yr savings.
- Inherits the page's monthly/annual billing toggle.
- Debounced emits the existing pricing_calculator_changed PostHog
  event (already in lib/analytics/events.ts).
- All sliders use the native range input styled with Tailwind +
  accent-primary — no new dependency.

Data extraction (pricing-data.ts):
- Lifts CLOUD_TIERS, FEATURED_TIERS, RESOURCE_UNITS, OVERAGE_PACKS
  out of pricing-client.tsx into a shared data module so the
  calculator and the page render from a single source of truth.
- Exports recommendPlan() and computeUnits() helpers.
- COMPETITOR_PER_DRIVER_USD constant ($35) is the documented anchor
  for the comparison panel — single point of truth for adjustments.

Rollout coupling:
- This PR must NOT merge to main / ship to production until
  fleetbase/billing#32 has been merged, the billing seeder & sync
  command have run on prod, and the subscription migration command
  has migrated all active accounts to v3 Stripe Prices.
- The marketing site will otherwise advertise prices we are not
  yet billing.

Verified locally via the dev server:
- Default inputs (5 drivers, 5 vehicles, 200 orders, 2 users + a
  small structural footprint) → 220 units → Lite $50/mo + 80 unit
  headroom. Competitor compare: $175 → $50, save $125/mo.
- Setting drivers to 100 and orders to 5,000: total unchanged at
  220 units; bill unchanged at $50; competitor compare shows $3,500
  vs $50 ($41,400/yr savings) — proves drivers/orders are free.
- Mid-size scenario (15 drivers, 15 vehicles, 1,000 orders + advanced
  inputs): 848 units → Starter Plus $300/mo with 152 unit headroom.
- Mobile 375px: no horizontal overflow; grid stacks single-column.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 13, 2026

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

Project Deployment Actions Updated (UTC)
fleetbase-io Ready Ready Preview, Comment May 13, 2026 7:54am

Request Review

Four fixes from initial review:

1. Condensed input rows.
   - Section header mb-10 → mb-8; sub-copy size and spacing trimmed.
   - Card padding p-6 → p-5; row gap space-y-5 → space-y-3.5.
   - Slider height-1.5; number input w-20 → w-16, py-1 → py-0.5.
   - Helper text now inline next to the label (e.g. "Users · 5 units
     each") rather than a separate row below the slider. For FREE
     fields, the FREE badge alone tells the story — the redundant
     "Free — never billed." helper line is removed.

2. Recommended-plan banner whitespace fix.
   - The Card had shadcn's default py-6 + gap-6, then we placed the
     "Your recommended plan" banner as a child, which left ~24px of
     blank padding above the banner. Added `py-0 gap-0` to the Card
     so the banner sits flush at the top edge. Matches the existing
     pattern used elsewhere on the page for the "Most Popular" badge.

3. Usage breakdown card whitespace fix.
   - Same double-padding pattern: Card's default py-6 plus an
     explicit p-6 on CardContent stacked vertical padding. Applied
     `py-0 gap-0` to the Card; CardContent uses p-5 by itself.

4. Compare card pop.
   - Background gradient at /5 opacity was nearly invisible. Replaced
     with a solid bg-green-50 (dark: bg-green-950/30) and a strong
     border-green-500/60.
   - "Per-driver TMS" price column now strikethrough red to make the
     "what you'd pay otherwise" framing visceral; Fleetbase column
     has a thicker primary border and tinted background.
   - Savings line promoted from a small inline sentence to a solid
     green-600 banner with a 2xl bold price ("Save $X/mo") plus a
     compact yearly figure underneath.
   - Card hidden entirely when there are no savings (drivers = 0
     OR monthlySavings = 0) to avoid showing a "Save $0" callout.

DOM-verified in the dev server:
- Recommended-plan banner-to-content gap: was ~24px, now 0px.
- Usage card content top padding: was doubled (~48px), now 20px.
- Compare card: rgb(220 252 231) bg + rgb(74 222 128 / 0.6) border
  (solid green, no more transparent gradient).
- Calculator section total height (default state, desktop):
  reduced from ~1480px to ~1223px.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
roncodes added a commit that referenced this pull request May 18, 2026
Tackles every Medium and Low audit item except #15 (unused video
cleanup) and #16 (images.formats explicit config), which were
explicitly out of scope this round.

Item by item:

- #11 Visual breadcrumbs: new Breadcrumbs component at
  components/ui/breadcrumbs.tsx that emits both the visible <nav>
  trail and matching BreadcrumbList JSON-LD in one call. Wired into
  all 3 compare pages and 14 solutions pages (8 verticals + 6 use
  cases) via a new optional `breadcrumbs` prop on the shared
  SolutionPageLayout.

- #12 Per-page Twitter cards: 41 pages now declare their own
  twitter.card block mirroring the page's openGraph title and
  description (previously every page inherited the site-wide default
  Twitter card, so social previews were identical regardless of URL).

- #13 Dynamic OG images: new /og route using next/og ImageResponse,
  parameterised by title/eyebrow/subtitle, returns a 1200x630 PNG
  with branded gradient and the Fleetbase logomark. Cached one year
  via immutable Cache-Control. Wired into the homepage, /pricing,
  /developers, all 3 compare pages, and blog posts (falls back to
  the dynamic OG when Ghost has no feature image).

- #14 Generic anchor text: replaced "Learn more" / "Read more" /
  "Learn More" with contextual anchors that include the destination's
  name (Explore Fleet-Ops, View Installation Service, Read the
  Fleet-Ops docs, etc.) across platform/solutions/services/pricing/
  licensing/platform-modules. Dead about-news component left alone.

- #17 next/dynamic for heavy components: the 7 below-the-fold
  homepage sections (FleetOpsShowcase, OpenSourceAdvantage,
  FeaturesTabsSection, IndustryUseCases, IntegrationsEcosystem,
  DeploymentOptions, FinalCTA) are now dynamically imported. SSR
  stays on (default) so crawlers still receive complete HTML; only
  the client JS bundle is split. Verified each dynamic section's
  text is present in the SSR'd HTML response.

- #18 Compare-page competitor schema: each compare page now emits a
  SoftwareApplication JSON-LD entity for the competitor (Onfleet,
  Tookan, Route4Me) in addition to the BreadcrumbList. Helps Google
  understand the page as a comparison between two distinct entities.

- #19 Hero <header> elements: replaced <section> with <header> on
  the three real page-hero components (Hero, ProductHero,
  AboutHero). Section heroes inside content remain <section>.

- #20 googleBot robots block: extended root metadata.robots with
  googleBot directives — max-image-preview:large, max-snippet:-1,
  max-video-preview:-1 — to opt into the largest possible SERP
  preview.

- #21 Trim keywords meta: the root keywords array went from 19
  generic terms to 6 focused, high-intent terms. Google ignores
  the keywords meta entirely so this was purely cosmetic SEO
  hygiene.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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