Skip to content

olegiv/ocms-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,247 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

oCMS

Go CodeQL Dependency review

A lightweight content management system built with Go, featuring a modern admin interface, session-based authentication, SQLite storage, and extensible architecture with themes and modules.

Features

Content Management

  • Page Management: Create, edit, publish, and version pages with a rich content editor
  • Video Embedding: Embed YouTube, Vimeo, and Dailymotion videos in pages with responsive rendering
  • Scheduled Publishing: Schedule pages to publish at a future date/time
  • Media Library: Upload and manage images, documents, and videos with automatic image processing
    • Automatic thumbnail and variant generation
    • Folder organization
    • Featured image support for pages
  • Menu Builder: Create navigation menus with drag-and-drop ordering
    • Hierarchical menu structures
    • Link to pages or external URLs
    • Multiple menu locations
  • Full-Text Search: Built-in SQLite FTS5 search for fast content discovery

Taxonomy

  • Categories: Organize content with hierarchical categories
  • Tags: Add flat taxonomy tags to pages

Forms

  • Form Builder: Create contact forms, surveys, and data collection forms
    • Multiple field types (text, email, textarea, select, checkbox, radio)
    • Form submissions management
    • Read/unread status tracking
    • Email notifications

Theme System

  • Multiple Themes: Switch between different frontend themes
  • Theme Settings: Configurable theme options (colors, layout, etc.)
  • Template Override: Themes can customize page templates
  • Static Assets: Theme-specific CSS, JavaScript, and images

Module System

  • Extensible Architecture: Add custom functionality via modules
  • Module Lifecycle: Init, routes, admin routes, and shutdown hooks
  • Module Migrations: Modules can have their own database migrations
  • Template Functions: Modules can add custom template functions
  • Active Status Toggle: Enable/disable modules from admin UI without restart
  • Module Translations: Modules can embed their own i18n locale files

REST API

  • Full CRUD API: Complete REST API for pages, media, tags, and categories
  • API Key Authentication: Secure API access with bearer token authentication
  • Permission-Based Access: Fine-grained permissions (read/write per resource)
  • Rate Limiting: Per-key and global rate limiting
  • API Documentation: Built-in API documentation page

SEO

  • Meta Tags: Custom title, description, and keywords per page
  • Open Graph: Full Open Graph and Twitter Card support
  • Sitemap: Auto-generated sitemap.xml
  • Robots.txt: Configurable robots.txt generation
  • Canonical URLs: Set canonical URLs to avoid duplicate content
  • NoIndex/NoFollow: Control search engine indexing per page

Administration

  • User Management: Role-based access control (admin/editor)
  • Authentication: Secure session-based authentication with argon2id password hashing
  • Event Logging: Comprehensive audit trail for all actions
  • Admin Dashboard: Modern responsive UI with HTMX and Alpine.js
    • Statistics overview
    • Recent submissions widget
    • Quick actions
    • Collapsible sidebar with persistent state
  • Cache Management: View cache stats and clear cache
  • API Key Management: Create and manage API keys
  • Bulk List Actions: Multi-select and bulk delete/revoke on paged admin lists (pages, tags, users, API keys, media, and form submissions)
  • Per-Page Selector: Choose items per page on delete-capable admin lists (URL query per_page, current-page state in URL only)
  • List Sorting: Sort delete-capable admin lists by safe whitelisted columns with clear active sort highlighting (URL queries sort + dir)
  • SQLite Database: Zero-configuration embedded database with migrations

Multi-Language Support

  • Content Translation: Translate pages, categories, and tags into multiple languages
  • Language Management: Configure site languages with ISO 639-1 codes
  • Translation Linking: Link content across languages for seamless switching
  • Language Switcher: Built-in frontend component for language navigation
  • URL Prefixes: Language-prefixed URLs (e.g., /ru/about-us)
  • RTL Support: Right-to-left language support
  • Admin UI Localization: Translatable admin interface (English + Russian included)

Webhooks

  • Event System: Trigger webhooks on content events (create, update, delete, publish)
  • Delivery Tracking: Monitor delivery status and response codes
  • Retry Logic: Exponential backoff retry for failed deliveries
  • HMAC Signatures: Secure payloads with HMAC-SHA256 signatures
  • Custom Headers: Add custom headers to webhook requests
  • Dead Letter Queue: Track permanently failed deliveries
  • Event Debouncing: Coalesce rapid-fire events to reduce webhook noise

