diff --git a/plans/relations-as-posts.md b/plans/relations-as-posts.md index b259d21b..e723c725 100644 --- a/plans/relations-as-posts.md +++ b/plans/relations-as-posts.md @@ -117,6 +117,42 @@ So the complete picture: the metamodel expresses **structure + validation** of t platform's domain model uniformly; **behaviour composes from the substrate loops**; **integrations stay referenced services**. It's the convergence point of every loop in the repo. +### Types define the UI — the editor maps onto the metamodel + +The payoff of typed fields (Slice 8): **a type drives both sides of the UI from one definition.** +Beyond name + schema, a type carries **fields** `{name, value-type, widget}` and **templates**: + +- **Fields drive the edit UI** — the editor renders one input per field, the widget chosen by the + field's `value-type` (`Date`→date-picker, `URL`→link input, `String`→text, `Image`→uploader). +- **Fields drive the render** — the type's **render template** (a parameterised SX template stored + on the type-post, instantiated with the instance's field-values) references those fields by name. +- An **instance** is then just *field-values* on a post. Add a field to the type → it appears in + the editor *and* the page, **no code touched**. Same definition, both surfaces. + +**"kg-cards become types."** Each Koenig/Ghost card — image, gallery, callout, embed, bookmark, +heading — becomes a **type-post** with fields + a render template. We've already enumerated that +whole vocabulary: `[[project_content_on_sx]]` modelled heading/text/code/quote/image/embed/divider/ +list/table/callout/media as block types — **that list is the seed set of card-types.** "The old +blog posts get typed" = migrate Ghost content into typed blocks, one type-post per block kind. + +**"The editor maps onto the types."** The editor stops being hardcoded card handlers and becomes a +**generic field-editor**: given a type, emit an input per field; on save, store the values; render +through the type's template. A new card = a new type-post, **zero editor code — the editor is +defined by the metamodel.** Proof the pattern works: the edit page's relation-editors are already +*generated* from relation definitions, not hand-coded (one level up from fields). + +Honest layer: the **render template is data** (editable, meta-circular); only the irreducible +**widgets** (the date-picker, the image-uploader) are platform pieces, and `value-type` is what +*selects* the widget — the same decidable-core / fenced-frontier line as everywhere else. + +**Refined build order** (this is what `/meta` is the on-ramp to): +1. `/meta` overview — DONE (the *see*; `host/blog-type-defs` + `host/blog-meta-index`). +2. **Slice 8 — typed fields** `{name, value-type, widget}` on a type — the **keystone** (drives form + template). +3. **Generic instance form** — input per field ("the editor maps onto types"). +4. **Render template per type** — data, field-placeholders. +5. **Cards-as-types + migrate** — seed the card-type vocabulary from content-on-sx; type the old posts. +Plus the editor surfaces on `/meta`: **create-type** / **create-relation** forms, then **clear-and-reseed**. + ## Behaviour as data — lifecycles + ECA over an effect vocabulary (DESIGN — Slice 9) Structure is inert; "place an order / ship goods" is the dynamic part. The principle: