From 65c30a823c5c60349f17a8b9bb6886089dbb5d42 Mon Sep 17 00:00:00 2001 From: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Date: Wed, 1 Jul 2026 09:23:17 +0800 Subject: [PATCH 1/8] =?UTF-8?q?docs(adr):=20ADR-0084=20=E2=80=94=20applica?= =?UTF-8?q?tion-builder=20information=20architecture?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Records the builder IA converged on over an extended design pass: the app builder is for BUILDING AN APP only. Four visual content pillars — Data · Automation · Interface · Access (Airtable's three plus the one it lacks) — each with an editor matched to its natural shape (grid / canvas / builder / matrix). Dashboards live in Interface (Analytics splits out later, gated on the dataset layer). A Settings area holds General (the app's basic info) and Advanced — the technical tier unified by audience (developers), holding both Code (hooks now; functions, custom components later) and Connections (datasources, connectors, webhooks) — so there is no separate Integration tier. Operate (ship/run) and Platform (AI, i18n, templates, plugins) are out of the builder entirely — different personas, different surfaces. v1 ships the four pillars + Settings (General + Advanced/Hooks). Refines ADR-0083 for the builder surface (AI is a platform capability, not a pillar; Integration folds into Advanced). Records the alternatives rejected along the way (6 flat pillars, Analytics-in-v1, Integration-as-tier, AI-as-pillar, Operate/Platform-in-builder, implicit auto datasets). Related: #2501, #2502. Co-Authored-By: Claude Opus 4.8 --- ...cation-builder-information-architecture.md | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 docs/adr/0084-application-builder-information-architecture.md diff --git a/docs/adr/0084-application-builder-information-architecture.md b/docs/adr/0084-application-builder-information-architecture.md new file mode 100644 index 000000000..c79ff2bf0 --- /dev/null +++ b/docs/adr/0084-application-builder-information-architecture.md @@ -0,0 +1,95 @@ +# ADR-0084: Application-builder information architecture — four content pillars + Settings/Advanced + +**Status**: Accepted (2026-07-01) +**Deciders**: ObjectStack Protocol Architects +**Builds on**: the metadata-type taxonomy (ADR-0083, in review — Airtable's Data/Automation/Interface plus the types Airtable lacks), [ADR-0077](./0077-authoring-surface-boundary-hook-flow-validation.md) (route authoring by intent + audience + verifiability — the hook/flow/validation boundary), [ADR-0033](./0033-ai-assisted-metadata-authoring.md) (draft-gated authoring), [ADR-0063](./0063-two-kernel-agents-skills-are-the-extension-primitive.md)/[ADR-0064](./0064-tool-scoping-to-agent.md) (two kernel agents — AI is a platform capability, not app metadata), [ADR-0080](./0080-ai-authored-ui-jsx-source.md)/[ADR-0081](./0081-trusted-react-page-tier.md) (the Interface pillar's page-authoring depth). +**Consumers**: `studio.app.ts` (the builder navigation), the Studio UI, `packages/cli/src/utils/format.ts` (`os` stats grouping), and the build agent (which surface authors which type). + +**Premise**: ObjectStack has far more metadata types than Airtable's clean three, but the **application builder** — the surface a person (or the build agent) uses to *build an app* — must not expose all of them at one altitude, or it stops being learnable. Studio's current grouping is inconsistent (mixes Data with Interface, splits "Logic" from "Automation", scatters the rest). This ADR fixes the builder's information architecture, once, after a long design pass that repeatedly corrected itself. The core question it answers: **which metadata types are the app builder's job, at what altitude, and which belong to entirely different surfaces?** + +> **Trigger**: an extended design conversation ("Airtable categorizes as Data / Automation / Interface — I have more types, how do I present them in the builder?"), which converged by successively ruling things in and out. + +--- + +## TL;DR + +1. **The app builder is for *building an application* — nothing else.** Running it (Operate) and the platform's own machinery (Platform) are different surfaces, different personas; they are **out of the builder entirely**, not deferred. +2. **Four visual content pillars** (Airtable's three plus the one it lacks): **Data · Automation · Interface · Access**. This is what a builder navigates. +3. **Each pillar's editor matches the pillar's natural shape**: Data = grid, Automation = canvas, Interface = builder/source, Access = matrix. +4. **Dashboards live in Interface** (Airtable-style: a dashboard is an interface surface of inline chart blocks). A separate **Analytics** pillar is a *future* split, gated on the reusable dataset/cube layer maturing — not a v1 concern. +5. **A Settings area** (distinct from the content pillars) holds **General** (the app's own basic info) and **Advanced** — the *technical tier* for developers. +6. **Advanced is unified by audience, not by "is it code."** It holds both **Code** (hooks now; functions, custom components, custom field types later) and **Connections** (datasources, connectors, webhooks, mappings — external data/systems). What unites them: technical, beyond visual authoring, developer audience. There is **no separate Integration tier** — connections are Advanced. +7. **v1 ships**: the four pillars + Settings(General + Advanced/**Hooks**). Everything else (the rest of Advanced, Analytics, Operate, Platform) is later or out-of-builder. + +--- + +## The information architecture + +``` +Data · Automation · Interface · Access ⚙ Settings +(four visual content pillars — for builders) ├ General the app's basic info + └ Advanced the technical tier — for developers + ├ Code hooks (v1) · functions · custom components · custom field types + └ Connections datasource · connector · webhook · mapping (later) + +Out of the builder entirely (separate surfaces / personas): + Operate ship & run — packages · migrations · flow runs · audit · api keys + Platform the platform's own capabilities — AI (agent/tool/skill) · i18n · email & notification templates · settings · studio plugins +``` + +### The four content pillars (shape → editor) + +| Pillar | Types (v1 core) | Natural shape | Editor | +|---|---|---|---| +| **Data** | object · field · validation | tabular | a live data **grid** (columns = fields, rows = real records) | +| **Automation** | flow · trigger · action · schedule | sequential | a flow **canvas** (trigger → steps) | +| **Interface** | app · page · view · form · dashboard · report | spatial | a **builder** (canvas + palette) or **source + preview** (html/react pages) | +| **Access** | role · permission · sharing | relational | a permission **matrix** (roles × objects × CRUD + record scope) | + +Charts/metrics are **blocks** inside a dashboard/page bound inline to objects — they reuse the SDUI page renderer, so a dashboard is a page with chart blocks, not a separate subsystem. + +### Settings + +- **General** — the app's own identity and defaults: name, id, icon, description, branding, default landing, and the navigation structure. (This is the `app` definition; it is not one of the content pillars — it's *about* the app, not content *in* it.) +- **Advanced** — the technical escape hatch, sub-grouped **Code** and **Connections** (above). Kept visually separate from General so a builder who opens Settings for app info isn't dropped into code (ADR-0077: same area is fine, but different audiences get different groups). + +--- + +## Principles the IA encodes + +- **Two altitudes, one job.** Authoring the app (the four pillars + Advanced) is the builder's job. Operating it and the platform beneath it are *different jobs, different people, different surfaces* — so they are not in the builder. The builder stays about building. +- **Shape → editor.** A pillar's data has a natural shape; its editor is that shape (grid/canvas/builder/matrix). This is what lets four different surfaces feel like one product. +- **Same renderer.** The builder manipulates the same live artifact the end user sees — edit a field on the real grid, style a page in a live preview, set a permission on the real matrix. This is also what makes AI authoring safe: the agent edits the same flat, explicit metadata a human does. +- **Audience routing (ADR-0077).** Visual/declarative → the four pillars (builder audience). Code and connections → Advanced (developer audience). AI → not here at all (platform capability). +- **Primary home + secondary surface for cross-cutting types.** A type is authored in one place and its *result* may appear elsewhere — e.g. a **datasource** is authored in Advanced › Connections, and the external objects it exposes appear in **Data** (with an "external" badge). No type is authored in two menus. +- **Inline-by-default analytics.** A chart carries its query inline (self-contained); a **dataset** is an explicit opt-in only when the query can't be expressed inline (see #2502), and a dashboard filter is a dashboard variable broadcast to inline charts (see #2501). No implicit/auto-generated datasets — hidden linked entities are hostile to both humans and AI authoring. + +--- + +## Relationship to ADR-0083 + +ADR-0083 categorizes *all* metadata types (Airtable's three plus Access, plus the types Airtable lacks). This ADR is the **builder-surface** decision layered on top, and it **refines** two of 0083's presentation choices for the app-builder specifically: + +- **AI (agent/tool/skill) is not a builder pillar** — it's a Platform capability (the build/ask agents), out of the builder. +- **Integration is not a peer tier** — connections fold into Advanced (technical, developer audience). + +0083's taxonomy stands; 0084 decides how the builder *surfaces* it. + +## Consequences + +- The builder is learnable in one glance: four content tabs shaped like their data, plus Settings. Airtable users transfer instantly (Data/Automation/Interface), and the one addition (Access) is obvious. +- The build agent gets a canonical "this type is authored on this surface" map, and a rule that keeps it out of code (Advanced) and off the platform's turf. +- Deferred and out-of-builder concerns have homes that don't distort the builder: Advanced (technical), Operate/Platform (separate surfaces). +- **Cost**: reconciling Studio's current nav (`studio.app.ts`) and the `os` stats grouping to this IA; and drawing the exact edges of "inline vs dataset" (#2502) and the dashboard-filter mechanism (#2501), tracked separately. + +## Alternatives considered + +- **Six flat pillars** (Data/Automation/Interface/Access/AI/Integration). Rejected — conflates authoring with a platform capability (AI) and a technical concern (Integration), and buries the differentiators as peers. +- **Analytics as a top-level pillar in v1.** Rejected — premature; dashboards are Interface surfaces (Airtable-style) until the reusable dataset/cube layer justifies a split. +- **Integration as its own tier/area.** Rejected — connections are technical, developer-audience, beyond visual authoring → they *are* Advanced. +- **AI as a builder pillar/tab.** Rejected — agent/tool/skill are the platform's capability (build/ask), not metadata *in* the app being built. +- **Operate / Platform inside the builder.** Rejected — different personas and moments; they're separate surfaces, not deferred builder tabs. +- **A bare "Advanced" top-level tab.** Rejected — the app also needs a home for its basic info; folding Advanced under **Settings** gives code a non-intimidating, expected home and reserves Settings for the deferred technical concerns. +- **Implicit auto-generated datasets behind inline charts.** Rejected — hidden linked state; two entities per intent; sync burden; violates the flat/explicit/local property that keeps AI authoring safe. + +Related issues: #2501 (dashboard-level filters), #2502 (inline-vs-dataset expressibility rule). From d71a2a86f9926cd8328fc400a6128b4de9d2ae3d Mon Sep 17 00:00:00 2001 From: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Date: Wed, 1 Jul 2026 09:25:58 +0800 Subject: [PATCH 2/8] =?UTF-8?q?docs(adr):=20make=200084=20self-contained?= =?UTF-8?q?=20=E2=80=94=20drop=20refs=20to=20voided=20ADR-0083?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADR-0083 (metadata-type taxonomy) was voided (#2499 closed); 0084 subsumes the builder-relevant taxonomy. Remove the Builds-on citation and the Relationship section — their content (AI is a platform capability not a pillar; Integration folds into Advanced) already lives in the TL;DR and Alternatives. Co-Authored-By: Claude Opus 4.8 --- ...84-application-builder-information-architecture.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/docs/adr/0084-application-builder-information-architecture.md b/docs/adr/0084-application-builder-information-architecture.md index c79ff2bf0..f65b1fc1d 100644 --- a/docs/adr/0084-application-builder-information-architecture.md +++ b/docs/adr/0084-application-builder-information-architecture.md @@ -2,7 +2,7 @@ **Status**: Accepted (2026-07-01) **Deciders**: ObjectStack Protocol Architects -**Builds on**: the metadata-type taxonomy (ADR-0083, in review — Airtable's Data/Automation/Interface plus the types Airtable lacks), [ADR-0077](./0077-authoring-surface-boundary-hook-flow-validation.md) (route authoring by intent + audience + verifiability — the hook/flow/validation boundary), [ADR-0033](./0033-ai-assisted-metadata-authoring.md) (draft-gated authoring), [ADR-0063](./0063-two-kernel-agents-skills-are-the-extension-primitive.md)/[ADR-0064](./0064-tool-scoping-to-agent.md) (two kernel agents — AI is a platform capability, not app metadata), [ADR-0080](./0080-ai-authored-ui-jsx-source.md)/[ADR-0081](./0081-trusted-react-page-tier.md) (the Interface pillar's page-authoring depth). +**Builds on**: [ADR-0077](./0077-authoring-surface-boundary-hook-flow-validation.md) (route authoring by intent + audience + verifiability — the hook/flow/validation boundary), [ADR-0033](./0033-ai-assisted-metadata-authoring.md) (draft-gated authoring), [ADR-0063](./0063-two-kernel-agents-skills-are-the-extension-primitive.md)/[ADR-0064](./0064-tool-scoping-to-agent.md) (two kernel agents — AI is a platform capability, not app metadata), [ADR-0080](./0080-ai-authored-ui-jsx-source.md)/[ADR-0081](./0081-trusted-react-page-tier.md) (the Interface pillar's page-authoring depth). **Consumers**: `studio.app.ts` (the builder navigation), the Studio UI, `packages/cli/src/utils/format.ts` (`os` stats grouping), and the build agent (which surface authors which type). **Premise**: ObjectStack has far more metadata types than Airtable's clean three, but the **application builder** — the surface a person (or the build agent) uses to *build an app* — must not expose all of them at one altitude, or it stops being learnable. Studio's current grouping is inconsistent (mixes Data with Interface, splits "Logic" from "Automation", scatters the rest). This ADR fixes the builder's information architecture, once, after a long design pass that repeatedly corrected itself. The core question it answers: **which metadata types are the app builder's job, at what altitude, and which belong to entirely different surfaces?** @@ -66,15 +66,6 @@ Charts/metrics are **blocks** inside a dashboard/page bound inline to objects --- -## Relationship to ADR-0083 - -ADR-0083 categorizes *all* metadata types (Airtable's three plus Access, plus the types Airtable lacks). This ADR is the **builder-surface** decision layered on top, and it **refines** two of 0083's presentation choices for the app-builder specifically: - -- **AI (agent/tool/skill) is not a builder pillar** — it's a Platform capability (the build/ask agents), out of the builder. -- **Integration is not a peer tier** — connections fold into Advanced (technical, developer audience). - -0083's taxonomy stands; 0084 decides how the builder *surfaces* it. - ## Consequences - The builder is learnable in one glance: four content tabs shaped like their data, plus Settings. Airtable users transfer instantly (Data/Automation/Interface), and the one addition (Access) is obvious. From a6b0f56ced45ae6b68ded175ffe8cecf74018a9a Mon Sep 17 00:00:00 2001 From: Jack Zhuang Date: Wed, 1 Jul 2026 11:28:56 +0800 Subject: [PATCH 3/8] =?UTF-8?q?docs(design):=20builder=20UI=20design=20doc?= =?UTF-8?q?=20=E2=80=94=20shell=20+=20Data=20pillar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Living companion to ADR-0084. Captures the shared 3-zone shell (pillar tabs / left rail / main work surface / right inspector / draft-publish), the design principles (facet=tab item=inspector, grid-primary via default tab, small-config→inspector big-designer→main, two-doors, same-renderer, no-modal), and the Data pillar in detail (object facet tabs with Records grid default, field manager, Validations grounded in the real 6-type ValidationRuleSchema, v1 scope). TODO placeholders for the other pillars. Co-Authored-By: Claude Opus 4.8 --- docs/design/builder-ui.md | 166 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 docs/design/builder-ui.md diff --git a/docs/design/builder-ui.md b/docs/design/builder-ui.md new file mode 100644 index 000000000..197adb2cc --- /dev/null +++ b/docs/design/builder-ui.md @@ -0,0 +1,166 @@ +# Application builder — UI design + +**Status**: Living design doc (draft, 2026-07-01). Companion to +[ADR-0084](../adr/0084-application-builder-information-architecture.md). The ADR +records the *decisions and rejected alternatives* (the information architecture); +this doc records *how it looks and flows* — it iterates as the UI is built, and is +not a binding contract. + +The atomic config panels (object designer, field editor, validation-rule editor, +form designer, …) already exist. This doc is about the **overall layout** that +composes them into one coherent builder, optimized for operation experience. + +--- + +## 1. The shell (every pillar shares it) + +``` +┌───────────────────────────────────────────────────────────────────┐ +│ app ▾ Data · Automation · Interface · Access ⚙ Save · Publish │ ← top bar +├─────────┬───────────────────────────────────────────┬──────────────┤ +│ left │ main (the work surface) │ right │ +│ rail │ │ inspector │ +│ │ grid / canvas / builder / matrix │ = selected │ +│ entities │ + a per-entity facet tab bar (see Data) │ item's │ +│ + search │ │ config │ +│ + new │ │ (non-block) │ +├─────────┴───────────────────────────────────────────┴──────────────┤ +│ breadcrumb · hints │ +└───────────────────────────────────────────────────────────────────┘ +``` + +- **Top bar** — the four pillar tabs (Data / Automation / Interface / Access), the + ⚙ Settings entry, the app switcher, and the draft indicator + Save draft / + Publish (draft-gated, ADR-0033). +- **Left rail** — the current pillar's primary entities (objects / automations / + surfaces / roles), with search and New. Collapsible. +- **Main** — the pillar's primary work surface, shaped to the pillar (Data = grid, + Automation = canvas, Interface = builder/source, Access = matrix). +- **Right inspector** — a *persistent, consistent* slot that shows the config panel + for whatever is selected in the main zone. Non-blocking (the main surface stays + visible); slides in on select, closable. This is the universal "inspector" + (Figma / Retool pattern). + +## 2. Design principles (for best operation experience) + +1. **Consistent three zones across all four pillars** — rail / main / inspector. + Muscle memory: config is always on the right, entities always on the left. +2. **Facet = tab, item = inspector.** Tabs switch *which facet* of an entity you're + on (an object's Records / Fields / Validations …); the right inspector configures + the *selected item* within that facet (a field, a rule, a node). They coexist. +3. **The default tab is the primary surface, not a demoted one.** In Data the first + tab is `Records` (the grid) — you always land on the data; tabs make the other + facets one click away without burying the grid. +4. **Small config → inspector; big designer → main.** A field / rule / node / + component configures in the right inspector. A full designer (form designer, + flow canvas) *is* the main zone. +5. **Two doors, one metadata.** An object-scoped surface that lives in another + pillar (an object's Actions, Hooks, Views, Permissions) is reachable from the + object (in-context, scoped) AND from its pillar (the cross-object lens). The + metadata is stored once; there are two navigational entries, no duplication. +6. **Same renderer.** The builder manipulates the same live artifact the end user + sees (edit a field on the real grid; set a permission on the real matrix). This + is also what keeps AI authoring safe — the agent edits the same flat, explicit + metadata a human does. +7. **No modals.** Config surfaces in the inspector or as a focused sub-view with a + breadcrumb; the work surface never fully disappears. Draft/publish is always + visible. + +--- + +## 3. Data pillar + +Data is the **object-model workbench**: define objects, their fields, relationships, +validations, and work with records. Data owns the *data layer*; presentation (saved +views, kanban, calendar, forms, dashboards) belongs to Interface. + +### Layout + +``` +┌ objects ─┬ Task ┈ Records · Fields · Validations │ Actions · Hooks · ⋯ ┬ inspector ┐ +│ Account │ ┌ filter · sort · hide ─────────────────────────────────┐ │ Edit field │ +│ Task ◄ │ │ # Title Status [Priority ▾] + │ │ Priority │ +│ Project │ │ 1 Audit IA In review ● Medium │ │ type: select│ +│ Invoice │ │ 2 Design system In progress ● High │ │ options … │ +│ + New │ │ + New record │ │ required │ +└──────────┴─┴───────────────────────────────────────────────────────┴─┴────────────┘ +``` + +### Left rail +The app's objects (v1: owned objects only), with search + New object. + +### Object facet tabs +Per selected object, a tab bar of its facets — grouped: + +- **Schema** (authored in Data): `Records` · `Fields` · `Validations` · `Relationships` · `Lifecycle` +- **Behavior**: `Actions` (Automation) · `Hooks` (Advanced) +- **⋯ More**: `Views` · `Forms` (Interface) · `Permissions` (Access) · `Settings` · `Indexes` + +`Records` is the default. Cross-pillar tabs carry a pillar tag and open **in-context, +scoped to this object** (their pillar is the cross-object lens — two doors, §2.5). + +Note: `Actions` / `Hooks` / `Validations` are the three authoring surfaces for logic +on an object, routed by intent per [ADR-0077](../adr/0077-authoring-surface-boundary-hook-flow-validation.md): +declarative validation · user-triggered action · write-path hook. + +### Main zone (content of the active tab) +| Tab | Main-zone content | +|---|---| +| **Records** | the functional **grid** — columns = fields, rows = records, inline edit, `+` add field (column header menu configures it), `+ New record`, ephemeral filter/sort/hide/group (not saved — saved views are Interface). | +| **Fields** | the **field manager** — a searchable vertical list (add without horizontal scroll, drag-reorder, type icons). Grouping into sections is *not* here — that is the form designer (layout is Interface). | +| **Validations** | the **rules list** (declarative). See below. | +| **Relationships** | lookup / master-detail fields + reverse relationships (list / graph). Relationships are created by adding a `lookup` field type. | +| **Actions / Hooks / Views / Forms / Permissions** | the object's scoped instances, opened in-context. | + +### Right inspector (per-item config — the existing panels) +Selecting an item in the main zone opens its existing config panel in the inspector, +non-blocking: +- a column / field → the **field editor** (type, options, required/unique, field-level validation) +- a validation rule → the **rule editor** (condition builder + message + severity + events) +- a record → record detail +- an action → action config + +### Validation (grounded in the schema) +`ObjectSchema.validations` is an array of `ValidationRuleSchema` — a discriminated +union of six declarative rule types (`packages/spec/src/data/validation.zod.ts`): +`script` (CEL predicate → fails when true), `cross_field`, `format`, +`state_machine`, `json`, `conditional`. Each carries `message`, `severity` +(error/warning/info), and `events` (insert/update/delete). + +- **Field-level** (required / unique / format) → configured in the **field editor** + (they belong to the field). +- **Cross-field / business rules** → the **Validations tab** → a declarative rules + list; each rule edits in the inspector via a **condition builder** (field / + operator / value, and/or) with a raw-expression escape hatch — never hand-written + CEL as the primary path. Validation stays **declarative** (not a hook); Data-owned. + +### v1 scope +- **Ship**: owned objects · `Records` grid · `Fields` manager · field editor (incl. + field-level validation) · `Validations` (condition builder) · object `Settings` + (label / icon / name field / compact / search). Relationships via the `lookup` + field type. +- **Defer**: Extended objects (objectExtensions) · External objects (datasources) · + the ERD / model view · formal `Lifecycle` (v1 status = a select field) · `Indexes` · + seed-data UI · saved views / kanban / calendar (presentation → Interface). + +--- + +## 4. Other pillars (to design — same shell) + +- **Automation** — left: automations grouped by trigger (record-change / scheduled / + API / manual action); main: the flow **canvas**; inspector: the selected node's + config; a Runs view for execution history. +- **Interface** — left: surfaces (Apps · Pages · Views · Dashboards · Reports); + main: the page **builder** (structured canvas) or **source + preview** (html/react + pages); inspector: component props. +- **Access** — left: roles; main: the permission **matrix** (objects × CRUD + record + scope); inspector: role / field-level detail. +- **Settings** (⚙) — General (app basic info) and Advanced (Code: hooks · functions; + Connections: datasources), grouped by audience. + +--- + +## Mockups +Interactive layout mockups were produced during the design session (grid + inspector, +field manager, validation rule builder, object facet tabs). The ASCII sketches above +capture their structure. From 34883f012c6152043e8ff741cbd5cb64b65579b4 Mon Sep 17 00:00:00 2001 From: Jack Zhuang Date: Wed, 1 Jul 2026 11:31:25 +0800 Subject: [PATCH 4/8] docs(design): Records + Fields are two views of one field designer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct the Data pillar: Records = grid/list-style field designer (preview data, add columns, select column → configure field), Fields = form-style field designer (drag-reorder, section grouping, field-property config). Both design the same fields and share the right-hand field editor. Drop the earlier claim that grouping lives only in Interface — the object's default field layout (order + grouping) is authored in the Fields form designer. Co-Authored-By: Claude Opus 4.8 --- docs/design/builder-ui.md | 43 ++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/docs/design/builder-ui.md b/docs/design/builder-ui.md index 197adb2cc..62ed083f0 100644 --- a/docs/design/builder-ui.md +++ b/docs/design/builder-ui.md @@ -52,7 +52,7 @@ composes them into one coherent builder, optimized for operation experience. tab is `Records` (the grid) — you always land on the data; tabs make the other facets one click away without burying the grid. 4. **Small config → inspector; big designer → main.** A field / rule / node / - component configures in the right inspector. A full designer (form designer, + component configures in the right inspector. A full designer (the field designer, flow canvas) *is* the main zone. 5. **Two doors, one metadata.** An object-scoped surface that lives in another pillar (an object's Actions, Hooks, Views, Permissions) is reachable from the @@ -71,8 +71,9 @@ composes them into one coherent builder, optimized for operation experience. ## 3. Data pillar Data is the **object-model workbench**: define objects, their fields, relationships, -validations, and work with records. Data owns the *data layer*; presentation (saved -views, kanban, calendar, forms, dashboards) belongs to Interface. +and validations, and work with records. Data owns the *data layer and the field +designer*; runtime presentation surfaces (saved grid views, kanban, calendar, pages, +dashboards) belong to Interface. ### Layout @@ -103,18 +104,36 @@ Note: `Actions` / `Hooks` / `Validations` are the three authoring surfaces for l on an object, routed by intent per [ADR-0077](../adr/0077-authoring-surface-boundary-hook-flow-validation.md): declarative validation · user-triggered action · write-path hook. +### Records and Fields — two views of one field designer +Both tabs design the *same* thing (the object's fields); they differ in presentation, +and both configure a selected field through the *same* right-hand **field editor**. + +- **`Records` — grid / list style (data-forward).** The functional grid: columns = + fields, rows = real records. Preview and inline-edit data, `+` add a column + (= add a field), select a column header to configure that field's properties in + the inspector, `+ New record`. Ephemeral filter / sort / hide / group for looking + at the data (not saved — saved views are Interface). +- **`Fields` — form style (layout-forward).** The field designer as a form canvas: + drag to reorder fields, group them into sections, and configure field properties. + No data rows — this is where the object's default field layout (order + grouping) + is authored. (This is the existing form-style field designer, reused here.) + +The choice between them is a working preference: reach for `Records` when you want to +see data while shaping fields, `Fields` when you want to arrange and group them. + ### Main zone (content of the active tab) | Tab | Main-zone content | |---|---| -| **Records** | the functional **grid** — columns = fields, rows = records, inline edit, `+` add field (column header menu configures it), `+ New record`, ephemeral filter/sort/hide/group (not saved — saved views are Interface). | -| **Fields** | the **field manager** — a searchable vertical list (add without horizontal scroll, drag-reorder, type icons). Grouping into sections is *not* here — that is the form designer (layout is Interface). | +| **Records** | grid-style field designer — preview data, add columns, select a column → configure the field (see above). | +| **Fields** | form-style field designer — drag-reorder, section grouping, field-property config (see above). | | **Validations** | the **rules list** (declarative). See below. | | **Relationships** | lookup / master-detail fields + reverse relationships (list / graph). Relationships are created by adding a `lookup` field type. | | **Actions / Hooks / Views / Forms / Permissions** | the object's scoped instances, opened in-context. | ### Right inspector (per-item config — the existing panels) Selecting an item in the main zone opens its existing config panel in the inspector, -non-blocking: +non-blocking. The field editor is shared by both Records (selected column) and Fields +(selected field): - a column / field → the **field editor** (type, options, required/unique, field-level validation) - a validation rule → the **rule editor** (condition builder + message + severity + events) - a record → record detail @@ -135,10 +154,10 @@ union of six declarative rule types (`packages/spec/src/data/validation.zod.ts`) CEL as the primary path. Validation stays **declarative** (not a hook); Data-owned. ### v1 scope -- **Ship**: owned objects · `Records` grid · `Fields` manager · field editor (incl. - field-level validation) · `Validations` (condition builder) · object `Settings` - (label / icon / name field / compact / search). Relationships via the `lookup` - field type. +- **Ship**: owned objects · `Records` grid (data + add/configure columns) · `Fields` + form-style designer (reorder + grouping + field editor, incl. field-level + validation) · `Validations` (condition builder) · object `Settings` (label / icon / + name field / compact / search). Relationships via the `lookup` field type. - **Defer**: Extended objects (objectExtensions) · External objects (datasources) · the ERD / model view · formal `Lifecycle` (v1 status = a select field) · `Indexes` · seed-data UI · saved views / kanban / calendar (presentation → Interface). @@ -162,5 +181,5 @@ union of six declarative rule types (`packages/spec/src/data/validation.zod.ts`) ## Mockups Interactive layout mockups were produced during the design session (grid + inspector, -field manager, validation rule builder, object facet tabs). The ASCII sketches above -capture their structure. +form-style field designer, validation rule builder, object facet tabs). The ASCII +sketches above capture their structure. From 855e9ade7879737e7ffe65d2764ed9667132be80 Mon Sep 17 00:00:00 2001 From: Jack Zhuang Date: Wed, 1 Jul 2026 11:36:01 +0800 Subject: [PATCH 5/8] docs(design): AI-first authoring as the builder's core constraint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add §1 north star: every layout decision is judged by whether AI can generate the artifact in one shot, whether the design prevents AI mistakes, and whether a human can confirm it in one pass. Ties these to the concrete mechanisms already in the shell (same-renderer, declarative/constrained surfaces, os validate gates, draft diff per ADR-0033, no-modal). Also record the rationale for keeping the Records/Fields tab names over Grid/Form. Co-Authored-By: Claude Opus 4.8 --- docs/design/builder-ui.md | 52 +++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/docs/design/builder-ui.md b/docs/design/builder-ui.md index 62ed083f0..93a6e6507 100644 --- a/docs/design/builder-ui.md +++ b/docs/design/builder-ui.md @@ -12,7 +12,36 @@ composes them into one coherent builder, optimized for operation experience. --- -## 1. The shell (every pillar shares it) +## 1. Core constraint — AI-first, human-confirmable authoring + +Every layout and interaction decision in the builder is judged against three +requirements. They are the north star: a design that fails any of them is wrong, +however convenient it looks. Each pillar's design (below) is checked against them. + +1. **AI generates it in one shot.** The builder must let the agent produce a whole, + correct artifact — an object with its fields, validations, and layout — in a + single pass. This works because the agent edits the *same flat, explicit metadata* + a human does (same-renderer, §3.6) and authors within *constrained, declarative* + surfaces (typed fields, enum options, the condition builder — not free-form code). + The *shape of the metadata*, not a click-through wizard, is what the AI targets. + +2. **The design prevents AI mistakes.** Constrain the space so an invalid result is + hard to express: declarative over code (a condition builder, not hand-written CEL, + §3 Validation), typed and enumerated inputs, and the pre-publish validation gates + (`os validate` / `os build`). Nothing the AI writes goes live implicitly — it lands + as a **draft** (ADR-0033), never auto-published. + +3. **A human confirms it in one pass.** A reviewer approves or rejects with one look: + AI changes arrive as a **draft diff** (ADR-0033), and the artifact renders on one + canvas (the grid + inspector) with no modals hiding state (§3.7) and a non-blocking + inspector, so the whole thing stays visible while it is reviewed. + +These three are *why* the shell is what it is — same-renderer, declarative surfaces, +no-modal, draft/publish all fall out of them. + +--- + +## 2. The shell (every pillar shares it) ``` ┌───────────────────────────────────────────────────────────────────┐ @@ -41,7 +70,7 @@ composes them into one coherent builder, optimized for operation experience. visible); slides in on select, closable. This is the universal "inspector" (Figma / Retool pattern). -## 2. Design principles (for best operation experience) +## 3. Design principles (for best operation experience) 1. **Consistent three zones across all four pillars** — rail / main / inspector. Muscle memory: config is always on the right, entities always on the left. @@ -60,15 +89,15 @@ composes them into one coherent builder, optimized for operation experience. metadata is stored once; there are two navigational entries, no duplication. 6. **Same renderer.** The builder manipulates the same live artifact the end user sees (edit a field on the real grid; set a permission on the real matrix). This - is also what keeps AI authoring safe — the agent edits the same flat, explicit - metadata a human does. + is also what keeps AI authoring safe (§1) — the agent edits the same flat, + explicit metadata a human does. 7. **No modals.** Config surfaces in the inspector or as a focused sub-view with a breadcrumb; the work surface never fully disappears. Draft/publish is always visible. --- -## 3. Data pillar +## 4. Data pillar Data is the **object-model workbench**: define objects, their fields, relationships, and validations, and work with records. Data owns the *data layer and the field @@ -98,7 +127,8 @@ Per selected object, a tab bar of its facets — grouped: - **⋯ More**: `Views` · `Forms` (Interface) · `Permissions` (Access) · `Settings` · `Indexes` `Records` is the default. Cross-pillar tabs carry a pillar tag and open **in-context, -scoped to this object** (their pillar is the cross-object lens — two doors, §2.5). +scoped to this object** (their pillar is the cross-object lens — the two-doors +principle, §3.5). Note: `Actions` / `Hooks` / `Validations` are the three authoring surfaces for logic on an object, routed by intent per [ADR-0077](../adr/0077-authoring-surface-boundary-hook-flow-validation.md): @@ -121,6 +151,12 @@ and both configure a selected field through the *same* right-hand **field editor The choice between them is a working preference: reach for `Records` when you want to see data while shaping fields, `Fields` when you want to arrange and group them. +**Why keep the names `Records` / `Fields`** (rather than `Grid` / `Form`): each name +states the tab's *distinguishing* trait — Records is the one that shows **data**, +Fields is the **pure field/layout** designer. They are also the conventional terms +(Salesforce, Airtable). Style-based names would collide with Interface's existing +`Views` (saved grid/kanban) and `Forms` (end-user form surfaces). + ### Main zone (content of the active tab) | Tab | Main-zone content | |---|---| @@ -152,6 +188,8 @@ union of six declarative rule types (`packages/spec/src/data/validation.zod.ts`) list; each rule edits in the inspector via a **condition builder** (field / operator / value, and/or) with a raw-expression escape hatch — never hand-written CEL as the primary path. Validation stays **declarative** (not a hook); Data-owned. + The condition builder is also what makes validation AI-generatable and + human-confirmable in one pass (§1). ### v1 scope - **Ship**: owned objects · `Records` grid (data + add/configure columns) · `Fields` @@ -164,7 +202,7 @@ union of six declarative rule types (`packages/spec/src/data/validation.zod.ts`) --- -## 4. Other pillars (to design — same shell) +## 5. Other pillars (to design — same shell) - **Automation** — left: automations grouped by trigger (record-change / scheduled / API / manual action); main: the flow **canvas**; inspector: the selected node's From da0e098238224fe339d133774d3e78fcee41c020 Mon Sep 17 00:00:00 2001 From: Jack Zhuang Date: Wed, 1 Jul 2026 11:41:18 +0800 Subject: [PATCH 6/8] docs(design): reuse-first core constraint + committed wireframe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the fourth core constraint — reuse Studio's protocol-generated metadata forms, never hand-roll config UI — and a Build-boundary section that answers how code written against this doc stays correct: the novel surface is only the shell/composition; the grid (ListView) and every inspector panel (protocol forms) are reused by reference. Commit an SVG wireframe of the Data pillar shell (rail/tabs/grid/inspector) with a solid=built / dashed=reused legend, embedded in the doc as the visual target. Co-Authored-By: Claude Opus 4.8 --- docs/design/builder-ui.md | 92 +++++++++--------- docs/design/builder-ui/data-pillar.svg | 129 +++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 45 deletions(-) create mode 100644 docs/design/builder-ui/data-pillar.svg diff --git a/docs/design/builder-ui.md b/docs/design/builder-ui.md index 93a6e6507..8ea8dce1a 100644 --- a/docs/design/builder-ui.md +++ b/docs/design/builder-ui.md @@ -6,17 +6,18 @@ records the *decisions and rejected alternatives* (the information architecture) this doc records *how it looks and flows* — it iterates as the UI is built, and is not a binding contract. -The atomic config panels (object designer, field editor, validation-rule editor, -form designer, …) already exist. This doc is about the **overall layout** that -composes them into one coherent builder, optimized for operation experience. +This doc specifies the **shell and layout** — how the builder composes surfaces. It +does **not** re-specify the per-item config panels: those are Studio's existing +protocol-generated metadata forms, reused as-is (§1.4). What the builder actually +builds is the composition; the panels are dropped in. --- -## 1. Core constraint — AI-first, human-confirmable authoring +## 1. Core constraints — AI-first, human-confirmable, reuse-first -Every layout and interaction decision in the builder is judged against three -requirements. They are the north star: a design that fails any of them is wrong, -however convenient it looks. Each pillar's design (below) is checked against them. +Every layout and interaction decision in the builder is judged against these. They +are the north star: a design that fails any of them is wrong, however convenient it +looks. Each pillar's design (below) is checked against them. 1. **AI generates it in one shot.** The builder must let the agent produce a whole, correct artifact — an object with its fields, validations, and layout — in a @@ -27,7 +28,7 @@ however convenient it looks. Each pillar's design (below) is checked against the 2. **The design prevents AI mistakes.** Constrain the space so an invalid result is hard to express: declarative over code (a condition builder, not hand-written CEL, - §3 Validation), typed and enumerated inputs, and the pre-publish validation gates + §4 Validation), typed and enumerated inputs, and the pre-publish validation gates (`os validate` / `os build`). Nothing the AI writes goes live implicitly — it lands as a **draft** (ADR-0033), never auto-published. @@ -36,27 +37,35 @@ however convenient it looks. Each pillar's design (below) is checked against the canvas (the grid + inspector) with no modals hiding state (§3.7) and a non-blocking inspector, so the whole thing stays visible while it is reviewed. -These three are *why* the shell is what it is — same-renderer, declarative surfaces, -no-modal, draft/publish all fall out of them. +4. **Reuse, never rebuild.** Every per-item config panel — the field editor, the + validation-rule editor, object settings, and every other metadata form — **is + Studio's existing protocol-generated form**, generated from the metadata-type + schemas, and is dropped into the inspector unchanged. The builder does **not** + hand-roll config UI. This is not just tidiness: reused, already-verified panels are + panels the AI cannot get wrong and a human has seen before, which is what makes + constraints 1–3 achievable in practice. + +### Build boundary — what the builder builds vs. reuses +This is the answer to *"how do we ensure code written against this doc is correct?"* — +shrink the novel surface to almost nothing: + +- **Built here (the shell / composition):** the top bar + pillar tabs, the left rail, + the per-object facet tab bar, the work-surface chrome, and the wiring that routes a + selection into the inspector and edits into draft metadata. +- **Reused (not rebuilt):** the data grid (the existing ListView renderer), and every + config panel in the inspector (Studio protocol-generated forms). These are + referenced by name; the builder composes them, it does not reimplement them. + +Solid vs. dashed in the wireframes marks this boundary. --- ## 2. The shell (every pillar shares it) -``` -┌───────────────────────────────────────────────────────────────────┐ -│ app ▾ Data · Automation · Interface · Access ⚙ Save · Publish │ ← top bar -├─────────┬───────────────────────────────────────────┬──────────────┤ -│ left │ main (the work surface) │ right │ -│ rail │ │ inspector │ -│ │ grid / canvas / builder / matrix │ = selected │ -│ entities │ + a per-entity facet tab bar (see Data) │ item's │ -│ + search │ │ config │ -│ + new │ │ (non-block) │ -├─────────┴───────────────────────────────────────────┴──────────────┤ -│ breadcrumb · hints │ -└───────────────────────────────────────────────────────────────────┘ -``` +![Data pillar shell — rail, facet tabs, grid, inspector](./builder-ui/data-pillar.svg) + +*Solid frame = shell/composition built in the builder; dashed frame = existing Studio +component (grid = ListView; inspector = protocol-generated form) reused as-is.* - **Top bar** — the four pillar tabs (Data / Automation / Interface / Access), the ⚙ Settings entry, the app switcher, and the draft indicator + Save draft / @@ -68,7 +77,7 @@ no-modal, draft/publish all fall out of them. - **Right inspector** — a *persistent, consistent* slot that shows the config panel for whatever is selected in the main zone. Non-blocking (the main surface stays visible); slides in on select, closable. This is the universal "inspector" - (Figma / Retool pattern). + (Figma / Retool pattern). Its contents are always reused protocol forms (§1.4). ## 3. Design principles (for best operation experience) @@ -94,6 +103,8 @@ no-modal, draft/publish all fall out of them. 7. **No modals.** Config surfaces in the inspector or as a focused sub-view with a breadcrumb; the work surface never fully disappears. Draft/publish is always visible. +8. **Reuse, never rebuild (§1.4).** Config panels are Studio protocol-generated + forms; the builder composes, it does not reimplement. --- @@ -104,18 +115,6 @@ and validations, and work with records. Data owns the *data layer and the field designer*; runtime presentation surfaces (saved grid views, kanban, calendar, pages, dashboards) belong to Interface. -### Layout - -``` -┌ objects ─┬ Task ┈ Records · Fields · Validations │ Actions · Hooks · ⋯ ┬ inspector ┐ -│ Account │ ┌ filter · sort · hide ─────────────────────────────────┐ │ Edit field │ -│ Task ◄ │ │ # Title Status [Priority ▾] + │ │ Priority │ -│ Project │ │ 1 Audit IA In review ● Medium │ │ type: select│ -│ Invoice │ │ 2 Design system In progress ● High │ │ options … │ -│ + New │ │ + New record │ │ required │ -└──────────┴─┴───────────────────────────────────────────────────────┴─┴────────────┘ -``` - ### Left rail The app's objects (v1: owned objects only), with search + New object. @@ -166,10 +165,10 @@ Fields is the **pure field/layout** designer. They are also the conventional ter | **Relationships** | lookup / master-detail fields + reverse relationships (list / graph). Relationships are created by adding a `lookup` field type. | | **Actions / Hooks / Views / Forms / Permissions** | the object's scoped instances, opened in-context. | -### Right inspector (per-item config — the existing panels) -Selecting an item in the main zone opens its existing config panel in the inspector, -non-blocking. The field editor is shared by both Records (selected column) and Fields -(selected field): +### Right inspector (per-item config — reused protocol forms, §1.4) +Selecting an item in the main zone opens its **existing Studio protocol-generated +form** in the inspector, non-blocking. Nothing here is bespoke to the builder. The +field editor is shared by both Records (selected column) and Fields (selected field): - a column / field → the **field editor** (type, options, required/unique, field-level validation) - a validation rule → the **rule editor** (condition builder + message + severity + events) - a record → record detail @@ -217,7 +216,10 @@ union of six declarative rule types (`packages/spec/src/data/validation.zod.ts`) --- -## Mockups -Interactive layout mockups were produced during the design session (grid + inspector, -form-style field designer, validation rule builder, object facet tabs). The ASCII -sketches above capture their structure. +## Wireframes +- [`builder-ui/data-pillar.svg`](./builder-ui/data-pillar.svg) — the Data pillar shell + (rail · facet tabs · Records grid · field inspector), with the solid/dashed + build-boundary legend. + +Wireframes are committed as SVG so they render on GitHub and stay the unambiguous +visual target for implementation. More are added per pillar as they are designed. diff --git a/docs/design/builder-ui/data-pillar.svg b/docs/design/builder-ui/data-pillar.svg new file mode 100644 index 000000000..26502213c --- /dev/null +++ b/docs/design/builder-ui/data-pillar.svg @@ -0,0 +1,129 @@ + + + + + + + app ▾ + + Data + + Automation + Interface + Access + + + Save + + Publish + + + + OBJECTS + + Search + + Account + + + + Task + Project + Invoice + + New object + + + + + Records + + Fields + Validations + + Actions + + auto + Hooks + + adv + + + + ⌕ Filter + ↕ Sort + ◨ Hide + ▦ Group + + New record + + + + + + # + Title + Status + + + Priority ▾ + + + + + 1 + Audit IA + In review + ● Medium + + 2 + Design system + In progress + ● High + + 3 + API surface + Todo + ● Low + + 4 + Release notes + Done + ● Medium + + New record + grid = existing ListView renderer (reused) + + + + EDIT FIELD + Priority + + + + Label + + Priority + Type + + Select ▾ + Options + + Low + + Medium + + High + + add + Required + + + Unique + + + Studio protocol- + generated field form (reused) + + + + + solid = shell / composition (built in the builder) + + dashed = existing Studio component (reused, not rebuilt) + From 9c18bfe63e88e86dd602266dea3396042b90dba0 Mon Sep 17 00:00:00 2001 From: Jack Zhuang Date: Wed, 1 Jul 2026 13:01:20 +0800 Subject: [PATCH 7/8] docs(design): switch mockups to annotated HTML, drop SVG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HTML is the better artifact for AI to build against and scales to the many surfaces still to design: the DOM maps ~1:1 to the component tree, and each region is tagged data-build="shell" (built) or data-reuse="" (existing Studio/objectui component to drop in), making the build boundary machine-readable. shell.css holds shared tokens + layout primitives so each new pillar mockup is a small, consistent file. Data pillar mockup added; inline ASCII kept for quick reading. No committed PNGs — open the .html. Co-Authored-By: Claude Opus 4.8 --- docs/design/builder-ui.md | 69 +++++++++++-- docs/design/builder-ui/data-pillar.html | 127 +++++++++++++++++++++++ docs/design/builder-ui/data-pillar.svg | 129 ------------------------ docs/design/builder-ui/shell.css | 99 ++++++++++++++++++ 4 files changed, 284 insertions(+), 140 deletions(-) create mode 100644 docs/design/builder-ui/data-pillar.html delete mode 100644 docs/design/builder-ui/data-pillar.svg create mode 100644 docs/design/builder-ui/shell.css diff --git a/docs/design/builder-ui.md b/docs/design/builder-ui.md index 8ea8dce1a..841a5e5f6 100644 --- a/docs/design/builder-ui.md +++ b/docs/design/builder-ui.md @@ -11,6 +11,11 @@ does **not** re-specify the per-item config panels: those are Studio's existing protocol-generated metadata forms, reused as-is (§1.4). What the builder actually builds is the composition; the panels are dropped in. +Each surface has an **HTML mockup** under [`builder-ui/`](./builder-ui/) — the precise +visual target and, because its DOM maps to the component tree and its regions are +tagged `data-build` / `data-reuse`, the implementation blueprint (see +[Mockups](#mockups)). The ASCII sketches inline below are for quick reading. + --- ## 1. Core constraints — AI-first, human-confirmable, reuse-first @@ -56,16 +61,29 @@ shrink the novel surface to almost nothing: config panel in the inspector (Studio protocol-generated forms). These are referenced by name; the builder composes them, it does not reimplement them. -Solid vs. dashed in the wireframes marks this boundary. +In every mockup this boundary is explicit: regions carry `data-build="shell"` or +`data-reuse=""`, and reused blocks are drawn with a dashed outline. --- ## 2. The shell (every pillar shares it) -![Data pillar shell — rail, facet tabs, grid, inspector](./builder-ui/data-pillar.svg) - -*Solid frame = shell/composition built in the builder; dashed frame = existing Studio -component (grid = ListView; inspector = protocol-generated form) reused as-is.* +``` +┌───────────────────────────────────────────────────────────────────┐ +│ app ▾ Data · Automation · Interface · Access ⚙ Save · Publish │ ← top bar +├─────────┬───────────────────────────────────────────┬──────────────┤ +│ left │ main (the work surface) │ right │ +│ rail │ + a per-entity facet tab bar (see Data) │ inspector │ +│ entities │ grid / canvas / builder / matrix │ = selected │ +│ + search │ ───────────────────────────────────── │ item's │ +│ + new │ [ reused renderer, e.g. ListView ] │ config │ +│ │ │ [reused form] │ +├─────────┴───────────────────────────────────────────┴──────────────┤ +│ legend: solid = built (shell) · dashed = reused (Studio component) │ +└───────────────────────────────────────────────────────────────────┘ +``` + +Mockup: [`builder-ui/data-pillar.html`](./builder-ui/data-pillar.html) (open in a browser). - **Top bar** — the four pillar tabs (Data / Automation / Interface / Access), the ⚙ Settings entry, the app switcher, and the draft indicator + Save draft / @@ -115,6 +133,18 @@ and validations, and work with records. Data owns the *data layer and the field designer*; runtime presentation surfaces (saved grid views, kanban, calendar, pages, dashboards) belong to Interface. +Mockup: [`builder-ui/data-pillar.html`](./builder-ui/data-pillar.html). + +``` +┌ objects ─┬ Task ┈ Records · Fields · Validations │ Actions · Hooks · ⋯ ┬ inspector ┐ +│ Account │ ┌ filter · sort · hide ─────────────────────────────────┐ │ Edit field │ +│ Task ◄ │ │ # Title Status [Priority ▾] + │ │ Priority │ +│ Project │ │ 1 Audit IA In review ● Medium │ │ type: select│ +│ Invoice │ │ 2 Design system In progress ● High │ │ options … │ +│ + New │ │ + New record │ │ required │ +└──────────┴─┴───────────────────────────────────────────────────────┴─┴────────────┘ +``` + ### Left rail The app's objects (v1: owned objects only), with search + New object. @@ -216,10 +246,27 @@ union of six declarative rule types (`packages/spec/src/data/validation.zod.ts`) --- -## Wireframes -- [`builder-ui/data-pillar.svg`](./builder-ui/data-pillar.svg) — the Data pillar shell - (rail · facet tabs · Records grid · field inspector), with the solid/dashed - build-boundary legend. +## Mockups + +Mockups live under [`builder-ui/`](./builder-ui/) as **HTML**, not images — HTML is +the better artifact for an AI to build against and it scales to the many surfaces +still to design: + +- **DOM ≈ component tree.** The markup maps almost 1:1 to the React components to + build, so there is little to infer or get wrong. +- **The build boundary is machine-readable.** Every region is tagged + `data-build="shell"` (built in the builder) or `data-reuse=""` (an + existing Studio/objectui component — e.g. `ListView`, `protocol-form:field` — to + drop in unchanged). Reused blocks render with a dashed outline. +- **One shared look.** [`shell.css`](./builder-ui/shell.css) holds the tokens and + layout primitives (top bar, rail, facet tabs, grid, inspector, form rows, toggles); + each pillar mockup composes them, so a new surface is a small file and stays + visually consistent for free. + +Open any `*.html` in a browser to view it. Current mockups: + +| Surface | Mockup | +|---|---| +| Data pillar | [`data-pillar.html`](./builder-ui/data-pillar.html) | -Wireframes are committed as SVG so they render on GitHub and stay the unambiguous -visual target for implementation. More are added per pillar as they are designed. +More are added per pillar as they are designed. diff --git a/docs/design/builder-ui/data-pillar.html b/docs/design/builder-ui/data-pillar.html new file mode 100644 index 000000000..8c8bc32ec --- /dev/null +++ b/docs/design/builder-ui/data-pillar.html @@ -0,0 +1,127 @@ + + + + + Builder — Data pillar + + + + +
+ + +
+ app ▾ + +
+ + Save draft + +
+
+ +
+ + + + + +
+ + + + + +
+ ⚲ Filter + ↕ Sort + ▨ Hide + ▦ Group + + + New record +
+ + +
+
+ + + + + + + + + + + + + + + + +
#TitleStatusPriority ▾+
1Audit IAIn review● Medium
2Design systemIn progress● High
3API surfaceTodo● Low
4Release notesDone● Medium
+
+ New record
+ grid = existing ListView renderer (reused) +
+
+
+ + + +
+ + +
+ solid = shell / composition (built in the builder) + dashed = existing Studio component (reused, not rebuilt) +
+
+ + diff --git a/docs/design/builder-ui/data-pillar.svg b/docs/design/builder-ui/data-pillar.svg deleted file mode 100644 index 26502213c..000000000 --- a/docs/design/builder-ui/data-pillar.svg +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - app ▾ - - Data - - Automation - Interface - Access - - - Save - - Publish - - - - OBJECTS - - Search - - Account - - - - Task - Project - Invoice - + New object - - - - - Records - - Fields - Validations - - Actions - - auto - Hooks - - adv - - - - ⌕ Filter - ↕ Sort - ◨ Hide - ▦ Group - + New record - - - - - - # - Title - Status - - - Priority ▾ - + - - - 1 - Audit IA - In review - ● Medium - - 2 - Design system - In progress - ● High - - 3 - API surface - Todo - ● Low - - 4 - Release notes - Done - ● Medium - + New record - grid = existing ListView renderer (reused) - - - - EDIT FIELD - Priority - - - - Label - - Priority - Type - - Select ▾ - Options - - Low - - Medium - - High - + add - Required - - - Unique - - - Studio protocol- - generated field form (reused) - - - - - solid = shell / composition (built in the builder) - - dashed = existing Studio component (reused, not rebuilt) - diff --git a/docs/design/builder-ui/shell.css b/docs/design/builder-ui/shell.css new file mode 100644 index 000000000..fb35f1bad --- /dev/null +++ b/docs/design/builder-ui/shell.css @@ -0,0 +1,99 @@ +/* Application-builder mockup shell — shared design primitives. + One source of truth for the look; every pillar mockup composes these classes. + Build boundary is encoded in markup: data-build="shell" = built in the builder, + .reuse (data-reuse="") = existing Studio/objectui component, dropped in. */ + +:root { + --surface-1: #ffffff; + --surface-2: #f7f8fa; + --border: #e3e6ea; + --line: #eef0f2; + --text: #1f2733; + --muted: #7a828c; + --faint: #9aa0a8; + --accent: #2f6feb; + --accent-bg: #eaf1fe; + --chip: #f0f1f4; + --radius: 6px; + --font: ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif; +} + +* { box-sizing: border-box; } +body { margin: 0; background: #eceef1; padding: 24px; font-family: var(--font); } + +/* ---- shell frame ---- */ +.builder { + width: 1000px; margin: 0 auto; background: var(--surface-1); + border: 1px solid var(--border); border-radius: 8px; overflow: hidden; + color: var(--text); font-size: 13px; +} +.topbar { + height: 44px; display: flex; align-items: center; gap: 24px; + padding: 0 16px; border-bottom: 1px solid var(--border); +} +.topbar .app { font-weight: 600; } +.topbar .pilltabs { display: flex; gap: 26px; margin: 0 auto; } +.topbar .pilltabs a { color: var(--muted); text-decoration: none; padding-bottom: 6px; } +.topbar .pilltabs a.active { color: var(--text); font-weight: 600; border-bottom: 2px solid var(--accent); } +.topbar .right { display: flex; align-items: center; gap: 14px; color: var(--muted); } +.btn-publish { background: var(--accent); color: #fff; border: 0; border-radius: 5px; padding: 5px 12px; font-weight: 600; font-size: 12px; } + +.body { display: flex; height: 560px; } + +/* ---- left rail ---- */ +.rail { width: 190px; background: var(--surface-2); border-right: 1px solid var(--border); padding: 14px 12px; } +.rail .label { font-size: 10.5px; letter-spacing: .6px; color: var(--muted); font-weight: 600; margin-bottom: 8px; } +.rail .search { width: 100%; height: 26px; border: 1px solid var(--border); border-radius: 5px; background: #fff; color: var(--muted); font-size: 11.5px; padding: 0 10px; line-height: 26px; } +.rail ul { list-style: none; margin: 12px 0 0; padding: 0; } +.rail li { padding: 6px 8px; border-radius: 5px; margin-bottom: 2px; } +.rail li.active { background: var(--accent-bg); font-weight: 600; box-shadow: inset 3px 0 0 var(--accent); } +.rail .new { color: var(--muted); padding: 6px 8px; margin-top: 6px; } + +/* ---- main zone ---- */ +.main { flex: 1; display: flex; flex-direction: column; min-width: 0; } +.facettabs { height: 36px; display: flex; align-items: center; gap: 18px; padding: 0 16px; border-bottom: 1px solid var(--border); } +.facettabs a { color: var(--muted); text-decoration: none; padding-bottom: 8px; margin-top: 8px; display: inline-flex; align-items: center; gap: 5px; } +.facettabs a.active { color: var(--text); font-weight: 600; border-bottom: 2px solid var(--accent); } +.facettabs .sep { width: 1px; height: 18px; background: var(--border); } +.facettabs .tag { font-size: 8.5px; color: var(--muted); background: var(--chip); border-radius: 7px; padding: 1px 6px; } +.toolbar { display: flex; align-items: center; gap: 18px; padding: 8px 16px; color: var(--muted); font-size: 11.5px; } +.toolbar .spacer { flex: 1; } +.toolbar .add { color: var(--accent); font-weight: 600; } +.workarea { flex: 1; padding: 0 16px 16px; overflow: auto; } + +/* ---- reused-component marker ---- */ +.reuse { position: relative; border: 1px dashed #c8ccd2; border-radius: var(--radius); } +.reuse > .reuse-tag { position: absolute; left: 10px; bottom: 6px; font-size: 9.5px; font-style: italic; color: var(--faint); background: var(--surface-1); padding: 0 4px; white-space: nowrap; } + +/* ---- data grid (reused ListView) ---- */ +table.grid { width: 100%; border-collapse: collapse; font-size: 11.5px; } +table.grid th { text-align: left; background: var(--surface-2); color: var(--muted); font-weight: 600; padding: 8px 12px; border-bottom: 1px solid var(--border); } +table.grid td { padding: 8px 12px; border-bottom: 1px solid var(--line); } +table.grid td.muted, table.grid th.muted { color: var(--muted); } +table.grid .col-selected { background: color-mix(in srgb, var(--accent-bg) 60%, transparent); } +table.grid th.col-selected { color: var(--accent); } +.grid-add { color: var(--muted); padding: 8px 12px; } + +/* ---- right inspector (reused protocol form) ---- */ +.inspector { width: 220px; background: var(--surface-2); border-left: 1px solid var(--border); padding: 14px 16px; } +.inspector .eyebrow { font-size: 10.5px; letter-spacing: .4px; color: var(--muted); } +.inspector h3 { margin: 4px 0 10px; font-size: 14px; } +.inspector hr { border: 0; border-top: 1px solid var(--border); margin: 0 0 12px; } +.form { padding: 12px 12px 30px; } +.form .flabel { font-size: 10.5px; color: var(--muted); margin: 12px 0 5px; } +.form .flabel:first-child { margin-top: 0; } +.form .field { height: 26px; border: 1px solid var(--border); border-radius: 5px; background: #fff; font-size: 11.5px; padding: 0 10px; line-height: 26px; } +.form .chips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; } +.chip { background: var(--chip); border-radius: 11px; padding: 3px 10px; font-size: 10.5px; } +.form .add { color: var(--accent); font-size: 11px; } +.form .toggle-row { display: flex; justify-content: space-between; align-items: center; margin-top: 12px; } +.toggle { width: 36px; height: 18px; border-radius: 9px; background: #d7dbe0; position: relative; } +.toggle::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: #fff; } +.toggle.on { background: var(--accent); } +.toggle.on::after { left: 20px; } + +/* ---- legend ---- */ +.legend { display: flex; gap: 26px; padding: 8px 16px; border-top: 1px solid var(--border); font-size: 10.5px; color: var(--muted); } +.legend .sw { display: inline-block; width: 14px; height: 12px; vertical-align: -1px; margin-right: 6px; } +.legend .sw.built { border: 1px solid var(--text); } +.legend .sw.reused { border: 1px dashed #c8ccd2; } From 2bcab533fee1a5324a5424f8051d80b3b440dfe1 Mon Sep 17 00:00:00 2001 From: Jack Zhuang Date: Wed, 1 Jul 2026 13:03:08 +0800 Subject: [PATCH 8/8] docs(design): reserve bottom clearance so grid + New record clears its caption Co-Authored-By: Claude Opus 4.8 --- docs/design/builder-ui/shell.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/design/builder-ui/shell.css b/docs/design/builder-ui/shell.css index fb35f1bad..cca7a5fd9 100644 --- a/docs/design/builder-ui/shell.css +++ b/docs/design/builder-ui/shell.css @@ -72,7 +72,7 @@ table.grid td { padding: 8px 12px; border-bottom: 1px solid var(--line); } table.grid td.muted, table.grid th.muted { color: var(--muted); } table.grid .col-selected { background: color-mix(in srgb, var(--accent-bg) 60%, transparent); } table.grid th.col-selected { color: var(--accent); } -.grid-add { color: var(--muted); padding: 8px 12px; } +.grid-add { color: var(--muted); padding: 8px 12px 26px; } /* ---- right inspector (reused protocol form) ---- */ .inspector { width: 220px; background: var(--surface-2); border-left: 1px solid var(--border); padding: 14px 16px; }