Add a Protected Page

GuideAuthenticated routesProtection boundaries

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

FilePropósito
src/app/[locale]/dashboard/layout.tsxShared protection boundary for dashboard routes.
src/server/auth/config.tsAuthentication behavior and session setup.
src/server/api/trpc.tsprotectedProcedure and role-aware API access.
src/server/servicesReusable business logic and ownership rules.
src/i18n/routing.tsLocale-aware route structure.
Planning the route

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/.

Use this order when creating a new protected route.

1

Choose the correct route boundary

Decide whether the page belongs as a dashboard section or as a standalone authenticated route under the locale tree.

2

Reuse or apply protection

Prefer existing layout-level protection when available, and add route-level protection only when the page sits outside those boundaries.

3

Connect authenticated data access

Use protected or role-restricted procedures for server access and keep request contracts out of the page component.

4

Validate the full access flow

Test redirects, authenticated rendering, locale routing, and permission behavior before considering the page complete.

Implementation

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 protectedProcedure in src/server/api/trpc.ts
  • use adminProcedure if 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

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.