Overview
Next.js frontend with App Router, shadcn/ui, and server components.
The HyperSaaS frontend is a Next.js 15 application using the App Router, React 19, and Tailwind CSS 4. It provides a complete SaaS dashboard with AI chat, document management, team collaboration, and Stripe billing.
Tech Stack
| Category | Technology | Version |
|---|---|---|
| Framework | Next.js (App Router) | 15.3 |
| Runtime | React | 19.0 |
| Language | TypeScript | 5.x |
| Styling | Tailwind CSS | 4.x |
| UI Library | shadcn/ui + Radix UI | Latest |
| Auth | NextAuth.js (Auth.js) | 5.0 beta |
| Forms | react-hook-form + Zod | 7.x / 3.x |
| Charts | Recharts | 2.15 |
| Payments | Stripe.js | Latest |
| Markdown | react-markdown + Shiki | Latest |
| Maps | Google Maps + Leaflet | Latest |
| pdfjs-dist | 4.10 | |
| Toasts | Sonner | Latest |
| Animations | Framer Motion | Latest |
Prerequisites
- Node.js 18+
- pnpm (recommended) or npm
- Running backend API (Django)
Quick Start
# Install dependencies
pnpm install
# Set up environment variables
cp .env.example .env.local
# Edit .env.local with your backend URL and auth secret
# Start development server (Turbopack)
pnpm dev
# Build for production
pnpm build
# Start production server
pnpm startKey Architectural Decisions
Server Components by Default
Pages and layouts are server components. They fetch data on the server using JWT tokens from the session, then pass data down to client components as props.
// app/(dashboard)/dashboard/workspaces/[workspaceId]/page.tsx
export default async function WorkspacePage({ params }) {
const user = await getCurrentUserServer();
const workspaces = await getUserWorkspaces();
return <WorkspaceHome user={user} workspaces={workspaces} />;
}API Route Proxy Pattern
Frontend API routes act as proxies to the Django backend. They extract the JWT token from the NextAuth session, attach it to the request, and forward to the backend:
// app/api/workspaces/route.ts
export async function GET() {
const token = await getAccessToken();
const res = await fetch(`${BACKEND_URL}/api/workspaces/`, {
headers: { Authorization: `JWT ${token}` },
});
return Response.json(await res.json());
}Type-Safe Validation
All data flowing between client and server is validated with Zod schemas. Types are inferred from schemas for zero-drift guarantees:
// lib/validations/chat.ts
export const chatSessionSchema = z.object({
id: z.string().uuid(),
name: z.string(),
ai_provider: aiProviderSchema,
ai_model: z.string(),
agent_framework: agentFrameworkSchema,
// ...
});
export type ChatSession = z.infer<typeof chatSessionSchema>;Permission-Based Rendering
UI components conditionally render based on the user's role in the workspace/team:
const permissionContext = getUserPermissionContext(user, workspace, team);
const canEdit = canUserPerformWorkspaceAction(permissionContext, "UPDATE_WORKSPACE");
{canEdit && <WorkspaceUpdateForm workspace={workspace} />}