Import/Export

  • JSON Export: Export site content to portable JSON format
  • ZIP Export: Include media files in export archives
  • Selective Export: Choose which content types to include
  • JSON Import: Import content from JSON files
  • ZIP Import: Restore media files from archives
  • Conflict Resolution: Skip, overwrite, or rename on conflicts
  • Dry Run Mode: Preview import changes before applying

Performance

  • Multi-Level Caching: In-memory and optional Redis caching
  • Redis Support: Distributed caching for multi-instance deployments
  • Response Compression: Gzip compression for HTML and JSON responses
  • Graceful Shutdown: Clean shutdown with request draining
  • Health Check: /health endpoint for monitoring

Prerequisites

  • Go 1.26 or later
  • Node.js (npm) for frontend dependencies
  • sqlc for SQL code generation
  • templ for type-safe HTML templates
  • goose for database migrations
  • Dart Sass for SCSS compilation
  • libvips for image processing (required for media library)

Installing libvips

macOS:

brew install vips

Ubuntu/Debian:

sudo apt-get install libvips-dev

Fedora:

sudo dnf install vips-devel

Installation

  1. Clone the repository:

    git clone https://github.com/olegiv/ocms-go.git
    cd ocms-go
  2. Install dependencies:

    go mod download
  3. Install required tools:

    go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
    go install github.com/a-h/templ/cmd/templ@latest
    go install github.com/pressly/goose/v3/cmd/goose@latest
  4. Generate code:

    sqlc generate
    templ generate
  5. Build assets (installs npm dependencies and compiles SCSS):

    make assets

Environment Variables

Variable Description Default Required
OCMS_SESSION_SECRET Secret key for session encryption (min 32 bytes) - Yes
OCMS_DB_PATH Path to SQLite database file ./data/ocms.db No
OCMS_SERVER_HOST Server host address localhost No
OCMS_SERVER_PORT Server port number 8080 No
OCMS_ENV Environment mode (development/production) development No
OCMS_LOG_LEVEL Log level (debug/info/warn/error) info No
OCMS_CUSTOM_DIR Directory for custom themes and modules ./custom No
OCMS_ACTIVE_THEME Active theme (overrides DB/admin setting) default No
OCMS_DO_SEED Seed database with default admin and config false No
OCMS_CACHE_TTL Default cache TTL in seconds 3600 No
OCMS_REDIS_URL Redis URL for distributed caching - No
OCMS_CACHE_PREFIX Redis key prefix ocms: No
OCMS_CACHE_MAX_SIZE Max entries for in-memory cache 10000 No
OCMS_HCAPTCHA_SITE_KEY hCaptcha site key for login protection - No
OCMS_HCAPTCHA_SECRET_KEY hCaptcha secret key for login protection - No
OCMS_HCAPTCHA_DISABLED Force-disable hCaptcha regardless of database settings false No
OCMS_GEOIP_DB_PATH Path to GeoLite2-Country.mmdb for country detection - No
OCMS_UPLOADS_DIR Directory for uploaded media files ./uploads No
OCMS_TRUSTED_PROXIES Trusted reverse-proxy CIDRs/IPs; forwarding headers are ignored unless peer is trusted - No
OCMS_REQUIRE_TRUSTED_PROXIES Fail startup in production if trusted proxy CIDRs/IPs are not configured false (true in production when unset) No
OCMS_API_ALLOWED_CIDRS Global source CIDRs/IPs allowed to use API keys - No
OCMS_REQUIRE_API_ALLOWED_CIDRS Fail API key auth when global API source CIDRs are not configured false (true in production when unset) No
OCMS_REQUIRE_API_KEY_EXPIRY Require API keys to have expiration timestamps false (true in production when unset) No
OCMS_REQUIRE_API_KEY_SOURCE_CIDRS Require API keys to have per-key source CIDR restrictions false (true in production when unset) No
OCMS_REVOKE_API_KEY_ON_SOURCE_IP_CHANGE Deactivate API keys when source IP changes and the key has no per-key CIDRs false (true in production when unset) No
OCMS_API_KEY_MAX_TTL_DAYS Maximum API key lifetime in days (0 disables, max 365) 0 (90 in production when unset) No
OCMS_EMBED_ALLOWED_ORIGINS Allowed browser origins for public embed proxy routes; required for working browser embed requests in production - No
OCMS_EMBED_ALLOWED_UPSTREAM_HOSTS Allowed upstream hosts for embed provider API endpoints - No
OCMS_REQUIRE_EMBED_ALLOWED_ORIGINS Fail startup in production if embed proxy is active without origin allowlist false (true in production when unset) No
OCMS_REQUIRE_EMBED_ALLOWED_UPSTREAM_HOSTS Fail startup in production if embed proxy is active without upstream host allowlist false (true in production when unset) No
OCMS_EMBED_PROXY_TOKEN Secret used to mint short-lived signed embed proxy tokens; required for active embed proxy in production - No
OCMS_REQUIRE_EMBED_PROXY_TOKEN Enforce embed proxy token requirement in non-production too false No
OCMS_REQUIRE_HTTPS_OUTBOUND Require HTTPS for outbound integration URLs false (true in production when unset) No
OCMS_REQUIRE_FORM_CAPTCHA Require captcha on all public form submissions false (true in production when unset) No
OCMS_WEBHOOK_FORM_DATA_MODE form.submitted payload data mode (redacted/none/full) redacted No
OCMS_REQUIRE_WEBHOOK_FORM_DATA_MINIMIZATION Fail startup in production when form webhook payload mode is full false (true in production when unset) No
OCMS_WEBHOOK_ALLOWED_HOSTS Allowed destination hosts for active webhook deliveries (exact hostname match) - No
OCMS_REQUIRE_WEBHOOK_ALLOWED_HOSTS Fail startup in production when active webhooks exist without destination host allowlist false (true in production when unset) No
OCMS_SANITIZE_PAGE_HTML Sanitize page HTML before rendering to visitors false (true in production when unset) No
OCMS_REQUIRE_SANITIZE_PAGE_HTML Fail startup in production if page HTML sanitization is disabled false (true in production when unset) No
OCMS_BLOCK_SUSPICIOUS_PAGE_HTML Reject page writes containing suspicious HTML patterns false (true in production when unset) No
OCMS_REQUIRE_BLOCK_SUSPICIOUS_PAGE_HTML Fail startup in production when suspicious page markup blocking is disabled or existing pages contain suspicious markers false (true in production when unset) No
OCMS_DEMO_MODE Enable demo content seeding (users, pages, media) false No

