Component Pipeline

CSF → EDU Schema → Puck Config → DSL Config

Architecture Overview

The Configurable Experiences pipeline converts HEN UI component definitions into operator-composable experiences without code changes or deployments. The Component Catalog (EDU Schema) is the canonical owned contract — Puck Config is derived from it at runtime, never authored directly.

hen-ui storiescsf-to-edu-catalog.tsComponentCatalogEntrycreatePuckConfig()Puck Editor*.dsl.jsonPuck <Render>

SAD §4 ADR-1 (Puck adoption) · ADR-2 (Catalog as single owned contract) · SAD §5.1 Component Onboarding Pipeline · SAD §5.4 Runtime Rendering

Pipeline Stages

demo: hen.flex
1

Storybook CSF Story

hen-ui/*.stories.tsx

The source of truth for HEN UI component metadata. Each story file includes parameters.edu (EduCSFParams) with componentId, displayName, description, category, slots, and argTypes for prop definitions. Written by HEN UI developers.

parameters.edu + argTypes
// composites/Flex/Flex.stories.tsx
import type { Meta } from '@storybook/react';
import type { EduCSFParams } from '@/hen-ui/types/edu-csf';
import { Flex } from './Flex';

const meta: Meta<typeof Flex> = {
  title: 'HEN/Layout/Flex',
  component: Flex,
  parameters: {
    edu: {
      componentId: 'hen.flex',
      displayName: 'Flex',
      description: 'Flexbox layout for vertical or horizontal arrangements.',
      category: 'layout',
      excludeProps: ['asChild', 'className', 'ref'],
      slots: { children: {} },
    } satisfies EduCSFParams,
  },
  argTypes: {
    direction: {
      control: 'select',
      options: ['column', 'row'],
      description: 'Flex direction',
    },
    gap: {
      control: 'select',
      options: ['xxs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'],
      description: 'Spacing between children',
    },
  },
};
csf-to-edu-catalog.ts (build-time parser)
2

EDU Component Schema

ComponentCatalogEntry

The canonical owned contract. Serializable JSON — Puck-independent. Generated by the CSF parser, published to EDU-Events (S3) in production. Consumed by the Runtime Adapter, the LLM prompt builder, and Layer 1 validation. Types live in src/lib/catalog/types.ts.

henUiCatalog → hen.flex
{
  "id": "hen.flex",
  "exportName": "Flex",
  "displayName": "Flex",
  "description": "Flexbox layout for vertical or horizontal arrangements. Use for stacking content (column), button groups (row), or tag lists. Supports gap, wrap, align, and justify.",
  "category": "layout",
  "props": {
    "direction": {
      "type": "enum",
      "description": "Flex direction",
      "required": false,
      "enumValues": [
        "column",
        "row"
      ]
    },
    "gap": {
      "type": "enum",
      "description": "Spacing between children",
      "required": false,
      "enumValues": [
        "xxs",
        "xs",
        "sm",
        "md",
        "lg",
        "xl",
        "2xl",
        "3xl"
      ]
    },
    "wrap": {
      "type": "enum",
      "description": "Whether items should wrap",
      "required": false,
      "enumValues": [
        "wrap",
        "nowrap"
      ]
    },
    "align": {
      "type": "enum",
      "description": "Cross-axis alignment (items-*)",
      "required": false,
      "enumValues": [
        "start",
        "center",
        "end",
        "stretch"
      ]
    },
    "justify": {
      "type": "enum",
      "description": "Main-axis alignment (justify-*)",
      "required": false,
      "enumValues": [
        "start",
        "center",
        "end",
        "between"
      ]
    }
  },
  "slots": {
    "children": {}
  }
}
runtime-adapter.tsx → createPuckConfig()
3

Puck Config

createPuckConfig(catalog, renderMap)

A runtime TypeScript object derived from the Catalog by the Runtime Adapter (src/lib/catalog/runtime-adapter.tsx). Maps prop types to Puck field types, resolves slots, wires React components from the hen-ui barrel export. Never stored — always derived at runtime.

Puck Editor → operator composes → onPublish
4

DSL Config (Puck Data JSON)

*.dsl.json → saved-configs/

The operator-authored experience. Pure JSON describing a composed UI. Stored in DynamoDB in production (dsl#entry# / dsl#result# SK prefixes). Consumed by Puck <Render> at runtime in site-publishing. This is the SAD §10.2 DSL Config Storage Schema.

Component Catalog

51 components
ComponentIDCategoryPropsSlotsEvents
Avatarhen.avatarcontent5
Badgehen.badgecontent3
Barhen.barcontent3
Browhen.browcontent3
Buttonhen.buttonform7
Checkboxhen.checkboxform5
Headinghen.headingcontent3
Iconhen.iconcontent6
Imagehen.imagecontent6
Inputhen.inputform8
Labelhen.labelform5children
Linkhen.linkform5
Listhen.listcontent2children
List Itemhen.listItemcontent1
Loading Dotshen.loadingDotscontent1
Navigation Wrapperhen.navigationWrappernavigation2children
Progresshen.progresscontent3
Radiohen.radioform3
Selecthen.selectform6children
Separatorhen.separatorcontent2
Spinnerhen.spinnercontent1
Switchhen.switchform4
Texthen.textcontent5
Brand Cardhen.brandCardcontent0children
Cardhen.cardcontent1children
Carouselhen.carouselcontent2children
Checkbox Buttonhen.checkboxButtonform4
Data Pointhen.dataPointcontent8
Drawerhen.drawercontent3children
Feedback Boxhen.feedbackBoxcontent3children
Flexhen.flexlayout5children
Footerhen.footercontent0children
Gridhen.gridlayout4children
Herohen.herocontent4children
Image Cardhen.imageCardcontent5children
Image Gridhen.imageGridcontent3children
Info Cardhen.infoCardcontent3
Navbarhen.navbarcontent4
Page Sectionhen.pageSectionlayout4children
Property Valuehen.propertyValuecontent5
Sectionhen.sectionlayout5children
Section Headerhen.sectionHeadercontent5
Simple Data Pointhen.simpleDataPointcontent5
Splithen.splitlayout4children
Stat Styleshen.statStylescontent1
Sticky Columnhen.stickyColumnlayout2children
Timelinehen.timelinecontent1children
Tooltiphen.tooltipcontent2children
Value Prophen.valuePropcontent2children
Reference Cardhen.referenceCardcontent5children, footer2
Reference Card Headerhen.referenceCardHeadercontent2

Schema Reference

ComponentCatalogEntry

src/lib/catalog/types.ts · SAD §10.1

interface ComponentCatalogEntry {
  id: string;          // "hen.camelCaseName"
  exportName: string;  // barrel export name
  displayName: string; // editor sidebar label
  description: string; // LLM semantic search
  category: ComponentCategory;
  props: Record<string, CatalogPropDefinition>;
  slots?: Record<string, CatalogSlotDefinition>;
  defaultProps?: Record<string, unknown>;
  events?: Record<string, CatalogEventDefinition>;
}

type ComponentCategory =
  | 'layout' | 'content' | 'form'
  | 'navigation' | 'data';

type CatalogPropType =
  | 'string' | 'number' | 'boolean' | 'enum';

DSL Config (Puck Data)

DynamoDB · SAD §10.2

// DynamoDB Storage Schema
PK: tenantId
SK: dsl#entry#uuid | dsl#result#uuid

Puck Data JSON:
{
  content: Array<{
    type: string;    // ComponentCatalogEntry.exportName
    props: Record<string, unknown>;
  }>;
  root: { props: { title?: string } };
  zones: Record<string, unknown>;
}

// Status lifecycle
status: "draft" → "published"
// Published configs are immutable (MVP)

EduCSFParams

hen-ui/src/types/edu-csf.ts · CSF authoring contract

interface EduCSFParams {
  componentId: string;      // "hen.camelCaseName"
  displayName: string;
  description: string;      // LLM-targeted
  category: EduComponentCategory;
  excludeProps?: string[];   // e.g. ['asChild','ref']
  slots?: Record<string,
    EduSlotDefinition>;      // named slot definitions
  propOverrides?: Record<string,
    EduPropOverride>;
  events?: Record<string,
    string>;                 // event: description
  subComponents?: Record<string,
    EduSubComponent>;
}

Runtime Adapter

src/lib/catalog/runtime-adapter.tsx · SAD §7

// Converts ComponentCatalog → Puck Config
// Never stored — always derived at runtime

function createPuckConfig(
  catalog: ComponentCatalog,
  renderMap: Record<string, ComponentType>
): HenPuckConfig {
  // 1. Map CatalogPropDefinition → Puck field type
  //    string → text | textarea
  //    enum   → select
  //    boolean → radio (Yes/No)
  //    number  → number
  // 2. Map CatalogSlotDefinition → Puck slot field
  // 3. Wire render function from barrel export
  // 4. Group by category for editor sidebar
}

SAD Reference

§4 ADR-1Adopt Puck as composition engine
§4 ADR-2Catalog as single owned contract
§4 ADR-3Tenant-themed preview via iframe CSS injection
§4 ADR-4LLM via Inference Enabler (Pattern B)
§5.1Component Onboarding Pipeline (build-time)
§5.2Experience Authoring (operator-time)
§5.4Runtime Rendering (user-time)
§7Library/Package Design — createPuckConfig()
§10.1Component Catalog Entry Schema (v1)
§10.2DSL Config Storage Schema (DynamoDB)
§17 Phase 1Foundation: catalog → render pipeline
§17 Phase 2Author-time: Puck editor + tenant theme