Construction Pro

A full-stack, production-ready construction company website and admin dashboard template built with Next.js 16, TypeScript, MongoDB, and Tailwind CSS 4.

Next.js 16 TypeScript MongoDB Tailwind CSS 4 NextAuth v5 Cloudinary v1.0.0

Introduction

Construction Pro is a modern, full-stack business website template designed specifically for construction, contracting, and engineering companies. It ships with a polished public-facing website and a comprehensive admin dashboard — all content is managed dynamically through the admin panel without requiring any code changes.

The template is built on Next.js 16 with the App Router, uses MongoDB as the primary database, NextAuth v5 for secure JWT-based authentication, and Cloudinary for cloud media storage. The entire frontend is fully responsive with built-in dark mode support.

Full-Stack Ready

Complete frontend and backend in a single Next.js project. No separate API server needed.

Admin Dashboard

Feature-rich CMS with projects, services, banners, settings, and more — all editable without code.

Cloud Media

Cloudinary integration for optimized image delivery via CDN. Auto-cleanup on record deletion.

Secure Authentication

JWT-based sessions with bcrypt password hashing and 30-day token expiry via NextAuth v5.

Dark Mode

System-aware theme with manual toggle. Persisted across sessions using next-themes.

SEO Optimized

Dynamic metadata, Open Graph tags, and keywords managed per-page from the admin panel.

System Requirements

RequirementMinimum VersionNotes
Node.js18.0.0LTS version recommended
npm9.0.0Included with Node.js 18+
MongoDB6.0+MongoDB Atlas free tier works
Cloudinary AccountFree tierRequired for image uploads

Quick Start

# 1. Install dependencies
npm install

# 2. Copy and configure environment file
cp .env.example .env.local
# Edit .env.local with your MongoDB URI, NEXTAUTH_SECRET, etc.

# 3. Start the development server
npm run dev

Open http://localhost:3000 for the public website and http://localhost:3000/admin/login for the admin panel.

Installation

Extract or Clone

If downloaded as a ZIP, extract to your project directory. Otherwise clone the repository.

Install Dependencies

Run npm install in the project root to install all packages.

Configure Environment

Copy .env.example to .env.local and fill in all required values. See the Environment Variables section for details.

Set Up MongoDB

Create a free MongoDB Atlas cluster or run a local MongoDB instance. Copy the connection URI into MONGODB_URI.

Start the Server

Run npm run dev — the default admin account is created automatically on first connection.

First Login & Cloudinary

Log in at /admin/login using the default credentials, then go to Settings → Cloudinary to configure your image storage.

Setting Up MongoDB Atlas

  1. Create a free account at mongodb.com/atlas
  2. Create a new cluster — the free M0 tier is sufficient
  3. Go to Database Access and add a user with read/write privileges
  4. Go to Network Access and whitelist your IP (use 0.0.0.0/0 for development)
  5. Click Connect → Drivers and copy the connection string
  6. Replace <user>, <password>, and <dbname> in the URI

Setting Up Cloudinary

  1. Create a free account at cloudinary.com
  2. Find your Cloud Name, API Key, and API Secret in the Cloudinary Dashboard
  3. After your first admin login, navigate to Settings → Cloudinary and enter these credentials

Environment Variables

Create a .env.local file in the project root using .env.example as a template.

VariableRequiredDescriptionExample
AUTH_TRUST_HOST required Trust proxy host headers for deployment true
NEXTAUTH_URL required Full URL of your deployment https://yourdomain.com
NEXTAUTH_SECRET required Secret key for signing JWT tokens — minimum 32 characters a-32-char-random-string
NEXT_PUBLIC_BASE_URL required Public base URL used by the frontend for API requests https://yourdomain.com
MONGODB_URI required MongoDB connection string (Atlas or local) mongodb+srv://user:pass@cluster.net/db
Cloudinary credentials are not set in environment variables. They are configured through the admin panel at Settings → Cloudinary and stored securely in the database.

Generating a Secure Secret

# Using Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