Development

Quick Start

# Set required environment variable
export OCMS_SESSION_SECRET="your-secret-key-at-least-32-bytes"

# Install repository-managed git hooks (run once per clone)
make install-hooks

# Run with asset compilation
make dev

# Or run without rebuilding assets
make run

Available Make Commands

Command Description
make dev Build assets and run development server
make run Run development server (no asset build)
make stop Stop development server on port 8080
make restart Stop and restart development server
make build Build binary to bin/ocms
make build-prod Build optimized binary (stripped, trimmed)
make build-linux-amd64 Cross-compile for Linux AMD64
make build-darwin-arm64 Cross-compile for macOS ARM64
make build-all-platforms Build for Linux AMD64 and macOS ARM64
make test Run all tests
make clean Remove build artifacts
make clean-db Remove database files
make migrate-up Apply pending migrations
make migrate-down Rollback last migration
make migrate-status Show migration status
make migrate-create Create new migration file
make assets Install npm deps and compile SCSS
make sqlc Regenerate sqlc code from SQL queries
make templ Regenerate templ Go code from .templ files
make deploy-binary Deploy binary to remote server (no custom content)
make commit-prepare Proxy to Claude slash command /commit-prepare
make commit-do Proxy to Claude slash command /commit-do
make code-quality Proxy to Claude slash command /code-quality
make security-audit Proxy to Claude slash command /security-audit
make commit-prepare-local Run local commit-prepare shell script
make commit-do-local Run local commit-do shell script
make code-quality-local Run local code quality shell script (golangci-lint, nilaway, go test)
make security-audit-local Run local security audit shell script (writes to .audit/)
make install-hooks Configure git to use repository-managed hooks from .githooks
make check-no-absolute-paths Fail if tracked files contain local absolute paths (/Users/..., /home/..., C:\Users\...)

Default Admin Credentials

On first run with OCMS_DO_SEED=true, the application seeds a default admin user:

Change these credentials immediately after first login.

Demo Mode

With OCMS_DEMO_MODE=true (requires OCMS_DO_SEED=true), additional demo content is seeded including sample pages, categories, tags, media, and menu items. Two demo users are created:

See docs/demo-deployment.md for Fly.io deployment and demo configuration details.

