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
| Surface | Status | Actual behavior |
|---|---|---|
| Dashboard shell/user menu | Integrated | Session identity, logout, locale-aware navigation, auth guard |
| Summary cards/chart/table | UI starter | Hard-coded stats, chart series, and initialData; interactive locally |
| Profile name | Integrated | React Hook Form + Zod → authenticated PUT /api/user/profile → D1 |
| Profile avatar | UI starter | Displays session image; Upload button has no handler |
| Admin users API | Integrated | Role check, search/role/ban filters, pagination, D1 query |
| Admin users page | UI starter | Renders mockUsers; does not call the real API; action items are not wired |
| Subscription API | Integrated | Reads the current user's subscription table row |
| Subscription page | UI starter | Uses a hard-coded Stripe example instead of the Creem/D1 API |
| Orders page | UI starter | Static empty state; does not query the order table |
| Billing page/API | Example/UI starter | Page says coming soon; API returns placeholder free-plan/usage data |
| Security page/settings API | Example/UI starter | Page 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
- Define the minimal serialized view model the page needs.
- Read the session and data in a route loader backed by
createServerFn, or call an authenticated API when client-driven refresh/mutations are useful. - Filter every query by the authenticated user/tenant; never trust a client user ID.
- Start independent reads together and return only display-safe fields.
- Add loading, empty, error, and stale-data states.
- 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.
