# Jade CMS Jade is Kabeli's lightweight, multi-tenant headless CMS for structuring content, managing drafts and assets, and delivering published entries through clean APIs. ## Product Summary Jade CMS is a lightweight, multi-tenant headless CMS by Kabeli. It gives each client or organization a clean workspace for users, roles, sites, content collections, entries, assets, API keys, and operational history. It is designed for blogs, websites, documentation, internal tools, and other content-backed products that need structured content without a heavyweight CMS. ## Capabilities - Organize: Keep every client, site, and content type in a predictable place. Multi-site context (Organizations, sites, users, and roles stay scoped.); Collection builder (Create pages, posts, reports, teams, and custom records.) - Operate: Give editors the everyday publishing tools they actually need. Drafts (Keep drafts private until content is approved.); Assets (Store files as portable CMS records.) - Secure + deliver: Publish clean content without losing control of who can change it. APIs (Serve published JSON with scoped keys.); Access (Roles, scopes, and audit history are built in.) ## Operating Principles - Every tenant-owned record carries workspace context. - CRUD stays boring before workflow gets clever. - Draft data and public responses remain separate. - Storage providers never become the content collection. ## Delivery Approach - Publish: Only approved entries and asset metadata become public. - Preview: Drafts stay behind scoped preview access. - Render: Websites and apps choose the routes, layout, and components. ## Audiences - Editors: Clear workspace context, draft states, media, and content forms that do not require touching code. - Workspace owners: Roles, API keys, activity, publishing history, and a CMS foundation that can serve more than one site. - Developers: Stable endpoints, scoped credentials, predictable payloads, and content that stays portable. ## Public Pages - https://jade.kabeli.org/: Product overview for Jade CMS. - https://jade.kabeli.org/docs: Developer documentation overview. - https://jade.kabeli.org/docs/api: Public content API reference. - https://jade.kabeli.org/docs/storage: Cloudflare R2 and asset-library setup. - https://jade.kabeli.org/docs/agents: Agentic coding and LLM integration guide. - https://kabeli.org/book-a-demo: Demo request page for teams evaluating Jade. ## API Contract Public base URL: https://jade.kabeli.org/api/public/v1 Management base URL: https://jade.kabeli.org/api/management/v1 Authentication: - Authorization: Bearer - X-API-Key: - api_key query parameter is accepted when headers are not practical. Behavior: - The public API is GET-only. - The management API also exposes project asset listing, upload, and delete for trusted integrations. - API keys are scoped to one workspace. - API keys are restricted by scopes: content:read, forms:submit, collections:read, collections:write, content:write, assets:read, assets:write. - Write scopes satisfy the matching read scope. - Public document endpoints return published documents only. - Management document endpoints can read drafts and published documents. - Document list endpoints return entries in the persistent collection order and expose each entry's `sort_order`. - Browser requests are allowed only when the request Origin matches the API key allowed origins. A blank allowed-origin list permits any browser origin. - Server-side requests usually do not send an Origin header and should store API keys in server-side environment variables. - Superadmins can lock API keys so non-superadmins cannot roll or delete them. Public endpoints: - GET /projects - GET /projects/{projectSlug}/collections - GET /projects/{projectSlug}/collections/{collectionSlug} - GET /projects/{projectSlug}/collections/{collectionSlug}/documents?limit=20&offset=0 - GET /projects/{projectSlug}/collections/{collectionSlug}/documents/{documentId} - POST /projects/{projectSlug}/forms/{formSlug}/submissions Management endpoints: - GET/POST /projects/{projectId}/collections - GET/PATCH/DELETE /collections/{collectionId} - GET/POST /collections/{collectionId}/fields - GET/PATCH /collection-fields/{fieldId} - POST /collection-fields/{fieldId}/archive - GET/POST /collections/{collectionId}/documents - GET/PATCH/DELETE /documents/{documentId} - GET /documents/{documentId}/translations - GET/PUT /documents/{documentId}/translations/{locale} - GET /projects/{projectId}/assets?search=hero - POST /projects/{projectId}/assets?filename=hero.png - DELETE /assets/{assetId} Collection field value shapes: - Create a repeatable field with `field_type: "list"`. - Set `settings.item_type` to `"text"` for `string[]` values. - Set `settings.item_type` to `"key_value"` for `{ "title": string, "key": string }[]` values. - List item format is fixed after field creation; create a new field to change the shape. - Text-list example: `{"learning_goals":["Understand agroecology principles","Practice observation-led learning"]}`. - Title/key-list example: `{"field_modules":[{"title":"Learning goals","key":"learning_goals"}]}`. - Lists cannot mix strings and objects. Key/value objects must contain exactly `title` and `key`, both non-empty strings. Authenticated asset and storage routes: - GET /workspaces/{workspaceId}/storage-settings (workspace owner/admin) - PATCH /workspaces/{workspaceId}/storage-settings (workspace owner/admin) - GET /projects/{projectId}/assets?search=hero (management API, assets:read) - POST /projects/{projectId}/assets?filename=hero.png (management API, assets:write) - DELETE /assets/{assetId} (management API, assets:write) Asset storage rules: - Workspace storage settings support Cloudflare R2 and S3-compatible providers. - For R2, the default private S3 endpoint is https://.r2.cloudflarestorage.com and the signing region is auto. - endpoint_url is for backend upload/delete requests. asset_base_url is the browser-facing delivery URL. Never swap them or expose R2 credentials to a browser. - Use an R2 custom domain for production delivery. The managed r2.dev URL is rate-limited and intended for development or low-volume temporary access. - The asset library is project-scoped. Media fields select or upload assets from that project's library and store the asset object in document data. - Current limitations: no signed private URLs, dimensions/checksums, soft deletion/recovery, reference-aware deletion, or presigned direct-to-R2 browser uploads. Localization: - Locales belong to a project. The project always has a default locale, which is the fallback language. - One content document has one stable document ID across all translations. - POST /collections/{collectionId}/documents creates one document identity and its first translation. Send values for one locale only. - To add or replace Nepali on that same content item, call PUT /documents/{documentId}/translations/ne-NP with the same document ID. - The PUT body is {"status":"draft|published","data":{...}}. The data object must contain only the selected locale's values. - GET /documents/{documentId}/translations lists enabled locales, their translation status, and which one is_default. - GET /documents/{documentId}/translations/{locale} reads one locale and returns the same document ID. - Public reads accept ?locale=ne-NP. Missing or empty published localized fields fall back per field to the published default-locale value. - Management responses expose requested_locale, translation_status, available_locales, and fallback_fields. - Do not POST a second document with locale=ne-NP when you mean to create a translation. Error model: - 401: API key missing or invalid. - 403: Origin is not allowed for this key, or the key lacks the required scope. - 404: Project, collection, field, or document was not found. - 422: Request parameters failed validation. Agent instructions: - Use https://jade.kabeli.org/docs/agents as the source of truth for coding-agent workflows. - Do not call private /api/workspaces, /api/collections, /api/documents, or session endpoints from public sites. - Use /api/management/v1 only for trusted schema or content writers with write-scoped keys. - Prefer server-side fetching with Authorization: Bearer process.env.JADE_API_KEY. - Never expose collections:write or content:write keys to browser bundles. - Keep unknown custom fields under document.data. - Generate local TypeScript types from collection metadata when possible. ## Contact and Ownership - Product: Jade CMS - Builder: Kabeli Kuna - Primary domain: https://jade.kabeli.org - Email: info@kabeli.org