ObjectStackObjectStack

Solution Blueprint

Solution Blueprint protocol schemas

Source: packages/spec/src/ai/solution-blueprint.zod.ts

TypeScript Usage

import { BlueprintAppSchema, BlueprintConditionSchema, BlueprintDashboardSchema, BlueprintFieldSchema, BlueprintNavItemSchema, BlueprintObjectSchema, BlueprintSeedSchema, BlueprintSummaryOperationsSchema, BlueprintViewSchema, BlueprintWidgetConditionSchema, SolutionBlueprintSchema, SolutionBlueprintStrictSchema } from '@objectstack/spec/ai';
import type { BlueprintApp, BlueprintCondition, BlueprintDashboard, BlueprintField, BlueprintNavItem, BlueprintObject, BlueprintSeed, BlueprintSummaryOperations, BlueprintView, BlueprintWidgetCondition, SolutionBlueprint, SolutionBlueprintStrict } from '@objectstack/spec/ai';

// Validate data
const result = BlueprintAppSchema.parse(data);

BlueprintApp

Properties

PropertyTypeRequiredDescription
namestringApp machine name (snake_case)
labelstringoptionalApp display label
iconstringoptionalLucide icon for the App Launcher
nav{ type: Enum<'object' | 'dashboard'>; target: string; label?: string; icon?: string }[]optionalNavigation entries; omit to auto-surface every created object and dashboard

BlueprintCondition

Properties

PropertyTypeRequiredDescription
fieldstringField on the target object to filter by (e.g. "stock_quantity", "status")
opEnum<'lt' | 'lte' | 'gt' | 'gte' | 'eq' | 'ne'>Comparison operator
valuenumber | string | booleanComparison value — for a select field use its option VALUE, never its label (e.g. "completed", not "已完成")

BlueprintDashboard

Properties

PropertyTypeRequiredDescription
namestringDashboard machine name (snake_case)
labelstringoptionalHuman-readable dashboard label
widgets{ id: string; title?: string; object?: string; chart?: Enum<'metric' | 'bar' | 'line' | 'pie' | 'table'>; … }[]optionalWidgets to place on the dashboard

BlueprintField

Properties

PropertyTypeRequiredDescription
namestringField machine name (snake_case)
labelstringoptionalHuman-readable field label
typeEnum<'text' | 'textarea' | 'email' | 'url' | 'phone' | 'password' | 'secret' | 'markdown' | 'html' | 'richtext' | 'number' | 'currency' | 'percent' | 'date' | … +35 more>Field data type
requiredbooleanoptionalWhether the field is required
referencestringoptionalTarget object name for lookup / master_detail relationship fields
options{ label: string; value: string }[]optionalChoices for select / multiselect / radio fields
summaryOperations{ object: string; function: Enum<'count' | 'sum' | 'avg' | 'min' | 'max'>; field?: string; relationshipField?: string; … }optionalREQUIRED when type is "summary" (a roll-up of child records: 任务总数 / 报名人数 / 合计金额 / 已完成任务数). Names the child object, the aggregation, and — for a qualified count/sum — the condition. A "summary" field without it materializes runtime-dead.
expressionstringoptionalREQUIRED when type is "formula" — the CEL body the field computes, e.g. "record.quantity * record.unit_price", or "record.order_no + ' · ' + record.customer" for a composed title. A "formula" field without it materializes runtime-dead: the engine builds its formula plan only from fields that HAVE an expression, so the field reads null everywhere, forever. Same failure shape as a "summary" with no summaryOperations. Note nameField on the object recommends a formula for numbered entities (invoice/ticket) — that formula needs THIS key, or the record title is blank on every card, lookup chip and breadcrumb.

Allowed Values: BlueprintField.type

  • text
  • textarea
  • email
  • url
  • phone
  • password
  • secret
  • markdown
  • html
  • richtext
  • number
  • currency
  • percent
  • date
  • datetime
  • time
  • boolean
  • toggle
  • select
  • multiselect
  • radio
  • checkboxes
  • lookup
  • master_detail
  • tree
  • user
  • image
  • file
  • avatar
  • video
  • audio
  • formula
  • summary
  • autonumber
  • composite
  • repeater
  • record
  • location
  • address
  • code
  • json
  • color
  • rating
  • slider
  • signature
  • qrcode
  • progress
  • tags
  • vector

BlueprintNavItem

Properties

PropertyTypeRequiredDescription
typeEnum<'object' | 'dashboard'>What this nav entry opens
targetstringObject or dashboard machine name to surface (snake_case)
labelstringoptionalNav entry label (defaults to the target label/name)
iconstringoptionalLucide icon name for the nav entry

BlueprintObject

Properties

PropertyTypeRequiredDescription
namestringObject machine name (snake_case)
labelstringoptionalHuman-readable singular label
descriptionstringoptionalWhat this object represents
fields{ name: string; label?: string; type: Enum<'text' | 'textarea' | 'email' | 'url' | 'phone' | 'password' | 'secret' | … +42 more>; required?: boolean; … }[]Fields to create on the object
nameFieldstringoptionalThe record title field — which field holds the human-readable name shown on cards, lookup chips, breadcrumbs and search (ADR-0079). Set it to the object's text label field (e.g. "product_name"). For a numbered entity (invoice/ticket), set it to a formula field that composes number + name (e.g. "{order_no} · {customer}"). Omitting it lets the platform auto-pick a text field, but declaring it is strongly preferred.

