LightCMS Version History
All notable changes to LightCMS, organized by version. Source: CHANGELOG.md
v6.1.1 — Security Hardening
Comprehensive security review and fixes for bulk operations and MCP features.
Security
- Search/replace input validation: Pairs array capped at 100 per request. Search and replace text capped at 100K characters. Regex patterns capped at 1,000 characters to prevent ReDoS.
- Legacy API keys deprecated: API keys without an associated user are auto-migrated to the first admin user on first use. Keys must have user context for permission enforcement.
- Script policy at write time: Bulk create and bulk update sanitize content data fields when script policy is admin_only or none, as defense-in-depth alongside render-time enforcement.
- Bulk field operation validation: System fields (_id, published, template_id, full_path, etc.) blocked from modification via bulk field operations.
- Per-page locking: Search/replace, bulk update, and bulk field operations use per-page mutual exclusion to prevent race conditions.
- Error message sanitization: Bulk operation errors no longer expose MongoDB internals. Detailed errors logged server-side only.
- Enhanced audit logging: Bulk create includes sample of created content IDs in audit trail.
v6.1.0 — Bulk Operations, Analytics & Programmatic SEO
Major release focused on scale, observability, and bulk content management for programmatic SEO workflows.
Added
- Bulk Create Content: New bulk_create_content MCP tool creates up to 100 pages per call with parallel HTML generation. Supports upsert mode for retry-safe operations.
- Content Upsert: create_content and bulk_create_content accept upsert: true — updates existing pages instead of failing on duplicates.
- Multi-Pair Search & Replace: Pass a pairs array to apply all replacements in a single O(pages) pass instead of O(pairs × pages).
- Content List Pagination: list_content supports limit (1-500) and offset with {items, total, has_more} envelope.
- Burst Rate Limiting: 20 requests/second per token, complementing the 300/min sliding window.
- Site Analytics Dashboard: Hourly visitor chart with hover tooltips, uptime monitoring strip, top pages by views, top referrers (Non-bot/Bots/All tabs), browser donut chart.
- Per-Page Analytics: View counts, referrer breakdown, and edit links for individual pages at /cm/analytics/page.
- Referrer Drill-Down: Click any referrer domain to see which pages received traffic from that source.
- Analytics Tab on Content Editor: 7d and 30d view counts plus top referrers inline on every content edit page.
- Page View Tracking: Buffered writes (30s flush) for page views, referrers, and user agents with zero performance impact.
Changed
- Search/Replace returns counts: Responses include pages_scanned, pages_modified, total_replacements.
- Conditional Republish: SHA-256 content hashing skips unchanged pages during regeneration.
Fixed
- Analytics data not recording: site_stats collection blocked by Atlas 500-collection limit; moved to user_activity sentinel pattern.
- Analytics chart empty: ISO time format mismatch between Go and JavaScript fixed with epoch-ms keys.
- Buffer flush BSON error: Null byte separator in page_refs keys rejected by BSON; changed to || separator.
v6.0.1 — Security Hardening
Comprehensive security patch addressing 15 issues identified in a full security review of the v6.0.0 API surface.
Security
- CSRF key hardening — CSRF protection key is now derived via SHA-256 hash of the session secret instead of zero-padding, eliminating low-entropy padding.
- OAuth system key user context — The system API key used for OAuth-authenticated MCP sessions is now associated with an admin user. OAuth sessions previously bypassed all permission checks via a nil-user path; they now properly resolve to admin-level RBAC.
- 20+ read-only API endpoints now require login — All
/api/v1/read endpoints (content, templates, assets, snippets, redirects, folders, collections, theme, config, comments) now require viewer-level credentials. Public end-user endpoints (/api/search,/api/chat,/api/contact) are unchanged. - Self-approval blocked — Users can no longer approve their own content submissions.
- Sequential workflow order enforced — Only the approver assigned to the current step may advance a sequential workflow.
- Workflow approver validation — Approver user IDs are validated against real users when creating or updating approval workflows.
- Comment rate limiting & length cap —
POST /api/v1/content/{id}/commentsis rate-limited to 20 req/min per token; text capped at 10,000 characters. - Comment XSS fix —
user_display_nameanduser_emailare HTML-escaped before injection into dynamically created comment DOM nodes and mention dropdowns. - Bulk export gated —
APIExportContentnow requirescontent.editpermission. - Config endpoint auth & token redaction —
GET /api/v1/configrequiressettings.viewpermission; Cloudflare API token is redacted in the response. - Force-unlock RBAC —
APIForceUnlockContentnow usesrequirePermissioninstead of a hardcoded role string check. - Sidebar badge efficiency — Approval badge count now uses
CountPending()(single O(1) query) instead of loading the full pending result set on every admin page render.
v6.0.0 — Content Approvals & Discussions
Adds configurable approval workflows for content publishing, a new Contributor role, and inline threaded discussion threads on every content item.
Content Approvals
- Approval workflows — Configurable trigger-based workflows by contributor, folder path, template ID, or tag. Supports sequential mode (approvers in order) and concurrent mode (any N-of-M).
- Approvals dashboard at
/cm/approvals— Shows “My Queue” and “Other Pending.” Approve/reject with a required rejection comment. Badge count in sidebar nav. - Contributor role — New RBAC role between Viewer and Editor. Contributors can create content and upload assets (held pending), submit for approval, and post discussion comments — but cannot publish directly.
- Dashboard integration — “Requiring Approvals” section and “Recent Comments” section on the admin dashboard.
Content Discussions
- Discussion tab — Inline threaded comment section at the bottom of every content edit page. Live badge count on the tab.
- @mention autocomplete — Type
@in a comment to search and mention other users. - Rejection comments — When an approval request is rejected, the rejection comment is auto-posted to the content discussion thread.
- Tabbed bottom section — Discussion, Version History, and Forks are now organized into tabs on the content edit page.
New MCP Tools (14 added, 92 → 106 total)
list_comments,create_comment,delete_commentlist_approval_workflows,get_approval_workflow,create_approval_workflow,update_approval_workflow,delete_approval_workflowlist_approval_requests,get_approval_request,submit_for_approval,approve_request,reject_request,cancel_approval_request
Webhook Events
- Three new event types:
comment.created,content.pending_approval,asset.pending_review - Messages “Mark All as Read” button added to the contact messages list page
v5.0.0 — Import Pipeline
Adds a unified content import pipeline with support for RSS/Atom feeds, Markdown files, and CSV data — with a live streaming job log and full MCP tool coverage.
Import Types
- RSS/Atom Import — Configure recurring feed sources with schedule (hourly/daily/weekly), template mapping, folder targeting, and auto-publish. Full run history and per-job logs.
- Markdown Import — Upload single
.mdfiles or.ziparchives. YAML frontmatter controls title, slug, folder, template, tags, and scheduling. Supports Notion, Obsidian, Hugo/Jekyll migrations, and AI-generated content. - CSV Import — Upload CSV files and map columns to content fields. Specify the title column; all other columns become fields automatically.
- Deduplication — Imports match by
full_path— re-importing the same slug updates rather than duplicating. - Real-time import status — SSE-powered live log stream at
/cm/imports/{jobID}. - Agentic bulk content creation —
import_markdownis specifically designed for AI agents to generate and import large batches of content in a single call.
New MCP Tools (10 added)
list_import_sources,create_import_source,update_import_source,delete_import_source,trigger_import_sourceimport_markdown,import_csv,list_import_jobs,get_import_job,cancel_import_job
v4.5.0 — Webhooks, Scheduled Publishing & Content Locking
Adds HMAC-signed webhook events, scheduled publishing, collaborative content locking, Cloudflare cache integration, edge caching headers, and structured JSON logging.
- Webhooks — HMAC-SHA256 signed webhook events for content lifecycle. Configurable per-webhook with retry logic and delivery history. Admin UI at
/cm/webhooks. - Scheduled Publishing — Set a future
publish_attimestamp; background scheduler publishes automatically. - Content Locking — Advisory lock when editing (30-minute expiry). Warning banner if another user is editing. Force unlock for admins.
- Incremental Static Regeneration — Template changes regenerate content in batches of 20, preventing server overload.
- Edge Caching Headers — ETag, Cache-Control, Last-Modified, and Vary headers on all public pages. 304 Not Modified support.
- Cloudflare Integration — Configure Zone ID and API Token to automatically purge Cloudflare cache on publish/unpublish.
- Structured JSON Logging — All server logs emit structured JSON with timestamp, level, message, and context fields.
- Rate Limit Dashboard — New tab on the audit log page showing locked IPs, attempt counts, and a clear button.
- MCP Prompt Resources — Three new MCP resources:
lightcms://site/structure,lightcms://content/recent,lightcms://theme/config.
v4.2.0 — AI Chat Widget, Security Hardening & Performance
Adds an embeddable AI-powered chat widget backed by hybrid semantic search, 8 new fork MCP tools (64 → 72 total), major security hardening, and a comprehensive performance overhaul.
AI Chat Widget
- Embeddable widget — Add a floating AI chat bubble to any page with a single
<script>tag. Self-contained JS widget fetches its config from/api/chat/configand streams answers from/api/chat/query. - Two-phase pipeline — Each query runs hybrid semantic+fulltext search to retrieve relevant excerpts, then streams those through Claude Haiku for a conversational synthesized answer — reusing the same infrastructure as
end_user_search. - SSE streaming — Haiku token-by-token output forwarded live to the browser via Server-Sent Events. Falls back to plain JSON for non-SSE clients.
- AI-optional mode — Without an Anthropic API key, the widget still returns ranked search results with excerpts — a useful search-in-chat experience with no API cost.
- Admin configuration — New “Chat Widget” admin page controls title, welcome message, placeholder, color, position, max results, and editable system/user prompt templates with
{siteName},{excerpts},{question}placeholders. - Dedicated rate limiting — Separate per-IP (5/min) and global (30/min) limiters, independent from API and search limits. CORS restricted to configured
BASE_URL. - Source attribution — Every response includes a
sourcesSSE event listing the content pages whose excerpts were used, with titles and paths.
New Fork MCP Tools (8 added, 64 → 72 total)
list_forks— list all forks with status and page countcreate_fork— create a named fork workspaceget_fork— retrieve fork details including merge conflicts from last mergefork_page— add a page to a fork by content ID or pathremove_fork_page— remove a page from a forkmerge_fork— merge all fork changes into live content (admin only)archive_fork— archive a fork without mergingdelete_fork— permanently delete a fork and all its page copies
Security
- Prompt injection defense — Chat query text wrapped in
<user_question>XML delimiters before interpolation;</sequences escaped. Saved prompts validated to only allow known placeholders. - Configurable upload limit —
MaxUploadBytesin SiteConfig, settable via admin Configuration orupdate_site_config. Defaults to 1 MiB, enforced viahttp.MaxBytesReader. - API body size cap — All
/api/v1/endpoints enforce a 10 MiB request body limit, preventing memory exhaustion from oversized payloads. - Fly.io IP spoofing fix —
TrustFlyProxymode reads the unspoofableFly-Client-IPheader instead ofX-Forwarded-Forwhich can be forged by clients. - Session secret entropy — Production hard-fails on startup if
SESSION_SECRETis shorter than 32 characters. - Per-endpoint rate limiters — Dedicated limiters for regenerate (2/min), search-replace execute (10/min), bulk-update (5/min), export (5/min), reindex-embeddings (1/min).
- Rate limiter map pruning — Background goroutine prunes stale entries every 5 minutes, preventing unbounded memory growth.
Performance
- Admin template caching — Templates compiled once at startup via
sync.Once; previously re-parsed on every admin page request. - Content list pagination — Admin Content page loads 100 items per page with Previous/Next controls; previously loaded the full collection into memory, causing OOM crashes at scale.
- New content indexes —
{updated_at: -1}and compound{fork_id, deleted, updated_at}indexes fixSort exceeded memory limiterrors on Atlas free tier. - Search/replace streaming — All four search/replace handlers stream documents via MongoDB cursor instead of loading the full collection. Complete coverage, O(1) memory.
- Wikilink index cache — 60-second TTL cache with explicit invalidation on publish/title/path changes; eliminates O(n) full collection scans per page on bulk publish.
- Parallel hybrid search — Full-text and semantic search now run concurrently, halving latency when both sources are enabled.
- Parallel content regeneration —
RegenerateAllContentuses a 6-worker goroutine pool instead of sequential per-page processing.
v4.1.0 — Bug Fixes
Fixes redirect deletion not taking effect immediately due to browser caching.
Bug Fixes
- Redirect deletion now takes effect immediately — Redirects were served with
Cache-Control: max-age=3600, causing browsers to cache redirect responses for up to an hour. Deleting a redirect had no visible effect until the browser cache expired. Changed toCache-Control: no-storeso browsers never cache redirect responses.
v4.0.0 — Content Forks
Adds fork workspaces for safe page experimentation, bulk operation resilience improvements, and content search refinements.
Content Forks
- Fork workspaces — Create isolated staging workspaces where sets of page changes can be authored, previewed, and reviewed before going live. Only touched pages live in a fork (sparse model — unmodified pages fall through to live).
- Fork preview mode — Activate via a floating bar injected into the live site. A
lc_fork_previewcookie routes page requests through the fork, showing exactly how the site will look after merge. - Merge with conflict detection — Admins merge forks into live content. If a live page was edited after the fork was created, the conflict is recorded (fork wins). Newly created fork pages are inserted as live content on merge.
- “Fork to workspace” button — Available on any content edit page; opens the forks list with a one-click “Add to this fork” action.
- Fork exclusion from content list — Fork copies are invisible in the main admin content list and search results.
Performance & Resilience
- Coalescing background workers —
RegenerateIndexPagesandRebuildKeywordsnow use debounce channels: a bulk update of 25 items triggers one regeneration pass instead of 25 concurrent goroutines. Eliminates the goroutine explosion that caused server timeouts during large bulk operations.
Content Search
- Slug search mode — New search option alongside Title Only and Full Text. Searches slug and full_path fields, sorted alphabetically by slug.
- Homepage always first — The site index page (
/) is always pinned to position 0 in the content list and all search modes. - “/” query fix — Searching
/in Title or Full Text mode now correctly includes the homepage.
Dashboard & Bug Fixes
- Removed Collections KPI — The Collections stat card has been removed from the admin dashboard.
- Fork page unique index — Replaced the single-field
full_pathunique index with a compound{full_path, fork_id}unique index, allowing fork copies to share paths with their live counterparts without constraint violations.
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