Docker

Quick Start with Docker

# Clone the repository
git clone https://github.com/olegiv/ocms-go.git
cd ocms-go

# Start with Docker Compose (generates session secret automatically)
OCMS_SESSION_SECRET=$(openssl rand -base64 32) OCMS_DO_SEED=true docker compose up -d

# View logs
docker compose logs -f ocms

Access the admin panel at http://localhost:8080/admin with:

Docker Commands

Command Description
docker compose up -d Start oCMS
docker compose --profile redis up -d Start with Redis caching
docker compose down Stop services
docker compose logs -f ocms View logs
docker compose pull && docker compose up -d Update to latest

Volume Mounts

Volume Container Path Purpose
ocms_data /app/data SQLite database
ocms_uploads /app/uploads Media uploads
./custom /app/custom Custom themes and modules

Building the Docker Image

# Build with version info
docker build \
  --build-arg VERSION=$(git describe --tags --always) \
  --build-arg GIT_COMMIT=$(git rev-parse --short HEAD) \
  --build-arg BUILD_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
  -t ocms:latest .

Production Configuration

Create a .env file for production:

OCMS_SESSION_SECRET=your-secure-secret-key-at-least-32-bytes
OCMS_ENV=production
OCMS_DO_SEED=false
OCMS_ACTIVE_THEME=default
OCMS_TRUSTED_PROXIES=127.0.0.1/32,10.0.0.0/8
OCMS_API_ALLOWED_CIDRS=203.0.113.0/24

# Hardened embed proxy baseline (when embed module/provider is enabled)
# Origin matching is exact (scheme + host). Include all real hostnames.
OCMS_EMBED_ALLOWED_ORIGINS=https://example.com,https://www.example.com
OCMS_EMBED_ALLOWED_UPSTREAM_HOSTS=api.dify.ai
OCMS_REQUIRE_EMBED_ALLOWED_ORIGINS=true
OCMS_REQUIRE_EMBED_ALLOWED_UPSTREAM_HOSTS=true
OCMS_EMBED_PROXY_TOKEN=replace-with-embed-proxy-token
OCMS_WEBHOOK_ALLOWED_HOSTS=hooks.example.com,events.example.com

# Required when OCMS_REQUIRE_FORM_CAPTCHA is enabled (enabled by default in production)
OCMS_HCAPTCHA_SITE_KEY=your-site-key
OCMS_HCAPTCHA_SECRET_KEY=your-secret-key

# Optional: Redis caching
OCMS_REDIS_URL=redis://redis:6379/0

Then start with:

docker compose --profile redis up -d

Project Structure

ocms-go/
├── cmd/ocms/             # Application entry point
├── docs/                 # Documentation
│   ├── multi-language.md # Multi-language guide
│   ├── webhooks.md       # Webhooks configuration
│   ├── import-export.md  # Import/export guide
│   └── reverse-proxy.md  # Nginx/Apache/NPM setup
├── internal/
│   ├── auth/             # Password hashing utilities
│   ├── cache/            # Caching layer (memory + Redis)
│   ├── config/           # Configuration loading
│   ├── handler/          # HTTP handlers
│   │   └── api/          # REST API handlers
│   ├── i18n/             # Internationalization (admin UI)
│   ├── imaging/          # Image processing (thumbnails, variants)
│   ├── middleware/       # HTTP middleware (auth, API, rate limiting)
│   ├── model/            # Domain models
│   ├── module/           # Module system (registry, hooks)
│   ├── render/           # Template rendering
│   ├── scheduler/        # Cron-based task scheduler
│   ├── seo/              # SEO utilities (sitemap, robots.txt, meta)
│   ├── service/          # Business logic (media, menus, forms)
│   ├── session/          # Session management
│   ├── store/            # Database layer (sqlc generated)
│   │   ├── migrations/   # Goose SQL migrations
│   │   └── queries/      # sqlc query definitions
│   ├── theme/            # Theme loading and management
│   ├── themes/           # Embedded core themes (default, developer)
│   ├── transfer/         # Import/export functionality
│   ├── util/             # Utility functions (slug generation)
│   └── webhook/          # Webhook system
├── modules/              # Custom modules directory
│   └── example/          # Example module implementation
├── custom/               # User content directory (gitignored)
│   ├── themes/           # Custom themes (override or extend core)
│   └── modules/          # Custom modules (future use)
├── web/
│   ├── static/           # Static assets (CSS, JS)
│   │   └── scss/         # SCSS source files
│   └── templates/        # HTML templates
│       ├── admin/        # Admin panel templates
│       ├── api/          # API documentation templates
│       ├── auth/         # Login/logout templates
│       ├── errors/       # Error pages (404, 403, 500)
│       ├── layouts/      # Base layouts
│       └── partials/     # Reusable components
├── uploads/              # Media uploads directory
├── scripts/              # Build scripts
├── Makefile              # Development commands
├── package.json          # npm dependencies (htmx, alpine.js)
└── sqlc.yaml             # sqlc configuration

