## Summary
Two related payments/dashboard changes:
1. **Customer page rework** (`/projects/<id>/payments/customers`) —
replaces the old single-customer selector page with **one unified
table** of users, teams, and custom customers, with filtering and
search. Clicking a row opens a customer view that renders the **same
data as the payments tab** on the user/team detail pages, plus a button
to return to the list.
2. **"Create checkout" everywhere** — the existing checkout dialog is
now reachable from every relevant surface (user table, team table,
user/team detail payments tabs, product detail page, product-lines
cards, and the customer detail view), all driven by **one shared
dialog**.
> ℹ️ Screenshots are from a local dev environment (test-mode banner +
dev-tools rail are dev-only chrome).
---
## 1. Customers page rework
A single `DataGrid` lists users + teams + custom customers (custom ones
are derived from transactions, since they aren't otherwise enumerable).
It uses the existing table/filter components: a **Type** filter (All /
Users / Teams / Custom) and quick-search.

Filtering by type — e.g. **Custom** customers surfaced from transaction
history:

Clicking a row opens a **read-only customer view** that is identical to
the payments tab on the user/team detail pages (metrics, products &
subscriptions, transaction history, item balances), with a **"Back to
customers"** button and a **Create checkout** button:

To guarantee the view is identical, the user/team payments tabs and this
page now share one generic `CustomerPaymentsSection` component keyed by
`(customerType, customerId)`.
---
## 2. Create checkout everywhere (one shared dialog)
The single `CreateCheckoutDialog` now supports:
- **Customer pre-selected** → just choose a product (tables, detail
tabs, customer detail view):

- **Locked product + customer selector** → launched from a product, the
product is fixed and you pick the customer:

The customer selector reuses the existing searchable user/team tables
(nested dialog):

Resulting checkout URL:

### Entry points
**Product detail page** — in the ellipsis menu:

**Product-lines** product-card menu:

**User table** row action (team table is analogous):

**User detail payments tab** (and **team detail payments tab**) get a
Create-checkout button in the header:


---
## Implementation notes
- **New SDK method**: `adminApp.createCheckoutUrl({ userId | teamId |
customCustomerId, productId, returnUrl? })` added to the
`@hexclave/template` **server** app (interface + impl). This is what
enables checkout for **custom** customers, which previously had no
checkout path (the old dialog only called
`customer.createCheckoutUrl(...)` on a `ServerUser`/`Team` object).
Regenerate SDKs after pulling (`pnpm -w run generate-sdks`).
- It lives on the server app (not client) deliberately: it targets an
*arbitrary* customer, which is a server/admin capability. The backend
route enforces this — for `client` auth it calls
`ensureClientCanAccessCustomer(...)` ("clients can only create purchase
URLs for their own user or teams they admin"). The client's safe, scoped
path is the existing customer-object method `user.createCheckoutUrl()` /
`team.createCheckoutUrl()`. The new method sits alongside
`grantProduct`/`createItemQuantityChange`/`getItem`, which take the same
`{ userId | teamId | customCustomerId }` shape.
- **New shared components** under
`apps/dashboard/src/components/payments/`:
- `customer-selector.tsx` — `CustomerSelector`, `CustomerTypeSelect`,
`SelectedCustomer`, `customerToMutationOptions` (extracted from the old
customers page).
- `customer-payments-section.tsx` — generic payments view;
`user-payments.tsx` / `team-payments.tsx` are now thin wrappers over it.
- `CreateCheckoutDialog` reworked to take a unified `customer`
descriptor and the new selector / locked-product props.
## Testing
- `pnpm typecheck` and `pnpm lint` pass.
- Manually verified end-to-end against a seeded local project (test
mode): generated real checkout URLs for a **custom** customer and a
**team**, exercised every entry point above, the type filter
(All/Users/Teams/Custom), search, row → detail → back, and the error
states (e.g. "product already granted", "no products for this customer
type").
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a unified Customers browser for payments with filter, quick
search, infinite scrolling, and a customer detail view.
* Enabled “Create checkout” directly from product and customer-related
screens (including list/dropdown actions).
* Added streamlined “customer payments” views (metrics, transactions,
product/subscription info, and item balances where available).
* Introduced a flexible customer picker to support user, team, and
custom customers in checkout flows.
* **Bug Fixes**
* Improved checkout validation, dialog open/close behavior, and
empty-state handling when no customer or products are available.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Hexclave handles everything around your users: authentication, teams,
payments, emails, analytics, and much more. Start in minutes on the hosted
cloud. Your data is always yours to export and self-host.
Hexclave ships as a catalog of apps you switch on as your product needs them.
Each one is built on the same user model, and new apps land regularly.
Authentication
Authentication that just works with passkeys, OAuth, and CLI auth. Drop in one component and ship the whole flow; auth methods toggle from the dashboard with no code changes needed.
Teams
Build for teams, not just users, with workspaces, email invites, and roles that actually gate the work. The workspace switcher remembers selection, invites auto sign up new users, and permissions hold up under audit.
RBAC
Permissions, sorted: roles that nest and one permission check that works the same on server or client. Define them in the dashboard, check them anywhere in your code.
API Keys
API keys without the footguns: leaked keys get auto-revoked, work for users and teams, and show the full secret only once. We never keep the plaintext after creation.
Payments
Payments without the plumbing for subscriptions, one-time charges, and usage metering with credits. Bill a person or a whole team with one model, no separate codepath.
Emails
Email that delivers and tells you so, handling transactional and marketing sends from one API. Edit templates with an AI editor, theme once, and track every open and click.
Analytics
Know your users with no data stack required, with live active user counts and session replays out of the box. Ask in plain English to build dashboards or write SQL to save queries, all with one flag enabled.
Webhooks
React to every user event in real time with signed, tamper-proof webhooks. Retries and backoff are handled for you; verify in five lines and manage endpoints from the dashboard.
Data Vault
A safe for the secrets your users hand you, locked with your secret so we never see the plaintext. Store and retrieve tokens in two lines each, server-only by design.
Launch Checklist
Run through the must-do checks before flipping to production: domain setup, callbacks locked, secrets rotated. The progress tracker keeps your team aligned so nothing critical slips through on launch day.
Contributing
Hexclave is open source, and contributions are welcome. Read
CONTRIBUTING.md to get started, and say hello in
Discord before picking up anything large.
Found a security issue? Email security@hexclave.com.