Amended by 0226: tenant
content types are day one, as data only (decision 6).
Context
Pages, forms, posts and many other authored things share drafts, versions, publishing, slugs, SEO, translation, permissions and search. One package per type would repeat all of that. A generic JSON store for every type would be the “JSONB-for-everything” that 0011 rejects. Tenants also want extra fields on both content and business records (a Student, an Order).Decision
-
CT1 —
@stackra/contentis the free content core. Page, form definition and post are built-in content types sharing drafts, versions, publishing, slugs, SEO, i18n, permissions, search and the document format of 0110. New types are declared in code with@ContentTypein any module. -
CT3 —
@ContentTypeis@Modelplus a trait bundle:HasRevisions,Publishable,Sluggable,HasSeo,Translatable,Searchable,HasCustomFieldsand routes (0096). Each type is a real, typed table generated by gen (0097); there is no generic JSON store. -
The decision rule:
-
CT4 — Built-in content types:
- page, post, form definition, gallery;
- help article, FAQ, announcement, changelog;
- legal document (acceptance feeds consent), testimonial, team member, job posting;
- reusable blocks, remote navigation menus (which feed
@stackra/navigation), redirects and short links.
-
CT2 —
HasCustomFieldsis free and bounded, on content types and on business models. Values live in a side table and are validated by the stored field schema; how many fields a tenant may add is a plan limit enforced through entitlements. - Tenant-defined new content types at runtime are Pro and later, and need their own amendment of 0011 first.
Consequences
- Every content type gets publishing, SEO and search for free, and stays a typed table that migrations and RLS understand.
- The decision rule gives reviewers a test for “should this be content”.
- Custom fields add a side-table join to reads; search and list filtering must learn about them.
Enforcement
Planned: the gen validation pass fails a@ContentType that also declares a state machine or money field without the
domain-model form, and a HasCustomFields model with no entitlement limit key. Nothing checks this today.