# Using OpenSSL
openssl rand -hex 32

Example .env.local

AUTH_TRUST_HOST=true
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-32-character-minimum-secret-key-here
NEXT_PUBLIC_BASE_URL=http://localhost:3000
MONGODB_URI=mongodb+srv://admin:password@cluster.mongodb.net/construction

Default Admin Credentials

On first startup, a default admin account is automatically created if no admin user exists in the database.

FieldValue
Emailadmin@example.com
PasswordChangeMe123!
Roleadmin
Security Warning: Change the default password immediately after your first login. Navigate to the admin panel, click your profile icon in the header, and select Change Password.

Project Structure

The project follows Next.js 16 App Router conventions with route groups for logical separation of public, private, and auth pages.

template-construction/
├── app/                              # Next.js App Router
│   ├── (auth)/                       # Authentication route group
│   │   └── admin/login/              # Admin login page
│   ├── (public)/                     # Public website route group
│   │   ├── layout.tsx                # Public layout (navbar + footer)
│   │   ├── page.tsx                  # Home page
│   │   ├── contact/                  # Contact form page
│   │   ├── services/                 # Services listing page
│   │   └── projects/
│   │       ├── page.tsx              # Projects listing
│   │       └── [slug]/page.tsx       # Project detail page
│   ├── (private)/                    # Protected admin route group
│   │   ├── layout.tsx                # Admin layout (sidebar + header)
│   │   └── admin/dashboard/          # Admin dashboard pages
│   │       ├── page.tsx              # Dashboard overview
│   │       ├── banner/               # Hero banner management
│   │       ├── projects/             # Projects CRUD
│   │       ├── services/             # Services CRUD
│   │       ├── site-projects/        # Site projects management
│   │       ├── contacts/             # Contact submissions
│   │       ├── subscribe/            # Newsletter subscribers
│   │       ├── settings/             # Settings hub (6 tabs)
│   │       ├── about-showcase/       # About section editor
│   │       ├── our-work/             # Our Work section editor
│   │       ├── our-strength/         # Strengths section editor
│   │       ├── service-banner/       # Service page banner
│   │       └── home-banner/          # Home banner config
│   ├── api/                          # API route handlers
│   │   ├── auth/[...nextauth]/       # NextAuth.js handler
│   │   ├── admin/                    # Protected admin endpoints
│   │   │   ├── auth/                 # Login, profile, password
│   │   │   ├── project/              # Project CRUD + status
│   │   │   ├── service/              # Service CRUD + status
│   │   │   ├── site/                 # Site CRUD + sort
│   │   │   ├── banner/               # Banner management
│   │   │   ├── banner-section/       # Banner section management
│   │   │   ├── home-section/         # Home section management
│   │   │   ├── contact-us/           # Contact management
│   │   │   ├── subscribe/            # Subscriber list
│   │   │   ├── file/                 # File upload/delete
│   │   │   ├── settings/             # All settings endpoints
│   │   │   └── dashboard/            # Dashboard statistics
│   │   └── public/                   # Open API endpoints
│   │       ├── project/              # Public projects
│   │       ├── service/              # Public services
│   │       ├── site/                 # Public sites
│   │       ├── banner/               # Public banners
│   │       ├── banner-section/       # Section by slug
│   │       ├── home-section/         # Home section by slug
│   │       ├── contact-us/           # Submit form
│   │       ├── subscribe/            # Newsletter subscription
│   │       └── settings/             # Public settings
│   ├── documentation/                # Documentation viewer route
│   ├── globals.css                   # Global CSS styles
│   └── layout.tsx                    # Root layout (providers + fonts)
│
├── components/                       # React components
│   ├── ui/                           # Base UI (Radix + Tailwind)
│   ├── features/landing/             # Landing page sections
│   ├── shared/                       # Header, Footer, etc.
│   ├── custom/                       # Domain-specific components
│   └── providers/                    # Context providers
│
├── models/                           # Mongoose models
│   ├── User.ts
│   ├── Project.ts
│   ├── Service.ts
│   ├── Banner.ts
│   ├── HomeSection.ts
│   ├── Settings.ts
│   ├── Sites.ts
│   ├── Subscribe.ts
│   └── ContactUs.ts
│
├── actions/                          # Next.js Server Actions
├── lib/                              # Utilities & helpers
│   ├── async-handler.ts              # API route wrapper
│   ├── authenticate.ts               # JWT utilities
│   ├── mongo-adapter.ts              # Pagination helper
│   ├── fileUpload.ts                 # Cloudinary utilities
│   ├── validation-schema.ts          # Zod schemas
│   └── types/                        # TypeScript types
│
├── config/
│   ├── database.ts                   # MongoDB + auto-seeding
│   ├── routes.ts                     # Route definitions
│   ├── cloudinary.ts                 # Cloudinary SDK config
│   └── constant.ts                   # App constants
│
├── hooks/                            # Custom React hooks
├── public/docs/                      # This documentation file
├── .env.example                      # Environment template
├── next.config.ts                    # Next.js config
├── tailwind.config.ts                # Tailwind config
└── Dockerfile.dev                    # Docker dev config

