Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Priyanshu471/ad-management/llms.txt

Use this file to discover all available pages before exploring further.

The Ad Management System is a Next.js 14 full-stack application structured around three role-gated portals — Advertiser, Creator, and Admin — each rendered under its own App Router segment. The frontend communicates with a lightweight REST API layer built entirely from Next.js API route handlers, which connect to a MongoDB database through a shared Mongoose connection helper. Client-side state is managed by a set of Zustand stores that act as singletons across the app, handling authentication, campaign data, and UI state without any React context providers.

Directory Structure

The repository is organized as follows:
ad-management/
├── app/
│   ├── page.tsx              # Login page
│   ├── register/             # Registration page
│   ├── admin/                # Admin portal (layout + pages)
│   ├── advertiser/           # Advertiser portal (layout + pages)
│   ├── creator/              # Creator portal (layout + pages)
│   └── api/
│       ├── campaign/route.ts # Campaign CRUD endpoints
│       ├── login/route.ts    # Authentication endpoint
│       ├── register/route.ts # Registration endpoint
│       └── users/route.ts    # Users listing endpoint
├── components/               # Shared UI components
│   ├── Cards/
│   ├── Header/
│   ├── Sidebar/
│   ├── Library/
│   ├── modals/
│   └── ui/                   # shadcn/ui primitives
├── hooks/                    # Zustand stores
│   ├── useUser.tsx           # Auth state
│   ├── useCampaign.tsx       # Campaign state & modal
│   ├── useFetchCamp.tsx      # Data fetching store
│   ├── useImage.tsx          # Profile/cover image URLs
│   ├── useOpen.tsx           # Create form open state
│   └── useProfile.tsx        # Profile modal state
├── lib/
│   ├── mongodb.js            # Mongoose connection helper
│   ├── routes.ts             # Route constants
│   ├── menu.ts               # Sidebar menu definitions per role
│   ├── data.ts               # Static seed/mock data
│   └── utils.ts              # cn() utility
└── models/
    ├── user.ts               # User Mongoose model
    └── campaign.ts           # Campaign Mongoose model

Routing

The application uses the Next.js App Router. Each portal (/admin, /advertiser, /creator) lives in its own directory under app/ with a dedicated layout.tsx that renders the role-specific sidebar and header. Route protection is handled by authGaurd.tsx components embedded in each portal’s layout: on mount they read the role field from the useUser() Zustand store and redirect unauthorized visitors to the login page if the role does not match the portal. Route constants are centralized in lib/routes.ts to avoid hardcoded strings throughout the codebase:
lib/routes.ts
export const LOGIN_ROUTE = "/";
export const ADMIN_ROUTE = "/admin";
export const ADVERTISER_ROUTE = "/advertiser";
export const CREATOR_ROUTE = "/creator";
export const REGISTER_ROUTE = "/register";
Each portal also has its own sidebar menu definition in lib/menu.ts. The advertiserMenu, creatorMenu, and adminMenu arrays each contain the tab label, route path, and Lucide icon for every navigation item in that role’s sidebar, keeping routing logic decoupled from UI components.

State Management

The app uses Zustand for all client-side state. Each store is a singleton created with create() — no Provider wrapping is needed. Any component that calls a store hook receives the same shared instance. All six stores are defined in the hooks/ directory:
StoreFileResponsibility
useUserhooks/useUser.tsxAuthentication state: userId, name, email, role, isLoggedIn, plus login(), register(), and logout() actions that call the API
useCampaignhooks/useCampaign.tsxCampaign modal open/close state and the campaign object currently being viewed or edited; also holds the campaigns array and editCampaign() action
useFetchCamphooks/useFetchCamp.tsxFetched campaigns and users data, split into creatorsData and advertisersData, with loading and error state and fetchData() / fetchUsers() actions
useImagehooks/useImage.tsxUser profile image URL (userImgUrl) and cover image URL (coverImgUrl) with setters for EdgeStore-uploaded assets
useOpenhooks/useOpen.tsxBoolean open flag that controls whether the campaign creation form is displayed
useProfilehooks/useProfile.tsxBoolean open flag that controls whether the profile edit modal is displayed
All Zustand stores are in-memory only — there is no localStorage middleware or cookie persistence configured in the current implementation. A full page reload resets all store state, including isLoggedIn, which means the user must log in again after a refresh. For production deployments, integrate NextAuth.js session persistence or a JWT stored in an HttpOnly cookie so that authentication state survives page reloads.

Data Layer

Database connectivity is handled by a single async connect() helper in lib/mongodb.js. It checks mongoose.connections[0].readyState before attempting a new connection, ensuring that Next.js hot-reload cycles do not open multiple simultaneous connections to MongoDB:
lib/mongodb.js
import mongoose from "mongoose";

const connect = async () => {
  if (mongoose.connections[0].readyState) return;

  try {
    await mongoose.connect(process.env.MONGO_URI);
    console.log("Mongo Connection successfully established.");
  } catch (error) {
    throw new Error("Error connecting to Mongoose");
  }
};

export default connect;
Every API route handler calls await connect() as its first statement before any database operation. The two Mongoose models follow the models.X || mongoose.model("X", schema) guard pattern to prevent model re-registration errors during Next.js development hot reloads:
models/campaign.ts (excerpt)
const Campaign = models.Campaign || mongoose.model("Campaign", campaignSchema);
export default Campaign;
models/user.ts (excerpt)
const User = models.User || mongoose.model("User", userSchema);
export default User;
The Campaign schema stores title, description, objective, status (default "Active"), impressions, click, ctr, budget, duration, and a user reference (ObjectIdUser), along with Mongoose timestamps. The User schema stores name, email (unique), password, and role, also with timestamps.

API Layer

All server-side logic is exposed through four Next.js App Router API route files under app/api/. CORS headers are applied globally to all /api/* routes via next.config.mjs, permitting GET, DELETE, PATCH, POST, and PUT methods from any origin.

POST /api/login

Accepts email and password in the request body. Looks up the user in MongoDB and returns the user document on success, or a 400 status if credentials are incorrect.

POST /api/register

Accepts name, email, password, and role. Returns 400 if the email is already registered, otherwise creates and returns the new User document.

GET · POST · PATCH · DELETE /api/campaign

Full campaign CRUD. GET returns all campaigns; POST creates a new campaign linked to a userId; PATCH updates status or other fields; DELETE removes a campaign by ID.

GET /api/users

Returns the full list of registered users from MongoDB. Used by the Admin portal to populate the users table and by useFetchCamp to split users into advertisersData and creatorsData.

Build docs developers (and LLMs) love