CMS is a server-first showcase/proof app that demonstrates local Kujo application patterns for content models, delivery routes, auth boundaries, and contract-tested APIs.
It boots from backend/runtime/main.kujo; there is no standalone CLI wrapper to validate.
CMS is production-capable as a Kujo showcase backend when deployed with rotated secrets, explicit CORS policy, durable storage/backup practices, and the documented release gate. It is not presented as universally enterprise-complete out of the box: default branch protection enforcement remains the known pre-launch governance gate, and teams should still run their own infrastructure, compliance, and threat-model review before public production use.
The current codebase is intentionally backend-first. Active source lives under backend/config, backend/core, backend/modules, backend/routes, and backend/runtime; empty migration-era placeholder folders are not part of the current architecture.
- Server-first architecture with clear module ownership under
backend/ - Canonical runtime entrypoint at
backend/runtime/main.kujo - Content-model coverage for content types, taxonomies/terms, entries, media, menus, plugins, themes, users, roles, API tokens, tenants, and workspaces
- Public delivery and discovery routes for
/.well-known/security.txt,/.well-known/llms.txt,/robots.txt,/sitemap.xml,/sitemap-index.xml,/rss.xml,/health,/v1,/v1/contract, and/v1/openapi.json - Auth-gated write routes, webhook delivery, background jobs, migration safety, and backup/restore
- Release-gate automation covering contract, smoke, startup compatibility, integration, security, and optional performance checks
- Content types, taxonomies/terms, entries, media, menus
- Plugin registry and webhook hooks
- Theme registry and activation controls
- Durable users and profiles with roles, account states, social links, derived credentials, and configurable open/approval/closed registration
- Roles and API tokens with lifecycle controls
- Tenants and workspaces with isolation controls
- Public delivery and discovery routes (
/.well-known/security.txt,/.well-known/llms.txt,/robots.txt,/sitemap.xml,/sitemap-index.xml,/rss.xml,/health,/v1,/v1/contract,/v1/openapi.json) - Scheduler, revisions, rollback, and entry locking
- CMS proves Kujo can support a practical server-first application surface.
- CRUD API Showcase demonstrates a smaller API pattern.
- SSG demonstrates static publishing.
- Lens and ShipCheck help review and gate the result.
Canonical runtime and module layout:
Verified startup path:
backend/runtime/main.kujo
| Area | Path |
|---|---|
| Runtime bootstrap | backend/runtime/main.kujo |
| Config | backend/config/config.kujo |
| Core transport/persistence | backend/core/http.kujo, backend/core/database.kujo, backend/core/migrations.kujo, backend/core/utils.kujo |
| Auth/Authz modules | backend/modules/auth.kujo, backend/modules/authz.kujo |
| Domain routes | backend/routes/*.kujo |
Import policy:
- Use dotted backend imports for local modules (for example,
from backend.core.http import fail). - Do not reintroduce root-level compatibility wrapper modules.
- Start the API from the verified runtime entrypoint; there is no standalone CLI wrapper.
Security controls:
- Bearer token enforcement for write routes
- Published-only anonymous entry reads; draft/scheduled/archived details and revision history require authenticated access
- Bootstrap token hardening (production-safe defaults, entropy policy)
- Strict JSON mutation validation and body-size limits
- Rate limiting (
memory,sqlite,external,offmodes) - Idempotency support for mutation retry safety
- Plugin hook URL policy controls (allowlist/denylist, scheme restrictions)
- Structured audit logging for sensitive mutations
Operations controls:
- Health, readiness, and metrics endpoints
- Webhook outbox retries + dead-letter replay
- Background job processing + dead-letter replay
- Migration safety and graceful restart validation
- Backup and restore scripts
Code and validation status:
- Contract tests, smoke API checks, compatibility startup, and the release gate
all pass in the 2026-07-10 local receipt, including enabled performance and
performance-budget checks; see
docs/release-gate-evidence-2026-07-10.md. - Contract coverage includes safe pagination parsing for malformed list query input across list endpoint helpers.
- The documented release gate enables performance checks by default.
- Repository code and docs are aligned to the backend-first architecture.
Open governance item before public launch:
- Branch protection/ruleset enforcement for required release-gate checks is pending repository plan/visibility constraints (documented in
docs/enterprise-production-readiness-plan.md).
- Configure environment:
cp .env.example .env- Start the API:
cd /path/to/cms
/path/to/kujo/target/debug/kujo run --interpreter backend/runtime/main.kujoDefault bind: http://127.0.0.1:4200
Use CMS_API_HOST if you need an explicit non-default bind host; the reviewed showcase path defaults to 127.0.0.1.
The API boots directly from backend/runtime/main.kujo; there is no standalone CLI wrapper.
Recommended env overrides:
CMS_API_HOSTCMS_ENVCMS_API_PORTCMS_API_TOKENCMS_DB_PATHCMS_SITE_URLCMS_CORS_ORIGINCMS_TRUSTED_INGRESS_LIMITSCMS_RATE_LIMIT_MODECMS_IDEMPOTENCY_ENABLEDCMS_PLUGIN_HOOK_URL_ALLOWLISTCMS_PLUGIN_HOOK_URL_DENYLISTCMS_READINESS_CHECK_DBCMS_METRICS_ENABLED
Bootstrap authentication has no usable default credential. Generate a unique bootstrap token for initial provisioning, then disable it and use scoped database-backed API tokens. Administrative routes require dedicated capabilities: admin.auth, admin.users, admin.settings, and admin.plugins; cms.write alone does not grant administrative access.
Security upgrade note: schema migration v9 deactivates all database-backed API tokens created by earlier schema versions because legacy environment-bootstrap credentials were not distinguishable from ordinary tokens after edits. Reissue the required scoped tokens after upgrading; the current environment bootstrap token remains available only when explicitly enabled and is never persisted.
Production startup also requires CMS_TRUSTED_INGRESS_LIMITS=true and CMS_RATE_LIMIT_MODE=external. The trusted ingress must enforce request-body size, connection/read timeouts, and per-client rate limits before traffic reaches Kujo; the current interpreter buffers request bodies and does not expose the socket peer address to application routes.
User APIs:
GET|POST /v1/userslists or creates user records.GET|PATCH /v1/users/:idreads or updates profiles, roles, and account status.GET /v1/users/:id/credentialsis a bearer-protected server-to-server credential lookup; password hashes are never included in normal user responses.GET|PATCH /v1/settings/registrationreads or changes theopen,approval, orclosedsignup policy and its default role.GET|PATCH /v1/settings/social-sharingreads or changes the allowed sharing networks and the content types that display them. This setting is bearer-protected and audited like other administration settings.
The backend stores portable PBKDF2 credential material supplied by the trusted authentication layer. Public applications should terminate password handling in a trusted server, keep the CMS token out of browsers, and use a managed identity provider where appropriate.
Contract tests:
cd /path/to/cms
/path/to/kujo/target/debug/kujo test-run tests/cms_contract_tests.kujoFull release gate:
cd /path/to/cms
CMS_GATE_RUN_PERF=false KUJO_BIN=/path/to/kujo/target/debug/kujo bash scripts/run-release-gate.shUseful targeted checks:
KUJO_BIN=/path/to/kujo/target/debug/kujo bash scripts/integration-enterprise-security.sh
KUJO_BIN=/path/to/kujo/target/debug/kujo bash scripts/integration-multitenant.sh
KUJO_BIN=/path/to/kujo/target/debug/kujo bash scripts/smoke-api.sh
KUJO_BIN=/path/to/kujo/target/debug/kujo bash scripts/verify-compat-startup.shWebhook pipeline:
bash scripts/process-webhook-outbox.sh
bash scripts/replay-webhook-dead-letters.shWebhook and background-job processors use renewable claim leases so overlapping workers cannot normally execute the same row. Webhook claim duration is automatically kept longer than the configured curl deadline. Receivers must still deduplicate by X-CMS-Webhook-Id, because a process can crash after a remote endpoint accepts a request but before local delivery state commits.
Background jobs:
bash scripts/process-background-jobs.sh
bash scripts/replay-background-job-dead-letters.shData safety:
bash scripts/backup-db.sh
bash scripts/restore-db.sh
bash scripts/migration-safety.shStart with the docs index:
docs/README.md
Key docs:
docs/backend-architecture-notes.mddocs/enterprise-production-readiness-plan.mddocs/enterprise-hardening-checklist.mddocs/error-codes.mddocs/high-sla-failure-drills.mddocs/runtime-limitations.md
- Use
docs/contributor-one-loop-playbook.mdfor contribution flow and validation expectations. - Keep copyable examples concise and canonical; treat tests, integration scripts, and historical records as validation evidence before shortening them.
- Keep changes scoped, behavior-compatible, and release-gate validated.