Home

NodePress Documentation

The complete guide to building, managing, and extending NodePress CMS - a modern, full-featured content management system built with NestJS, React, Prisma, and PostgreSQL.

πŸš€

Quick Start

Get up and running with NodePress in under 5 minutes.

πŸ“š

LMS & Courses

Build online courses with quizzes, certificates, and progress tracking.

πŸ›’

eCommerce

Full shopping cart, Stripe payments, and order management.

🎨

Theme Development

Create custom themes with Handlebars templating.

What is NodePress?

NodePress is an enterprise-grade CMS that combines the best of modern web technologies to deliver a powerful, extensible platform for building websites, online courses, and eCommerce stores.

Key Features

  • Content Management - Posts, pages, media library, SEO tools, and rich text editing
  • Learning Management (LMS) - Courses, lessons, quizzes, certificates, and progress tracking
  • eCommerce - Products, shopping cart, Stripe checkout, orders, and inventory
  • Real-time Features - WebSocket messaging, video calls, live notifications
  • Social Timeline - Posts, likes, comments, shares, hashtags, and @mentions
  • Developer Marketplace - Freelancer profiles, hiring system, and project management
  • Plugin System - Extend functionality with custom plugins
  • Theme Engine - Handlebars-based templating with CSS/JS customization

Tech Stack

LayerTechnologies
BackendNode.js 20+, NestJS 11, TypeScript 5.9, Prisma 5
FrontendReact 18, Vite 6, Tailwind CSS, Zustand
DatabasePostgreSQL 15+, Redis (caching)
Real-timeSocket.IO, WebRTC
PaymentsStripe
AIOpenAI GPT-4, Anthropic Claude

Quick Start

Get NodePress running on your local machine in minutes.

Prerequisites

  • Node.js 20+ - JavaScript runtime
  • PostgreSQL 15+ - Database server
  • Redis - Caching and sessions (optional but recommended)
  • Git - Version control

Installation

πŸ’‘ Tip

After purchasing, you'll receive the source code as a ZIP file. Extract it and follow the steps below.

Step 1: Extract the Source Code

# Extract the downloaded ZIP file
unzip nodepress-source.zip
cd NodePress

Step 2: Install Dependencies

# Install backend dependencies
npm install

# Install frontend dependencies
cd admin && npm install && cd ..

Step 3: Configure Environment

# Copy environment template
cp .env.example .env

# Edit with your settings
# DATABASE_URL="postgresql://user:pass@localhost:5432/nodepress"
# JWT_SECRET="your-secure-secret-key"
# REDIS_URL="redis://localhost:6379"

Step 4: Setup Database

# Generate Prisma client
npx prisma generate

# Run migrations
npx prisma migrate dev

# Seed initial data (optional)
npx prisma db seed

Step 5: Start Development Server

# Start backend (port 3000)
npm run start:dev

# In another terminal, start frontend (port 5173)
cd admin && npm run dev
βœ… Success

NodePress is now running! Visit http://localhost:3000 for the public site and http://localhost:5173/admin for the admin panel.

Windows Quick Setup

For Windows users, we provide an automated setup script that handles all installation steps:

πŸ’‘ Windows Users

The setup-windows.bat script is included in the source code download package.

Using the Windows Setup Script

@echo off
REM Extract the downloaded ZIP file and open Command Prompt in that folder
REM Then run:

setup-windows.bat

REM The script will:
REM 1. Check for Node.js installation
REM 2. Install all dependencies
REM 3. Copy .env.example to .env
REM 4. Generate Prisma client
REM 5. Prompt you for database configuration
REM 6. Run database migrations
REM 7. Start the development server

Windows Manual Setup (PowerShell)

# Extract the downloaded ZIP file
Expand-Archive nodepress-source.zip -DestinationPath .
cd NodePress

# Install dependencies
npm install
cd admin; npm install; cd ..

# Copy environment template
Copy-Item .env.example .env

# Edit .env file with your settings
notepad .env

# Setup database
npx prisma generate
npx prisma migrate dev

# Start development servers
npm run start:dev

Installing Prerequisites on Windows

# Using winget (Windows Package Manager)
winget install OpenJS.NodeJS.LTS
winget install PostgreSQL.PostgreSQL

# Or download installers directly:
# Node.js: https://nodejs.org/
# PostgreSQL: https://www.postgresql.org/download/windows/

# Verify installations
node --version
npm --version
psql --version

Default Credentials

RoleEmailPassword
Adminadmin@nodepress.devadmin123
Editoreditor@nodepress.deveditor123
⚠️ Important

Change default passwords immediately in production environments.

Architecture Overview

NodePress follows a modular, layered architecture designed for scalability and maintainability.

System Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        Client Layer                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ Public Site β”‚  β”‚ Admin Panel β”‚  β”‚ Mobile Apps (API)   β”‚  β”‚
β”‚  β”‚ (Handlebars)β”‚  β”‚   (React)   β”‚  β”‚                     β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      API Gateway Layer                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  REST API   β”‚  β”‚  WebSocket  β”‚  β”‚    Authentication   β”‚  β”‚
β”‚  β”‚ Controllers β”‚  β”‚   Gateway   β”‚  β”‚      (JWT/OAuth)    β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      Service Layer                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ Content β”‚ β”‚   LMS   β”‚ β”‚  Shop   β”‚ β”‚Messages β”‚ β”‚ Media β”‚  β”‚
β”‚  β”‚ Service β”‚ β”‚ Service β”‚ β”‚ Service β”‚ β”‚ Service β”‚ β”‚Serviceβ”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      Data Layer                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚   Prisma    β”‚  β”‚    Redis    β”‚  β”‚   File Storage      β”‚  β”‚
β”‚  β”‚    ORM      β”‚  β”‚   Cache     β”‚  β”‚   (Local/S3)        β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚         β”‚                                                    β”‚
β”‚         β–Ό                                                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                            β”‚
β”‚  β”‚ PostgreSQL  β”‚                                            β”‚
β”‚  β”‚  Database   β”‚                                            β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

NestJS Module Structure

Each feature is encapsulated in a NestJS module with its own controllers, services, and DTOs:

@Module({
  imports: [PrismaModule, ConfigModule],
  controllers: [CoursesController, LessonsController],
  providers: [CoursesService, LessonsService],
  exports: [CoursesService],
})
export class LmsModule {}

Request Flow

  1. Request - Client sends HTTP request or WebSocket message
  2. Guards - Authentication and authorization checks (JWT, Roles)
  3. Pipes - Request validation and transformation
  4. Controller - Route handling and request parsing
  5. Service - Business logic execution
  6. Repository - Database operations via Prisma
  7. Response - Data serialization and response

Content Management

NodePress provides a comprehensive content management system for creating and organizing posts, pages, and media.

Posts

Posts are the primary content type for blogs, news, and articles.

Creating a Post

// POST /api/posts
const post = await postsService.create({
  title: 'Getting Started with NodePress',
  slug: 'getting-started-nodepress',
  content: '<p>Welcome to NodePress...</p>',
  excerpt: 'A quick introduction to NodePress CMS',
  status: 'PUBLISHED',
  categoryIds: ['cat-123'],
  tagIds: ['tag-456'],
  featuredImageId: 'media-789',
});

Post Status Workflow

  • DRAFT - Work in progress, not visible to public
  • PENDING - Awaiting editorial review
  • PUBLISHED - Live and visible to public
  • SCHEDULED - Will publish at specified date/time
  • ARCHIVED - Hidden from public, preserved for reference

Pages

Pages are static content like About, Contact, and Terms of Service.

// Pages support hierarchical structure
const page = await pagesService.create({
  title: 'About Us',
  slug: 'about',
  content: '<p>Our company story...</p>',
  parentId: null, // Top-level page
  template: 'about', // Uses about.hbs template
});

Categories & Tags

Organize content with hierarchical categories and flat tags.

// Categories support nesting
const category = await categoriesService.create({
  name: 'Web Development',
  slug: 'web-development',
  description: 'Articles about web development',
  parentId: 'parent-cat-id', // Optional parent
});

// Tags are flat
const tag = await tagsService.create({
  name: 'JavaScript',
  slug: 'javascript',
});

Media Library

Upload and manage images, videos, documents, and other files.

Uploading Files

// POST /api/media/upload
const formData = new FormData();
formData.append('file', fileBlob);
formData.append('alt', 'Product screenshot');

const media = await fetch('/api/media/upload', {
  method: 'POST',
  headers: { Authorization: `Bearer ${token}` },
  body: formData,
});

Supported File Types

TypeExtensionsMax Size
Imagesjpg, png, gif, webp, svg10 MB
Videosmp4, webm, mov100 MB
Documentspdf, doc, docx, xls, xlsx25 MB
Audiomp3, wav, ogg50 MB

Learning Management System

Build and sell online courses with NodePress's integrated LMS.

Courses

Courses are the top-level container for educational content.

// Create a course
const course = await coursesService.create({
  title: 'Complete TypeScript Masterclass',
  slug: 'typescript-masterclass',
  description: 'Learn TypeScript from beginner to advanced',
  price: 9900, // $99.00 in cents
  currency: 'USD',
  level: 'INTERMEDIATE',
  status: 'PUBLISHED',
  thumbnailId: 'media-123',
});

Course Levels

  • BEGINNER - No prior knowledge required
  • INTERMEDIATE - Some experience recommended
  • ADVANCED - Significant experience required
  • ALL_LEVELS - Suitable for everyone

Lessons

Lessons contain the actual educational content within a course.

// Create a lesson
const lesson = await lessonsService.create({
  courseId: 'course-123',
  title: 'Introduction to Types',
  slug: 'intro-to-types',
  content: '<p>TypeScript adds static typing...</p>',
  videoUrl: 'https://vimeo.com/123456',
  duration: 1200, // 20 minutes in seconds
  order: 1,
  isFree: true, // Preview lesson
});

Quizzes

Test student knowledge with interactive quizzes.

// Create a quiz
const quiz = await quizzesService.create({
  lessonId: 'lesson-123',
  title: 'Types Quiz',
  passingScore: 70, // Percentage
  questions: [
    {
      question: 'What is the type of "hello"?',
      type: 'MULTIPLE_CHOICE',
      options: ['number', 'string', 'boolean', 'object'],
      correctAnswer: 1, // Index of correct option
      points: 10,
    },
  ],
});

Certificates

Award certificates upon course completion.

// Certificate is auto-generated when course is completed
// Configure certificate template in course settings
const courseSettings = {
  certificateEnabled: true,
  certificateTemplate: 'modern', // Template name
  certificateTitle: 'Certificate of Completion',
  instructorSignature: 'media-signature-id',
};

eCommerce

Sell physical and digital products with NodePress's integrated shop.

Products

// Create a product
const product = await productsService.create({
  name: 'NodePress Pro License',
  slug: 'nodepress-pro',
  description: 'Lifetime access to NodePress Pro features',
  price: 19900, // $199.00 in cents
  salePrice: 14900, // Optional sale price
  currency: 'USD',
  type: 'DIGITAL', // PHYSICAL or DIGITAL
  status: 'PUBLISHED',
  inventory: {
    trackInventory: false, // Digital products
    unlimited: true,
  },
  images: ['media-1', 'media-2'],
});

Shopping Cart

// Add to cart
await cartService.addItem({
  userId: 'user-123',
  productId: 'product-456',
  quantity: 1,
  variant: { size: 'Large', color: 'Blue' }, // Optional
});

// Get cart
const cart = await cartService.getCart('user-123');
// Returns: { items: [...], subtotal, tax, total }

Checkout & Payments

NodePress integrates with Stripe for secure payment processing.

// Create checkout session
const session = await checkoutService.createSession({
  userId: 'user-123',
  successUrl: 'https://example.com/success',
  cancelUrl: 'https://example.com/cart',
});

// Returns Stripe checkout URL
// Redirect user to: session.url
πŸ’³ Stripe Configuration

Set STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET in your environment variables.

Orders

// Orders are created automatically after successful payment
// Webhook handles: checkout.session.completed

// Query orders
const orders = await ordersService.findAll({
  userId: 'user-123',
  status: 'COMPLETED',
});

