LightCMS Version History

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 capPOST /api/v1/content/{id}/comments is rate-limited to 20 req/min per token; text capped at 10,000 characters.
  • Comment XSS fixuser_display_name and user_email are HTML-escaped before injection into dynamically created comment DOM nodes and mention dropdowns.
  • Bulk export gatedAPIExportContent now requires content.edit permission.
  • Config endpoint auth & token redactionGET /api/v1/config requires settings.view permission; Cloudflare API token is redacted in the response.
  • Force-unlock RBACAPIForceUnlockContent now uses requirePermission instead 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_comment
  • list_approval_workflows, get_approval_workflow, create_approval_workflow, update_approval_workflow, delete_approval_workflow
  • list_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 .md files or .zip archives. 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 creationimport_markdown is 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_source
  • import_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_at timestamp; 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/config and 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 sources SSE 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 count
  • create_fork — create a named fork workspace
  • get_fork — retrieve fork details including merge conflicts from last merge
  • fork_page — add a page to a fork by content ID or path
  • remove_fork_page — remove a page from a fork
  • merge_fork — merge all fork changes into live content (admin only)
  • archive_fork — archive a fork without merging
  • delete_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 limitMaxUploadBytes in SiteConfig, settable via admin Configuration or update_site_config. Defaults to 1 MiB, enforced via http.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 fixTrustFlyProxy mode reads the unspoofable Fly-Client-IP header instead of X-Forwarded-For which can be forged by clients.
  • Session secret entropy — Production hard-fails on startup if SESSION_SECRET is 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 fix Sort exceeded memory limit errors 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 regenerationRegenerateAllContent uses 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 to Cache-Control: no-store so 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_preview cookie 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 workersRegenerateIndexPages and RebuildKeywords now 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.
  • 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_path unique 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 MongoDBbulk_field_operation, scoped_search_replace_execute, and export_content now 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 GetContent calls replaced with a single $in query. 100-item bulk update: 100 DB round-trips → 1 for the initial fetch.
  • content_versions index on content_id — Previously missing; every UpdateContent call triggered a full collection scan on content_versions for 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 $in query, 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_execute and scoped_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), and kpis (DAU, MAU, pages created today)
  • HTTP 503 on unhealthy — Returns 503 when status is unhealthy; 200 otherwise
  • Existing /health unchanged — Plain-text OK endpoint for Fly.io TCP probes is preserved

Analytics & KPIs

  • AnalyticsService — New service backed by user_activity collection. 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.Map dedup 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_data and include_fields parameters 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": true for Go RE2 regular expression matching
  • Use $1, $2 for capture group references in replace strings
  • Input validation: 500-char pattern limit, max 20 capture groups, 10× expansion guard

Wiki-Like Markup System

  • WikilinksPage Title, display, /path syntax in any content field. Resolves to <a> at page generation time; broken links render as broken-link spans
  • Snippet includesinclude: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 markdown for 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_policy controls 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 supportGET /api/v1/content?tag=TAGNAME filters 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 snippets collection — 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 optionstag, category, template, folder
  • Sort optionstitle: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:query directives 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 snippets
  • get_snippet — retrieve a snippet by ID or name
  • create_snippet — create a new named HTML snippet
  • update_snippet — update a snippet’s name or HTML
  • delete_snippet — delete a snippet

Security Fix

  • XSS in lc:query default fallback — When no snippet attribute was specified, title and path were concatenated without escaping. Fixed to use template.HTMLEscapeString()

v2.6.0 — MCP Tool Improvements

Bug Fixes

  • get_theme returned empty stringsThemeSettings struct was missing json struct tags; all theme fields now serialize correctly via the REST API and MCP
  • search_replace_execute response missing search/replace fields — Both search_replace_execute and scoped_search_replace_execute now echo back the search and replace strings used

New MCP Feature: Rendered HTML in get_content

  • get_content now accepts an include_rendered boolean parameter
  • When true, the response includes a rendered_html field 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 preventionupload_asset_from_url blocks 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 startupstatic/css/theme-vars.css is 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_html and warnings (missing required fields, unclosed tags, unresolved placeholders)
  • Rendered HTML in get_contentinclude_rendered=true returns 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: true in version history

Scoped Search & Replace

  • Targeted replacements — Run search-and-replace filtered by content_ids, folder_path, template_name, and/or category — 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 fields
  • publish_multiple — batch publish by ID list or all drafts at once
  • preview_content — render HTML without saving; supports field overrides
  • scoped_search_replace_preview / scoped_search_replace_execute — folder/template/category-scoped search & replace
  • upload_asset_from_url — fetch remote file and store as asset
  • pin_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

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/users for 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/audit page 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; $vectorSearch pipeline 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/suggest endpoint 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 /assets path 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.json with 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 authenticationlc_-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