Routing and Layouts
Relevant source files
The following files were used as context for generating this wiki page:
The GUC Resume Enhancer application utilizes the Next.js App Router to define its structure, manage navigation, and enforce access control. This system employs a file-based routing convention where directories create URL segments and special files like page.tsx and layout.tsx define the UI for those segments. The architecture is divided into public-facing pages, authenticated user dashboards, and a protected admin area, each with its own specific layout and access rules.
Layouts are a key feature, providing a consistent UI shell for different sections of the application. A root layout wraps the entire application, while nested layouts can be defined for specific route groups, such as the /admin section. This hierarchical structure allows for shared components, state, and styles across related pages while maintaining clear separation of concerns.
Core Application Structure
The application's routing is organized into several distinct sections, each corresponding to a directory in the app folder.
Root Layout
The foundation of the application's UI is the RootLayout defined in layout.tsx. This component wraps every page, providing a consistent structure and global context.
Its key responsibilities include:
- Defining the main
<html>and<body>tags. - Applying the global
Interfont. - Setting global metadata for SEO, such as the title and description.
- Wrapping all children in an
<ErrorBoundary>component for graceful error handling. - Including a global
<Header />component. - Wrapping children with
<Providers>which likely handle state management or other global contexts.
Sources: layout.tsx:1-40
The following diagram illustrates the component hierarchy of the root layout.
Sources: layout.tsx:25-35
Page and Route Definitions
The application defines several key routes, each with specific purposes and access controls.
| Route Path | File | Description | Access Control |
|---|---|---|---|
/ | page.tsx | The public-facing landing page. | Public |
/dashboard | dashboard/page.tsx | The main dashboard for authenticated users. | Authenticated User |
/admin/resumes | admin/resumes/page.tsx | The admin interface for managing resumes. | Admin User |
/enhance/[id] | enhance/[id]/page.tsx | Dynamic page to view and enhance a specific resume. | Authenticated User (owner) |
/history | history/page.tsx | Page to view a user's resume enhancement history. | Authenticated User |
Sources: page.tsx, dashboard/page.tsx, admin/resumes/page.tsx, enhance/[id]/page.tsx, history/_components/history-list.tsx:98
Authentication and Access Control
The application implements route protection using NextAuth.js session management. Pages that require authentication check for a valid session and redirect unauthenticated users to the sign-in page.
This diagram shows the general flow for accessing a protected route like /dashboard.
Sources: dashboard/page.tsx:9-13
User Dashboard
The /dashboard route is accessible only to authenticated users. The DashboardPage component performs a session check and redirects to /auth/signin if no session is found.
// dashboard/page.tsx
export default async function DashboardPage() {
const session = await getServerSession(authOptions);
if (!session) {
redirect("/auth/signin");
}
// ...
}
Sources: dashboard/page.tsx:9-13
Admin Section
The /admin/resumes route has a more stringent, two-level access control check:
- A valid user session must exist.
- The user object within the session must have a
roleproperty equal to"admin".
If the user is not authenticated, they are redirected to /auth/signin. If they are authenticated but not an admin, they are redirected to their regular /dashboard.
// admin/resumes/page.tsx
export default async function AdminResumesPage() {
const session = await getServerSession(authOptions);
if (!session?.user) {
redirect("/auth/signin");
}
// Check if user has admin role
const userRole = (session.user as { role?: string }).role;
if (userRole !== "admin") {
redirect("/dashboard");
}
// ...
}
Sources: admin/resumes/page.tsx:9-17
The admin section also has its own layout.tsx file, which suggests it could have a unique layout (e.g., a different sidebar or header) applied to all pages under /admin/resumes. The provided file is empty, but its presence is significant for the structure.
Sources: admin/resumes/layout.tsx
Dynamic Routing
The application uses dynamic routing for the resume enhancement page, located at /enhance/[id]. The [id] segment in the path is a placeholder for the unique identifier of a resume.
Enhancement Page (/enhance/[id])
When a user navigates to a URL like /enhance/123, the enhance/[id]/page.tsx file is rendered. This page component is an async function that receives the id from the params object. It uses this ID to fetch the specific resume data and then passes it as a prop to the client-side EnhanceInterface component, which handles the interactive parts of the UI.
The page also checks if the user has configured API keys and passes this boolean to the interface.
Sources: enhance/[id]/page.tsx
Navigation and Redirection
Navigation between pages is handled primarily through the Next.js <Link> component for client-side transitions and the useRouter hook for programmatic navigation.
Upload and Redirect
A key navigational flow occurs after a user uploads a resume. The UploadSection component, used on both the user and admin dashboards, handles the file upload via a POST request to an API endpoint. Upon a successful upload, the API returns the new resumeId. The client-side code then uses the useRouter hook to programmatically redirect the user to the dynamic enhancement page for that new resume.
This sequence diagram illustrates the upload and redirect flow.
Summary
The routing and layout system in GUC Resume Enhancer is built on the conventions of the Next.js App Router. It effectively separates public, user, and admin sections of the application. Authentication and role-based access control are enforced at the page level using server-side session checks. The use of a root layout ensures a consistent look and feel, while dynamic routing enables functionality for specific data entities like individual resumes. Programmatic navigation via the useRouter hook provides a seamless user experience for flows such as post-upload redirection.