// Order statuses: PENDING, PROCESSING, COMPLETED, CANCELLED, REFUNDED

API Reference

NodePress exposes a RESTful API for all operations.

Authentication

All API requests require authentication via JWT tokens.

Login

POST /api/auth/login
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "securepassword"
}

# Response
{
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs...",
  "user": { "id": "...", "email": "...", "role": "ADMIN" }
}

Using Tokens

# Include in Authorization header
GET /api/posts
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Core Endpoints

ResourceEndpointsDescription
Posts/api/postsCRUD for blog posts
Pages/api/pagesCRUD for static pages
Media/api/mediaFile upload and management
Users/api/usersUser management
Courses/api/coursesLMS course management
Products/api/productseCommerce products
Orders/api/ordersOrder management
Settings/api/settingsSite configuration

Pagination

# All list endpoints support pagination
GET /api/posts?page=1&limit=10&sort=createdAt&order=desc

# Response includes pagination metadata
{
  "data": [...],
  "meta": {
    "total": 100,
    "page": 1,
    "limit": 10,
    "totalPages": 10
  }
}

Error Handling

{
  "statusCode": 400,
  "message": "Validation failed",
  "errors": [
    { "field": "email", "message": "Invalid email format" }
  ]
}

Posts API

# List posts
GET /api/posts?page=1&limit=10&status=published&category=tech

# Get single post
GET /api/posts/:id
GET /api/posts/slug/:slug

# Create post (requires auth)
POST /api/posts
{
  "title": "My New Post",
  "content": "<p>Post content here...</p>",
  "excerpt": "Brief summary",
  "status": "draft",
  "categoryIds": ["cat_1", "cat_2"],
  "tagIds": ["tag_1"],
  "featuredImage": "media_id",
  "seo": {
    "title": "Custom SEO Title",
    "description": "Meta description"
  }
}

# Update post
PUT /api/posts/:id

# Delete post
DELETE /api/posts/:id

# Publish/unpublish
POST /api/posts/:id/publish
POST /api/posts/:id/unpublish

Courses API (LMS)

# List courses
GET /api/courses?status=published&instructor=user_id

# Get course with lessons
GET /api/courses/:id?include=lessons,reviews

# Create course
POST /api/courses
{
  "title": "Complete Web Development",
  "description": "Learn full-stack development",
  "price": 99.99,
  "currency": "USD",
  "level": "beginner",
  "categoryId": "cat_1"
}

# Course lessons
GET /api/courses/:id/lessons
POST /api/courses/:id/lessons
PUT /api/courses/:id/lessons/:lessonId
DELETE /api/courses/:id/lessons/:lessonId

# Enrollments
POST /api/courses/:id/enroll
GET /api/courses/:id/enrollments
GET /api/users/me/enrollments

# Progress tracking
PUT /api/courses/:id/lessons/:lessonId/complete
GET /api/courses/:id/progress

# Quizzes
GET /api/courses/:id/lessons/:lessonId/quiz
POST /api/courses/:id/lessons/:lessonId/quiz/submit

# Certificates
GET /api/courses/:id/certificate
POST /api/courses/:id/certificate/generate

eCommerce API

# Products
GET /api/products?category=electronics&inStock=true
POST /api/products
PUT /api/products/:id
DELETE /api/products/:id

# Cart
GET /api/cart
POST /api/cart/add
PUT /api/cart/:itemId
DELETE /api/cart/:itemId
DELETE /api/cart/clear

# Checkout
POST /api/checkout
{
  "shippingAddress": { ... },
  "paymentMethod": "stripe"
}

# Orders
GET /api/orders
GET /api/orders/:id
PUT /api/orders/:id/status

# Payments (Stripe)
POST /api/payments/create-intent
POST /api/payments/confirm
POST /api/webhooks/stripe

Media API

# Upload file
POST /api/media/upload
Content-Type: multipart/form-data
file: <binary>
folder: "posts"

# List media
GET /api/media?folder=posts&type=image

# Get media details
GET /api/media/:id

# Delete media
DELETE /api/media/:id

# Bulk operations
POST /api/media/bulk-delete
{
  "ids": ["media_1", "media_2"]
}

Settings API

# Get all settings
GET /api/settings

# Get specific setting
GET /api/settings/:key

# Update settings (admin only)
PUT /api/settings
{
  "siteName": "My NodePress Site",
  "siteDescription": "A modern CMS",
  "locale": "en",
  "timezone": "America/New_York"
}

# Theme settings
GET /api/settings/theme
PUT /api/settings/theme

Theme Development

Create custom themes using Handlebars templates.

Theme Structure

themes/
└── my-theme/
    β”œβ”€β”€ theme.json          # Theme metadata
    β”œβ”€β”€ assets/
    β”‚   β”œβ”€β”€ css/
    β”‚   β”‚   └── style.css
    β”‚   └── js/
    β”‚       └── main.js
    β”œβ”€β”€ templates/
    β”‚   β”œβ”€β”€ layouts/
    β”‚   β”‚   └── main.hbs    # Base layout
    β”‚   β”œβ”€β”€ partials/
    β”‚   β”‚   β”œβ”€β”€ header.hbs
    β”‚   β”‚   └── footer.hbs
    β”‚   β”œβ”€β”€ home.hbs        # Homepage
    β”‚   β”œβ”€β”€ post.hbs        # Single post
    β”‚   β”œβ”€β”€ page.hbs        # Static page
    β”‚   └── archive.hbs     # Post listing
    └── screenshot.png      # Theme preview

theme.json

{
  "name": "My Custom Theme",
  "version": "1.0.0",
  "author": "Your Name",
  "description": "A beautiful custom theme",
  "homepage": "https://example.com",
  "license": "MIT",
  "supports": {
    "customColors": true,
    "customFonts": true,
    "darkMode": true
  }
}

Handlebars Helpers

NodePress provides many built-in helpers:

<!-- Date formatting -->
Invalid Date

<!-- Truncate text -->


<!-- Conditional classes -->
<div class="">

<!-- Asset URLs -->
<link href="/themes/default/assets/css/style.css" rel="stylesheet">

