Add a Protected Page
Protected pages in Fast Unicorn should follow the same architecture as the existing dashboard and authenticated flows: route-first UI, clear protection boundaries, and reusable backend logic.
This guide shows how to decide where a protected page belongs, how to apply access control at the correct layer, and how to keep business logic out of route components as the app grows.
Before adding a protected page
Review Configure Auth and Project Structure first so the new route reuses the current protection model instead of inventing a new one.
What this guide covers
Route placement
How to choose between dashboard sections, nested authenticated flows, and standalone protected routes.
Access control
How to protect routes through layouts, server pages, and tRPC procedures without duplicating checks everywhere.
Business logic boundaries
How to keep pages thin while routers and services handle contracts, permissions, and reusable domain behavior.
Main files and folders
| File | Propósito |
|---|---|
src/app/[locale]/dashboard/layout.tsx | Shared protection boundary for dashboard routes. |
src/server/auth/config.ts | Authentication behavior and session setup. |
src/server/api/trpc.ts | protectedProcedure and role-aware API access. |
src/server/services | Reusable business logic and ownership rules. |
src/i18n/routing.ts | Locale-aware route structure. |
Decide where the page belongs
Before creating the file, decide which kind of protected page you are adding.
Common cases:
- a new dashboard section inside the existing section switcher
- a nested authenticated workflow inside an existing protected area
- a standalone authenticated route that still lives under
src/app/[locale]
If the page should share the dashboard shell and sidebar, it belongs as a new section in src/features/dashboard/.
Recommended implementation sequence
Use this order when creating a new protected route.
Choose the correct route boundary
Decide whether the page belongs as a dashboard section or as a standalone authenticated route under the locale tree.
Reuse or apply protection
Prefer existing layout-level protection when available, and add route-level protection only when the page sits outside those boundaries.
Connect authenticated data access
Use protected or role-restricted procedures for server access and keep request contracts out of the page component.
Validate the full access flow
Test redirects, authenticated rendering, locale routing, and permission behavior before considering the page complete.
1. Create the route or section
For a new dashboard section, create a section component:
src/features/dashboard/<name>-section.tsx
For a protected page outside the dashboard shell:
src/app/[locale]/account/page.tsx
2. Reuse an existing protection boundary when possible
If the page is a dashboard section, it is already protected by the dashboard layout.
That layout:
- loads the current session
- redirects unauthenticated users
- keeps the sidebar shell consistent
This is the preferred pattern for dashboard sections.
3. Protect standalone authenticated pages explicitly
If the new page lives outside the dashboard layout, protect it at the route level.
Typical pattern:
- load the session on the server
- redirect unauthenticated users
- keep the page itself focused on rendering and page-level data
4. Use the API layer correctly
For authenticated data access:
- use
protectedProcedureinsrc/server/api/trpc.ts - use
adminProcedureif the page is role-restricted - keep request contracts in tRPC routers
- move reusable domain logic into
src/server/services
5. Keep business logic out of the page
A protected page should not become the place where all the rules live.
Good separation:
- page file for layout and orchestration
- tRPC router for API contract and access boundary
- service layer for reusable business logic
6. Add navigation only if needed
If this protected page belongs in the dashboard:
- add it to the section switcher in
src/features/dashboard/dashboard-page.tsx - add a navigation entry in
src/features/dashboard/sidebar.tsx - update translation keys
If it is a standalone authenticated page, do not force it into dashboard navigation unless it is truly part of that product area.
7. Validate the full flow
After creating the page, test:
- unauthenticated access redirects correctly
- authenticated access renders normally
- locale-prefixed routing still works
- any protected procedures return the expected data
- role restrictions work if applicable
Recommended rule
Protect access at the closest correct boundary:
- route access in layouts or server pages
- API access in tRPC procedures
- domain ownership in services
That keeps the app readable, predictable, and easier to extend as protected areas grow.
Closest correct boundary
Protect access where it naturally belongs: route access in layouts or server pages, API access in tRPC procedures, and domain ownership rules in services.