Skip to main content

Tier Deliverability Checklist (v1)

Pricing readiness tier (where we are)​

Use this as the internal launch bar for β€œcan we sell Starter / Growth truthfully?” It is separate from Stripe checkout polishβ€”this is product + API truth.

ReadinessNameCriteria (all must hold to claim the level)Status (2026-04-30)
P0Copy onlyMarketing claims exist; no reliable enforcement.Past (superseded)
P1Enforceable coreTIER_DEFAULTS + TIER_LIMITS in code; requireFeature on tiered modules; seat/report cap paths exist (default monitor).Met
P2Discoverable + honestTenants can see planTier + tierLimits via GET /config β†’ billingEntitlements; landing bullets match flags/caps; VIP path via grandfatherFullAccess.Met
P3Hardened revenueHard cap mode piloted per-tenant or via env; aggregate logging/metrics for at-cap and FEATURE_DISABLED; billing status doesn’t leak wrong tier.In progress β€” Shipped: enforcement toggles + tier_gate logs; invalidateCustomerConfigCache after Stripe webhooks (fresh GET /config / entitlements after subscription changes); service app toast on 402 TIER_LIMIT. Still open: pilot cohorts, log dashboards/alerts, ongoing Stripe price-ID / QA hygiene
P4ScaleGrandfather + new-customer policies automated; self-serve upgrade/downgrade stories tested end-to-end.Future

One-line summary: P2 is met for honest Starter/Growth packaging. P3 adds hard/monitor controls, tier_gate logs, Stripe β†’ config invalidation, and 402 UX in the web app; finishing P3 is mostly operational (pilot hard enforce, log pipelines, billing ops)β€”not missing enforcement code.

Purpose​

Ensure public pricing (Starter, Growth, AI waitlist) is backed by enforceable behavior: each promise maps to a gate (feature flag) or cap (tier limit), with known API + UI enforcement points.

Source of truth​

  • Pricing copy: attunelogic-landing/src/pages/Home/Pricing.jsx
  • Packaging proposal: docs/proposals/billing/monetization-and-tiers-v1.md
  • Feature gates: attunelogic-api/src/services/config/default-configs/feature-flags.js (FEATURE_REGISTRY, TIER_DEFAULTS)
  • Numeric caps: same file (TIER_LIMITS) enforced by attunelogic-api/src/middlewares/requireSeatCap.js
  • Entitlements: attunelogic-api/src/services/billing/index.js (getEntitlementsForCustomer, buildBillingEntitlements)

Client discovery (no extra billing round-trip)​

Tenant apps load GET /api/v1/config. The API includes:

  • config.configs.billingEntitlements β€” same shape as billing summary entitlements (planTier, tierLimits, monitorOnly, seatCapEnforcementMode, …)

Use this for upgrade prompts, showing caps in Settings, and matching UI to monitor vs hard seat-cap enforcement.

Stripe β†’ config freshness (P3): When Stripe webhooks update a tenant (planTier, billing.status, etc.), the API calls invalidateCustomerConfigCache so the next GET /config is rebuilt with the new Customer document β€” entitlements do not stay stale after subscription changes.

Web app β€” hard cap blocks: The service app’s RTK baseQuery shows a toast on HTTP 402 with code: TIER_LIMIT (seat/report limit) so users get an immediate message to upgrade, not a silent failure.

Starter ($99/mo)​

Caps​

  • Office seats = 3 β†’ tierLimits.officeSeats
  • Driver seats = 25 β†’ tierLimits.driverSeats
  • Saved reports = 3 β†’ tierLimits.savedReports

Feature gates (tier1 defaults)​

  • Live updates OFF β†’ jobs.liveUpdates.enabled
  • Route mapping OFF β†’ routing.enabled (maps/routes API guarded)
  • Advanced settings OFF β†’ settings.advanced.enabled (incl. raw customer-config edit API)

Growth ($249/mo)​

Caps​

  • Office = 10, drivers = unlimited, saved reports = unlimited

Feature gates (tier2 defaults)​

  • Live updates ON, routing ON, advanced settings OFF

Rollout​

  • Seat caps default to monitor. Hard blocks: set SEAT_CAP_HARD_ENFORCE=true on the API (global), or per tenant Customer.billing.enforcementMode: "hard" (Super Admin β†’ Customer β†’ Seat / report cap enforcement). Env wins for emergency rollback (false forces monitor).
  • Logs: console.info lines with _evt: "tier_gate" β€” events seat_cap_monitor, seat_cap_blocked, feature_disabled (attunelogic-api/src/utils/tierGateLog.js). Parse in Datadog / CloudWatch / etc.

Grandfather / VIP (single-customer full access)​

Some tenants must stay untied from tier packaging (founding customers, VIP pilots): all GA product surface area stays on, numeric caps treated as unlimited.

Mechanism (Product DB): Customer.grandfatherFullAccess (boolean, default false).

  • Feature flags: Resolver applies synthetic tier defaults = all GA keys ON from FEATURE_REGISTRY (tenant overrides still win; dev/beta lifecycle rules unchanged β€” beta still requires latest + allowlist in prod).
  • Seat/report caps: requireSeatCap, programmatic driver cap check, and billing entitlements treat caps as unlimited (same numeric behavior as tier4).
  • Super Admin: Web β†’ Super Admin β†’ Customer β†’ Settings β†’ Grandfather: full product access; Seat / report cap enforcement (monitor vs hard vs default).
  • API: PUT /admin/customers/:id may set grandfatherFullAccess, planTier, and merged billing (e.g. enforcementMode) β€” superAdmin-only; billing is merged, not replaced wholesale.