REST API

The CMS provides a RESTful API for programmatic access to content.

Authentication

API requests require a Bearer token in the Authorization header:

curl -H "Authorization: Bearer your-api-key" http://localhost:8080/api/v2/pages

Create API keys in the admin panel under Settings > API Keys.

The REST surface is /api/v2. The OpenAPI 3.1 spec is generated from Go types via huma and served live at /api/v2/openapi.json (or .yaml). Swagger UI is available at /api/v2/docs.

Endpoints

Method Endpoint Description Auth
GET /api/v2/status API status Public
GET /api/v2/auth Inspect the calling API key Required
GET /api/v2/pages List pages Optional
GET /api/v2/pages/{id} Get page by ID Optional
GET /api/v2/pages/slug/{slug} Get page by slug Optional
POST /api/v2/pages Create page Required
PUT /api/v2/pages/{id} Update page Required
DELETE /api/v2/pages/{id} Delete page Required
GET /api/v2/media List media Optional
GET /api/v2/media/{id} Get media by ID Optional
POST /api/v2/media Upload a single file Required
POST /api/v2/media/batch Upload multiple files Required
PUT /api/v2/media/{id} Update media metadata Required
DELETE /api/v2/media/{id} Delete media Required
GET /api/v2/tags List tags Public
POST /api/v2/tags Create tag Required
PUT /api/v2/tags/{id} Update tag Required
DELETE /api/v2/tags/{id} Delete tag Required
GET /api/v2/categories List categories (tree or flat) Public
POST /api/v2/categories Create category Required
PUT /api/v2/categories/{id} Update category Required
DELETE /api/v2/categories/{id} Delete category Required
GET /api/v2/openapi.json OpenAPI 3.1 spec (JSON) Public
GET /api/v2/openapi.yaml OpenAPI 3.1 spec (YAML) Public
GET /api/v2/docs Swagger UI Public
GET /health Health check Public

Response Format

{
  "data": { ... },
  "meta": {
    "total": 100,
    "page": 1,
    "per_page": 20
  }
}

Error Format

{
  "error": {
    "code": "validation_error",
    "message": "Validation failed",
    "details": { "title": "Title is required" }
  }
}

Theme Development

Core themes (default, developer) are embedded in the binary. To create a custom theme, add a directory in custom/themes/:

custom/themes/my-theme/
├── theme.json          # Theme configuration
├── templates/
│   ├── layouts/
│   │   └── base.html   # Base layout
│   ├── pages/
│   │   ├── home.html   # Homepage template
│   │   ├── page.html   # Single page template
│   │   └── 404.html    # Not found page
│   └── partials/
│       ├── header.html
│       └── footer.html
└── static/
    ├── css/
    └── js/

To override an embedded theme, create a custom theme with the same name:

custom/themes/default/    # Overrides the embedded 'default' theme

Custom themes with the same name as core themes take priority.

theme.json

{
  "name": "My Theme",
  "version": "1.0.0",
  "author": "Your Name",
  "description": "A custom theme",
  "settings": [
    {
      "key": "primary_color",
      "label": "Primary Color",
      "type": "color",
      "default": "#3b82f6"
    }
  ]
}

Module Development

Create custom modules to extend functionality:

package mymodule

import (
    "database/sql"
    "embed"

    "github.com/olegiv/ocms-go/internal/module"
    "github.com/go-chi/chi/v5"
)

//go:embed locales
var localesFS embed.FS

type MyModule struct {
    module.BaseModule
}

func New() *MyModule {
    return &MyModule{
        BaseModule: module.NewBaseModule("mymodule", "1.0.0", "My custom module"),
    }
}

func (m *MyModule) RegisterRoutes(r chi.Router) {
    r.Get("/my-endpoint", m.handleEndpoint)
}