Pages & Routes

Public Pages

RouteDescription
/Home page with all landing sections
/servicesServices grid listing
/projectsProject portfolio listing
/projects/[slug]Individual project detail page
/contactContact form page
/documentationDocumentation viewer (this page)

Admin Pages (Authentication Required)

RouteDescription
/admin/loginAdmin authentication
/admin/dashboardStatistics overview
/admin/dashboard/projectsProjects CRUD table
/admin/dashboard/servicesServices CRUD table
/admin/dashboard/site-projectsSite projects with drag-and-drop reorder
/admin/dashboard/contactsContact form submissions
/admin/dashboard/subscribeNewsletter subscribers
/admin/dashboard/bannerHero section banners
/admin/dashboard/about-showcaseAbout section editor
/admin/dashboard/our-workOur Work section editor
/admin/dashboard/our-strengthStrengths section editor
/admin/dashboard/service-bannerService page banner editor
/admin/dashboard/home-bannerHome banner configuration
/admin/dashboard/settingsFull settings hub with 6 tabs

API Reference

All admin endpoints require a valid NextAuth session cookie. Public endpoints require no authentication. All responses follow a consistent JSON structure:

// Success response
{ "success": true, "data": {}, "message": "Optional message" }

// Paginated list response
{
  "success": true,
  "data": [],
  "pagination": { "page": 1, "limit": 10, "total": 50, "hasNext": true, "hasPrev": false }
}

// Error response
{ "success": false, "message": "Error description", "errors": {} }

Authentication

MethodEndpointDescriptionBody
POST /api/admin/auth/login Admin login — returns JWT token { email, password }
GET /api/admin/auth/me Get current admin profile
PUT /api/admin/auth/me Update admin display name { name }
PUT /api/admin/auth/password Change admin password { currentPassword, newPassword }

Login Response Example:

{
  "success": true,
  "data": {
    "token": "<jwt_token>",
    "user": {
      "_id": "...",
      "name": "Admin",
      "email": "admin@example.com",
      "role": "admin"
    }
  }
}

Projects

MethodEndpointDescription
GET/api/admin/projectList projects — query: ?page=1&limit=10&search=query
POST/api/admin/projectCreate project (FormData with 4 images)
GET/api/admin/project/[id]Get project by MongoDB ID
PUT/api/admin/project/[id]Update project (FormData)
DELETE/api/admin/project/[id]Delete project and its Cloudinary images
PUT/api/admin/project/status/[id]Toggle active/inactive status

Project FormData Fields

FieldTypeRequiredDescription
titlestringrequiredProject title (text-indexed)
subTitlestringrequiredShort subtitle
descriptionstringrequiredFull description — HTML content
typestringrequiredProject type or category
statusbooleanoptionalVisible on site (default: true)
imageOneFilerequiredPrimary image
imageTwoFilerequiredSecond image
imageThreeFilerequiredThird image
imageFourFilerequiredFourth image

