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
| Layer | Technologies |
|---|---|
| Backend | Node.js 20+, NestJS 11, TypeScript 5.9, Prisma 5 |
| Frontend | React 18, Vite 6, Tailwind CSS, Zustand |
| Database | PostgreSQL 15+, Redis (caching) |
| Real-time | Socket.IO, WebRTC |
| Payments | Stripe |
| AI | OpenAI 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
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
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:
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
| Role | Password | |
|---|---|---|
| Admin | admin@nodepress.dev | admin123 |
| Editor | editor@nodepress.dev | editor123 |
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
- Request - Client sends HTTP request or WebSocket message
- Guards - Authentication and authorization checks (JWT, Roles)
- Pipes - Request validation and transformation
- Controller - Route handling and request parsing
- Service - Business logic execution
- Repository - Database operations via Prisma
- 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 publicPENDING- Awaiting editorial reviewPUBLISHED- Live and visible to publicSCHEDULED- Will publish at specified date/timeARCHIVED- 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
| Type | Extensions | Max Size |
|---|---|---|
| Images | jpg, png, gif, webp, svg | 10 MB |
| Videos | mp4, webm, mov | 100 MB |
| Documents | pdf, doc, docx, xls, xlsx | 25 MB |
| Audio | mp3, wav, ogg | 50 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 requiredINTERMEDIATE- Some experience recommendedADVANCED- Significant experience requiredALL_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
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
| Resource | Endpoints | Description |
|---|---|---|
| Posts | /api/posts | CRUD for blog posts |
| Pages | /api/pages | CRUD for static pages |
| Media | /api/media | File upload and management |
| Users | /api/users | User management |
| Courses | /api/courses | LMS course management |
| Products | /api/products | eCommerce products |
| Orders | /api/orders | Order management |
| Settings | /api/settings | Site 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
| Hook | Trigger | Parameters |
|---|---|---|
onInit | Plugin initialization | config |
onPostCreate | New post created | post |
onPostUpdate | Post updated | post, changes |
onUserLogin | User logs in | user |
onUserRegister | New user registers | user |
onOrderComplete | Order completed | order |
onCourseEnroll | User enrolls in course | enrollment |
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 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
| Preset | Description | Best For |
|---|---|---|
default | Modern dark theme with green accents | General purpose |
light-minimal | Clean white theme with minimal styling | Professional blogs |
dark-mode | High contrast dark theme | Developer sites |
blog-focused | Typography-focused reading experience | Content-heavy sites |
ecommerce | Product-focused with conversion optimization | Online stores |
lms-professional | Clean interface for learning platforms | Course platforms |
corporate | Professional business appearance | Company websites |
creative | Bold colors and dynamic layouts | Portfolio 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
| Variable | Required | Description |
|---|---|---|
DATABASE_URL | Yes | PostgreSQL connection string |
JWT_SECRET | Yes | Secret for JWT signing |
REDIS_URL | No | Redis connection string |
STRIPE_SECRET_KEY | No | Stripe API key |
STRIPE_WEBHOOK_SECRET | No | Stripe webhook secret |
OPENAI_API_KEY | No | OpenAI API key for AI features |
SMTP_HOST | No | Email server host |
SMTP_PORT | No | Email server port |
SMTP_USER | No | Email username |
SMTP_PASS | No | Email 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 },
]
});
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:
- Go to Admin Panel β Appearance β Menus
- Select the menu you want to edit (e.g., "Primary Menu")
- Click on each menu item to edit
- Update any hardcoded localhost URLs to relative paths or your domain
- 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%';
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
| Issue | Solution |
|---|---|
| Mixed content warnings | Ensure all URLs use HTTPS, including images and scripts |
| CORS errors | Add your domain to CORS_ORIGINS in .env |
| Login not working | Check COOKIE_DOMAIN matches your domain |
| Images not loading | Update media URLs or configure CDN/S3 storage |
| API calls failing | Update 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
| Role | Description | Key Permissions |
|---|---|---|
SUPER_ADMIN | Full system access | All permissions including security |
ADMIN | Site administrator | Manage users, content, shop, settings (no security) |
INSTRUCTOR | Course instructor | Manage courses, messages, groups, media |
STUDENT | Default signup role | Messages, 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)