<!-- Site settings -->
<title> - </title>

<!-- Navigation -->

Template Data

Each template receives context data:

// post.hbs receives:
{
  post: {
    title, slug, content, excerpt,
    author: { name, avatar },
    categories: [...],
    tags: [...],
    featuredImage: { url, alt },
    createdAt, updatedAt,
  },
  site: { name, description, logo },
  navigation: [...],
  sidebar: { recentPosts, categories },
}

Plugin Development

Extend NodePress functionality with custom plugins.

Plugin Structure

plugins/
└── my-plugin/
    β”œβ”€β”€ plugin.json         # Plugin metadata
    β”œβ”€β”€ index.ts            # Entry point
    β”œβ”€β”€ services/
    β”‚   └── my-service.ts
    β”œβ”€β”€ controllers/
    β”‚   └── my-controller.ts
    └── views/
        └── settings.hbs    # Admin settings page

plugin.json

{
  "name": "my-plugin",
  "displayName": "My Plugin",
  "version": "1.0.0",
  "author": "Your Name",
  "description": "Adds awesome features",
  "main": "index.ts",
  "hooks": ["onInit", "onPostCreate", "onUserLogin"],
  "settings": {
    "apiKey": { "type": "string", "label": "API Key" },
    "enabled": { "type": "boolean", "default": true }
  }
}

Available Hooks

HookTriggerParameters
onInitPlugin initializationconfig
onPostCreateNew post createdpost
onPostUpdatePost updatedpost, changes
onUserLoginUser logs inuser
onUserRegisterNew user registersuser
onOrderCompleteOrder completedorder
onCourseEnrollUser enrolls in courseenrollment

Example Plugin

// index.ts
import { Plugin, Hook } from '@nodepress/plugin-sdk';

export default class MyPlugin extends Plugin {
  @Hook('onInit')
  async initialize() {
    console.log('My plugin initialized!');
  }

  @Hook('onPostCreate')
  async handleNewPost(post: Post) {
    // Send notification, update analytics, etc.
    await this.notifySubscribers(post);
  }

  private async notifySubscribers(post: Post) {
    // Plugin logic here
  }
}

Theme Designer

NodePress includes a powerful visual theme customizer that allows you to modify your site's appearance without writing code.

Accessing the Theme Designer

Access the Theme Designer from the admin panel or directly via URL:

# Via Admin Panel
Admin β†’ Appearance β†’ Theme Designer

# Direct URL
https://your-site.com/theme-designer

Interface Overview

The Theme Designer is divided into several panels:

  • Colors Panel - Primary, secondary, accent, and background colors
  • Typography Panel - Fonts, sizes, weights, and line heights
  • Layout Panel - Container widths, spacing, and grid settings
  • Components Panel - Buttons, cards, forms, and navigation styles
  • Live Preview - Real-time preview of your changes

Color Customization

// Available color variables
{
  primary: '#10b981',      // Main brand color
  primaryDark: '#059669',  // Darker variant for hover states
  secondary: '#6366f1',    // Secondary accent color
  background: '#0f172a',   // Page background
  surface: '#1e293b',      // Card/panel backgrounds
  text: '#f8fafc',         // Primary text color
  textMuted: '#94a3b8',    // Secondary text color
  border: '#334155',       // Border color
  success: '#22c55e',      // Success state
  warning: '#f59e0b',      // Warning state
  error: '#ef4444',        // Error state
}

Typography Settings

// Typography configuration
{
  fontFamily: {
    heading: "'Inter', sans-serif",
    body: "'Inter', sans-serif",
    code: "'JetBrains Mono', monospace"
  },
  fontSize: {
    xs: '0.75rem',   // 12px
    sm: '0.875rem',  // 14px
    base: '1rem',    // 16px
    lg: '1.125rem',  // 18px
    xl: '1.25rem',   // 20px
    '2xl': '1.5rem', // 24px
    '3xl': '1.875rem', // 30px
    '4xl': '2.25rem',  // 36px
  },
  fontWeight: {
    normal: 400,
    medium: 500,
    semibold: 600,
    bold: 700
  },
  lineHeight: {
    tight: 1.25,
    normal: 1.5,
    relaxed: 1.75
  }
}

AI Theme Generation

Use AI to generate complete theme configurations based on natural language descriptions:

// API endpoint for AI theme generation
POST /api/themes/generate

{
  "prompt": "Modern dark theme with green accents, professional look for a tech blog",
  "basePreset": "dark-mode" // Optional starting point
}

// Response
{
  "theme": {
    "name": "AI Generated: Tech Blog Dark",
    "colors": { ... },
    "typography": { ... },
    "spacing": { ... }
  },
  "preview": "data:image/png;base64,..."
}
πŸ’‘ AI Features

AI theme generation requires an OpenAI API key configured in your environment variables.

Export & Import Themes

// Export current theme
GET /api/themes/export
// Returns: theme.json file download

// Import theme
POST /api/themes/import
Content-Type: multipart/form-data
file: theme.json

// Theme JSON structure
{
  "name": "My Custom Theme",
  "version": "1.0.0",
  "colors": { ... },
  "typography": { ... },
  "layout": { ... },
  "components": { ... }
}

Theme Presets

NodePress includes several built-in theme presets to quickly style your site.

Built-in Presets

PresetDescriptionBest For
defaultModern dark theme with green accentsGeneral purpose
light-minimalClean white theme with minimal stylingProfessional blogs
dark-modeHigh contrast dark themeDeveloper sites
blog-focusedTypography-focused reading experienceContent-heavy sites
ecommerceProduct-focused with conversion optimizationOnline stores
lms-professionalClean interface for learning platformsCourse platforms
corporateProfessional business appearanceCompany websites
creativeBold colors and dynamic layoutsPortfolio sites

Applying Presets

// Via API
POST /api/themes/presets/apply
{
  "preset": "dark-mode",
  "overrides": {
    "colors": {
      "primary": "#8b5cf6" // Override primary color
    }
  }
}

// Via Admin Panel
Admin β†’ Appearance β†’ Theme Designer β†’ Presets β†’ Select preset β†’ Apply