Services

MethodEndpointDescription
GET/api/admin/serviceList services — ?page=1&limit=10&search=query
POST/api/admin/serviceCreate service (FormData)
GET/api/admin/service/[id]Get service by ID
PUT/api/admin/service/[id]Update service (FormData)
DELETE/api/admin/service/[id]Delete service and image
PUT/api/admin/service/status/[id]Toggle status

Site Projects

MethodEndpointDescription
GET/api/admin/siteList sites
POST/api/admin/siteCreate site (FormData)
GET/api/admin/site/[id]Get site by ID
PUT/api/admin/site/[id]Update site (FormData)
DELETE/api/admin/site/[id]Delete site and image
PUT/api/admin/site/status/[id]Toggle status
PUT/api/admin/site/sortReorder — body: { items: [{ id, position }] }

Banners & Sections

MethodEndpointDescription
GET/api/admin/bannerList all banners
POST/api/admin/bannerCreate banner
GET/api/admin/banner-section/[slug]Get banner section by slug
PUT/api/admin/banner-sectionUpdate banner section (FormData)
GET/api/admin/home-section/name/[slug]Get home section by slug
POST/api/admin/home-sectionCreate or update home section

Contacts

MethodEndpointDescription
GET/api/admin/contact-usList contact submissions — ?page=1&limit=10
GET/api/admin/contact-us/[id]Get single submission
PUT/api/admin/contact-us/[id]Update read/unread status
DELETE/api/admin/contact-us/[id]Delete submission

Subscribers

MethodEndpointDescription
GET/api/admin/subscribeList all newsletter subscribers — ?page=1&limit=10

File Management

MethodEndpointDescriptionBody
POST /api/admin/file Upload file to Cloudinary FormData { file }
DELETE /api/admin/file Delete file from Cloudinary { publicId }
// Upload response
{
  "success": true,
  "data": {
    "url": "https://res.cloudinary.com/your-cloud/image/upload/v1234/folder/filename.jpg",
    "publicId": "folder/filename"
  }
}

Settings

MethodEndpointDescription
GET/api/admin/settings/generalGet general settings
PUT/api/admin/settings/generalUpdate general settings — includes logo & favicon upload
GET/api/admin/settings/metadataGet SEO metadata
PUT/api/admin/settings/metadataUpdate SEO metadata — includes OG image upload
GET/api/admin/settings/business-hourGet business hours config
PUT/api/admin/settings/business-hourUpdate business hours (7 day entries)
GET/api/admin/settings/cloudinaryGet Cloudinary credentials
PUT/api/admin/settings/cloudinaryUpdate Cloudinary credentials
GET/api/admin/settings/page-bannerGet per-page banner settings
PUT/api/admin/settings/page-bannerUpdate per-page banners (FormData)
GET/api/admin/settings/termsGet terms & privacy policy HTML
PUT/api/admin/settings/termsUpdate terms & privacy policy
MethodEndpointDescription
GET/api/admin/dashboard/statsGet counts: projects, services, contacts, subscribers

Public API (No Authentication)

All public endpoints return only active and published records. No authentication header is required.

MethodEndpointDescription
GET/api/public/projectActive projects — ?page=1&limit=9&search=query
GET/api/public/project/[slug]Single project by slug
GET/api/public/serviceAll active services
GET/api/public/siteAll active site projects
GET/api/public/bannerAll active banners
GET/api/public/banner-section/[slug]Banner section by slug
GET/api/public/home-section/name/[slug]Home section by slug
POST/api/public/contact-usSubmit contact form — { name, email, phone?, message? }
POST/api/public/subscribeNewsletter subscription — { email }
GET/api/public/settingsAll public-facing settings

Database Schema

The database uses MongoDB with Mongoose ODM. All models include automatic createdAt and updatedAt timestamps.

User

{
  _id:       ObjectId,
  name:      String,          // Admin display name
  email:     String,          // Unique — used for login
  password:  String,          // bcrypt hashed (never returned in API responses)
  role:      "admin" | "user",
  createdAt: Date,
  updatedAt: Date
}

