Skip to content

badhon252/Second-sight

Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

142 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸš€ Next.js Full-Stack Template

A production-ready, opinionated Next.js 16 template with a clean feature-driven architecture, authentication, typed API layer, and developer tooling pre-configured out of the box.


πŸ“‹ Table of Contents


🧰 Tech Stack

Category Library / Tool Version
Framework Next.js 16.1.4
Language TypeScript ^5
Styling Tailwind CSS ^4
UI Components Shadcn UI + Radix UI Latest
Icons Lucide React ^0.553.0
Authentication NextAuth.js ^4.24
Data Fetching Axios + TanStack Query ^1.13 / ^5.90
Forms React Hook Form + Zod ^7.66 / ^3.25
State Management Zustand ^5.0
Rich Text Editor Tiptap ^3.17
Animations Framer Motion ^12
Notifications Sonner ^2.0
Testing Jest + Testing Library ^30
Linting ESLint + Prettier ^9 / ^3
Commit Hooks Husky + Lint-staged + Commitlint ^8 / ^16 / ^20

πŸ“ Project Structure

src/
β”œβ”€β”€ app/                        # Next.js App Router
β”‚   β”œβ”€β”€ api/
β”‚   β”‚   └── auth/
β”‚   β”‚       └── [...nextauth]/  # NextAuth route handler
β”‚   β”‚           └── route.ts
β”‚   β”œβ”€β”€ layout.tsx              # Root layout with global providers
β”‚   β”œβ”€β”€ page.tsx                # Home page
β”‚   β”œβ”€β”€ globals.css             # Global styles
β”‚   └── not-found.tsx           # Custom 404 page
β”‚
β”œβ”€β”€ Providers/
β”‚   β”œβ”€β”€ MainProviders.tsx       # TanStack Query client provider
β”‚   └── Provider.tsx            # NextAuth SessionProvider
β”‚
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ ui/                     # Shadcn UI primitives (Button, Input, Dialog, etc.)
β”‚   └── shared/                 # Cross-feature shared components
β”‚
β”œβ”€β”€ features/
β”‚   β”œβ”€β”€ auth/
β”‚   β”‚   └── api/
β”‚   β”‚       └── refresh-token.api.ts  # Token refresh used by NextAuth
β”‚   └── sample-feature/         # Reference architecture β€” copy this for new features
β”‚       β”œβ”€β”€ api/                # API call functions (uses src/lib/api.ts)
β”‚       β”œβ”€β”€ components/         # Feature-specific UI components
β”‚       β”œβ”€β”€ hooks/              # TanStack Query custom hooks
β”‚       └── types.ts            # Feature TypeScript types
β”‚
β”œβ”€β”€ hooks/                      # Global reusable hooks
β”‚   └── readme.md
β”‚
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ api.ts                  # Axios instance with auth interceptors
β”‚   β”œβ”€β”€ utils.ts                # Utility functions (cn, etc.)
β”‚   β”œβ”€β”€ indexed-db-storage.ts   # IndexedDB helpers
β”‚   └── readme.md
β”‚
β”œβ”€β”€ store/
β”‚   β”œβ”€β”€ ui.store.ts             # Global UI state (Zustand)
β”‚   └── readme.md
β”‚
β”œβ”€β”€ types/
β”‚   β”œβ”€β”€ next-auth.d.ts          # Extended NextAuth TypeScript types
β”‚   └── readme.md
β”‚
β”œβ”€β”€ tests/                      # Jest unit test files
β”‚
└── proxy.ts                    # Next.js middleware for RBAC routing

⚑ Getting Started

Prerequisites

  • Node.js 18+
  • npm or pnpm

1. Clone the repository

git clone <your-repo-url>
cd <project-folder>

2. Install dependencies

npm install

3. Set up environment variables

cp example.env.local .env.local

Edit .env.local with your actual values (see Environment Variables).

4. Run the development server

npm run dev

Open http://localhost:3000 in your browser.


πŸ”‘ Environment Variables

Copy example.env.local to .env.local and fill in the following:

Variable Required Description
NEXT_PUBLIC_API_URL βœ… Base URL of your backend REST API (e.g. http://localhost:5001/api/v1)
NEXTAUTH_SECRET βœ… A random secret string used to encrypt JWT sessions. Generate with: openssl rand -hex 32
NEXTAUTH_URL βœ… The canonical URL of your deployed app (e.g. http://localhost:3000 for local)
NEXT_PUBLIC_SOCKET_URL ⬜ Optional WebSocket server URL

Security: Never commit your .env.local file. It is already listed in .gitignore.


πŸ” Authentication

Authentication is handled via NextAuth.js v4 using its Credentials Provider strategy.

How It Works

  1. The user submits their email and password.
  2. NextAuth calls your backend POST /auth/login endpoint.
  3. On success, the user object and accessToken are stored in a JWT session.
  4. The JWT is automatically refreshed when it expires (1 hour default), via POST /auth/refresh-access-token.
  5. If the refresh fails, the session is destroyed and the user is signed out.

Session Shape

The session is extended to include custom fields. The types are declared in src/types/next-auth.d.ts:

session.user = {
  id: string;
  name: string;
  email: string;
  image: string;    // Maps to profileImage from backend
  role: string;     // e.g. "ADMIN" | "USER"
};
session.accessToken  = string;
session.refreshToken = string;

Accessing the Session

Client-side (in a Client Component):

"use client";
import { useSession } from "next-auth/react";

export default function MyComponent() {
  const { data: session } = useSession();
  // session.accessToken, session.user.role, etc.
}

Server-side (in a Server Component or API Route):

import { getServerSession } from "next-auth";
import { authOptions } from "@/app/api/auth/[...nextauth]/route";

const session = await getServerSession(authOptions);

🌐 API Layer

All HTTP requests go through the centralized Axios instance at src/lib/api.ts.

Features

  • Auto-auth injection: Every request automatically includes the Bearer token from the active NextAuth session.
  • Auto-retry on 401: If a request fails with a 401, it tries to use the refreshed token from the session and retries once.
  • Auto-signout: If the token refresh has failed (RefreshAccessTokenError), the user is immediately signed out and redirected to /login.

Usage

import { api } from "@/lib/api";

// Example GET request
const response = await api.get("/users");

// Example POST request
const response = await api.post("/users", { name: "John" });

Note: You never need to manually set Authorization headers. The interceptor handles it globally.


🧩 Feature Pattern

All business logic lives inside src/features/. Each feature is a self-contained module with a consistent internal structure. Use src/features/sample-feature as your starting point.

Structure

src/features/your-feature/
β”œβ”€β”€ api/
β”‚   └── your-feature.api.ts   # Raw API call functions
β”œβ”€β”€ components/
β”‚   └── YourComponent.tsx     # Feature UI components
β”œβ”€β”€ hooks/
β”‚   └── useYourFeature.ts     # TanStack Query hooks
└── types.ts                  # TypeScript types for this feature

Step-by-Step: Adding a New Feature

1. Define your types (types.ts):

export interface User {
  id: string;
  name: string;
  email: string;
}

2. Write your API function (api/users.api.ts):

import { api } from "@/lib/api";
import { User } from "../types";

export async function getUsers(): Promise<User[]> {
  const res = await api.get("/users");
  return res.data;
}

3. Create a TanStack Query hook (hooks/useUsers.ts):

import { useQuery } from "@tanstack/react-query";
import { getUsers } from "../api/users.api";

export function useUsers() {
  return useQuery({
    queryKey: ["users"],
    queryFn: getUsers,
  });
}

4. Consume in a component (components/UserList.tsx):

"use client";
import { useUsers } from "../hooks/useUsers";

export default function UserList() {
  const { data, isLoading, error } = useUsers();

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error loading users.</p>;

  return (
    <ul>
      {data?.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

5. Add a route in src/app/(your-group)/your-route/page.tsx and import the component.


πŸ—‚οΈ State Management

Global UI state is managed with Zustand in src/store/.

Adding a New Store

// src/store/example.store.ts
import { create } from "zustand";

interface ExampleState {
  count: number;
  increment: () => void;
}

export const useExampleStore = create<ExampleState>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}));

Convention: Keep stores small and focused. One store per concern (e.g. ui.store.ts, sidebar.store.ts).


πŸ›‘οΈ Routing & Middleware

The src/proxy.ts file is a Next.js Middleware that runs at the edge before any page renders. It handles Role-Based Access Control (RBAC).

Current Rules

Condition Action
Unauthenticated user visits /dashboard Redirect to /login?callbackUrl=...
Non-admin user visits /dashboard Redirect to /
All other requests next() β€” passes through

Customizing Routes

Edit the matcher in src/proxy.ts to control which paths trigger the middleware:

export const config = {
  matcher: [
    "/((?!api|_next/static|_next/image|assets|favicon.ico|sitemap.xml|robots.txt).*)",
  ],
};

Adding Route Groups

Create a folder with parentheses in src/app/ to group routes without affecting the URL:

src/app/
β”œβ”€β”€ (dashboard)/
β”‚   └── dashboard/
β”‚       └── page.tsx    β†’  URL: /dashboard
β”œβ”€β”€ (auth)/
β”‚   └── login/
β”‚       └── page.tsx    β†’  URL: /login

🎨 UI Components

All primitive UI components come from Shadcn UI and live in src/components/ui/.

Available Components

Component Description
Button Multi-variant button (default, outline, ghost, etc.)
Input Styled form input
Label Accessible form label
Dialog Modal dialog
Select Dropdown select
Checkbox Accessible checkbox
Avatar User avatar with fallback
Dropdown Menu Context/dropdown menus
Accordion Collapsible accordion panels
And more... Run npx shadcn add <component> to add more

Adding a New Shadcn Component

npx shadcn add <component-name>
# e.g.
npx shadcn add sheet
npx shadcn add calendar

πŸ› οΈ Developer Tooling

ESLint

Configured in eslint.config.mjs. Extends eslint-config-next.

npm run lint

Prettier

Config in .prettierrc. Auto-formats on commit via lint-staged.

# Format all files manually
npx prettier --write .

Husky + Lint-staged

Pre-commit hooks auto-run linting on staged files before every commit.

Config in .lintstagedrc.json and .lintstagedrc.

Jest

Unit and integration tests live in src/tests/.

npm run test         # Run all tests once
npm run test:watch   # Run tests in watch mode

TypeScript Type Checking

npm run type-check   # Runs tsc --noEmit

πŸ“œ Scripts Reference

Script Command Description
Development npm run dev Start the dev server with Webpack
Build npm run build Create an optimized production build
Start npm run start Start the production server
Lint npm run lint Run ESLint
Test npm run test Run Jest tests
Test Watch npm run test:watch Run tests in watch mode
Type Check npm run type-check TypeScript type validation
Commit npm run commit Interactive commit with Commitizen

πŸ“ Commit Convention

This project enforces Conventional Commits via Commitlint. Every commit message must follow the format:

<type>: <subject>

Allowed Types

Type When to Use
feat A new feature
fix A bug fix
docs Documentation changes only
style Code style / formatting (no logic change)
refactor Code refactoring (no feature or bug fix)
test Adding or updating tests
build Build system or dependency changes
chore Maintenance tasks
ci CI/CD configuration changes
perf Performance improvements
revert Reverting a previous commit
security Security-related changes

Examples

feat: add user profile page
fix: resolve token expiry loop on 401
docs: update environment variable guide
refactor: extract api calls into feature module

Using Commitizen (Interactive)

npm run commit

This launches an interactive CLI to guide you through writing a valid commit message.


πŸ“„ License

This project is a starter template. You are free to use, modify, and distribute it.

About

Enabling Businesses and Organizations to Create High-Quality, Professional Scenario Plans with AI

Resources

Contributing

Stars

Watchers

Forks

Contributors

Languages

  • TypeScript 97.4%
  • CSS 1.5%
  • JavaScript 1.1%