Production-grade headless CMS built with Strapi v5 + Next.js 14 + PostgreSQL + Redis + Docker
Feature
Details
Strapi v5 Backend
Headless CMS with REST + GraphQL APIs
Next.js 14 Frontend
App Router, SSR, ISR, static generation
PostgreSQL
Primary database with connection pooling
Redis Caching
API response caching, rate limiting store
JWT Auth
Register, login, forgot password, email verify
RBAC
Admin, Moderator, Author, Public roles
Blog CMS
Draft/publish, slugs, SEO meta, OpenGraph
Comment System
Nested comments, moderation, spam detection
Newsletter
Subscribe, confirm, unsubscribe flows
AI Generation
OpenAI integration for content generation
Trending Engine
Score-based trending with decay algorithm
Search API
Full-text search across blogs
Related Posts
Category + tag based recommendations
Image Upload
Cloudinary (prod) / local (dev)
Docker
Dev + prod compose files, multi-stage builds
CI/CD
GitHub Actions β lint, test, build, deploy
Nginx
Reverse proxy, SSL, gzip, rate limiting
ai-blog-cms/
βββ backend/ # Strapi v5
β βββ config/
β β βββ database.js # PostgreSQL config
β β βββ server.js # Host/port/admin
β β βββ middlewares.js # Middleware stack
β β βββ plugins.js # GraphQL, email, upload
β βββ src/
β βββ api/
β β βββ blog/ # Blog CRUD + custom endpoints
β β βββ category/ # Categories
β β βββ tag/ # Tags
β β βββ comment/ # Comments + moderation
β β βββ newsletter/ # Newsletter subscription
β βββ middlewares/
β β βββ rate-limit.js # Redis-backed rate limiting
β β βββ redis-cache.js # Response caching
β β βββ audit-log.js # Write operation logging
β βββ policies/
β β βββ is-owner.js # Resource ownership check
β β βββ is-admin.js # Role-based access
β β βββ is-authenticated.js
β βββ extensions/
β β βββ users-permissions/ # Custom auth + lifecycle hooks
β βββ index.js # Cron jobs, health endpoint
β
βββ frontend/ # Next.js 14
β βββ src/
β βββ app/
β β βββ page.tsx # Home (ISR)
β β βββ blog/page.tsx # Blog list
β β βββ blog/[slug]/page.tsx # Blog detail (SSG + ISR)
β β βββ (auth)/login/page.tsx
β β βββ (auth)/register/page.tsx
β β βββ (dashboard)/dashboard/page.tsx
β βββ components/
β β βββ blog/ # BlogCard, BlogList, RelatedPosts
β β βββ comment/ # CommentSection (nested)
β β βββ layout/ # Header, Footer
β βββ hooks/
β β βββ useAuth.ts # Authentication hook
β β βββ useBlogs.ts # Blog data hooks
β βββ lib/
β β βββ strapi.ts # Axios API client
β β βββ utils.ts # Utilities
β βββ store/
β β βββ auth.store.ts # Zustand auth store
β βββ types/index.ts # TypeScript interfaces
β
βββ nginx/nginx.conf # Reverse proxy config
βββ docker-compose.yml # Development stack
βββ docker-compose.prod.yml # Production stack
βββ .github/workflows/ci-cd.yml # GitHub Actions pipeline
β‘ Quick Start (Docker β recommended)
Docker Desktop 4.x+
Docker Compose v2+
# 1. Clone the repo
git clone https://github.com/yourusername/ai-blog-cms.git
cd ai-blog-cms
# 2. Copy environment files
cp backend/.env.example backend/.env
cp frontend/.env.example frontend/.env.local
# 3. Edit backend/.env β set your secrets
nano backend/.env
# 4. Start all services
docker compose up -d
# 5. Open the apps
# Strapi Admin: http://localhost:1337/admin
# Next.js: http://localhost:3000
# PgAdmin: http://localhost:5050
# GraphQL: http://localhost:1337/graphql
π Local Development (without Docker)
cd backend
npm install
cp .env.example .env
# Edit .env with your PostgreSQL/Redis credentials
npm run develop
cd frontend
npm install
cp .env.example .env.local
# Edit .env.local with NEXT_PUBLIC_STRAPI_URL
npm run dev
π Environment Variables
Variable
Description
Example
DATABASE_CLIENT
DB driver
postgres
DATABASE_HOST
DB host
localhost
DATABASE_NAME
DB name
aiblog
DATABASE_USERNAME
DB user
aiblog
DATABASE_PASSWORD
DB password
secret
REDIS_HOST
Redis host
localhost
REDIS_PASSWORD
Redis password
secret
JWT_SECRET
32+ char secret
your_secret
OPENAI_API_KEY
OpenAI key
sk-...
CLOUDINARY_NAME
Cloudinary cloud
mycloud
SMTP_HOST
Email host
smtp.gmail.com
Frontend (frontend/.env.local)
Variable
Description
NEXT_PUBLIC_STRAPI_URL
Strapi base URL
NEXT_PUBLIC_STRAPI_API_TOKEN
Strapi API token
NEXT_PUBLIC_SITE_URL
Your frontend URL
REVALIDATE_SECRET
ISR revalidation token
Method
Endpoint
Description
GET
/api/blogs
List blogs (paginated, filterable)
GET
/api/blogs/slug/:slug
Get blog by slug
GET
/api/blogs/trending
Get trending blogs
GET
/api/blogs/search?q=...
Full-text search
GET
/api/blogs/:id/related
Get related posts
POST
/api/blogs
Create blog (auth required)
PUT
/api/blogs/:id
Update blog (owner only)
DELETE
/api/blogs/:id
Delete blog (owner only)
POST
/api/blogs/generate
AI-generate content
Method
Endpoint
Description
GET
/api/categories
List all categories with blog count
GET
/api/categories/slug/:slug
Category + paginated blogs
Comments
Method
Endpoint
Description
GET
/api/comments/blog/:blogId
Get approved comments
POST
/api/comments
Post comment (auth required)
POST
/api/comments/:id/like
Like a comment
PATCH
/api/comments/:id/moderate
Moderate (admin only)
Method
Endpoint
Description
POST
/api/auth/local
Login
POST
/api/auth/local/register
Register
POST
/api/auth/forgot-password
Forgot password
POST
/api/auth/reset-password
Reset password
GET
/api/users/me
Get current user
Method
Endpoint
Description
POST
/api/newsletters/subscribe
Subscribe
GET
/api/newsletters/confirm?token=
Confirm email
GET
/api/newsletters/unsubscribe?email=
Unsubscribe
http://localhost:1337/graphql
Sample query:
query GetBlogs ($page : Int , $pageSize : Int ) {
blogs (
pagination : { page : $page , pageSize : $pageSize }
sort : " publishedDate:desc"
filters : { publishedAt : { notNull : true } }
) {
data {
id
attributes {
title
slug
excerpt
publishedDate
viewCount
featuredImage { data { attributes { url } } }
author { data { attributes { username firstName lastName } } }
category { data { attributes { name slug } } }
}
}
meta { pagination { total pageCount } }
}
}
π Production Deployment
See DEPLOYMENT.md for the full production guide.
Quick summary:
# 1. Set production secrets in .env files
# 2. Build and start production stack
docker compose -f docker-compose.prod.yml up -d
# 3. Set up SSL (Let's Encrypt)
certbot certonly --webroot -w /var/www/certbot -d yourdomain.com
βββββββββββββββββββ
β Nginx (443) β SSL termination, rate limiting
ββββββββββ¬βββββββββ
ββββββββββββ΄βββββββββββ
βββββββββΌβββββββ βββββββββΌββββββββ
β Next.js:3000β β Strapi:1337 β
β (SSR/ISR) β β (REST/GraphQL)β
ββββββββββββββββ βββββββββ¬ββββββββ
βββββββββ΄ββββββββ
βββββββΌββββββ βββββββΌββββββ
βPostgreSQL β β Redis β
β (primary) β β (cache) β
βββββββββββββ βββββββββββββ
Role
Permissions
Public
Read published blogs, categories, tags, comments
Authenticated
+ Create comments, like, subscribe
Author
+ Create/edit/delete own blogs
Moderator
+ Moderate comments, manage categories/tags
Administrator
Full access to everything + admin panel
π Performance Features
ISR (Incremental Static Regeneration) β blog pages cached and revalidated every 5 mins
Redis caching β API responses cached (5min default, configurable per route)
CDN-friendly β all static assets have immutable cache headers
Image optimisation β Next.js <Image> with AVIF/WebP, Cloudinary CDN
Connection pooling β PostgreSQL pool (min 2, max 10)
Query optimisation β selective populate on every Strapi query
Gzip compression β enabled in both Nginx and Next.js
π€ AI Content Generation
# POST /api/blogs/generate
curl -X POST http://localhost:1337/api/blogs/generate \
-H " Authorization: Bearer YOUR_JWT" \
-H " Content-Type: application/json" \
-d ' {
"topic": "Strapi v5 Production Setup Guide",
"tone": "professional",
"length": "long",
"keywords": ["strapi tutorial", "headless cms", "nodejs"]
}'
Returns: { title, excerpt, content (markdown), tags, seoMeta }
MIT Β© 2024 AI Blog CMS β Open source and free to use.
Strapi tutorial Β· Strapi CMS example Β· Strapi production setup Β· Strapi with Next.js Β· Strapi Docker setup Β· Strapi authentication Β· Strapi PostgreSQL guide Β· Build CMS with Strapi Β· Strapi REST API example Β· Strapi GraphQL tutorial