Project

{
  _id:         ObjectId,
  title:       String,        // Text-indexed for full-text search
  slug:        String,        // Unique — auto-generated from title
  subTitle:    String,        // Text-indexed
  description: String,        // HTML content — text-indexed
  type:        String,        // Project category or type
  status:      Boolean,       // true = visible on public site
  imageOne:    String,        // Cloudinary URL
  imageTwo:    String,        // Cloudinary URL
  imageThree:  String,        // Cloudinary URL
  imageFour:   String,        // Cloudinary URL
  createdAt:   Date,
  updatedAt:   Date
}

Service

{
  _id:         ObjectId,
  title:       String,        // Text-indexed
  description: String,        // HTML content — optional
  image:       String,        // Cloudinary URL
  status:      Boolean,       // true = visible on public site
  createdAt:   Date,
  updatedAt:   Date
}

Banner

{
  _id:         ObjectId,
  heading:     String,
  shortDesc:   String,
  image:       String,        // Cloudinary URL
  sectionName: "banner" | "section",
  position:    Number,        // Display order — indexed
  status:      Boolean,
  cards: [
    { title: String, image: String, link: String }
  ],
  createdAt: Date,
  updatedAt: Date
}

HomeSection

{
  _id:          ObjectId,
  sectionKey:   String,       // Unique slug (e.g. "about", "our-work", "our-strength")
  title:        String,
  subTitle:     String,
  sectionImage: String,       // Cloudinary URL
  orderBy:      Number,       // Display order — indexed
  status:       Boolean,
  sectionType:  String,       // Content type hint
  images:       [String],     // Array of Cloudinary URLs
  videos:       [String],
  features: [
    { title: String, description: String, image: String }
  ],
  stats: [
    { value: String, suffix: String, label: String }
  ],
  serviceIds:   [ObjectId],   // References to Service documents
  content:      Mixed,        // Flexible additional JSON data
  createdAt:    Date,
  updatedAt:    Date
}

Settings (Single Document)

{
  general: {
    companyName, companyDialCode, companyPhone, companyAddress,
    logo,        // Cloudinary URL
    favicon,     // Cloudinary URL
    supportEmail, ownerName, ownerEmail,
    facebook, instagram, twitter, youtube,
    homeView, title
  },
  pageBanner: {
    service:  { title, description, image },  // Service page hero
    project:  { title, description, image },  // Projects page hero
    contact:  { title, description, image }   // Contact page hero
  },
  cloudinary: {
    cloudName, apiKey, apiSecret, folderName, secureUrlBase
  },
  metadata: {
    title, applicationName, description,
    keywords: [String],
    openGraphImage   // Cloudinary URL
  },
  termsPolicy: {
    terms:  String,  // HTML content
    policy: String   // HTML content
  },
  businessHours: [   // Exactly 7 entries — one per day
    {
      dayOfWeek:  0 | 1 | 2 | 3 | 4 | 5 | 6,  // 0=Sunday, 6=Saturday
      openTime:   Number,  // Minutes from midnight (540 = 9:00 AM)
      closeTime:  Number,  // Minutes from midnight (1080 = 6:00 PM)
      isClosed:   Boolean
    }
  ]
}

Site

{
  _id:      ObjectId,
  title:    String,
  subTitle: String,
  image:    String,    // Cloudinary URL
  link:     String,    // External URL
  position: Number,    // Sort order — managed via drag-and-drop
  status:   Boolean,
  createdAt: Date,
  updatedAt: Date
}

Subscribe

{
  _id:       ObjectId,
  email:     String,   // Unique, lowercase, trimmed
  createdAt: Date,
  updatedAt: Date
}

ContactUs

{
  _id:       ObjectId,
  name:      String,
  email:     String,   // Lowercase
  phone:     String,   // Optional
  message:   String,   // Optional
  status:    Boolean,  // true = read, false = unread
  createdAt: Date,
  updatedAt: Date
}

