Dashboard & Admin

Turn the template's dashboard examples into connected product surfaces.

The dashboard is a polished UI starter around several connected auth and D1 boundaries. The shell, session user, profile-name update, user APIs, and admin authorization work; much of the visible business data remains static or mock.

Shell and protection

{-$locale}/_dashboard.tsx uses requireAuth in beforeLoad, then renders DashboardSidebar, locale-aware breadcrumbs, theme/language controls, and an Outlet. The sidebar reads the Better Auth session for the user menu and role- based navigation; logout is wired.

Every sensitive API independently reads the session. This is essential: a route guard protects navigation, not direct API requests. The admin users route adds requireAdmin, and /api/admin/users separately returns 401 or 403 before querying D1.

Current feature status

SurfaceStatusActual behavior
Dashboard shell/user menuIntegratedSession identity, logout, locale-aware navigation, auth guard
Summary cards/chart/tableUI starterHard-coded stats, chart series, and initialData; interactive locally
Profile nameIntegratedReact Hook Form + Zod → authenticated PUT /api/user/profile → D1
Profile avatarUI starterDisplays session image; Upload button has no handler
Admin users APIIntegratedRole check, search/role/ban filters, pagination, D1 query
Admin users pageUI starterRenders mockUsers; does not call the real API; action items are not wired
Subscription APIIntegratedReads the current user's subscription table row
Subscription pageUI starterUses a hard-coded Stripe example instead of the Creem/D1 API
Orders pageUI starterStatic empty state; does not query the order table
Billing page/APIExample/UI starterPage says coming soon; API returns placeholder free-plan/usage data
Security page/settings APIExample/UI starterPage says coming soon; API returns real sessions plus static preferences/security defaults

Seeing a protected, polished screen does not mean its data is connected. In particular, the admin page ignores the working admin API, and the subscription page shows a stale Stripe mock even though this template's payment example is Creem.

Dashboard components

SectionCards demonstrates responsive KPI cards. ChartAreaInteractive uses Recharts with local time-range filtering. DataTable demonstrates @tanstack/react-table sorting/filtering/pagination/visibility/selection plus @dnd-kit row reordering. These are reusable interaction patterns, not an analytics data model.

Replace each component's module-level sample arrays with loader data or props. Define the metric source and aggregation period on the server; avoid shipping raw events or privileged rows simply to aggregate them in the browser.

Connect a page to D1

  1. Define the minimal serialized view model the page needs.
  2. Read the session and data in a route loader backed by createServerFn, or call an authenticated API when client-driven refresh/mutations are useful.
  3. Filter every query by the authenticated user/tenant; never trust a client user ID.
  4. Start independent reads together and return only display-safe fields.
  5. Add loading, empty, error, and stale-data states.
  6. Revalidate router/session data after successful mutations.

For the admin page, reuse /api/admin/users?page=&pageSize=&search=&role=&banned= or move the same query behind a server function. Keep both requireAdmin and the server-side role check. Wire ban/edit actions through Better Auth admin APIs or explicit authorized handlers rather than mutating table state alone.

For account pages, query the order and subscription tables populated by the Creem flow. Decide how refunds, cancellations, pending payments, entitlements, and provider reconciliation appear before exposing management actions.

Verify productization

  • Logged-out users are redirected; direct user API requests return 401.
  • Non-admin users cannot open the admin route or call its API.
  • Dashboard metrics and tables come from scoped server data, not sample arrays.
  • Admin search/pagination displays D1 users and actions persist safely.
  • Profile name updates D1 and session/UI refresh consistently; avatar upload is wired or removed.
  • Orders/subscriptions reflect Creem tables and webhook changes.
  • Billing/security controls are either implemented end to end or clearly removed.
  • Loading, empty, failure, mobile, keyboard, and localization states are tested.

On this page