Creating Custom Presets

// Save current theme as preset
POST /api/themes/presets
{
  "name": "my-custom-preset",
  "displayName": "My Custom Preset",
  "description": "Custom theme for my brand",
  "theme": {
    "colors": {
      "primary": "#3b82f6",
      "primaryDark": "#2563eb",
      "background": "#0f172a",
      "surface": "#1e293b",
      "text": "#f8fafc"
    },
    "typography": {
      "fontFamily": {
        "heading": "'Poppins', sans-serif",
        "body": "'Open Sans', sans-serif"
      }
    },
    "components": {
      "borderRadius": "12px",
      "buttonStyle": "rounded"
    }
  }
}

// List available presets
GET /api/themes/presets
// Returns: Array of preset objects

Internationalization (i18n)

NodePress supports multiple languages and localization out of the box.

Setting Up Multi-Language Support

// config/i18n.ts
export default {
  defaultLocale: 'en',
  supportedLocales: ['en', 'es', 'fr', 'de', 'zh', 'ja', 'ar'],
  fallbackLocale: 'en',
  detectBrowserLocale: true,
  cookieName: 'locale',
  urlPrefix: true // Enables /en/, /es/, /fr/ URL prefixes
};

Translation File Structure

locales/
β”œβ”€β”€ en/
β”‚   β”œβ”€β”€ common.json      # Common UI strings
β”‚   β”œβ”€β”€ admin.json       # Admin panel strings
β”‚   β”œβ”€β”€ errors.json      # Error messages
β”‚   └── emails.json      # Email templates
β”œβ”€β”€ es/
β”‚   β”œβ”€β”€ common.json
β”‚   β”œβ”€β”€ admin.json
β”‚   β”œβ”€β”€ errors.json
β”‚   └── emails.json
└── fr/
    └── ...

Translation File Example

// locales/en/common.json
{
  "nav": {
    "home": "Home",
    "about": "About",
    "blog": "Blog",
    "courses": "Courses",
    "contact": "Contact"
  },
  "auth": {
    "login": "Log In",
    "logout": "Log Out",
    "register": "Sign Up",
    "forgotPassword": "Forgot Password?",
    "resetPassword": "Reset Password"
  },
  "content": {
    "readMore": "Read More",
    "publishedOn": "Published on ",
    "byAuthor": "by ",
    "comments": " comments"
  }
}

Using Translations

<!-- In Handlebars templates -->
<nav>
  <a href="/">nav.home</a>
  <a href="/blog">nav.blog</a>
  <a href="/courses">nav.courses</a>
</nav>

<!-- With variables -->
<p>content.publishedOn</p>
<p>content.byAuthor</p>

<!-- Pluralization -->
<span>content.comments</span>
// In TypeScript/Backend
import { I18nService } from '@nestjs/i18n';

@Injectable()
export class NotificationService {
  constructor(private readonly i18n: I18nService) {}

  async sendWelcome(user: User) {
    const message = await this.i18n.translate('emails.welcome', {
      lang: user.locale,
      args: { name: user.name }
    });
    // Send email with translated message
  }
}

Language Switching

<!-- Language Selector Component -->
<div class="language-selector">
  <select onchange="changeLanguage(this.value)">
  </select>
</div>

<script>
function changeLanguage(locale) {
  // Option 1: Cookie-based
  document.cookie = `locale=${locale}; path=/`;
  window.location.reload();

  // Option 2: URL-based
  window.location.href = `/${locale}${window.location.pathname}`;
}
</script>

RTL Language Support

NodePress automatically handles Right-to-Left (RTL) languages like Arabic and Hebrew:

<!-- Auto RTL detection in layout -->
<html lang="" dir="ltr">

<!-- RTL-aware CSS -->
<style>
  [dir="rtl"] .sidebar {
    right: 0;
    left: auto;
  }
  [dir="rtl"] .content {
    margin-right: var(--sidebar-width);
    margin-left: 0;
  }
</style>

Content Translation

Manage translated versions of posts and pages:

// Create translated version of a post
POST /api/posts/:id/translations
{
  "locale": "es",
  "title": "Bienvenido a NodePress",
  "content": "...",
  "excerpt": "..."
}

// Get post in specific language
GET /api/posts/:id?locale=es

// List all translations for a post
GET /api/posts/:id/translations

Deployment

Deploy NodePress to production environments.

Docker Deployment

# Dockerfile
FROM node:20-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npx prisma generate
RUN npm run build

EXPOSE 3000
CMD ["npm", "run", "start:prod"]

Docker Compose

# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://postgres:password@db:5432/nodepress
      - REDIS_URL=redis://redis:6379
    depends_on:
      - db
      - redis

  db:
    image: postgres:15-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=nodepress
      - POSTGRES_PASSWORD=password

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data

volumes:
  postgres_data:
  redis_data:

Production Checklist

  • βœ… Set NODE_ENV=production
  • βœ… Use strong, unique JWT_SECRET
  • βœ… Configure SSL/TLS certificates
  • βœ… Set up database backups
  • βœ… Configure Redis for sessions and caching
  • βœ… Set up monitoring and logging
  • βœ… Configure CDN for static assets
  • βœ… Enable rate limiting
  • βœ… Set up health checks

Environment Variables

VariableRequiredDescription
DATABASE_URLYesPostgreSQL connection string
JWT_SECRETYesSecret for JWT signing
REDIS_URLNoRedis connection string
STRIPE_SECRET_KEYNoStripe API key
STRIPE_WEBHOOK_SECRETNoStripe webhook secret
OPENAI_API_KEYNoOpenAI API key for AI features
SMTP_HOSTNoEmail server host
SMTP_PORTNoEmail server port
SMTP_USERNoEmail username
SMTP_PASSNoEmail password

Configuration

Configure NodePress behavior through settings and environment variables.

Site Settings

Manage site settings through the admin panel or API:

// GET /api/settings
const settings = await settingsService.getAll();

// PATCH /api/settings
await settingsService.update({
  siteName: 'My Awesome Site',
  siteDescription: 'A NodePress powered website',
  siteUrl: 'https://example.com',
  timezone: 'America/New_York',
  dateFormat: 'MMMM D, YYYY',
  postsPerPage: 10,
  commentsEnabled: true,
  registrationEnabled: true,
});