Admin Dashboard Guide

The admin dashboard is accessible at /admin/dashboard after logging in. It provides a complete CMS for managing all website content.

Managing Projects

  1. Go to Dashboard → Projects
  2. Click Add New Project to open the create form
  3. Fill in: Title, Subtitle, Type, Description (rich text editor), and upload 4 images
  4. Click Save — the URL slug is auto-generated from the title
  5. Use the Status toggle to show or hide the project on the public site
  6. Click the Edit icon to modify existing projects
  7. Click the Delete icon to permanently remove a project — this also deletes its images from Cloudinary

Managing Services

  1. Go to Dashboard → Services
  2. Click Add New Service
  3. Enter a title, optional description (rich text), and upload a featured image
  4. Toggle Status to control visibility on the public site

Managing Site Projects

  1. Go to Dashboard → Site Projects
  2. Add entries with title, subtitle, a thumbnail image, and an external URL
  3. Drag and drop rows in the table to reorder their display position on the website
  4. Toggle status per site to control visibility

Contact Submissions

  1. Go to Dashboard → Contacts
  2. View all contact form submissions including name, email, phone, and message
  3. Mark submissions as read or unread to track follow-up status
  4. Delete processed submissions as needed

Banner Management

  1. Go to Dashboard → Banner
  2. Edit the hero section heading, short description, and background image
  3. Add, edit, or remove CTA cards — each card has a title, image, and link URL

Home Section Editors

Admin RouteSectionContent You Edit
/about-showcaseAbout UsTitle, description, image, statistics
/our-workOur WorkTitle, description, project gallery
/our-strengthOur StrengthsTitle, feature cards (icon + text)
/service-bannerService BannerService page hero image and text
/home-bannerHome BannerAdditional home page hero configuration

Settings Hub

Accessible at /admin/dashboard/settings — organized into six tabs:

General

Company name, phone number (with international dial code), address, support email, owner name and email, social media links (Facebook, Instagram, Twitter, YouTube), logo upload, and favicon upload.

Metadata

SEO page title, application name, meta description, keywords array, and Open Graph image for social media sharing previews.

Business Hours

Configure open and close times for each day of the week (Sunday through Saturday). Mark individual days as permanently closed. Times are stored as minutes from midnight — e.g. 540 = 9:00 AM, 1080 = 6:00 PM.

Cloudinary

Enter your Cloudinary Cloud Name, API Key, API Secret, and upload folder name. All image uploads will use these credentials.

Page Banners

Set a custom hero banner (image, title, and description) independently for the Services page, Projects page, and Contact page.

Terms & Policy

Rich text editor for the Terms of Service and a separate editor for the Privacy Policy. Both support full HTML formatting.

Image Management (Cloudinary)

All images in this template are stored and served via Cloudinary. No files are saved to the server filesystem.

Initial Setup

  1. Create a free account at cloudinary.com
  2. After your first admin login, navigate to Settings → Cloudinary
  3. Enter your Cloud Name, API Key, and API Secret from your Cloudinary Dashboard
  4. Set a folder name (e.g., construction-template) to keep uploads organized
  5. Click Save — all subsequent uploads will use these credentials

How It Works

When any image is uploaded in the admin panel, the file is sent to /api/admin/file. The server uploads it to your Cloudinary account using the stored credentials, then returns a secure CDN URL. Only the URL string is saved in MongoDB. When a record (project, service, etc.) is deleted, the corresponding Cloudinary images are also automatically removed.

Supported Formats

JPEG · JPG · PNG · WebP · SVG

Upload Limits

Maximum 50 MB per file, configured in next.config.ts under serverActions.bodySizeLimit.

Customization Guide

Changing Brand Colors

Update CSS custom properties in app/globals.css:

:root {
  --primary: your-hsl-value;
  --primary-foreground: your-hsl-value;
}

Or extend the Tailwind theme in tailwind.config.ts:

theme: {
  extend: {
    colors: {
      primary: {
        DEFAULT: "#your-color",
        foreground: "#your-foreground-color"
      }
    }
  }
}

