Skip to content

CMS Overview ​

The CMS (cms-myeasyguide) is a standalone Next.js 16 application for managing blog posts, travel guides, authors, categories, and AI-powered content generation. It operates independently from the main Express API with its own PostgreSQL database and admin UI.

Purpose ​

The CMS was extracted from the main API to provide:

  • Dedicated content management — Rich text editing, post scheduling, SEO management
  • AI content generation — Batch blog post generation via Claude API
  • Independent deployments — Content updates don't require API deployments
  • Focused admin experience — Tailored for content editors, not commerce operations

Key Features ​

FeatureDescription
Post CRUDCreate, edit, publish, schedule, trash blog posts and travel guides
Rich Text EditorLexical-based editor with HTML output
Categories & SubcategoriesHierarchical content organization
Author ManagementAuthor profiles, authentication, dashboard
AI GenerationClaude API batch generation for bulk blog creation
City & Country ManagementGeographic tagging for content
Tag ManagementContent tagging system
Image UploadFile upload for post cover images
Scheduled Publishingnode-cron checks every minute for scheduled posts
OpenAPI SpecAuto-generated API documentation
SEO ToolsMeta titles/descriptions, canonical URLs, JSON-LD schema

Admin UI ​

The CMS admin is at /admin and includes:

RoutePurpose
/admin/postsPost list with status filtering
/admin/posts/editCreate/edit post
/admin/posts/edit/{slug}Edit specific post
/admin/authorsAuthor CRUD
/admin/post-categoriesCategory management
/admin/subcategoriesSubcategory management
/admin/manage-citiesCity management
/admin/manage-countriesCountry management
/admin/generateAI blog generation

CMS API Routes ​

The CMS exposes a RESTful API for the admin UI and for the public frontend:

RoutePurpose
GET /api/posts/{slug}Public: single post with related content
GET /api/posts/publishedPublic: published posts (paginated, searchable)
GET /api/posts/category/{slug}Public: posts by category (blog/travel-guide)
GET /api/posts/author/{id}Public: posts by author
GET /api/posts/resolve/{slug}Public: resolve slug to canonical path
GET /api/postsAuth: all posts (admin)
POST /api/postsAuth: create post
PATCH /api/posts/{slug}Auth: update post
DELETE /api/posts/{slug}Auth: trash/delete post
GET /api/posts/restore/{id}Auth: restore from trash
GET /api/authorsPublic: list authors
POST /api/authorsAuth: create author
PATCH /api/authors/{id}Auth: update author
DELETE /api/authors/{id}Auth: delete author
GET /api/post-categoriesPublic: list categories
POST /api/post-categoriesAuth: create category
PATCH /api/post-categories/{id}Auth: update category
DELETE /api/post-categories/{id}Auth: delete category
GET /api/citiesPublic: list cities
POST /api/citiesAuth: create city
GET /api/countriesPublic: list countries
GET /api/tagsPublic: list tags
POST /api/uploadAuth: upload file
POST /api/auth/loginPublic: author login

Authentication ​

The CMS uses JWT-based auth with the jose library:

  • Authors log in via POST /api/auth/login
  • JWT stored in httpOnly cookie
  • Protected routes use requireAuth() from lib/auth.ts
  • Session retrieval via getSession() from cookies

Scheduled Publishing ​

The CMS runs a node-cron job (initialized in instrumentation.ts) that runs every minute:

  1. Queries for posts where status = "scheduled" and scheduledAt <= now
  2. Updates status to "published" and sets publishedAt
  3. Generates canonical URL

Post Status Lifecycle ​

     ┌─────────┐
     │  DRAFT  │
     └────┬────┘
          │
          ▼
     ┌───────────┐
     │ SCHEDULED │──(cron)──▶ ┌───────────┐
     └───────────┘            │ PUBLISHED │
                              └─────┬─────┘
          ┌─────────┐               │
          │  TRASH  │◀──────────────┘
          └─────────┘

Separated from API ​

The CMS was originally part of the Express API. The Editorial Migration page documents the full extraction process, including which API files were removed and why.

Built with VitePress