Add a Dashboard Page
Add a new authenticated page to the product app, wired into the localized dashboard layout, sidebar, and Convex data.
Add a new authenticated screen to the product app (apps/app). Dashboard pages
live under the localized (dashboard) route group and inherit its sidebar,
header, and auth guard.
1. Create the route
Add a folder and page.tsx under
apps/app/src/app/[locale]/(dashboard)/. For example, a "Reports" page:
apps/app/src/app/[locale]/(dashboard)/reports/page.tsxThe (dashboard) layout already enforces authentication and renders the shell,
so the page only needs its own content.
2. Load data the route needs
Prefer a page-level Convex query that returns the route's initial view model,
then preload it in the Server Component and pass its Preloaded result to the
client component. Read it there with usePreloadedAuthQuery, following the
loading UX standard. Include
ordinary permission and capability state in that view model when the route
needs it.
import { convexAuth } from "@/lib/convex-auth-server";
import { api } from "@leavelocalhost/backend/convex/_generated/api";
export default async function ReportsPage() {
const preloaded = await convexAuth.preloadAuthQuery(api.reports.pageView, {});
return <ReportsClient preloaded={preloaded} />;
}Add a loading.tsx next to the page that renders a skeleton matching the final
layout.
Use a preliminary server authorization decision only when a protected query
would otherwise throw. The billing settings page first fetches
api.permissions.getCurrentPermissions, then preloads its independent plan and
billing-state queries in parallel. This is intentionally not a one-query
aggregate.
Use a client useQuery only for data that genuinely needs a live,
paginated, or interaction-driven subscription. Existing route-level examples
are api.users.getDashboardLayoutContext in the dashboard layout and the
page-level queries in packages/backend/convex/settings.ts.
Dashboard shell data ownership
api.users.getDashboardLayoutContext is the dashboard shell's single initial
read model. It owns the current user display data, organization switcher data,
selected-organization permissions and billing summary, super-admin access, and
the notification-bell summary. Do not add page-specific records to this query:
give each dashboard route its own authorized page view instead. The shell read
model composes domain helpers directly, while the individual public queries
remain independently authorized for live or route-specific use.
3. Add navigation and labels
- Add the sidebar entry in the dashboard navigation — see Customizing the Dashboard.
- Add localized labels in
apps/app/src/locales/en.ts(andes.ts,fr.ts). See Internationalization (i18n).
4. Gate it (optional)
If the page should be role- or plan-restricted, enforce the permission in its backend query. Use the route's preloaded permission snapshot to conditionally render navigation and controls; the backend check remains the real boundary.
Related
- Routes — the existing route map.
- Customizing the Dashboard — sidebar, header, nav.
Removing the Admin Panel and Audit Log
These features are optional. You can remove the admin panel alone, or also remove the audit log underneath it. The audit log can stand on its own; the admin panel depends on it.
Add a Public Marketing Page
Add a new public page to the marketing site, using shared UI, semantic theme tokens, and centralized destination links.