Changing Fonts

The template uses Poppins for body text and Teko for headings. To change them, edit app/layout.tsx:

import { YourFont } from "next/font/google";

const yourFont = YourFont({
  weight: ["400", "600", "700"],
  subsets: ["latin"],
  variable: "--font-your-font",
});

Adding New Admin Pages

  1. Create the folder and page.tsx at app/(private)/admin/dashboard/your-page/
  2. Register the route in config/routes.ts
  3. Add a sidebar navigation link in the admin sidebar component

Adding New Public Pages

  1. Create app/(public)/your-page/page.tsx
  2. The page is immediately available at /your-page and inherits the public layout (navbar + footer)

API Response Format

All API routes use a consistent response wrapper. To extend the API, follow this pattern:

// lib/async-handler.ts wraps all API routes
// Return a consistent response shape:
return NextResponse.json({
  success: true,
  data: yourData,
  message: "Optional success message"
});

// For errors:
return NextResponse.json(
  { success: false, message: "Descriptive error" },
  { status: 400 }
);

Deployment

Vercel (Recommended)

Vercel is the recommended deployment platform for Next.js applications.

  1. Push the project to GitHub, GitLab, or Bitbucket
  2. Import the repository at vercel.com/new
  3. Add all environment variables in the Vercel project settings
  4. Set AUTH_TRUST_HOST=true in Vercel environment settings
  5. Deploy — Vercel handles builds, HTTPS, and CDN automatically
# Optional: deploy via Vercel CLI
npm i -g vercel
vercel --prod

Docker

A Dockerfile.dev is included for containerized development:

docker build -f Dockerfile.dev -t construction-template .
docker run -p 3000:3000 --env-file .env.local construction-template

For production, create a multi-stage Dockerfile:

FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-alpine AS runner
WORKDIR /app
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["npm", "start"]

Traditional VPS / Server

# Install Node.js 18+
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs

# Build
npm ci
npm run build

# Run with PM2
npm i -g pm2
pm2 start npm --name "construction" -- start
pm2 save
pm2 startup

Nginx reverse proxy configuration:

server {
    listen 80;
    server_name yourdomain.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_cache_bypass $http_upgrade;
    }
}
For HTTPS on a VPS, use Certbot with Let's Encrypt: sudo certbot --nginx -d yourdomain.com

Build Commands

CommandDescription
npm run devStart development server with Turbopack (fast HMR)
npm run buildBuild the application for production
npm run startStart the production server
npm run lintRun ESLint for code quality checks

Changelog

v1.0.0 — Initial Release

  • Full-stack construction website template with admin dashboard
  • Public pages: Home, Services, Projects (with detail), Contact
  • MongoDB connection pooling and automatic default admin seeding
  • NextAuth v5 JWT authentication with 30-day sessions
  • Cloudinary media management with auto-cleanup on record deletion
  • Fully responsive design with dark mode support
  • Dynamic SEO metadata management from admin panel
  • Business hours configuration (per day, open/close times)
  • Drag-and-drop site project reordering with dnd-kit
  • Rich text editor (SunEditor) for descriptions and legal content
  • Zod validation on all API endpoints (client and server)
  • TanStack React Table with search, sort, and pagination for all data grids

Support

For questions, bugs, or customization assistance:

  • Documentation: Visit /documentation in the app or open public/docs/documentation.html
  • Issues: Report via the purchase platform's comments or support system

Before Contacting Support

  1. Verify all environment variables in .env.local are correctly set
  2. Confirm your MongoDB connection string is valid and the IP address is whitelisted in Atlas
  3. Check that Cloudinary credentials are saved under Settings → Cloudinary in the admin panel
  4. Ensure Node.js version is 18.0.0 or higher: node --version
Quick Debug Tip: Check the browser console and terminal output together. API errors are returned as JSON with a message field that describes the exact issue.

Built with Next.js 16 · TypeScript · MongoDB · Tailwind CSS 4 · v1.0.0