Admin Console Pages and Operations
Understand every shipped admin page, its operational purpose, and the safety rules around billing, moderation, and writes.
Synced with starter commit
7d452a6.
The admin console is an operations workspace, not a replacement for product analytics. Its overview highlights conditions that change what an operator does next: recent signups, live and past-due subscriptions, suspended accounts, and Stripe events waiting for a decision. Revenue, conversion, and churn remain in Stripe or your analytics tool.
Workspace
/shows operational metrics, recent accounts and orders, attention queues, and the tools for manual plan and credit grants. User-targeted grants apply to that user's personal organization./userssearches email, UUID, or nickname and identifies the exact provider-backed account. One email can have multiple account rows, so email is not an authorization key./organizationssearches name, slug, UUID, or Stripe customer ID. An organization is the tenant that owns pooled credits, plans, subscriptions, and the Stripe customer. Its detail page exposes identity, members, resolved plan, subscription history, credit ledger, orders, and seat-limit overrides.
This account-versus-organization distinction matters during support work: use /users to identify a person, then use /organizations to investigate the workspace where billing and entitlements live.
Revenue
/ordersfilters and searches orders by order number, subscription, organization, user UUID, or email. Its fulfillment column compares credits promised by a paid order with matching ledger entries, making a missing or duplicate grant visible./stripe-eventsshows recorded webhook deliveries and their processing state without exposing the raw Stripe payload. For a parked event, fix the cause and use Resend in Stripe to run it again against current provider state. Resolve instead records that an operator handled it outside the system and requires a note; resolution is terminal and is not replay./reconciliationruns the local half of billing reconciliation for a 7-, 30-, or 90-day window. It detects paid orders without credits, ledger balance drift, and stuck webhook events. It cannot discover a Stripe charge that never reached the application; usepnpm reconcile:stripefor the provider-side comparison.
Product Operations
/reservationslists appointment number, service, user, time, timezone, and status. When reservations are disabled in product configuration, the page says so instead of querying an inactive feature./feedbackslists customer rating, content, status, identity, and submission time./affiliatesshows the referred user, inviter, state, qualifying order, paid amount, and reward.
These are inspection surfaces in the released console. They do not add workflow states or editing controls that the underlying product services do not already implement.
Trust and Safety
/moderationsuspends or restores accounts and manages exact-email or domain signup blocklist entries. Suspension revokes active sessions and blocks sign-in, but deliberately keeps the user, ledger, uploads, and organization records. It is not account erasure./auditis the paginated trail for admin writes, including actor, role, action, target, status, note, network context, and metadata.
By default a suspension covers every account row sharing the address and adds a blocklist entry, preventing a fresh OAuth row from bypassing the restriction. Email matching normalizes plus suffixes and Gmail dots; domain entries are intended for disposable-email floods.
Write Guardrails
The shipped write tools are limited to manual credit grants, complimentary plan grants and revocation, organization seat-limit override and reset, account suspension and restoration, blocklist changes, and terminal Stripe-event resolution.
All included write routes require admin_rw, validate same-origin requests, and call the admin audit logger. Credit grants require an idempotency key and derive a deterministic unique ledger transaction number, so retrying the same attempt cannot grant twice. Manual plans and credit grants default to no expiration; optional 7-, 30-, 90-day, or custom expiration values must be in the future.
The console intentionally has no button that replays a stored Stripe webhook payload. Use Stripe's Resend action after correcting the cause. It also does not turn suspension into deletion: user-requested export and erasure follow the separate account-data lifecycle.
See Admin Console Setup and Access before exposing this application outside local development.