func (m *MyModule) Migrations() []module.Migration {
    return []module.Migration{
        {
            Version:     1,
            Description: "Create my_table",
            Up: func(db *sql.DB) error {
                _, err := db.Exec("CREATE TABLE my_table (...)")
                return err
            },
        },
    }
}

// TranslationsFS returns embedded locale files for i18n support
func (m *MyModule) TranslationsFS() embed.FS {
    return localesFS
}

Add self-registration in register.go:

package mymodule

import "github.com/olegiv/ocms-go/internal/module"

func init() {
    module.RegisterCustomModule(New())
}

Then add a blank import to custom/modules/imports.go:

_ "github.com/olegiv/ocms-go/custom/modules/mymodule"

See docs/custom-modules.md for the full guide and custom/modules/bookmarks/ for a working example.

Module Translations

Modules can embed their own translation files:

mymodule/
├── module.go
├── handlers.go
└── locales/
    ├── en/
    │   └── messages.json
    └── ru/
        └── messages.json

Translation keys should be prefixed with the module name (e.g., mymodule.title).

Module Active Status

Modules can be enabled/disabled from the admin UI at Admin > Modules. When a module is disabled:

  • Public routes return 404
  • Admin routes redirect to the modules list
  • Template functions are not registered
  • The module remains initialized but inactive

Testing

Run all tests:

OCMS_SESSION_SECRET=test-secret-key-32-bytes-long!! go test ./...

Run tests with verbose output:

OCMS_SESSION_SECRET=test-secret-key-32-bytes-long!! go test -v ./...

Run tests for a specific package:

OCMS_SESSION_SECRET=test-secret-key-32-bytes-long!! go test -v ./internal/store/...

Check for vulnerabilities:

govulncheck ./...

Wiki

Project documentation is published at the GitHub Wiki and managed as a git submodule at wiki/.

Editing Wiki Pages

# Edit a page
vim wiki/Getting-Started.md

# Publish changes
/update-wiki

# Or manually:
cd wiki
git add -A && git commit -m "Update page" && git push
cd ..
git add wiki
git commit -m "Update wiki submodule"

Cloning with Wiki

git clone --recurse-submodules https://github.com/olegiv/ocms-go.git

Claude Code Support Tools

This project uses a shared submodule at .claude/shared containing reusable Claude Code extensions:

  • Agents: security-auditor, project-architect, code-quality-auditor
  • Commands: commit-prepare, commit-do, security-audit, setup-project-tools
  • Global config: CLAUDE.md rules and settings.json templates

Updating the Submodule

To update the shared Claude Code tools to the latest version:

# Using the slash command (recommended)
/update-submodule

# Or manually
git submodule update --remote --merge

If you are using Codex, Claude slash commands are not registered in the Codex UI and may show No commands. Use shell/make commands directly, or ask Codex in chat to run them.

You can run slash-command equivalents through Claude CLI:

claude -p "/commit-prepare" --dangerously-skip-permissions
claude -p "/commit-do" --dangerously-skip-permissions
claude -p "/code-quality" --dangerously-skip-permissions
claude -p "/security-audit" --dangerously-skip-permissions

Codex wrapper commands (Claude proxy by default):

./scripts/codex-commands code-quality
./scripts/codex-commands security-audit
./scripts/codex-commands commit-prepare
./scripts/codex-commands commit-do

# Explicit local fallback scripts
./scripts/codex-commands code-quality-local
./scripts/codex-commands security-audit-local
./scripts/codex-commands commit-prepare-local
./scripts/codex-commands commit-do-local

After updating, stage and commit the submodule change if you want to keep it:

git add .claude/shared
git commit -m "Update Claude Code shared submodule"

Technology Stack

  • Backend: Go 1.26+
  • Database: SQLite with goose migrations
  • SQL: Type-safe queries with sqlc
  • Templates: templ for type-safe HTML
  • Frontend: HTMX + Alpine.js
  • Rich Text Editor: TinyMCE for content editing
  • Styling: Custom SCSS framework
  • Authentication: Secure sessions with argon2id password hashing
  • Containerization: Docker with multi-stage builds

License

Copyright (C) 2025-2026 Oleg Ivanchenko

GNU General Public License v3.0 - see LICENSE file for details.

About

Lightweight CMS built with Go and SQLite. Features HTMX/Alpine.js admin, REST API, theme & module systems, multi-language support, webhooks, media library, form builder and SEO tools. Single binary, zero config database.

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Contributors