LightCMS Version History
All notable changes to LightCMS, organized by version. Source: CHANGELOG.md
v3.3.0 — Bulk Operation Performance
Significantly improves performance of all bulk and batch operations, with particular gains at scale (hundreds of content items).
Performance Improvements
- Scope filters pushed to MongoDB —
bulk_field_operation,scoped_search_replace_execute, andexport_contentnow push template, category, folder, and content_ids filters down to MongoDB instead of loading all content and filtering in Go. For a 600-item site scoped to 100 pages, this eliminates ~500 unnecessary document transfers. - Goroutine worker pool (10 concurrent) — All four bulk/search-replace execute handlers now process items concurrently with a pool of 10 workers instead of sequentially. On a 100-item batch this yields up to 8–10× faster wall time.
- Batch content fetch in bulk_update_content — Per-item
GetContentcalls replaced with a single$inquery. 100-item bulk update: 100 DB round-trips → 1 for the initial fetch. - content_versions index on content_id — Previously missing; every
UpdateContentcall triggered a full collection scan oncontent_versionsfor the version count. Now O(log n) per item. - template_name index on content — Enables MongoDB-level template scope filters to use an index scan instead of a full collection scan.
New Service Methods
- ListContentScoped — MongoDB-native scoped list with support for template_name, category, folder_path, and content_ids filters.
- GetContentByIDs — Batch-fetch multiple content items in one
$inquery, returning a map keyed by ID.
MCP Tool Fixes
- list_content include_data / include_fields — Fixed a bug where enriched field data was fetched correctly by the API but silently dropped before being returned to MCP callers.
- auto_republish on search & replace execute — New boolean parameter on
search_replace_executeandscoped_search_replace_execute. When true, pages that were published before the change are automatically re-published after replacement. - bulk_field_operation dry_run has_value — Dry-run results now report whether each matching page currently has a non-empty value for the target field.
v3.2.0 — Healthz Endpoint & DAU/MAU Analytics
Adds a structured health check endpoint following the VibeCtl Health Check Protocol, plus user activity tracking for DAU/MAU metrics surfaced in the health endpoint and admin dashboard.
/healthz Endpoint
- GET /healthz — Unauthenticated structured JSON status:
status,name,version,uptime,dependencies(live MongoDB ping), andkpis(DAU, MAU, pages created today) - HTTP 503 on unhealthy — Returns 503 when status is
unhealthy; 200 otherwise - Existing /health unchanged — Plain-text
OKendpoint for Fly.io TCP probes is preserved
Analytics & KPIs
- AnalyticsService — New service backed by
user_activitycollection. Activity recorded on admin login and API key auth via fire-and-forget goroutine (no request latency impact) - Unique-per-day deduplication — In-process
sync.Mapdedup prevents repeat DB writes for the same user on the same calendar day. Storage: at most one document per user per day with 90-day TTL auto-expiry - DAU / MAU — Daily Active Users (distinct today) and Monthly Active Users (distinct last 30 days) via aggregation pipeline
- Dashboard stat cards — Three new cards added: Daily Active Users, Monthly Active Users, Pages Created Today
v3.1.0 — Bulk Operations, Wiki-Like Markup & Security Hardening
First-class bulk content operations (eliminating N×1 API call patterns), a full wiki-like markup system for content authoring, configurable script policy, and comprehensive security fixes.
Bulk Content Operations
- bulk_update_content — Update up to 100 content items in a single MCP/API call with merge semantics. Supports
clear_fields,dry_run, and per-item success/error details - bulk_field_operation — Apply a single operation (clear, set, prepend, append, wrap) to a field across all matching pages. Scoped by template, folder, category, or IDs. Supports dry_run
- export_content — Export content items with full field data as structured JSON. Designed for the export → transform → bulk_update pipeline
- list_content with field data — New
include_dataandinclude_fieldsparameters return full template field values in list results, eliminating per-item get_content calls - clear_fields on update_content — Explicitly zero out fields, removing ambiguity about merge semantics
- dry_run validation — Validate update payloads without committing changes on both update_content and bulk_update_content
Regex Search & Replace
- All four search/replace tools now accept
"regex": truefor Go RE2 regular expression matching - Use
$1,$2for capture group references in replace strings - Input validation: 500-char pattern limit, max 20 capture groups, 10× expansion guard
Wiki-Like Markup System
- Wikilinks — Page Title, display, /path syntax in any content field. Resolves to <a> at page generation time; broken links render as broken-link spans
- Snippet includes — include:snippet-name embeds a named snippet inline in any content field. Depth limit 3, cycle detection
- Table of contents — Add {{.lc_toc}} in a template layout to auto-generate a <nav class="lc-toc"> from page headings
- Heading IDs — All h1–h6 tags automatically get id= attributes for deep-linking
- Markdown field type — Set a template field type to
markdownfor GFM rendering (tables, strikethrough, task lists, autolinks) - Inline #tag detection — Mentioning #tagname in any content field automatically tags the page for lc:query index pages
- get_backlinks MCP tool — Returns all published pages that wikilink or link to a given path. Useful before renaming or deleting pages
- Version history attribution — "By" column in version history shows the email of the editor who made each change
Configurable Script Policy
- New site config
markdown_script_policycontrols who may use raw <script> tags in content "all"(default) — all users may use scripts; fully backward-compatible"admin_only"— editor-authored content sanitized via bluemonday; admin content passes through unchanged"none"— all content sanitized regardless of author role- Configurable via admin Settings page or update_site_config MCP tool
Security Fixes
- Export authorization: export_content now requires authentication
- Regex DoS protection: pattern length cap (500 chars), capture group limit (20), expansion guard
- Snippet recursion guard: depth limit 3 with cycle detection
- Version history permissions: get_content_versions and get_content_version now enforce PermContentView
- Folder path scope bug: scoped search/replace with /blog no longer matches /blog-old
- Bulk field op limit: 500-page cap prevents unbounded database writes per request
- Wikilink href safety: resolved links not starting with / render as broken-link spans
- TOC HTML escaping: heading IDs in TOC anchors are properly HTML-escaped
- Rate limiter cleanup: background goroutine prunes stale entries every 10 minutes
v3.0.0 — Dynamic Index Pages: Tags, Snippets & lc:query
The most significant content modelling capability added since v1.0 — a first-class system for building dynamic, automatically-updated index pages.
Content Tagging
- Tags field on all content items — Any content item can carry zero or more freeform string labels, set in the admin editor or via
{"tags": [...]}in the REST API - Full API support —
GET /api/v1/content?tag=TAGNAMEfilters by tag;PUT /api/v1/content/{id}accepts a tags array - Tags are exact-match strings with preserved capitalization, indexed in MongoDB for efficient filtering
Snippets
- New
snippetscollection — Named HTML template fragments with Go template variable support - Admin UI at
/cm/snippets— Create, edit, and delete snippets with a live editor - REST API — Full CRUD at
/api/v1/snippets - Available variables —
{{.Title}},{{.FullPath}},{{.Slug}},{{.MetaDescription}},{{.PublishedAt}} - Rendered through Go’s
html/template— safe from XSS by default
lc:query Directives
- Embed live content queries in template layouts — Using HTML comment syntax:
<!-- lc:query filter="tag:X" snippet="name" --> - Processed at page generation time, replaced with rendered output of all matching published content items
- Filter options —
tag,category,template,folder - Sort options —
title:asc,title:desc,created_at:asc,created_at:desc - Multiple directives per template — each is an independent query
Automatic Cascade Regeneration
- Auto-regeneration — When tagged content is published or updated, all index pages whose templates contain
lc:querydirectives are automatically regenerated - Also triggers when a template layout or snippet is updated
New MCP Tools (5 added, 54 → 59 total)
list_snippets— list all snippetsget_snippet— retrieve a snippet by ID or namecreate_snippet— create a new named HTML snippetupdate_snippet— update a snippet’s name or HTMLdelete_snippet— delete a snippet
Security Fix
- XSS in
lc:querydefault fallback — When no snippet attribute was specified, title and path were concatenated without escaping. Fixed to usetemplate.HTMLEscapeString()
v2.6.0 — MCP Tool Improvements
Bug Fixes
get_themereturned empty strings —ThemeSettingsstruct was missingjsonstruct tags; all theme fields now serialize correctly via the REST API and MCPsearch_replace_executeresponse missing search/replace fields — Bothsearch_replace_executeandscoped_search_replace_executenow echo back thesearchandreplacestrings used
New MCP Feature: Rendered HTML in get_content
get_contentnow accepts aninclude_renderedboolean parameter- When
true, the response includes arendered_htmlfield containing the fully rendered page HTML (template + theme header/footer applied) - Works for both published and draft content — lets agents inspect exactly what visitors see without publishing
v2.5.0 — Security Hardening
- SSRF prevention —
upload_asset_from_urlblocks all private/reserved IP ranges (loopback, RFC1918, link-local, CGNAT, IPv6 ULA) before making any network request - ReDoS prevention — Full-text search runs under a 5-second context deadline, preventing pathological queries from pinning CPU
- Permission checks — Search-replace preview and reindex-embeddings endpoints now require admin-only permissions
- API rate limiting — Per-bearer-token sliding-window limiter: 300 requests per token per minute across the entire
/api/v1/subrouter - Asset serve_path whitelist — Upload paths restricted to
/assets/,/images/,/docs/,/media/, or/files/ - Trusted proxy IP extraction — Rate limiter uses configured trusted proxy settings, preventing IP spoofing via forged headers
- Database indexes — Compound index on the content collection for improved query performance under load
- Session secret validation — Server warns if secret is too short, fails hard in production if under 16 characters
v2.1.0 — Agentic API Improvements
Theme Reliability
- Theme CSS on startup —
static/css/theme-vars.cssis now regenerated from the database every time the server starts, preventing blank styles after a deploy or container restart
New Content Endpoints
- Update by path — Update content by URL path instead of MongoDB ID, useful when you know the page URL but not its ID
- Batch publish — Publish multiple content items in one call; pass an ID list or
publish_all_drafts: true - Content preview — Render a content item’s HTML without publishing; accepts optional title/data overrides to preview unsaved edits; returns
rendered_htmlandwarnings(missing required fields, unclosed tags, unresolved placeholders) - Rendered HTML in get_content —
include_rendered=truereturns the fully rendered page HTML alongside regular content data
New Asset Endpoints
- Upload from URL — Fetch a remote URL and store it as a LightCMS asset (HTTP/HTTPS only, 50 MB cap, MIME validation)
Theme Version Pinning
- Pin/unpin theme versions — Lock a theme version to protect it from auto-pruning; pinned versions are marked with
locked: truein version history
Scoped Search & Replace
- Targeted replacements — Run search-and-replace filtered by
content_ids,folder_path,template_name, and/orcategory— safer than a full site-wide replacement
New MCP Tools (13 added, 41 → 54 total)
update_content_by_path— update by URL path; merges data fieldspublish_multiple— batch publish by ID list or all drafts at oncepreview_content— render HTML without saving; supports field overridesscoped_search_replace_preview/scoped_search_replace_execute— folder/template/category-scoped search & replaceupload_asset_from_url— fetch remote file and store as assetpin_theme_version/unpin_theme_version— protect important theme milestones- Improved descriptions on existing tools with workflow guidance and examples
v2.0.1 — Configurable Search Ranking
- Database-stored ranking config — All search ranking parameters now stored in the database and editable from the admin panel at Tools → End User Search → Search Ranking
- Configurable fields — Title match boost, nav page boost, boosted template name substrings, template boost score, demoted path prefixes, demotion penalty score
- Safety clamping — Values clamped to −1.0…1.0 to prevent accidental misconfiguration
- Instant effect — Changes take effect immediately; in-memory cache invalidated on save
- Search API documentation — Expanded typeahead suggest API docs, full parameter tables, response schemas, and JavaScript examples in the admin Integration Guide and README
v2.0.0 — Multi-User RBAC & Smart Search
Multi-User Access Control
- Role-Based Access Control (RBAC) — Three roles (admin, editor, viewer) with granular permissions enforced on every admin UI page and REST API endpoint
- User Management — Admin-only panel at
/cm/usersfor creating users, assigning roles, disabling accounts, and resetting passwords - Email-based login — Authentication migrated from a single shared password to per-user email + password credentials
- Force password change — Temporary passwords prompt a mandatory change on first login
- Automatic migration — On first startup with an empty users collection, the existing admin password hash is carried over into a new admin user account
Audit Logging
- Persistent audit trail — All mutations logged with acting user, action, resource, and timestamp
- 365-day retention — Audit logs auto-expire via MongoDB TTL index
- Filterable UI at
/cm/audit— Filter by action type, resource, and date range - Async logging — LogAsync fire-and-forget pattern to avoid blocking request handlers
User-Scoped API Keys
- API keys now belong to a specific user and inherit that user’s permissions
- Admins can view and manage all keys; non-admins can only manage their own
- Keys created before v2.0 remain functional as system-level keys with full access
Smart Search Ranking
- Structural boost — Nav-linked pages (parsed from header HTML, cached 5 min) surface above other results
- Template-based ranking — Concept pages rank above generic body-only content
- Video deprioritisation — Pages under
/videos/rank below all other content types - Typeahead suggestions — Same structural ranking applied to prefix-match suggestions
- Ranking priority: title+nav > title-only > nav-linked > concept pages > body-only > video transcripts
Bug Fixes
- Fixed
/cm/auditpage crash caused by subtract/add template functions receiving mismatched integer types - Made arithmetic template functions type-flexible via
interface{}dispatch
v1.4.0 — End-User Search API
- Full-text search (
/api/search?q=...) — Regex-based exact matching across all published content - Semantic vector search — Voyage AI embeddings stored in MongoDB Atlas;
$vectorSearchpipeline for similarity queries - Hybrid mode — Reciprocal rank fusion (RRF, k=60) merges full-text and semantic results into a single ranked list
- Title boosting — Results where the query appears in the page title float above body-only matches
- Graceful degradation — Works without a Voyage API key (full-text only); automatically enables semantic search when configured
- Rate limiting — Per-IP (10 req/min) and global (100 req/min) limits with DDoS protection
- Embedding pipeline — Background batch generation with progress tracking in the admin panel
- Typeahead suggestions —
/api/search/suggestendpoint for prefix-matching page titles and extracted keywords - WARP proxy for Voyage API calls on Fly.io to avoid IP-based rate limiting
- Upgraded embedding model from voyage-3-lite to voyage-4-lite
- Fixed SVG assets not displaying when uploaded with
/assetspath prefix - Expanded upload allowlist to include CSS, JS, JSON, and other text-based web assets
v1.2.0 — OAuth 2.1 & HTTP MCP Transport
- OAuth 2.1 authorization server — Full authorization code flow with PKCE (S256), dynamic client registration (RFC 7591), token rotation, and revocation (RFC 7009)
- Remote MCP clients — HTTP streamable MCP endpoint at
/mcp— connects Cowork, Claude Desktop, and any MCP-compatible app without embedding credentials - Discovery endpoints —
/.well-known/oauth-authorization-server(RFC 8414) and/.well-known/oauth-protected-resource(RFC 9728) for automatic client setup - Dynamic MCP server card —
/.well-known/mcp/server-card.jsonwith full tool schemas, served live from the running server - Smithery registry support — smithery.yaml and packaging config for registry publication
- Test suite: 82% → 86% coverage with CI via GitHub Actions and Codecov integration
- Loading state feedback on OAuth authorize buttons
v1.1.0 — REST API, CLI Tool & API Keys
- REST API at
/api/v1/— Full JSON API for all content management operations (content, templates, assets, theme, config, redirects, folders, collections) - API key authentication —
lc_-prefixed keys stored as SHA-256 hashes; created and managed in the admin panel - CLI tool (
cmd/cli) — Command-line interface wrapping the REST API for scripting and CI/CD workflows - MCP refactor — MCP tools now use the REST API client rather than direct DB access
- Partial update support on all PUT endpoints (send only changed fields)
v1.0.0 — Initial Release
- Content management — Create, edit, publish, and delete content using customizable templates
- Template system — Define reusable page structures with typed fields; HTML layout with
{{.field_name}}placeholders - Static page generation — Published content rendered to
content/generated/for fast, zero-runtime serving - Content versioning — Automatic version snapshots on every update; revert to any prior version
- Soft delete — Deleted content recoverable from the admin panel
- Content collections — Auto-generated paginated listing pages filtered by category
- MCP server (stdio) — 43 tools for managing the entire site through AI agents
- Theme customization — Colors, fonts, border radius, custom CSS; header/footer HTML injection with versioning
- Asset management — Upload, organize, and serve images, documents, and other files
- URL redirects — 301/302 rules managed from the admin panel
- Rich text editor — TinyMCE integration for visual editing
- Search & replace — Site-wide text replacement with preview before execution
- Security — CSRF protection, bcrypt passwords (cost 12), session cookies (SameSite=Strict), file upload validation, login rate limiting
- Fly.io deployment — fly.toml and Dockerfile for one-command production deploy
MIT License · Copyright 2026 Metavert LLC