Customers
Customers gives operators a searchable view of provider customers, customer detail, billing history, and related provider records.
On this page
Where to look
| Area | Paths |
|---|---|
| Routes | src/app/(dashboard)/customers, /customers/[providerCustomerId], /billing/customers |
| List server code | src/features/customers/server/list |
| Detail server code | src/features/customers/server/detail |
| Billing grouping | src/features/customers/server/billing/grouping.ts |
| Shared | src/features/customers/shared |
| UI | src/features/customers/ui/list-page.tsx, detail-page.tsx, people-lists.tsx |
| Billing data | billing_customers, billing_subscriptions, billing_orders, billing_invoices, billing_charges, billing_refunds, billing_disputes |
Code-backed customers map
Customer list and detail
Customer pages delegate list projection, filtering, and detail reads to the customers feature.
src/app/(dashboard)/customers/page.tsxsrc/app/(dashboard)/customers/[providerCustomerId]/page.tsxsrc/features/customers/ui/list-page.tsxsrc/features/customers/ui/detail-page.tsx
List query pipeline
List helpers parse filters, build projections, and paginate before rendering customer tables.
src/features/customers/server/list/page-query.tssrc/features/customers/server/list/filters.tssrc/features/customers/server/list/sensitive-data.ts
Billing-backed detail
Customer detail uses provider customer ids and billing grouping helpers without treating provider ids as profile ids.
src/features/customers/server/detail/customer.tssrc/features/customers/server/billing/grouping.tssrc/features/customers/shared/provider-customer-id.ts
Customer lookup flow
- 1
Parse filters and pagination
Customer list requests use server-side filters and page queries before UI renders rows.
src/features/customers/server/list/filters.tssrc/features/customers/server/list/page-query.ts
- 2
Project list rows
Projection helpers keep list rows compact and prevent detail-only fields from being loaded for every customer.
src/features/customers/server/list/sensitive-data.ts
- 3
Resolve provider detail
Detail pages use provider customer ids to load customer, billing, and related records.
src/features/customers/shared/provider-customer-id.tssrc/features/customers/server/detail/customer.ts
- 4
Group billing context
Billing grouping helpers organize subscriptions, invoices, charges, refunds, and disputes for detail UI.
src/features/customers/server/billing/grouping.ts
Customer list bounded query
Source: src/features/customers/server/list/page-query.ts
Customer list pages filter server-side, use the active billing provider, and apply a limit before joining detail data.
const provider = await getBillingProvider();
const providerLabel = provider === "lemonsqueezy" ? "Lemon Squeezy" : "Stripe";
const safeQuery = normalizeCustomerQuery(filters.q);
let customersQuery = supabase
.from("billing_customers")
.select("provider,provider_customer_id,customer_email,customer_name,profile_id,latest_billing_model,latest_checkout_kind,last_checkout_completed_at,updated_at")
.eq("provider", provider as never)
.order("updated_at", { ascending: false })
.limit(filters.limit);
if (safeQuery) {
customersQuery = customersQuery.or(buildOrIlikeFilter(["customer_email", "customer_name", "provider_customer_id"], safeQuery) ?? "");
}Customer view rules
- Paginate before customer tables grow.
- Read only fields needed for list pages.
- Keep provider customer ids separate from internal profile ids.
- Use explicit sync paths for provider refresh work.