BlueprintSeed

Properties

PropertyTypeRequiredDescription
objectstringTarget object name (snake_case)
recordsRecord<string, any>[]Rows to seed

BlueprintSummaryOperations

Properties

PropertyTypeRequiredDescription
objectstringThe CHILD object whose records are aggregated (snake_case). It must carry a lookup / master_detail field pointing back at this parent, or the roll-up never computes.
functionEnum<'count' | 'sum' | 'avg' | 'min' | 'max'>Aggregation: "数量 / 个数 / 计数" → count; "合计 / 总额 / 累计" → sum; "平均" → avg
fieldstringoptionalNumeric field on the CHILD object to aggregate. Ignored for "count" (pass "id" or omit it).
relationshipFieldstringoptionalThe child FK field pointing back at this parent. Auto-detected from the child's lookup / master_detail; set it only when the child has more than one reference to this parent.
conditions{ field: string; op: Enum<'lt' | 'lte' | 'gt' | 'gte' | 'eq' | 'ne'>; value: number | string | boolean }[]optionalCONDITIONAL roll-up: aggregate only the child rows matching these comparisons (ANDed). REQUIRED whenever the field name carries a qualifier — "已完成任务数 / 已收货金额 / 待处理工单数", any 已X / 未X / <某状态>的 count-or-sum → e.g. [{ field: "status", op: "eq", value: "completed" }]. WITHOUT it the roll-up silently counts EVERY child and reports a plausible-looking WRONG number, which is worse than a visible 0.
filteranyoptionalThe same predicate as a canonical query filter map (e.g. { status: "completed" }, { status: { $in: ["received", "partial"] } }). Use it when hand-authoring a blueprint; the structured design path uses conditions instead. Wins over conditions when both are given.

BlueprintView

Properties

PropertyTypeRequiredDescription
objectstringObject this view displays (snake_case)
namestringView machine name (snake_case)
labelstringoptionalHuman-readable view label
typeEnum<'list' | 'form' | 'kanban' | 'calendar' | 'gallery' | 'gantt'>View kind. Pick the surface that fits the data: "gallery" for a visual card/cover browse when the user asks for a 画廊/相册/卡片墙/封面/海报/图集 (a gallery / card wall / cover / poster grid) or the object has an image/avatar/file field worth showing as a card cover; "gantt" for a 甘特图/时间线/排期 (timeline / schedule) when the object has BOTH a start and an end date field; "kanban" for a board grouped by a status/select field; "calendar" for a single-date schedule; "form" for a record editor; else "list".
columnsstring[]optionalField names shown as columns (in order). For a gallery, INCLUDE the image/avatar/file field (it becomes the card cover); for a gantt, INCLUDE the start date column before the end date column.
groupBystringoptionalREQUIRED for kanban views: the select/status field whose options become the board columns (e.g. "stage", "status"). Without it a kanban renders as a plain list. Optional for gantt (groups leaf tasks into summary rows).

BlueprintWidgetCondition

Properties

PropertyTypeRequiredDescription
fieldstringField on the target object to filter by (e.g. "stock_quantity", "status")
opEnum<'lt' | 'lte' | 'gt' | 'gte' | 'eq' | 'ne'>Comparison operator
valuenumber | string | booleanComparison value — for a select field use its option VALUE, never its label (e.g. "completed", not "已完成")

SolutionBlueprint

Properties

PropertyTypeRequiredDescription
summarystringoptionalOne-line description of the proposed solution
assumptionsstring[]Design assumptions made from the underspecified goal
questionsstring[]optionalAt most 1-2 structure-deciding questions to confirm before building
objects{ name: string; label?: string; description?: string; fields: object[]; … }[]Objects (tables) to create
views{ object: string; name: string; label?: string; type: Enum<'list' | 'form' | 'kanban' | 'calendar' | 'gallery' | 'gantt'>; … }[]optionalViews to create
dashboards{ name: string; label?: string; widgets?: object[] }[]optionalDashboards to create
app{ name: string; label?: string; icon?: string; nav?: object[] }optionalThe navigation shell (app) that surfaces the created objects/dashboards to end users
seedData{ object: string; records: Record<string, any>[] }[]optionalSuggested seed data (reported, not auto-applied in Phase C)

SolutionBlueprintStrict

Properties

PropertyTypeRequiredDescription
summarystringOne-line description of the proposed solution
assumptionsstring[]Design assumptions made from the underspecified goal
questionsstring[] | nullAt most 1-2 structure-deciding questions to confirm before building, or null
objects{ name: string; label: string | null; description: string | null; fields: object[] }[]Objects (tables) to create
views{ object: string; name: string; label: string | null; type: Enum<'list' | 'form' | 'kanban' | 'calendar' | 'gallery' | 'gantt'> | null; … }[] | nullViews to create, or null
dashboards{ name: string; label: string | null; widgets: object[] | null }[] | nullDashboards to create, or null
app{ name: string; label: string | null; icon: string | null; nav: object[] | null } | nullThe navigation shell (app) that surfaces the created objects/dashboards, or null

On this page