> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cryptocheckout.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Dashboards

> Three roles, three entry points, and the pool-only invariant that governs every merchant surface.

Three roles, three entry points, all SIWE-only.

| Route                 | Role           | Tabs                                                                                                           |
| --------------------- | -------------- | -------------------------------------------------------------------------------------------------------------- |
| `/admin`              | Merchant       | Overview · Analytics · Payments · Customers · Tokens · Pool · API & SDK · Webhooks · Logs · Settings · Account |
| `/referral-dashboard` | Partner        | Overview KPIs, referral performance, commissions                                                               |
| `/platform-admin`     | Platform admin | Overview · Indexer · Merchants · Partners · Treasury · Health · Audit log                                      |

Platform admin is gated on membership in `platform_admins`; `AdminRoute` renders a 403 on a miss rather than redirecting.

## The pool-only invariant

<Danger>
  Every **merchant** surface reads pool data only — `pool_deposit_intents`, `pool_distributions`, `merchant_pools`, and on-chain state. `paid_events` and `payment_intents` are the legacy atomic rail and are **dropped from all merchant reads**.
</Danger>

Locked in the 2026-07-01 redesign. Violating it produces the exact bug the redesign fixed: a pool-only merchant watching money arrive while their dashboard showed an empty table.

The invariant applies to merchant surfaces only. **Platform-admin** surfaces still legitimately read `paid_events`.

Two tabs regressed after the redesign and were fixed: Analytics merged `paid_events` with pool data, and Customers merged `paid_events` with `pool_events` while keeping a realtime subscription on the legacy table.

## Merchant dashboard

Governing principle: the pool system is the only real checkout path. No merchant-facing copy uses the words "phase", "v3", "legacy", or "atomic".

* **Overview.** The LIVE dot reflects **service readiness** — can this merchant accept money right now — not payment recency. It previously pulsed green only when a settlement had occurred within 60 seconds, which meant a perfectly healthy merchant with no recent orders looked offline. Totals show a single display currency with per-token chips beneath.
* **Payments.** One pool ledger over `pool_deposit_intents` at all statuses, with a fees strip above it sourced from `pool_distributions`, network and token and status filters, CSV export, and a per-order rail badge.
* **Tokens.** Surfaces TRON alongside Available and Coming groups. Per-(token, chain) cells are individually enableable.
* **Pool.** A unified settlement card that absorbed six earlier cards, plus per-chain activation.

Invoices and Team were Phase-2 stubs and were deleted in the redesign.

## Non-happy-path visibility

The deposit rail has explicit per-invoice statuses and every one is surfaced: `underpaid`, `overpaid`, `wrong_token`, `held_sanctioned`, `swept`, `expired`, `expired_paid_late`, with `confirmed_amount` shown against `expected_amount`.

Before this, an operator could not see "customer paid 47 of 49 EURC" — money simply appeared to be missing with no explanation.

<Info>
  An "unsettled deposits" surface is designed but unbuilt: every case where money arrived but never settled, in one place. It pairs with the gas-debt ledger, since a sweep that produced nothing still cost real money.
</Info>

## Shared patterns

* Numerals use `tabular-nums` and `font-mono` so columns align.
* Queries refetch every 30 seconds **and** subscribe to Supabase Realtime, so a new insert invalidates without polling.
* Any table over 50 rows gets CSV export via `src/lib/csv.ts`.
* Dashboard tabs are routable through `?tab=` — before that, the browser Back button ejected a merchant to the landing page.

## Known gaps

<Warning>
  **Partner earnings always display \$0.00**, and partner-visible merchants RLS is incomplete. Both are open from the 2026-07-28 audit. This matters beyond the dashboard: if a fee change accidentally reduces the partner's 0.25%, nobody would notice, which is why the gas-reimbursement work carries an explicit regression test on the partner share.
</Warning>

## Claim experience

The dashboard is moving to a **single Claim button** with a live gas estimate, hiding `distribute()` entirely as an implementation detail. A `DistributeAndClaim` helper contract makes it one signature.

The estimate is not cosmetic. On TRON a claim costs the merchant roughly \$4.59 in TRX, so claim cadence is a real economic decision they need visibility into. See [Distribution](/settlement/distribution).