Updating Site URL & Domain

When moving from localhost to a production domain, you need to update several configuration points.

Step 1: Update Environment Variables

Update your .env file with your production domain:

# .env - Change from localhost to your domain
SITE_URL=https://yourdomain.com
APP_URL=https://yourdomain.com

# If using separate admin subdomain
ADMIN_URL=https://admin.yourdomain.com

# Update CORS origins
CORS_ORIGINS=https://yourdomain.com,https://admin.yourdomain.com

# Update cookie domain for authentication
COOKIE_DOMAIN=.yourdomain.com

Step 2: Update Site Settings via Admin Panel

Navigate to Admin Panel β†’ Settings β†’ General and update:

  • Site URL - Your full domain (e.g., https://yourdomain.com)
  • Site Name - Your site's display name
  • Site Description - SEO meta description

Step 3: Update Navigation Menus

Update menu links from localhost URLs to your production domain:

// Via API: GET /api/menus to list all menus
const menus = await menusService.findAll();

// Update menu items with new URLs
// PATCH /api/menus/:id
await menusService.update(menuId, {
  items: [
    { label: 'Home', url: '/', order: 1 },
    { label: 'Blog', url: '/blog', order: 2 },
    { label: 'Shop', url: '/shop', order: 3 },
    { label: 'Courses', url: '/courses', order: 4 },
    { label: 'Contact', url: '/contact', order: 5 },
  ]
});
πŸ’‘ Use Relative URLs

Always use relative URLs (e.g., /blog instead of http://localhost:3000/blog) in your navigation menus. This way, links work correctly in both development and production without changes.

Step 4: Update via Admin Panel UI

The easiest way to update navigation:

  1. Go to Admin Panel β†’ Appearance β†’ Menus
  2. Select the menu you want to edit (e.g., "Primary Menu")
  3. Click on each menu item to edit
  4. Update any hardcoded localhost URLs to relative paths or your domain
  5. Click Save Menu

Step 5: Update Database URLs (Bulk Update)

If you have many hardcoded localhost URLs in your content, run this SQL to update them:

# PostgreSQL - Update all localhost references in posts
UPDATE posts
SET content = REPLACE(content, 'http://localhost:3000', 'https://yourdomain.com')
WHERE content LIKE '%localhost:3000%';

# Update pages
UPDATE pages
SET content = REPLACE(content, 'http://localhost:3000', 'https://yourdomain.com')
WHERE content LIKE '%localhost:3000%';

# Update menu items
UPDATE menu_items
SET url = REPLACE(url, 'http://localhost:3000', 'https://yourdomain.com')
WHERE url LIKE '%localhost:3000%';

# Update media URLs if stored as absolute
UPDATE media
SET url = REPLACE(url, 'http://localhost:3000', 'https://yourdomain.com')
WHERE url LIKE '%localhost:3000%';
⚠️ Backup First

Always backup your database before running bulk update queries. Use pg_dump to create a backup.

Step 6: SSL/HTTPS Configuration

For production, always use HTTPS:

# Force HTTPS in .env
FORCE_HTTPS=true

# If behind a reverse proxy (nginx, Cloudflare)
TRUST_PROXY=true

Step 7: Clear Caches

After updating URLs, clear all caches:

# Clear Redis cache
redis-cli FLUSHALL

# Or via API (admin only)
POST /api/cache/clear
Authorization: Bearer <admin-token>

Common URL Configuration Issues

IssueSolution
Mixed content warningsEnsure all URLs use HTTPS, including images and scripts
CORS errorsAdd your domain to CORS_ORIGINS in .env
Login not workingCheck COOKIE_DOMAIN matches your domain
Images not loadingUpdate media URLs or configure CDN/S3 storage
API calls failingUpdate frontend API base URL configuration

Email Configuration

// Email templates are in /templates/emails/
// Customize welcome, password reset, order confirmation, etc.

// Example: Send custom email
await emailService.send({
  to: 'user@example.com',
  subject: 'Welcome to Our Site',
  template: 'welcome',
  context: { userName: 'John', activationLink: '...' },
});

Caching

// Redis caching is automatic for:
// - Database queries
// - API responses
// - Session data
// - Rate limiting

// Manual cache control
await cacheService.set('key', value, 3600); // 1 hour TTL
const cached = await cacheService.get('key');
await cacheService.del('key');

Security Overview

NodePress is built with security as a core principle. This section covers security features and best practices.

Built-in Security Features

  • JWT Authentication - Secure token-based authentication with refresh tokens
  • Password Hashing - bcrypt with configurable salt rounds (default: 12)
  • CSRF Protection - Cross-site request forgery prevention
  • XSS Prevention - Content sanitization and CSP headers
  • SQL Injection Protection - Parameterized queries via Prisma ORM
  • Rate Limiting - Configurable rate limits per endpoint
  • CORS Configuration - Whitelist allowed origins
  • Helmet.js - Security headers middleware
  • Input Validation - class-validator for DTO validation

Security Headers

// Automatically configured security headers
{
  'X-Content-Type-Options': 'nosniff',
  'X-Frame-Options': 'DENY',
  'X-XSS-Protection': '1; mode=block',
  'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
  'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline'",
  'Referrer-Policy': 'strict-origin-when-cross-origin'
}

Rate Limiting Configuration

// config/security.ts
export default {
  rateLimit: {
    // Global rate limit
    global: {
      windowMs: 15 * 60 * 1000, // 15 minutes
      max: 100 // requests per window
    },
    // Auth endpoints (stricter)
    auth: {
      windowMs: 60 * 1000, // 1 minute
      max: 5 // 5 login attempts per minute
    },
    // API endpoints
    api: {
      windowMs: 60 * 1000,
      max: 60
    },
    // File uploads
    upload: {
      windowMs: 60 * 60 * 1000, // 1 hour
      max: 50 // 50 uploads per hour
    }
  }
};

Data Validation & Sanitization

// Example DTO with validation
import { IsEmail, IsString, MinLength, MaxLength, Matches } from 'class-validator';
import { Sanitize } from '@nodepress/validators';

export class CreateUserDto {
  @IsEmail()
  email: string;

  @IsString()
  @MinLength(8)
  @MaxLength(72)
  @Matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, {
    message: 'Password must contain uppercase, lowercase, and number'
  })
  password: string;

  @IsString()
  @MinLength(2)
  @MaxLength(50)
  @Sanitize() // Removes HTML tags and dangerous characters
  name: string;
}

Authentication

NodePress uses JWT-based authentication with support for multiple auth methods.

JWT Authentication Flow

// Login endpoint
POST /api/auth/login
{
  "email": "user@example.com",
  "password": "securePassword123"
}

// Response
{
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs...",
  "expiresIn": 3600,
  "user": {
    "id": "user_123",
    "email": "user@example.com",
    "role": "USER"
  }
}

// Using the token
GET /api/posts
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

// Refresh token
POST /api/auth/refresh
{
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

OAuth Providers

// Supported OAuth providers
// Google
GET /api/auth/google
GET /api/auth/google/callback

// GitHub
GET /api/auth/github
GET /api/auth/github/callback

// Facebook
GET /api/auth/facebook
GET /api/auth/facebook/callback

// Configuration in .env
GOOGLE_CLIENT_ID=your_client_id
GOOGLE_CLIENT_SECRET=your_client_secret
GITHUB_CLIENT_ID=your_client_id
GITHUB_CLIENT_SECRET=your_client_secret

Two-Factor Authentication (2FA)

// Enable 2FA for user
POST /api/auth/2fa/enable
// Returns QR code for authenticator app

// Verify 2FA setup
POST /api/auth/2fa/verify
{
  "code": "123456"
}

// Login with 2FA
POST /api/auth/login
{
  "email": "user@example.com",
  "password": "securePassword123",
  "twoFactorCode": "123456"
}

User Roles & Permissions

NodePress implements role-based access control (RBAC) with granular permissions.

Default Roles

RoleDescriptionKey Permissions
SUPER_ADMINFull system accessAll permissions including security
ADMINSite administratorManage users, content, shop, settings (no security)
INSTRUCTORCourse instructorManage courses, messages, groups, media
STUDENTDefault signup roleMessages, groups, media, view LMS courses

Permission System

// Available permissions
const PERMISSIONS = {
  // Content
  'content:create': 'Create new content',
  'content:read': 'View content',
  'content:update': 'Edit content',
  'content:delete': 'Delete content',
  'content:publish': 'Publish content',

  // Users
  'users:read': 'View users',
  'users:manage': 'Manage users',
  'users:delete': 'Delete users',

  // Courses
  'courses:create': 'Create courses',
  'courses:manage': 'Manage all courses',
  'courses:enroll': 'Enroll in courses',

  // System
  'settings:read': 'View settings',
  'settings:manage': 'Manage settings',
  'plugins:manage': 'Manage plugins',
  'themes:manage': 'Manage themes'
};

Using Permission Guards

// In controllers
import { Roles, Permissions, Public } from '@nodepress/decorators';

@Controller('posts')
export class PostsController {
  @Get()
  @Public() // No authentication required
  findAll() {}

  @Post()
  @Roles('ADMIN', 'EDITOR', 'AUTHOR')
  create(@Body() dto: CreatePostDto) {}

  @Delete(':id')
  @Permissions('content:delete')
  remove(@Param('id') id: string) {}
}

Creating Custom Roles

// Create custom role via API
POST /api/roles
{
  "name": "MODERATOR",
  "displayName": "Moderator",
  "permissions": [
    "content:read",
    "content:update",
    "users:read"
  ]
}

// Assign role to user
PUT /api/users/:id/role
{
  "role": "MODERATOR"
}

Backup & Restore

Protect your data with regular backups and know how to restore when needed.

Database Backup

# Full PostgreSQL backup
pg_dump -U postgres -h localhost -d nodepress -F c -f backup_$(date +%Y%m%d).dump

# SQL format backup
pg_dump -U postgres -h localhost -d nodepress > backup_$(date +%Y%m%d).sql

# Backup specific tables
pg_dump -U postgres -d nodepress -t users -t posts > partial_backup.sql

# Compressed backup
pg_dump -U postgres -d nodepress | gzip > backup_$(date +%Y%m%d).sql.gz

Database Restore

# Restore from custom format
pg_restore -U postgres -h localhost -d nodepress -c backup.dump

# Restore from SQL format
psql -U postgres -d nodepress < backup.sql

# Restore compressed backup
gunzip -c backup.sql.gz | psql -U postgres -d nodepress

# Create fresh database and restore
dropdb -U postgres nodepress
createdb -U postgres nodepress
pg_restore -U postgres -d nodepress backup.dump

Media Files Backup

# Backup uploads folder
tar -czvf uploads_backup_$(date +%Y%m%d).tar.gz uploads/

# Sync to S3 (if using AWS)
aws s3 sync uploads/ s3://your-bucket/backups/uploads/

# Restore from S3
aws s3 sync s3://your-bucket/backups/uploads/ uploads/

Full Site Backup Script

#!/bin/bash
# backup.sh - Full NodePress backup script

BACKUP_DIR="/backups/nodepress"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR

# Database backup
echo "Backing up database..."
pg_dump -U postgres -h localhost -d nodepress -F c -f "$BACKUP_DIR/db_$DATE.dump"

# Media files
echo "Backing up uploads..."
tar -czvf "$BACKUP_DIR/uploads_$DATE.tar.gz" uploads/

# Configuration files
echo "Backing up configuration..."
tar -czvf "$BACKUP_DIR/config_$DATE.tar.gz" .env prisma/

# Cleanup old backups (keep last 7 days)
find $BACKUP_DIR -type f -mtime +7 -delete

echo "Backup completed: $BACKUP_DIR"

Automated Backups

# Add to crontab for daily backups at 2 AM
crontab -e

# Add this line:
0 2 * * * /path/to/nodepress/backup.sh >> /var/log/nodepress-backup.log 2>&1

Windows Backup Script

@echo off
REM backup-windows.bat - Full NodePress backup for Windows

SET BACKUP_DIR=C:\Backups\NodePress
SET DATE=%date:~-4,4%%date:~-10,2%%date:~-7,2%

mkdir %BACKUP_DIR% 2>nul

REM Database backup
echo Backing up database...
pg_dump -U postgres -d nodepress -F c -f "%BACKUP_DIR%\db_%DATE%.dump"

REM Media files
echo Backing up uploads...
powershell Compress-Archive -Path uploads -DestinationPath "%BACKUP_DIR%\uploads_%DATE%.zip"

REM Configuration
echo Backing up configuration...
copy .env "%BACKUP_DIR%\.env_%DATE%"

echo Backup completed!

Full Restore Procedure

# 1. Stop the application
pm2 stop nodepress

# 2. Restore database
pg_restore -U postgres -h localhost -d nodepress -c backup.dump

# 3. Restore uploads
tar -xzvf uploads_backup.tar.gz

# 4. Restore configuration if needed
cp .env.backup .env

# 5. Reinstall dependencies (if needed)
npm install

# 6. Run migrations (if needed)
npx prisma migrate deploy

# 7. Restart application
pm2 start nodepress

Troubleshooting

Common issues and their solutions.

Common Issues

Database Connection Failed

# Check PostgreSQL is running
sudo systemctl status postgresql

# Verify connection string format
DATABASE_URL="postgresql://user:password@localhost:5432/nodepress?schema=public"

# Test connection
npx prisma db pull

Port Already in Use

# Find process using port 3000
# Linux/Mac
lsof -i :3000
kill -9 <PID>

# Windows
netstat -ano | findstr :3000
taskkill /PID <PID> /F

# Or change port in .env
PORT=3001

Prisma Migration Issues

# Reset database and reapply migrations
npx prisma migrate reset

# Generate Prisma client
npx prisma generate

# Push schema without migrations (dev only)
npx prisma db push

Redis Connection Failed

# Check Redis is running
redis-cli ping

# Start Redis
# Linux
sudo systemctl start redis

# macOS
brew services start redis

# Windows - using Docker
docker run -d -p 6379:6379 redis:7-alpine

Build Errors

# Clear caches and rebuild
rm -rf node_modules dist .next
npm cache clean --force
npm install
npm run build

Debug Mode

# Enable verbose logging
DEBUG=true
LOG_LEVEL=debug

# Enable Prisma query logging
DATABASE_DEBUG=true

# Run with Node.js inspector
node --inspect dist/main.js

Performance Optimization

# Database indexes - ensure these exist
npx prisma db push

# Enable Redis caching
REDIS_URL=redis://localhost:6379

# Enable gzip compression
ENABLE_COMPRESSION=true

# Enable CDN for static files
CDN_URL=https://cdn.your-site.com

# Production optimizations
NODE_ENV=production
npm run build
npm run start:prod

FAQ

General Questions

Is NodePress free to use?

Yes, NodePress is open-source and free to use under the MIT license. You can use it for personal and commercial projects.

What are the system requirements?

NodePress requires Node.js 20+, PostgreSQL 15+, and optionally Redis. For production, we recommend at least 2GB RAM and 2 CPU cores.

Can I migrate from WordPress?

Yes, we provide a migration tool that imports posts, pages, users, and media from WordPress. See the migration guide for details.

Technical Questions

How do I reset the admin password?

# Using the CLI
npx nodepress reset-password admin@example.com

# Or directly in the database
UPDATE users SET password = '$2b$10$...' WHERE email = 'admin@example.com';

How do I enable debug mode?

# Set in .env
DEBUG=true
LOG_LEVEL=debug

How do I backup my database?

# PostgreSQL backup
pg_dump -U postgres nodepress > backup.sql

# Restore
psql -U postgres nodepress < backup.sql

eCommerce Questions

How do I configure Stripe payments?

# Add to .env
STRIPE_SECRET_KEY=sk_live_...
STRIPE_PUBLISHABLE_KEY=pk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...

# Test with Stripe CLI
stripe listen --forward-to localhost:3000/api/webhooks/stripe

How do I manage product inventory?

Inventory is managed automatically when orders are placed. You can also manually adjust stock levels in the admin panel under Products β†’ Inventory, or via API:

PUT /api/products/:id/inventory
{ "stock": 100, "trackInventory": true }

LMS Questions

How do I create a course with quizzes?

Create a course, add lessons, then attach quizzes to specific lessons:

# 1. Create course
POST /api/courses
{ "title": "Web Development", "price": 99 }

# 2. Add lessons
POST /api/courses/:id/lessons
{ "title": "Introduction", "content": "...", "order": 1 }

# 3. Add quiz to lesson
POST /api/courses/:id/lessons/:lessonId/quiz
{
  "questions": [
    {
      "question": "What is HTML?",
      "type": "multiple_choice",
      "options": ["Markup Language", "Programming Language"],
      "correctAnswer": 0
    }
  ]
}

How do I generate certificates?

Certificates are automatically generated when students complete all lessons and pass required quizzes. Configure certificate templates in Admin β†’ LMS β†’ Certificate Templates.

Theme Questions

How do I create a child theme?

// themes/my-child-theme/theme.json
{
  "name": "My Child Theme",
  "parent": "default",
  "version": "1.0.0"
}

Child themes inherit all templates from the parent and only override specific files you create.

How do I use custom fonts?

/* In your theme's style.css */
@import url('https://fonts.googleapis.com/css2?family=Your+Font&display=swap');

:root {
  --font-heading: 'Your Font', sans-serif;
  --font-body: 'Your Font', sans-serif;
}

Performance Questions

How do I enable caching?

# Enable Redis caching
REDIS_URL=redis://localhost:6379

# Configure cache TTL in settings
Admin β†’ Settings β†’ Performance β†’ Cache Duration

How do I optimize images?

NodePress automatically optimizes uploaded images. Configure optimization settings in Admin β†’ Settings β†’ Media:

  • Max dimensions (default: 2000px)
  • Quality (default: 85%)
  • WebP conversion (recommended)
  • Lazy loading (enabled by default)