- Remove auto-discovery entirely (~450 lines) * Delete internal/content/discoverer.go * Simplify enhancer to single-phase processing * Remove duplicate container expansion logic - Consolidate repository implementations * Move internal/content/client.go → internal/db/http_client.go * Group all repository implementations in db/ package - Add file utilities to engine following Go stdlib patterns * Add engine.ProcessFile() and ProcessDirectory() methods * Engine now handles both content processing AND file operations - Move site management to dedicated package * Move internal/content/site_manager.go → internal/sites/manager.go * Clear separation of site lifecycle from content processing - Preserve container expansion (syntactic sugar) * .insertr on containers still auto-applies to viable children * Container detection logic consolidated in engine/utils.go Result: Clean architecture with single source of truth for .insertr processing
Insertr
The Tailwind of CMS - Zero-configuration content editing for any static site
Insertr adds editing capabilities to any HTML website by simply adding class="insertr" to elements. No complex setup, no architectural changes, no framework dependencies. Just mark what should be editable and get a production-ready CMS.
✨ Zero Configuration Philosophy
Just Add a Class
<!-- Individual elements -->
<h1 class="insertr">Main Title</h1>
<p class="insertr">Description text</p>
<a href="/contact" class="insertr">Contact Us</a>
<!-- Container expansion -->
<section class="insertr">
<h1>Hero Title</h1>
<p>Hero description</p>
<button>Call to Action</button>
</section>
That's it! No manual IDs, no configuration files, no schema definitions.
Container Expansion
Containers with class="insertr" automatically make their viable children editable:
- Viable children: Elements containing only text (h1-h6, p, span, a, button)
- Automatic detection: Skip complex nested elements
- Semantic convenience: One class enables section-wide editing
🎯 Three User Experiences
1. Regular Visitors (99% of traffic)
- Pure static HTML performance
- Zero editor assets loaded
- No runtime overhead
2. Content Editors (Authenticated users)
- Style-aware editing interface loads on demand
- Click-to-edit any marked element
- Rich text editor with style preservation and formatting toolbar
- Link editor with popup configuration for complex elements
- Changes saved to database with version history
3. Developers (You)
- Add
class="insertr"to any element - Use HTML
idattributes for complex cases - Never see or manage generated content IDs
- Works with any static site generator
🔐 Authentication & Security
Insertr provides enterprise-grade authentication with multiple provider support for secure content editing.
Authentication Providers
Mock Authentication (Development)
auth:
provider: "mock"
- Zero setup - Works immediately for development
- Automatic login - No credentials needed
- Perfect for testing - Focus on content editing workflow
Authentik OIDC (Production)
auth:
provider: "authentik"
oidc:
endpoint: "https://auth.example.com/application/o/insertr/"
client_id: "insertr-client"
client_secret: "your-secret" # or use AUTHENTIK_CLIENT_SECRET env var
Enterprise-grade security features:
- ✅ OIDC Discovery - Automatic endpoint configuration
- ✅ PKCE Flow - Proof Key for Code Exchange security
- ✅ JWT Verification - RSA/ECDSA signature validation via JWKS
- ✅ Secure Sessions - HTTP-only cookies with CSRF protection
- ✅ Multi-tenant - Per-site authentication configuration
Authentication Flow
1. Editor clicks gate → Popup opens to Authentik
2. User authenticates → Authentik returns authorization code
3. Backend exchanges code for JWT → Validates with OIDC provider
4. Editor UI loads → Full editing capabilities enabled
Authentik Setup Guide
-
Create OIDC Provider in Authentik:
Applications → Providers → Create → OAuth2/OIDC Provider - Name: "Insertr CMS" - Authorization flow: default-authorization-flow - Client type: Confidential - Client ID: insertr-client - Redirect URIs: https://your-domain.com/auth/callback -
Create Application:
Applications → Applications → Create - Name: "Insertr CMS" - Slug: insertr - Provider: (select the provider created above) -
Configure Insertr:
auth: provider: "authentik" oidc: endpoint: "https://auth.example.com/application/o/insertr/" client_id: "insertr-client" client_secret: "your-generated-secret" -
Environment Variables (Recommended):
export AUTHENTIK_CLIENT_SECRET="your-secret" export AUTHENTIK_ENDPOINT="https://auth.example.com/application/o/insertr/"
Security Best Practices
- Environment Variables: Store secrets in env vars, not config files
- HTTPS Only: Always use HTTPS in production for OAuth flows
- Restricted Access: Use Authentik groups/policies to limit editor access
- Token Validation: All JWTs verified against provider's public keys
- Session Security: Secure cookie settings prevent XSS/CSRF attacks
🚀 Current Status
✅ Complete Full-Stack CMS
- Style-Aware Editor: Rich text editor with automatic style detection and formatting toolbar
- HTML Preservation: Perfect fidelity editing that maintains all element attributes and styling
- Enterprise Authentication: Production-ready OIDC integration with Authentik, PKCE security
- Content Persistence: SQLite/PostgreSQL database with REST API, complete version control
- Version History: Complete edit history with user attribution and one-click rollback
- Build Enhancement: Parse HTML, inject database content, build-time optimization
- Smart Detection: Auto-detects content types and generates style-based formatting options
- Link Management: Popup-based link configuration for complex multi-property elements
- Full Integration: Seamless development workflow with hot reload
🚀 Production Ready
- ✅ Full HTTP API server with authentication and version control
- ✅ Build-time enhancement for static site generators
- ✅ PostgreSQL and SQLite database support
- ✅ Authentik OIDC integration for enterprise authentication
- Deploy enhanced static files to any CDN or host
- Run content API server on separate infrastructure
🛠️ Quick Start
Quick Start (Recommended)
# Clone and setup
git clone <repository-url>
cd insertr
# Install dependencies and build everything
just install build
# Start full-stack development
just dev
This starts:
- Demo sites: http://localhost:8080/sites/demo/ (auto-enhanced for testing)
- API server: http://localhost:8080/api/* (with content persistence and version control)
Using NPM
# Alternative using npm
npm run install:all
npm run build
npm run dev
Available Commands
just --list # Show all available commands
# Development (Full-Stack by Default)
just dev # Start full-stack development (recommended)
just demo [site] # Start specific demo site (default, dan-eden)
just list-demos # Show all available demo sites
just demo-only # Demo site only (no content persistence)
just serve # API server only (localhost:8080)
# Building
just build # Build library + unified binary (complete stack)
just build-lib # Build JavaScript library only
# Utilities
just check # Validate project setup
just status # Show project status
just clean # Clean build artifacts
🎯 Complete Development Experience
Running just dev gives you the complete Insertr CMS:
- ✅ Style-Aware Editor - Rich text editing with automatic style detection and formatting
- ✅ HTML Preservation - Perfect fidelity editing that maintains all styling and attributes
- ✅ Real-Time Persistence - SQLite database with REST API and authentication
- ✅ Version Control - Complete edit history with user attribution and rollback
- ✅ Content Management - Create, read, update content via browser with popup-based link editing
- ✅ Build Integration - Binary enhances HTML with database content
- ✅ Hot Reload - Changes reflected immediately
📚 Version Control Features
Complete Edit History
Every content change is automatically tracked with:
- User Attribution - Who made each change
- Timestamps - When changes were made
- Content Snapshots - Full content preserved for each version
Easy Rollback
- View History button in any content editor
- One-Click Restore to any previous version
- Version Comparison - See what changed between versions
- Safe Rollback - Current content is preserved before restoration
Example Workflow
1. Editor clicks on any element with class="insertr"
2. Professional editing modal opens
3. Click "View History" to see all previous versions
4. Each version shows: timestamp, author, content preview
5. Click "Restore" on any version to rollback instantly
6. All changes are tracked automatically
📊 Parser Output Example
🔍 Parsing HTML files in: ../demo-site/
📊 Parse Results:
Files processed: 2
Elements found: 40
Container expansions: 3
Generated IDs: 34
📝 Content Types:
text: 19 # Headlines, short content
markdown: 19 # Rich content, paragraphs
link: 2 # Buttons, navigation
🎯 Container Expansions:
hero-section → 3 children (h1, p, button)
services-grid → 6 children (3×h3, 3×p)
🏗️ Architecture: Unified Binary
Enhancement Pipeline
Static Site Build → insertr enhance → Enhanced Deployment
↓ ↓ ↓
Pure HTML Parse + Inject Smart Loading
Database Content (Auth-dependent)
↓
Runtime Content API ← insertr serve ← Database (SQLite/PostgreSQL)
Unified Commands:
insertr enhance- Build-time content injectioninsertr serve- Runtime API server- Single binary handles both development and production workflows
Smart Loading Strategy
<!-- Regular visitors: zero overhead -->
<h1 class="insertr">Welcome to Our Site</h1>
<!-- Authenticated editors: rich editing -->
<h1 class="insertr" data-content-id="hero-title-abc123"
data-editor-loaded="true">Latest Content From Database</h1>
Benefits:
- Performance: Zero runtime cost for regular visitors
- Framework agnostic: Works with Hugo, Next.js, Jekyll, etc.
- Zero configuration: No schema files or content mappings
- Developer friendly: Stay in HTML markup, no context switching
🔧 Unified Binary Commands
Build-Time Enhancement
# Production build with remote API
./insertr enhance src/ --output ./dist --api https://cms.example.com --api-key xyz
# Development build with local database
./insertr enhance demo-site/ --output ./dist --db ./content.db
# Development build with mock data
./insertr enhance demo-site/ --output ./dist --mock
# Use justfile shortcuts
just enhance # Default: demo-site/ → dist/ with mock data
just enhance input="src" output="public" # Custom paths
Runtime API Server
# Development server with automatic site enhancement
./insertr serve --dev-mode --port 8080
# Production server with PostgreSQL
./insertr serve --db "postgresql://user:pass@host:5432/dbname" --config production.yaml
# Production server with custom config and Authentik
./insertr --config ./production.yaml serve
# Use justfile shortcuts
just serve # Development server on :8080 with auto-enhanced demo sites
just dev # Full development stack (recommended)
Configuration Options
# YAML configuration file
./insertr --config ./custom.yaml [command]
# Environment variables
export INSERTR_DB_PATH="./content.db"
export INSERTR_API_URL="https://api.example.com"
export INSERTR_API_KEY="your-api-key"
export INSERTR_SITE_ID="production"
# Command-line flags (highest priority)
./insertr --db ./custom.db --site-id staging serve --port 3000
# Show all options
./insertr --help
./insertr enhance --help
./insertr serve --help
📚 Integration Examples
GitHub Actions Workflow
# .github/workflows/deploy.yml
- name: Build static site
run: hugo --minify
- name: Enhance with Insertr
run: insertr enhance ./public --output ./dist
- name: Deploy enhanced site
uses: peaceiris/actions-gh-pages@v3
with:
publish_dir: ./dist
Container vs Individual Elements
<!-- Semantic convenience: entire section editable -->
<section id="hero" class="insertr">
<h1>Dynamic Title</h1> <!-- → text input -->
<p>Dynamic description</p> <!-- → textarea -->
<button>Dynamic CTA</button> <!-- → link editor -->
</section>
<!-- Granular control: specific elements -->
<nav>
<h1 class="insertr">Site Name</h1>
<ul>
<li><a href="/" class="insertr">Home</a></li>
<li><a href="/about" class="insertr">About</a></li>
</ul>
</nav>
Content Type Detection
- Headlines (
h1-h6) → Rich text editor with style-aware formatting - Paragraphs (
p) → Rich text editor with detected style options from CSS - Links/Buttons (
a,button) → Popup-based link editor with text + URL configuration - Containers (
div,section) → Expand to viable children with automatic style detection
🔌 API Reference
Simple Content Management
# Create or update content (single endpoint for both)
curl -X POST http://localhost:8080/api/content?site_id=demo \
-H "Content-Type: application/json" \
-d '{"value": "New content", "type": "text"}'
# Get all content for a site
curl http://localhost:8080/api/content?site_id=demo
# Get specific content by ID
curl http://localhost:8080/api/content/content-id?site_id=demo
# View edit history
curl http://localhost:8080/api/content/content-id/versions?site_id=demo
# Rollback to previous version
curl -X POST http://localhost:8080/api/content/content-id/rollback \
-d '{"version_id": 123}'
Key Features:
- Single POST endpoint handles both create and update (upsert)
- Automatic ID generation from element context if no ID provided
- Version control preserves all changes with user attribution
- Auto-enhancement updates static files when content changes
🔧 Development Workflow
Live Development with Hot Reload
# 🔥 Hot Reload: watches BOTH library AND unified binary
just air
# Alternative: Watch library only
just watch
# or: cd lib && npm run dev
# Library changes: lib/src/**/*.js → Auto rebuild library + binary
# Binary changes: cmd/**/*.go, internal/**/*.go → Auto rebuild binary
# Both trigger server restart with latest embedded assets
# Visit localhost:3000 → Refresh to see changes
What Gets Hot Reloaded:
- JavaScript library changes (
lib/src/) - Go unified binary changes (
cmd/,internal/) - Enhanced HTML output (real-time content injection)
Content ID Management
Development Phase:
- Generated IDs are disposable and change freely
- Focus on markup, ignore content persistence
- Use HTML
idattributes for complex cases
Production Phase:
- Preserve existing content mappings for stability
- Binary warns about orphaned content
- Simple migration tools for structural changes
⚙️ Configuration
YAML Configuration (insertr.yaml)
# Database configuration
database:
path: "./insertr.db" # SQLite file or PostgreSQL connection string
# API configuration (for remote content API)
api:
url: "" # Content API URL (leave empty to use local database)
key: "" # API authentication key
# Server configuration
server:
port: 8080 # HTTP server port
dev_mode: false # Enable development mode features
# Build configuration
build:
input: "./src" # Default input directory
output: "./dist" # Default output directory
# Global settings
site_id: "demo" # Site ID for content lookup
mock_content: false # Use mock content instead of real data
Configuration Precedence
- CLI flags (highest priority) -
./insertr --db ./custom.db serve - Environment variables -
INSERTR_DB_PATH=./custom.db - YAML config file -
insertr.yamlor--config custom.yaml - Smart defaults (lowest priority)
Environment Variables
INSERTR_DB_PATH- Database pathINSERTR_API_URL- Remote API URLINSERTR_API_KEY- API authentication keyINSERTR_SITE_ID- Site identifier
📖 Documentation
- Command Reference - Complete command and configuration guide
- Development Guide - Setup and contribution workflow
- Research Document - Strategic analysis and market positioning
- Integration Summary - Complete architecture overview
🎯 Market Position: "The Tailwind of CMS"
Tailwind CSS Approach:
- Utility-first classes:
class="text-lg font-bold" - Zero configuration, build-time optimization
- Framework agnostic, developer workflow integration
Insertr CMS Approach:
- Content-first classes:
class="insertr" - Zero configuration, build-time enhancement
- Framework agnostic, developer workflow integration
Shared Principles:
- Stay in markup, don't context switch
- Build-time optimization, zero runtime overhead
- Works with any framework or generator
- Developer experience focused
🚀 Production Deployment Workflow
Build-time enhancement + Runtime API for content management.
Production Architecture
The production workflow separates content management from site hosting:
1. Static Site Build → `insertr enhance` → Enhanced Static Files → Deploy to CDN/Host
2. Content Editing → `insertr serve` API → Database → Triggers rebuild
Two-Server Architecture
- Content API Server: Runs
insertr servefor content management and authentication - Static Site Host: Serves enhanced static files (CDN, GitHub Pages, Netlify, etc.)
Production Workflow
# 1. Build-time enhancement
./insertr enhance ./src --output ./dist --api https://cms.example.com
# 2. Deploy enhanced static files
rsync ./dist/ user@cdn:/var/www/site/
# 3. Run content API server (separate infrastructure)
./insertr serve --config production.yaml --db "postgresql://..."
Benefits
- ✅ Performance: Static files served from CDN with zero CMS overhead
- ✅ Scalability: Content API and static hosting scale independently
- ✅ Reliability: Static site works even if CMS server is down
- ✅ Security: Content editing isolated from public site hosting
- ✅ Framework Agnostic: Works with any static site generator or CDN
Development Server (Current Multi-Site Feature)
For development convenience, insertr serve --dev-mode can host multiple demo sites:
# insertr.yaml (development only)
server:
sites:
- site_id: "demo"
path: "./demos/demo_enhanced"
source_path: "./demos/demo"
auto_enhance: true
This serves sites at http://localhost:8080/sites/demo/ for testing the editor interface.
⚙️ Configuration
YAML Configuration (insertr.yaml)
# Global settings
dev_mode: false # Development mode features
# Database configuration
database:
path: "./insertr.db" # SQLite file or PostgreSQL connection string
# Server configuration (multi-site hosting)
server:
port: 8080 # HTTP server port
sites: # Server-hosted static sites
- site_id: "mysite"
path: "/var/www/mysite_enhanced" # Enhanced site output directory
source_path: "/var/www/mysite" # Original static site files
auto_enhance: true # Auto-enhance on startup and content changes
discovery:
enabled: false # Use explicit class="insertr" markings (true = auto-discover)
aggressive: false # Aggressive element discovery
# CLI enhancement configuration
cli:
site_id: "default" # Default site ID for CLI operations
output: "./dist" # Default output directory for enhanced files
inject_demo_gate: true # Inject demo editing gate if none exist
# API configuration (for CLI remote mode)
api:
url: "" # Content API URL (empty = use local database)
key: "" # API authentication key
# Authentication configuration
auth:
provider: "mock" # "mock" for development, "authentik" for production
jwt_secret: "" # JWT signing secret (auto-generated in dev mode)
# Authentik OIDC configuration (production)
oidc:
endpoint: "" # https://auth.example.com/application/o/insertr/
client_id: "" # insertr-client (OAuth2 client ID)
client_secret: "" # OAuth2 client secret (or use AUTHENTIK_CLIENT_SECRET env var)
Environment Variables
Core Configuration
INSERTR_DB_PATH- Database path overrideINSERTR_API_URL- Remote API URL overrideINSERTR_API_KEY- API authentication keyINSERTR_SITE_ID- Site identifier override
Authentication (Recommended for Production)
AUTHENTIK_CLIENT_SECRET- OIDC client secret (overrides config file)AUTHENTIK_ENDPOINT- OIDC endpoint URL (overrides config file)
Configuration Precedence
- CLI flags (highest priority)
- Environment variables
- YAML config file
- Smart defaults (lowest priority)
Database Options
# SQLite (development)
./insertr serve --db "./content.db"
# PostgreSQL (production)
./insertr serve --db "postgresql://user:pass@host:5432/insertr"
# Environment-based
export INSERTR_DB_PATH="postgresql://prod-host/insertr"
./insertr serve
🤝 Contributing
This project follows the "Tailwind philosophy" of developer-first design:
- Zero configuration - Markup-driven approach
- Build-time optimization - No runtime performance cost
- Framework agnostic - Works with any tech stack
- Developer friendly - Minimal cognitive overhead
See DEVELOPMENT.md for technical setup and contribution guidelines.
📄 License
MIT License - see LICENSE file for details.
Built with ❤️ for developers who want powerful editing without the complexity