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.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.
Directory Structure
The repository is organized as follows: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
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 withcreate() — 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:
| Store | File | Responsibility |
|---|---|---|
useUser | hooks/useUser.tsx | Authentication state: userId, name, email, role, isLoggedIn, plus login(), register(), and logout() actions that call the API |
useCampaign | hooks/useCampaign.tsx | Campaign modal open/close state and the campaign object currently being viewed or edited; also holds the campaigns array and editCampaign() action |
useFetchCamp | hooks/useFetchCamp.tsx | Fetched campaigns and users data, split into creatorsData and advertisersData, with loading and error state and fetchData() / fetchUsers() actions |
useImage | hooks/useImage.tsx | User profile image URL (userImgUrl) and cover image URL (coverImgUrl) with setters for EdgeStore-uploaded assets |
useOpen | hooks/useOpen.tsx | Boolean open flag that controls whether the campaign creation form is displayed |
useProfile | hooks/useProfile.tsx | Boolean 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 asyncconnect() 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
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)
models/user.ts (excerpt)
title, description, objective, status (default "Active"), impressions, click, ctr, budget, duration, and a user reference (ObjectId → User), 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 underapp/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.