Pricing Page: Keeping Plans in Sync with the Database
Pricing Page: Keeping Plans in Sync with the Database
⚠️ Known Issue (v1.0.46): The current pricing page displays hardcoded template data and is not connected to the database. This page documents the problem and the recommended fix.
Overview
The platform's billing system manages subscription plans in the database and keeps them synchronised with Stripe. The public-facing pricing page should reflect these same plans so that customers always see accurate, up-to-date pricing.
As of v1.0.46, this synchronisation is broken — the pricing page (src/app/pricing/page.tsx) renders a static, hardcoded plans array instead of querying the database.
Current (Broken) Behaviour
The pricing page currently displays:
| Plan | Price |
|---|---|
| Free | $0 |
| Pro | $29 |
| Enterprise | Custom |
This data is hardcoded in the component and does not update when plans are changed in the database or Stripe dashboard.
Impact
- Stale pricing: If plan prices or names are updated in Stripe/the database, the public pricing page will not reflect those changes.
- Incorrect plan display: Plans that have been added, removed, or restructured in the database will not appear correctly for prospective customers.
- Trust risk: Customers may sign up expecting prices or features shown on the pricing page that do not match what the billing system actually charges.
Recommended Fix
Refactor src/app/pricing/page.tsx to fetch plans dynamically from the database rather than using a static array.
Option A: tRPC (preferred)
Call the existing trpc.billing.getPlans procedure to retrieve live plan data:
// src/app/pricing/page.tsx
const { data: plans } = trpc.billing.getPlans.useQuery();
This ensures the pricing page is always in sync with the plans returned by the billing API, which in turn reflects what is configured in Stripe.
Option B: Direct database query (for server components)
If the pricing page is a Next.js server component, query the database directly:
// src/app/pricing/page.tsx (server component)
import { db } from '@/lib/db';
const plans = await db.plan.findMany({ where: { active: true } });
How Plans Are Managed
The authoritative source of plan data is the database plans table. Plans are:
- Configured in Stripe and synced to the database via webhooks or admin tooling.
- Read by the billing system for checkout, subscription management, and invoicing.
- Should be read by the pricing page to ensure consistency.
Any hardcoded plan data in UI components creates a maintenance burden and a source of truth conflict.
Related
- Billing system:
trpc.billing.getPlans - Affected file:
src/app/pricing/page.tsx - Changelog: v1.0.46