Routing
This document explains the routing system used in the Rhesis frontend application, which is built with Next.js App Router.
App Router Overview
The Rhesis frontend uses Next.js App Router, which provides a file-system based routing approach where:
- Folders define routes
- Files define UI
- Special files handle specific functionality (layout, page, error, not-found, etc.)
- Dynamic segments are supported with brackets notation
Route Structure
Route Groups
The (protected) route group organizes authenticated pages without affecting the URL structure. There is no separate (public) group — public routes (/, /auth/*) simply live outside (protected).
Layouts
Layouts share UI between multiple pages:
- Root Layout (
app/layout.tsx): theme provider, global providers, top-level metadata, and the runtimewindow.__ENV__injection script - Protected Layout (
app/(protected)/layout.tsx): session check, main navigation (AppShell/Sidebar), feature-flag provider
Navigation
Link Component
For client-side navigation, use the Next.js Link component:
Programmatic Navigation
For programmatic navigation, use the useRouter hook:
Route Protection
Next.js 16 renamed the edge middleware convention from middleware.ts to src/proxy.ts. Route protection happens in two layers:
src/proxy.ts: runs on every matched request (see itsconfig.matcher), decodes the session JWT locally, refreshes the access token viaPOST /auth/refreshonly when it’s within 60 seconds of expiry, and redirects to/onboardingif the decoded token has no organization. Public paths are defined insrc/constants/paths.ts(isPublicPath()), not a(public)route group.- Protected layout / page checks:
app/(protected)/layout.tsxandapp/layout.tsxcall NextAuth’sauth()server-side to gate rendering.
There is no auth-token cookie check — the session is a NextAuth JWE cookie, decoded rather than looked up by name. See Frontend Authentication for the full session/token-refresh flow.
Dynamic Routes
Dynamic routes use parameters in the URL, defined with brackets notation. This codebase uses [identifier], not [id]:
/projects/[identifier]: Project detail page/tests/[identifier]: Test detail page
Access parameters in the page component:
Error Handling
app/(protected)/error.tsx is a shared client-side error boundary for every route under (protected) (there is no per-route error.tsx in this app):
Not Found Pages
app/not-found.tsx (root) and app/(protected)/not-found.tsx (protected routes) handle 404s — both shared, not defined per dynamic route.
Metadata
Page metadata is defined using the metadata export, typically in a route’s layout.tsx:
Best Practices
- Keep Pages Thin: Page components should focus on data fetching and layout, with most UI logic in components
- Client Components: Use the
'use client'directive only when needed for interactivity - Parallel Routes: Consider parallel routes for complex layouts with independent navigation
- Intercepting Routes: Consider intercepting routes for modals and overlays