HyperSaaS
FrontendGetting Started

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

CategoryTechnologyVersion
FrameworkNext.js (App Router)15.3
RuntimeReact19.0
LanguageTypeScript5.x
StylingTailwind CSS4.x
UI Libraryshadcn/ui + Radix UILatest
AuthNextAuth.js (Auth.js)5.0 beta
Formsreact-hook-form + Zod7.x / 3.x
ChartsRecharts2.15
PaymentsStripe.jsLatest
Markdownreact-markdown + ShikiLatest
MapsGoogle Maps + LeafletLatest
PDFpdfjs-dist4.10
ToastsSonnerLatest
AnimationsFramer MotionLatest

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 start

Key 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} />}

On this page