{
  "id": "docs-page",
  "meta": {
    "title": "OlonJS Architecture Specifications v1.3",
    "description": "Mandatory Standard — Sovereign Core Edition. Architecture, Studio/ICE UX, Path-Deterministic Nested Editing."
  },
  "slug": "docs",
  "sections": [
    {
      "id": "docs-main",
      "data": {
        "content": "# OlonJS Architecture Specifications v1.6 Draft\n\n**Status:** Draft\\\n**Version:** 1.6.0 (Complete Draft - Core-Agnostic Theme Transport, Shell/Menu Contract Clarification, Full v1.5 Consolidation)\\\n**Target:** Senior Architects / AI Agents / Enterprise Governance\n\n**Scope v1.6:** This edition is intended as a complete replacement specification, not as an addendum. It preserves the valid architecture of v1.5 while correcting the parts that could mislead agents or implementers. It keeps the full architecture surface (MTRP, JSP, TBP, CIP, ECIP, IDAC, TOCC, BSDS, ASC, JEB, JAP, Appendix A) and clarifies three architectural laws that were under-specified before: Core theme agnosticism, explicit theme flattening/publication, and `menu.json` as the source of truth for menu structures.\n\n**Primary v1.6 clarifications:**\n\n- `@olonjs/core` is a token transporter/publisher, not the semantic authority for tenant theme vocabulary\n- theme flattening is explicit and normative\n- tenant theme sovereignty is explicit\n- `menu.json` is the source of truth for menu structures\n- `site.json` owns shell structure and shell instance declaration\n- `header` and `footer` are shell-scoped section instances, not conceptually reserved types\n- normative companion JSON Schemas are defined for `site.json` and `menu.json`\n\n**Scope note:** v1.6 does not freeze every current runtime compatibility shortcut as architectural law. Where runtime adapters or compatibility branches exist, architecture takes precedence.\n\n---\n\n## 1. Modular Type Registry Pattern (MTRP) v1.3\n\n**Objective:** Establish a strictly typed, open-ended protocol for extending content data structures where the Core engine is the orchestrator and the Tenant is the provider.\n\n### 1.1 The Sovereign Dependency Inversion\n\nThe Core defines empty registries. Tenant injects concrete definitions using module augmentation.\n\nThis allows Core to be distributed as a compiled NPM package while remaining aware of tenant-specific types at compile time.\n\n### 1.2 Technical Implementation (`@olonjs/core/kernel`)\n\n```typescript\nexport interface SectionDataRegistry {} // Augmented by Tenant\nexport interface SectionSettingsRegistry {} // Augmented by Tenant\n\nexport interface BaseSection<K extends keyof SectionDataRegistry> {\n  id: string;\n  type: K;\n  data: SectionDataRegistry[K];\n  settings?: K extends keyof SectionSettingsRegistry\n    ? SectionSettingsRegistry[K]\n    : BaseSectionSettings;\n}\n\nexport type Section = {\n  [K in keyof SectionDataRegistry]: BaseSection<K>\n}[keyof SectionDataRegistry];\n```\n\nCore exports or allows the tenant to infer `SectionType` as `keyof SectionDataRegistry`. After tenant augmentation this becomes the union of all supported section keys.\n\n### 1.3 Architectural Rule\n\nCore must remain open to tenant augmentation. Tenant-specific section types must not require Core source edits.\n\n**Why it matters:** MTRP is the foundation that allows one Core engine to serve many tenants while preserving end-to-end type safety.\n\n---\n\n## 2. JsonPages Site Protocol (JSP) v1.9\n\n**Objective:** Define deterministic content/config topology and the site-level document contract.\n\n### 2.1 The File System Ontology\n\nEvery tenant should expose a deterministic content/config silo:\n\n- `src/data/config/site.json`\n- `src/data/config/menu.json`\n- `src/data/config/theme.json`\n- `src/data/pages/**/*.json`\n\nThe CLI or projection workflow may use different physical staging paths, but the runtime contract remains that the app receives `siteConfig`, `menuConfig`, `themeConfig`, `pages`, and optional `refDocuments`.\n\n### 2.2 Source Of Truth Separation\n\nThe canonical tenant document responsibilities are:\n\n- `site.json` -&gt; site identity, shell structure, shell-scoped section instances, page listing metadata\n- `menu.json` -&gt; menu trees and named menu collections\n- `theme.json` -&gt; theme token source of truth\n- `pages/**/*.json` -&gt; page-scoped content sections\n\n### 2.3 Menu Source Of Truth Rule\n\n`menu.json` is the source of truth for menu data.\n\nShell components may consume menu data. Shell components must not be treated as the authoritative source of menu structure.\n\n### 2.4 Shell Binding Rule\n\nIf a shell component uses menu data, it should bind to `menu.json` through `data.menu.$ref`.\n\nCanonical rule:\n\n### 2.5 Bound External Field Rule\n\nIf an authored field contains a `$ref` to an external document, that field is a binding field, not an ownership field.\n\nCanonical consequences:\n\n- the authored document keeps the binding expression\n- the referenced document remains the owner of the bound data\n- Studio may present the resolved value in Inspector as if it were local\n- draft mutation and persistence must target the referenced owner document, not the binding document\n- the binding document must not be canonically materialized with the resolved payload during save\n\nExample:\n\n- `site.json -> header.data.menu.$ref -> ../config/menu.json#/main`\n\n- Inspector may render `header.data.menu` as concrete `MenuItem[]`\n\n- edits must update `menu.json.main`\n\n- `site.json` must keep `data.menu.$ref`\n\n- no menu -&gt; omit the field\n\n- has menu -&gt; use `$ref`\n\n### 2.5 Deterministic Projection\n\nTenant generation and scaffolding should preserve deterministic paths for:\n\n- config documents\n- page documents\n- component capsules\n- registries\n- schemas\n\nCanonical projection workflow:\n\n1. Infra projection generates the shell files such as `package.json`, `tsconfig.json`, and `vite.config.ts`\n2. Source projection reconstructs the tenant DNA under `src/`\n3. Dependency resolution pins the expected runtime/build stack for the tenant\n\nThe exact tool implementation may evolve, but the projection result must remain deterministic enough that agents and tooling can rediscover the same contract surfaces without heuristic scanning.\n\n**Why it matters:** JSP gives agents and tooling stable paths for discovery, projection, validation, and migration.\n\n---\n\n## 3. Tenant Block Protocol (TBP) v1.1\n\n**Objective:** Standardize the capsule structure for tenant section/component types.\n\n### 3.1 The Atomic Capsule Structure\n\nComponents are self-contained directories under `src/components/<sectionType>/`:\n\n- `View.tsx` -&gt; pure React component\n- `schema.ts` -&gt; Zod schema(s) for the data contract and optionally settings\n- `types.ts` -&gt; TypeScript interfaces inferred from the schema\n- `index.ts` -&gt; public API re-exporting View, schema(s), and types\n\n`schema.ts` must export at least one data schema for the type. Data schema should extend `BaseSectionData`. Array items should extend `BaseArrayItem`.\n\n### 3.2 Shell-Scoped Section Instances\n\n`header` and `footer` are not conceptually reserved types.\n\nThey are ordinary tenant section/component types whose instances are declared in `site.json` instead of page JSON.\n\nThey therefore share:\n\n- the same component model\n- the same schema-driven contract style\n- the same compositional principles\n\nThey differ only in:\n\n- data placement\n- rendering scope\n\nThey also participate in two distinct contracts that must not be conflated:\n\n- authored shell config contract in `site.json`, where menu usage is expressed as `data.menu.$ref`\n- resolved runtime props contract, where a shell component may receive concrete `MenuItem[]` after resolution\n\n### 3.3 Runtime Special Handling\n\nCore may render shell-scoped instances specially in the global shell path. This is a runtime/layout concern, not a separate ontological category of section type.\n\n**Why it matters:** TBP keeps extension uniform and prevents shell components from becoming a hidden second component system.\n\n---\n\n## 4. Component Implementation Protocol (CIP) v1.7\n\n**Objective:** Ensure system-wide stability, theme portability, and Admin UI integrity.\n\n### 4.1 The Sovereign View Law\n\nComponents receive `data` and `settings` and return JSX. Shell-scoped instances may receive additional resolved props such as resolved menu trees when the shell binding contract requires it.\n\nViews are metadata-blind:\n\n- they do not import Zod schemas\n- they do not embed form logic\n- they do not become the semantic authority for tenant theme vocabulary\n\n### 4.2 Z-Index Neutrality\n\nComponents must not use `z-index > 1` for ordinary section content. Layout delegation such as sticky or fixed behavior belongs to the renderer/shell contract, not to arbitrary page sections.\n\nDocumented exceptions may exist for shell chrome such as header/footer, but they must remain compatible with overlay visibility.\n\n### 4.3 Agnostic Asset Protocol\n\nUse `resolveAssetUrl(path, tenantId)` for all tenant media. Resolved URLs are published under `/assets/...`.\n\n### 4.4 Local Design Tokens\n\n**Objective:** Standardize how a section consumes tenant theme values without leaking global styling assumptions into section implementation.\n\n#### 4.4.1 Theme Source Of Truth\n\nFor themed tenants, `theme.json` is the tenant-level source of truth for theme tokens.\n\nThe tenant decides:\n\n- which token groups exist\n- which token names exist\n- which semantic vocabulary is used\n- how those tokens are bridged into semantic CSS and utilities\n\nCore and section Views are read-only consumers of that contract.\n\n#### 4.4.2 Core Theme Transport Rule\n\n`@olonjs/core` is a token transporter/publisher, not a semantic authority.\n\nThat means:\n\n- Core reads `theme.json`\n- Core recursively flattens discovered token paths\n- Core publishes those values as CSS custom properties before section rendering\n- Core may expose convenience aliases\n- Core must not govern or restrict the tenant semantic vocabulary\n\nIf a tenant token tree is flattenable, Core should publish it.\n\n#### 4.4.3 The Required Layered Chain\n\nFor any section that controls background, text color, border color, accent color, or radii, the following chain is normative:\n\n1. Tenant theme source of truth in `theme.json`\n2. Runtime theme publication through flattened CSS custom properties\n3. Tenant semantic bridge in global CSS such as `:root` and `@theme`\n4. Section-local scope through `--local-*` variables when the section owns those concerns\n5. Rendered utilities/classes consuming the local or tenant semantic layer\n\nCanonical chain:\n\n`theme.json -> published runtime vars -> tenant semantic bridge -> section --local-* -> JSX classes`\n\n#### 4.4.4 Flattening Rule\n\nNormative rule:\n\n`theme.json object path -> kebab-case path segments -> --theme-... CSS variable`\n\nExamples:\n\n- `tokens.colors.primary` -&gt; `--theme-colors-primary`\n- `tokens.typography.fontFamily.display` -&gt; `--theme-typography-font-family-display`\n- `tokens.typography.tracking.tight` -&gt; `--theme-typography-tracking-tight`\n- `tokens.borderRadius.md` -&gt; `--theme-border-radius-md`\n- `tokens.spacing.container-max` -&gt; `--theme-spacing-container-max`\n- `tokens.modes.light.colors.background` -&gt; `--theme-modes-light-colors-background`\n\nThis flattening rule is architectural law and must not be inferred indirectly by agents.\n\n#### 4.4.5 Runtime Theme Publication\n\nRuntime publication is mandatory for themed tenants.\n\nThe compliant bridge is a layered architecture typically implemented in tenant `index.css`:\n\n`theme.json -> engine injection -> :root bridge -> @theme bridge -> JSX classes`\n\nLayer roles:\n\n- engine injection publishes flattened `--theme-*` variables\n- `:root` bridge maps published runtime variables into tenant semantic names\n- `@theme` bridge exposes those names to Tailwind or equivalent utilities\n- section-local `--local-*` variables scope owned concerns to a section root\n\nConcrete bridge examples:\n\nLayer 0 - Engine injection:\n\nJSON path Injected CSS var `tokens.colors.{name}` `--theme-colors-{name}` `tokens.typography.fontFamily.{role}` `--theme-font-{role}` `tokens.typography.scale.{step}` `--theme-typography-scale-{step}` `tokens.typography.tracking.{name}` `--theme-typography-tracking-{name}` `tokens.typography.leading.{name}` `--theme-typography-leading-{name}` `tokens.typography.wordmark.*` `--theme-typography-wordmark-*` `tokens.borderRadius.{name}` `--theme-border-radius-{name}` `tokens.spacing.{name}` `--theme-spacing-{name}` `tokens.zIndex.{name}` `--theme-z-index-{name}` `tokens.modes.{mode}.colors.{name}` `--theme-modes-{mode}-colors-{name}`\n\nLayer 1 - Tenant semantic bridge:\n\n```css\n:root {\n  --background: var(--theme-colors-background);\n  --foreground: var(--theme-colors-foreground);\n  --card: var(--theme-colors-card);\n  --primary: var(--theme-colors-primary);\n  --border: var(--theme-colors-border);\n\n  --font-primary: var(--theme-font-primary);\n  --font-display: var(--theme-font-display);\n\n  --theme-container-max: var(--theme-spacing-container-max);\n  --z-overlay: var(--theme-z-index-overlay);\n}\n```\n\nLayer 2 - `@theme` bridge:\n\n```css\n@theme {\n  --color-background: var(--background);\n  --color-foreground: var(--foreground);\n  --color-card: var(--card);\n  --color-primary: var(--primary);\n  --color-border: var(--border);\n\n  --font-primary: var(--font-primary);\n  --font-display: var(--font-display);\n\n  --radius-md: var(--theme-radius-md);\n  --radius-lg: var(--theme-radius-lg);\n}\n```\n\nAdditional modes should override the Layer 1 semantic bridge, for example under `[data-theme=\\\"light\\\"]`, while leaving Layer 2 unchanged.\n\nRule:\n\n- skipping Layer 2 breaks utility resolution\n- skipping Layer 1 couples sections to engine-internal naming\n- hardcoding values in any bridge layer is non-compliant\n\n#### 4.4.6 Alias Rule\n\nAliases such as:\n\n- `--theme-font-primary`\n- `--theme-font-display`\n- `--theme-radius-md`\n\nare conveniences only.\n\nThey do not redefine tenant vocabulary ownership and must not be mistaken for the canonical contract.\n\n#### 4.4.7 Tenant Semantic Bridge\n\nThe tenant owns the bridge from published runtime vars into:\n\n- `:root` semantic variables\n- Tailwind `@theme` variables\n- section-local `--local-*` variables\n- utility classes\n\nThe naming in this bridge is the tenant's sovereign choice. Core does not impose semantic names such as `foreground`, `card`, or `muted-foreground`.\n\n#### 4.4.8 Local Token Consumption Rule\n\nIf a section visually owns background, text, border, accent, or radius concerns, it must not bypass local scoping for those concerns.\n\nRequired pattern:\n\n- section root defines `--local-*` variables for owned color/radius concerns\n- child utilities consume `var(--local-*)`\n\nDirectly using global theme variables throughout JSX for section-owned concerns is non-canonical for a fully themed section.\n\n#### 4.4.9 Typography Rule\n\nTypography follows the same source-of-truth rule, but local scoping is optional unless the section truly remaps typography locally.\n\nCanonical typography chain:\n\n`theme.json -> published runtime vars -> tenant semantic font bridge -> utility or CSS variable -> JSX typography`\n\n#### 4.4.10 Allowed Exceptions\n\nThe following are acceptable if documented and intentionally limited:\n\n- tiny decorative one-off values that are not part of the tenant theme contract\n- temporary migration shims where the compliant path still exists and is primary\n- semantic alias bridges in tenant CSS whose source remains the published theme layer\n\n#### 4.4.11 Non-Compliant Patterns\n\nThe following are non-compliant:\n\n- reading `theme.json` directly inside a View\n- hardcoding primary themed values in JSX or section-local inline styles\n- using `rounded-[7px]`, `bg-blue-500`, `text-zinc-100`, or similar literals as the primary themed contract\n- defining `--local-*` at the root and then bypassing them with raw global utilities for the same owned concerns\n- treating tenant-specific extension keys as a replacement for the tenant's own primary semantic contract\n\n#### 4.4.12 Practical Interpretation\n\n`--local-*` is not the source of truth. It is the section-local scoping layer between tenant theme publication and section rendering.\n\n### 4.5 Z-Index & Overlay Governance\n\nSection content roots must remain at `z-index <= 1` so the Studio overlay can remain authoritative. Shell-scoped instances may use higher values only as documented shell exceptions.\n\n**Why it matters:** View components stay dumb and portable, themed tenants remain reproducible, and Studio overlay behavior remains deterministic.\n\n---\n\n## 5. Editor Component Implementation Protocol (ECIP) v1.6\n\n**Objective:** Standardize the schema-driven editing contract used by Studio tooling.\n\n### 5.1 Recursive Form Factory\n\nThe Admin UI builds forms by traversing the Zod ontology rather than hardcoding per-type editor implementations.\n\n### 5.2 UI Metadata\n\nSchema descriptions may encode UI metadata using `.describe('ui:...')`. This is the contract by which the Form Factory chooses widgets.\n\n### 5.3 Deterministic IDs\n\nEvery object in an editable `ZodArray` must extend `BaseArrayItem` or otherwise include stable `id`. This guarantees React reconciliation stability during reorder/delete flows.\n\n### 5.4 UI Metadata Vocabulary\n\nStandard keys for the Form Factory are:\n\nKey Use case `ui:text` Single-line text input `ui:textarea` Multi-line text `ui:select` Enum or single choice `ui:number` Numeric input `ui:list` Array editor with add/remove/reorder `ui:icon-picker` Icon selection via tenant-registered icon registry\n\nUnknown keys may be treated as `ui:text`.\n\n#### `ui:icon-picker` — Tenant Icon Registry Contract\n\nThe icon picker is **empty by default**. Core does not ship any hardcoded icons.\n\nThe tenant must pass an `iconRegistry` in `JsonPagesConfig` at bootstrap:\n\n```typescript\n// App.tsx\nconst config: JsonPagesConfig = {\n  // ...\n  iconRegistry: iconMap, // Record<string, LucideIcon> from tenant IconResolver\n};\n```\n\nCore provides `iconRegistry` via `IconRegistryContext`. The Form Factory reads this context and renders only the tenant-registered icons in the picker dialog.\n\n**Tenant responsibility:** declare all usable icons in `src/lib/IconResolver.tsx` and export `iconMap`. Pass it to `JsonPagesConfig.iconRegistry`. If `iconRegistry` is empty or not provided, the picker renders no options.\n\n### 5.5 Path-Only Nested Selection & Expansion\n\nIn strict nested editing behavior, nested targets are represented by path segments from root to leaf:\n\n```typescript\nexport type SelectionPathSegment = { fieldKey: string; itemId?: string };\nexport type SelectionPath = SelectionPathSegment[];\n```\n\nRules:\n\n- expansion and focus for nested arrays must be computed from `SelectionPath`\n- matching by `fieldKey` alone is non-compliant for nested structures\n- legacy flat payload fields such as `itemField` and `itemId` are not the normative nested protocol\n\n**Why it matters:** ECIP keeps the editor machine-discoverable and prevents nested arrays from opening the wrong branch or mutating the wrong node.\n\n---\n\n## 6. ICE Data Attribute Contract (IDAC) v1.2\n\n**Objective:** Mandatory data attributes so Stage and Inspector can bind selection and field/item editing without coupling to tenant DOM structure.\n\n### 6.1 Section-Level Markup\n\n`SectionRenderer` or equivalent Core shell wrapper provides:\n\n- `data-section-id` for the section instance identity\n- a sibling overlay element using `data-jp-section-overlay`\n\nTenant Views render the content root inside the Core wrapper.\n\n### 6.2 Field-Level Binding\n\nFor every editable scalar field, the View must attach:\n\n- `data-jp-field=\"<fieldKey>\"`\n\nThe field key must match the schema/data path such as `title`, `description`, `label`, or `sectionTitle`.\n\n### 6.3 Array-Item Binding\n\nFor every editable array item, the View must attach:\n\n- `data-jp-item-id=\"<stableId>\"`\n- `data-jp-item-field=\"<arrayKey>\"`\n\nThe preferred source of identity is `item.id`. Index fallback is non-canonical in strict editable object arrays.\n\n### 6.4 Compliance\n\nAll editable Stage content that participates in Studio editing must implement field and array-item bindings. Shell-scoped instances may omit these bindings only when they are out of editing scope for the current Studio surface.\n\n### 6.5 Strict Path Extraction For Nested Arrays\n\nFor nested array targets, the runtime selection target is expressed as `SelectionPath` from root to leaf.\n\nRules:\n\n- flat identity is not sufficient for nested structures\n- nested editable object arrays require stable item identity\n- path derivation must remain deterministic from DOM bindings and item identity\n\n**Why it matters:** IDAC is the bridge between tenant DOM and Studio orchestration. Without it, Stage clicks and Inspector focus become guesswork.\n\n---\n\n## 7. Tenant Overlay CSS Contract (TOCC) v1.1\n\n**Objective:** The Stage iframe loads tenant HTML/CSS. Core injects overlay markup but does not own tenant overlay visuals.\n\n### 7.1 Required Selectors\n\nTenant global CSS must style at least:\n\n1. `[data-jp-section-overlay]` as absolute overlay shell with transparent base state\n2. `[data-section-id]:hover [data-jp-section-overlay]` for hover state\n3. `[data-section-id][data-jp-selected] [data-jp-section-overlay]` for selected state\n4. `[data-jp-section-overlay] > div` for the type label\n\n### 7.2 Z-Index\n\nOverlay z-index must remain above section content and consistent with CIP overlay governance.\n\n### 7.3 Responsibility Split\n\n- Core injects wrapper, overlay DOM, and selection state\n- Tenant owns overlay appearance through CSS\n\n**Why it matters:** Without TOCC, selection rings and type labels are structurally present but visually absent.\n\n---\n\n## 8. Base Section Data & Settings (BSDS) v1.1\n\n**Objective:** Standardize base schema fragments for anchors, array items, and section settings.\n\n### 8.1 BaseSectionData\n\nEvery section data schema must extend a base with at least:\n\n- `anchorId?: string`\n\nCanonical Zod:\n\n```typescript\nexport const BaseSectionData = z.object({\n  anchorId: z.string().optional().describe('ui:text'),\n});\n```\n\n### 8.2 BaseArrayItem\n\nEvery array item schema editable in the Inspector must include:\n\n- `id?: string`\n\nCanonical Zod:\n\n```typescript\nexport const BaseArrayItem = z.object({\n  id: z.string().optional(),\n});\n```\n\nRecommended: generate stable UUIDs for newly created items.\n\n### 8.3 BaseSectionSettings\n\nCommon section-level settings may be defined once and extended by capsules.\n\nCanonical example:\n\n```typescript\nexport const BaseSectionSettingsSchema = z.object({\n  paddingTop: z.enum(['none', 'sm', 'md', 'lg', 'xl', '2xl']).default('md').describe('ui:select'),\n  paddingBottom: z.enum(['none', 'sm', 'md', 'lg', 'xl', '2xl']).default('md').describe('ui:select'),\n  theme: z.enum(['dark', 'light', 'accent']).default('dark').describe('ui:select'),\n  container: z.enum(['boxed', 'fluid']).default('boxed').describe('ui:select'),\n});\n```\n\n**Why it matters:** Shared base fragments keep capsules aligned and make validation, add-section defaults, and Inspector behavior deterministic.\n\n---\n\n## 9. AddSectionConfig (ASC) v1.1\n\n**Objective:** Formalize the Add Section contract used by Studio.\n\nCore-facing type:\n\n```typescript\ninterface AddSectionConfig {\n  addableSectionTypes: readonly string[];\n  sectionTypeLabels: Record<string, string>;\n  getDefaultSectionData(sectionType: string): Record<string, unknown>;\n}\n```\n\nRequired shape:\n\n- `addableSectionTypes` lists addable section type keys\n- `sectionTypeLabels` maps type keys to display labels\n- `getDefaultSectionData(type)` returns valid default data for a new section\n\nCore creates a new section with deterministic UUID, type, and default data.\n\n**Why it matters:** ASC gives Studio a deterministic add-section library without hardcoding tenant knowledge into Core.\n\n---\n\n## 10. JsonPagesConfig & Engine Bootstrap (JEB) v1.2\n\n**Objective:** Define the bootstrap contract between tenant app and `JsonPagesEngine`.\n\n### 10.1 JsonPagesConfig\n\nThe tenant passes a single config object to `JsonPagesEngine`. Required fields are:\n\nField Type Description `tenantId` string Used by asset resolution and runtime tenant identity `registry` `{ [K in SectionType]: React.FC<SectionComponentPropsMap[K]> }` Component registry matching MTRP keys `schemas` `Record<SectionType, ZodType>` Data schema aggregate used by the Form Factory `pages` `Record<string, PageConfig>` Slug to page config map `siteConfig` `SiteConfig` Site identity and shell instance declarations `themeConfig` `ThemeConfig` Tenant theme source of truth `menuConfig` `MenuConfig` Menu document payload and bootstrap resolver surface `refDocuments` `Record<string, unknown>` optional Extra JSON documents available to `$ref` resolution `themeCss` `{ tenant: string }` Tenant CSS bridge data for Stage/runtime injection `addSection` `AddSectionConfig` Add-section configuration\n\n### 10.2 JsonPagesEngine\n\n`<JsonPagesEngine config={config} />` owns:\n\n- route to page resolution\n- section rendering orchestration\n- runtime config resolution\n- Studio shell integration\n- wrapper/overlay injection for editable sections\n\nTenant does not reimplement the shell.\n\n### 10.3 Runtime Config Resolution\n\nThe engine may combine:\n\n- page documents\n- authored config drafts (`siteConfig`, `themeConfig`, `menuConfig`, page drafts)\n- referenced documents from the local JSON graph and optional `refDocuments`\n\nThis is what allows shell bindings and document indirection to resolve before rendering.\n\nResolution precedence rule:\n\n- active mutable drafts take precedence over bootstrap/reference inputs\n- `refDocuments` act as initial resolution/bootstrap sources unless a mutable draft for the same document is present\n\n### 10.3.1 RefDocuments Bootstrap Rule\n\n`refDocuments` are bootstrap and reference-resolution inputs.\n\nThey may provide the initial external JSON documents used to resolve authored `$ref` bindings at runtime or at Studio startup.\n\nThey are not, by themselves, the mutable source of truth for an active Studio editing session.\n\nWhen Studio creates a mutable draft for a referenced document, that draft takes precedence over the corresponding `refDocuments` entry for subsequent resolution and editing.\n\nWhy it matters: without this rule, Studio may resolve a referenced field from a stale bootstrap snapshot instead of from the active mutable document draft.\n\n### 10.4 Menu Binding Clarification\n\n`menu.json` remains the source of truth for menu structures. `menuConfig` in bootstrap is the resolved menu document surface passed into the engine.\n\nShell instances do not become menu owners because bootstrap includes `menuConfig`.\n\n**Why it matters:** JEB is the runtime boundary between sovereign tenant data and Core orchestration.\n\n---\n\n# OlonJS Admin Protocol (JAP) v1.3\n\n**Objective:** Deterministic orchestration of the Studio environment.\n\n## 1. The Sovereign Shell Topology\n\nThe Admin interface is a sovereign shell from `@olonjs/core`.\n\n1. The Stage is an isolated iframe using postMessage and IDAC bindings\n2. The Inspector consumes tenant schemas to generate editors\n3. Studio actions orchestrate save, hot save, add, reorder, and delete flows\n\n## 2. State Orchestration & Persistence\n\n- Working Draft holds reactive local state for unsaved changes\n- Inspector changes propagate into Working Draft and then Stage synchronization\n- persistence channels are explicit callbacks rather than implicit file mutation on every keystroke\n\n## 3. Context Switching\n\n- shell-scoped selection enters global mode and maps to `site.json`\n- page-local selection enters page mode and maps to the current page document\n\n## 4. Section Lifecycle Management\n\n1. Add Section uses `AddSectionConfig`\n2. Reorder mutates the working draft array deterministically\n3. Delete removes the section and clears invalid selection\n\n## 5. Stage Isolation & Overlay\n\n- Stage runs in an iframe so tenant CSS does not leak into Admin chrome\n- overlay markup is injected by Core\n- overlay appearance is styled by the tenant per TOCC\n\n## 6. Green Build Validation\n\nStudio and supporting build flows must remain compatible with a green `tsc && vite build` standard.\n\n## 7. Path-Deterministic Selection & Sidebar Expansion\n\n- section and nested focus synchronization uses path segments for nested targets\n- sidebar expansion state for nested arrays derives from the full root-to-leaf path\n- flat-only heuristics are non-compliant for nested structures\n\n**Why it matters:** JAP keeps editing deterministic across shell and page scopes without collapsing Studio into tenant-specific admin logic.\n\n---\n\n## Compliance Model\n\nv1.6 distinguishes between:\n\n- architectural law\n- current implementation limitations\n- tenant drift\n\nAgents and implementers must not treat narrow runtime shortcuts as final architectural law when the spec states otherwise.\n\nDimension Transitional / Narrow Implementation Full v1.6 Architecture ICE binding Missing or partial `data-jp-*` coverage IDAC on editable fields and array items Overlay styling Markup exists but visuals are ad hoc or absent Core injects markup, tenant styles TOCC selectors Theme handling Core or tenant-specific semantic assumptions Core publishes flattened tokens; tenant owns semantics Design token chain Raw utilities or literals bypass theme layers `theme.json -> runtime vars -> tenant bridge -> local scope -> JSX` Typography chain Fonts are hardcoded or ambiguously bridged Published semantic font chain with optional local remapping Menu ownership `header/footer` appear to own links locally `menu.json` is SOT; shell instances bind by reference in authored config and receive resolved props at runtime Referenced field editing Resolved values are edited and saved back into the binding document Binding document preserves `$ref`; edits persist into the referenced owner document draft Shell types Treated as conceptually reserved Same compositional model, different scope and placement Add section Ad hoc defaults or modal wiring `AddSectionConfig` with labels and valid default payloads Bootstrap Implicit app wiring `JsonPagesConfig` plus `JsonPagesEngine` Nested editing Shorthands and flat adapters may survive Deterministic path-based nested targeting Array identity Index-based fallback as primary model Stable item identity across schema, DOM, and editor Agent contract Narrative-only understanding Narrative plus machine-readable contract artifacts\n\n---\n\n## Appendix A - Tenant Type & Code-Generation Annex\n\n**Objective:** Make the specification sufficient to generate or audit a full tenant without a reference codebase.\n\n**Status:** Mandatory for code-generation and governance.\n\nAppendix A distinguishes between:\n\n- authored document contracts, formalized by normative companion JSON Schemas\n- resolved runtime contracts, consumed by Core and tenant components after document resolution\n\n## A.1 Core-Provided Types\n\nThe following are assumed to be exported by Core and consumed by the tenant:\n\nType Description `SectionType` `keyof SectionDataRegistry` after tenant augmentation `Section` Union of `BaseSection<K>` for all K `BaseSectionSettings` Optional shared settings type `MenuItem` Minimum menu node shape such as `{ label: string; href: string }` `AddSectionConfig` Add-section contract described in ASC `JsonPagesConfig` Bootstrap contract described in JEB\n\n## A.2 Tenant-Provided Types\n\nThe tenant should define these in a single module such as `src/types.ts`. That module performs module augmentation for `@olonjs/core` and exports the tenant-facing contract types.\n\n### A.2.1 SectionComponentPropsMap\n\nMaps section type keys to React props. Shell-scoped instances may have additional resolved props such as materialized menu trees.\n\nImportant distinction:\n\n- authored config in `site.json` expresses menu usage via `data.menu.$ref`\n- resolved runtime props passed to the component may contain concrete `MenuItem[]`\n\nExplicit pattern:\n\n```typescript\nimport type { MenuItem } from '@olonjs/core';\n\nexport type SectionComponentPropsMap = {\n  header: { data: HeaderData; settings?: HeaderSettings; menu?: MenuItem[] };\n  footer: { data: FooterData; settings?: FooterSettings; menu?: MenuItem[] };\n  hero: { data: HeroData; settings?: HeroSettings };\n};\n```\n\nMapped pattern:\n\n```typescript\nexport type SectionComponentPropsMap = {\n  [K in SectionType]:\n    { data: SectionDataRegistry[K]; settings?: K extends keyof SectionSettingsRegistry ? SectionSettingsRegistry[K] : BaseSectionSettings }\n};\n```\n\nUse an explicit variant when shell-scoped props differ from ordinary page sections.\n\n### A.2.2 ComponentRegistry\n\nThe registry object must be typed as:\n\n```typescript\nexport const ComponentRegistry: {\n  [K in SectionType]: React.FC<SectionComponentPropsMap[K]>;\n} = { /* ... */ };\n```\n\nConventional file: `src/lib/ComponentRegistry.tsx`.\n\n### A.2.3 PageConfig\n\nMinimum page shape:\n\n```typescript\nexport interface PageConfig {\n  id?: string;\n  slug: string;\n  meta?: {\n    title?: string;\n    description?: string;\n  };\n  sections: Section[];\n}\n```\n\n### A.2.4 SiteConfig\n\n`site.json` owns shell structure and shell instance declaration.\n\nCanonical direction for v1.6:\n\n- `header` is optional and `footer` is required in `site.json`\n- each shell instance must provide `id`, `type`, and `data`\n- `data` is tenant-sovereign in shape\n- if a shell instance uses menu data, it binds to `menu.json` through `data.menu.$ref`\n- no menu means `data.menu` is omitted\n\nIllustrative minimum shape:\n\n```typescript\nexport interface JsonRef {\n  $ref: string;\n}\n\nexport interface SiteConfig {\n  header: {\n    id: string;\n    type: 'header';\n    data: HeaderData & { menu?: JsonRef };\n    settings?: HeaderSettings;\n  };\n  footer: {\n    id: string;\n    type: 'footer';\n    data: FooterData & { menu?: JsonRef };\n    settings?: FooterSettings;\n  };\n}\n```\n\nNormative companion schema:\n\n- site.schema.json\n\nAuthored config rule:\n\n- `site.json` stores reference intent in `data.menu`\n- it does not canonically own the materialized menu tree\n- the authored JSON contract is formalized by the companion schema above\n\nStudio editing rule:\n\n- if `data.menu` is a `$ref`, the editable menu draft belongs to the referenced menu document\n- editing the resolved menu value must not rewrite authored `site.json` to inline the resolved array\n\nResolved runtime rule:\n\n- after config resolution, shell components may receive concrete `MenuItem[]` props\n- this runtime convenience does not change authorship or source of truth\n\n### A.2.5 MenuConfig\n\n`menu.json` is the source of truth for menu structures. Named menu collections are allowed.\n\nIllustrative minimum shape:\n\n```typescript\nexport interface MenuConfig {\n  main?: MenuItem[];\n  [key: string]: MenuItem[] | undefined;\n}\n```\n\nRuntime may resolve references such as `menu.json#/main` before passing concrete `MenuItem[]` into shell instances.\n\nNormative companion schema:\n\n- menu.schema.json\n\nAuthored config rule:\n\n- `menu.json` is the authored menu source of truth\n- named menu collections are formalized by the companion schema above\n- shell/runtime consumers read materialized menu trees after resolution rather than redefining menu ownership\n\nStudio persistence rule:\n\n- if a shell instance binds `data.menu.$ref` to a branch such as `menu.json#/main` or `menu.json#/footer`\n- Inspector edits to that resolved menu must persist into the referenced branch of `menu.json`\n- persistence must not redirect those edits into `site.json`\n\n### A.2.6 ThemeConfig\n\n`theme.json` is the single source of truth for the visual token contract.\n\nv1.6 rule:\n\n- Core should not define tenant semantic vocabulary\n- Core should publish flattenable token paths\n- tenant owns semantic interpretation and bridging\n\nIllustrative grouped-open contract:\n\n```typescript\nexport interface ThemeValueMap {\n  [key: string]: string | undefined;\n}\n\nexport interface ThemeTypography {\n  fontFamily?: ThemeValueMap;\n  scale?: ThemeValueMap;\n  tracking?: ThemeValueMap;\n  leading?: ThemeValueMap;\n  wordmark?: ThemeValueMap;\n  [key: string]: ThemeValueMap | undefined;\n}\n\nexport interface ThemeModes {\n  [mode: string]: {\n    colors?: ThemeValueMap;\n    [key: string]: ThemeValueMap | undefined;\n  } | undefined;\n}\n\nexport interface ThemeTokens {\n  colors?: ThemeValueMap;\n  typography?: ThemeTypography;\n  borderRadius?: ThemeValueMap;\n  spacing?: ThemeValueMap;\n  zIndex?: ThemeValueMap;\n  modes?: ThemeModes;\n  [key: string]: ThemeValueMap | ThemeTypography | ThemeModes | undefined;\n}\n\nexport interface ThemeConfig {\n  name: string;\n  tokens: ThemeTokens;\n}\n```\n\nPractical expectation:\n\n- `tokens.colors`, `tokens.typography`, `tokens.borderRadius`, `tokens.spacing`, `tokens.zIndex`, and `tokens.modes` are canonical groups when present\n- each group remains open-map and tenant-sovereign internally\n- extra groups are allowed as additive extensions\n- tenant naming is sovereign\n\n## A.3 Schema Contract (SECTION_SCHEMAS)\n\nConventional location: `src/lib/schemas.ts`.\n\nContract:\n\n- `SECTION_SCHEMAS` is a single object keyed by `SectionType`\n- values are Zod schemas for section data\n- base fragments such as `BaseSectionData` and `BaseArrayItem` are reused by capsules\n- the app passes this aggregate to `JsonPagesEngine` as `config.schemas`\n\nImportant distinction:\n\n- `SECTION_SCHEMAS` formalize section data contracts for component/editing/runtime surfaces\n- the companion JSON Schemas formalize authored document contracts for `site.json` and `menu.json`\n- these contract layers complement each other and must not be conflated\n\n## A.4 File Paths & Data Layout\n\nPurpose Path (conventional) Description Site config `src/data/config/site.json` `SiteConfig` Menu config `src/data/config/menu.json` `MenuConfig` Theme config `src/data/config/theme.json` `ThemeConfig` Page data `src/data/pages/<slug>.json` `PageConfig` Base schemas `src/lib/base-schemas.ts` Base fragments Schema aggregate `src/lib/schemas.ts` `SECTION_SCHEMAS` Registry `src/lib/ComponentRegistry.tsx` `ComponentRegistry` Add-section config `src/lib/addSectionConfig.ts` `AddSectionConfig` Tenant types `src/types.ts` augmentation and contract types Bootstrap `src/App.tsx` builds `JsonPagesConfig` and renders `JsonPagesEngine`\n\n## A.5 Integration Checklist\n\nWhen generating or auditing a tenant, ensure:\n\n 1. capsules exist for each section type with `View.tsx`, `schema.ts`, `types.ts`, and `index.ts`\n 2. base schemas define `BaseSectionData`, `BaseArrayItem`, and optional `BaseSectionSettings`\n 3. `src/types.ts` performs module augmentation and exports tenant contract types\n 4. `ComponentRegistry` is typed against `SectionType` and `SectionComponentPropsMap`\n 5. `SECTION_SCHEMAS` is a single keyed schema aggregate\n 6. `addSectionConfig` provides addable types, labels, and valid defaults\n 7. `App.tsx` builds `JsonPagesConfig` with pages, site, theme, menu, registry, schemas, CSS bridge data, and optional `refDocuments`\n 8. config/page JSON files conform to `SiteConfig`, `MenuConfig`, `ThemeConfig`, and `PageConfig`\n 9. themed tenants publish runtime theme variables before themed sections render\n10. tenant global CSS includes TOCC selectors and semantic/theme bridge rules\n11. shell instances consume menu data by reference binding rather than canonical local ownership\n\n## A.6 Path/Nested Strictness Addendum\n\nThis addendum preserves prior obligations and adds:\n\n1. `SelectionPathSegment` and `SelectionPath` should be exported for Studio messaging\n2. nested targeting uses path segments from root to leaf\n3. editable object arrays require stable item identity\n4. legacy flat fields are transitional adapters, not the normative nested protocol\n\n## A.7 Local Design Tokens Implementation Addendum\n\nThis addendum preserves prior obligations and adds:\n\n1. tenant theme values live in `src/data/config/theme.json`\n2. runtime publication is mandatory for themed tenants\n3. themed sections scope owned color/radius concerns through `--local-*`\n4. section-owned color/radius classes consume the local or tenant semantic layer, not hardcoded literals\n5. typography consumes the published semantic font chain\n6. migration shims may exist temporarily but are not the primary themed contract\n\nCanonical implementation pattern:\n\n```text\ntheme.json -> published runtime theme vars -> tenant semantic bridge -> section --local-* -> JSX classes\n```\n\nCanonical typography pattern:\n\n```text\ntheme.json -> published runtime theme vars -> tenant semantic font bridge -> section typography\n```\n\nMinimal compliant example:\n\n```tsx\n<section\n  style={{\n    '--local-bg': 'var(--background)',\n    '--local-text': 'var(--foreground)',\n    '--local-primary': 'var(--primary)',\n    '--local-radius-md': 'var(--theme-radius-md)',\n  } as React.CSSProperties}\n  className=\"bg-[var(--local-bg)]\"\n>\n  <h2 className=\"font-display text-[var(--local-text)]\">Title</h2>\n  <a className=\"bg-[var(--local-primary)] rounded-[var(--local-radius-md)]\">CTA</a>\n</section>\n```\n\nDeterministic compliance checklist:\n\n1. tenant theme source of truth exists\n2. runtime publication exists\n3. tenant semantic bridge exists\n4. section-local scope exists when the section owns the concern\n5. section-owned classes consume local or tenant semantic variables\n6. primary themed values are not hardcoded"
      },
      "type": "tiptap",
      "settings": {}
    }
  ]
}
