Skip to content

managed-pages

Tenant-editable, server-rendered public pages with per-tenant branding. Stores one Markdown page per (tenantId, slug, lang) in the read_pages entity table with a published gate plus description/ogImage SEO meta. Registers an anonymous GET {basePath}/:slug route that resolves the tenant from the request Host via the app-supplied resolveApexTenant, serves only published pages (drafts → 404), renders Markdown through the hardened page-render core, and isolates per-tenant content with Vary: Host. Ships TenantAdmin/SystemAdmin admin screens (entityList + entityEdit) backed by convention CRUD handlers (managed-pages:write:page:{create,update,delete}, managed-pages:query:page:{list,detail}); the app wires nav/workspace onto managed-pages:screen:page-list. Also exposes managed-pages:query:by-tenant-published (anonymous, SQL-filtered on published) for sitemap/discovery consumers such as the seo feature. Branding (via config, scope tenant): branding-{title,description,site-url,accent-color,logo-url,layout-preset} keys with write-time validation (hex color, https URLs), a configEdit self-service screen (managed-pages:screen:branding-settings), and a managed-pages:query:branding read that the render path applies as scoped :root CSS vars + a logo/title header. Also exposes managed-pages:write:set (idempotent slug-keyed upsert, SystemAdmin cross-tenant via tenantIdOverride) as a provisioning API. Requires config + anonymousAccess wired at app bootstrap.

From recipes-managed-pages — the smallest working mount:

import { createConfigFeature } from "@cosmicdrift/kumiko-bundled-features/config";
import {
createManagedPagesCssFeature,
createManagedPagesFeature,
} from "@cosmicdrift/kumiko-bundled-features/managed-pages";
import { SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
// managed-pages declares `r.requires("config")` for its branding keys — the
// config feature must be in the stack (runProdApp auto-mounts it; setupTestStack
// does not, so the recipe lists it explicitly).
export const configFeature = createConfigFeature();
// Single-tenant apex: every request maps to the one system tenant. A multi-
// tenant app resolves the tenant from the request Host (subdomain / custom
// domain) and returns the matching tenantId instead — see README.
export const managedPagesFeature = createManagedPagesFeature({
resolveApexTenant: () => SYSTEM_TENANT_ID,
allowCustomCss: true,
});
// Companion per-tenant toggle for the CSS-inject capability. Compose it and wire
// feature-toggles to gate custom CSS per tier; without a toggle runtime,
// `ctx.hasFeature` fails open and CSS stays on (the render-time sanitizer is the
// safety boundary regardless).
export const managedPagesCssFeature = createManagedPagesCssFeature();

📄 On GitHub: samples/recipes/managed-pages/src/feature.ts

managed-pages feature preview

What this feature needs to run (Requires, top) and the write commands it provides (Provides, bottom).

flowchart TB
  n_managed_pages["managed-pages"]
  subgraph how_reqs["Requires"]
    n_config["config"]
  end
  subgraph how_provides["Provides"]
    n_cmd_managed_pages_write_page_create(["create"])
    n_cmd_managed_pages_write_page_delete(["delete"])
    n_cmd_managed_pages_write_page_update(["update"])
    n_cmd_managed_pages_write_set(["set"])
  end
  n_config --> n_managed_pages
  n_managed_pages --> n_cmd_managed_pages_write_page_create
  n_managed_pages --> n_cmd_managed_pages_write_page_delete
  n_managed_pages --> n_cmd_managed_pages_write_page_update
  n_managed_pages --> n_cmd_managed_pages_write_set

Provides — write commands this feature registers (dispatch them through the command bus):

  • managed-pages:write:page:create
  • managed-pages:write:page:delete
  • managed-pages:write:page:update
  • managed-pages:write:set

Start with recipes-managed-pages for a step-by-step walkthrough with runnable code and integration tests.

  • Requires: config
  • Activation: always on (not toggleable)

Per-tenant config keys, set via the tenant-admin UI or a seed. 🔒 = encrypted at rest.

KeyTypeDefaultScopeWho can writeWho can read
branding-accent-colortext""tenantsystem, TenantAdmin, Admin, SystemAdminall
branding-custom-csstext""tenantTenantAdmin, Admin, SystemAdminall
branding-descriptiontext""tenantsystem, TenantAdmin, Admin, SystemAdminall
branding-layout-presetselect (minimal | centered | wide)centeredtenantsystem, TenantAdmin, Admin, SystemAdminall
branding-logo-urltext""tenantsystem, TenantAdmin, Admin, SystemAdminall
branding-site-urltext""tenantsystem, TenantAdmin, Admin, SystemAdminall
branding-titletext""tenantsystem, TenantAdmin, Admin, SystemAdminall