ObjectStackObjectStack

Field

Field protocol schemas

Field Type Enum

Source: packages/spec/src/data/field.zod.ts

TypeScript Usage

import { CurrencyConfigSchema, CurrencyValueSchema, FieldSchema, FieldType, LocationCoordinatesSchema, SelectOptionSchema, UniqueScopeSchema } from '@objectstack/spec/data';
import type { CurrencyConfig, CurrencyValue, Field, FieldType, LocationCoordinates, SelectOption, UniqueScope } from '@objectstack/spec/data';

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

CurrencyConfig

Properties

PropertyTypeRequiredDescription
precisionintegeroptionalDecimal precision (default: 2)
currencyModeEnum<'dynamic' | 'fixed'>Currency mode: dynamic (user selectable) or fixed (single currency)
defaultCurrencystringDefault or fixed currency code (ISO 4217, e.g., USD, CNY, EUR)

CurrencyValue

Properties

PropertyTypeRequiredDescription
valuenumberMonetary amount
currencystringCurrency code (ISO 4217)

Field

Properties

PropertyTypeRequiredDescription
namestringoptionalMachine name (snake_case)
labelstringoptionalHuman readable label
typeEnum<'text' | 'textarea' | 'email' | 'url' | 'phone' | 'password' | 'secret' | 'markdown' | 'html' | 'richtext' | 'number' | 'currency' | 'percent' | 'date' | … +35 more>Field Data Type
descriptionstringoptionalTooltip/Help text
formatstringoptionalFormat string (e.g. email, phone)
requiredbooleanoptionalWrite-time contract (ADR-0113): an insert must provide a non-null value, and an update may not null it out. NOT a column constraint — the physical NOT NULL is a separate explicit opt-in (storage.notNull), so tightening this on a deployed object is safe: existing null rows stay readable, and editable as long as the write does not touch this field.
storage{ notNull?: boolean }optionalPhysical storage constraints (ADR-0113). Owns the DDL the write contract deliberately does not imply. Absent = no storage-level constraint requested.
searchablebooleanoptionalIs searchable
multiplebooleanoptionalAllow multiple values (Stores as Array/JSON). Applicable for select, lookup, file, image.
uniqueboolean | 'global' | 'organization'optionalUnique constraint and its scope (ADR-0120). 'organization' = one holder per organization (NULL-safe composite with the organization key part on organization-scoped objects) — prefer this explicit spelling in new code; true = same per-organization scope (positional synonym, stays valid); 'global' = one holder across the whole installation. 'tenant'/'org' are rejected — the word is 'organization'
defaultValueanyoptionalDefault applied on INSERT when the field is omitted or null ('' is a real value, not absence). Three legal shapes (#7127), discriminated in the engine's own order: a CEL Expression envelope { dialect: 'cel', source: 'today()' } (accepted structurally; result type is a runtime concern); a runtime TOKEN — NOW() on datetime/date/time only, current_user on user or lookup with reference: 'sys_user' only, neither on a multi-value field; or a LITERAL, which must satisfy this field's own stored value contract (ADR-0104 D1 valueSchemaFor). Anything else is refused at parse time with a prescriptive message.
maxLengthnumberoptionalMax character length
minLengthnumberoptionalMin character length
precisionnumberoptionalTotal digits
scalenumberoptionalDecimal places
minnumberoptionalMinimum value
maxnumberoptionalMaximum value
useGroupingbooleanoptionalDigit-grouping presentation hint for number fields (#7768) — maps to Intl.NumberFormat's useGrouping. Absent = renderer decides (interim heuristic today, locale default eventually); false = author opts out of grouping (e.g. a year or other ordinal/identifier integer); true = author pins grouping on.
acceptstring[]optionalPermitted upload types for media fields, as MIME types or extensions (e.g. ["image/*", ".pdf"]). Offered to the file picker AND enforced on write.
maxSizeintegeroptionalMaximum permitted file size in BYTES for media fields. Enforced on write against the stored file size, not just checked in the browser.
options{ label: string; value: string; color?: string; default?: boolean; … }[]optionalStatic options for select/multiselect
referencestringoptionalTarget object name (snake_case) for lookup/master_detail fields. Required for relationship types. Used by $expand to resolve foreign key IDs into full objects.
deleteBehaviorEnum<'set_null' | 'cascade' | 'restrict'>optionalWhat happens if referenced record is deleted
inlineEditboolean | Enum<'grid' | 'form'>optionalEdit these child records inline within the parent's form (atomic master-detail). true = auto-pick grid/form by child shape; 'grid' = editable line-item grid; 'form' = list + per-row full form.
inlineTitlestringoptionalTitle for the inline master-detail grid
inlineColumnsany[]optionalExplicit columns for the inline grid (derived from the child object when omitted)
inlineAmountFieldstringoptionalNumeric child field summed for the inline grid total
relatedListboolean | 'primary'optionalShow this child collection as a related list on the parent's detail page (read-side mirror of inlineEdit). false = suppress; true/absent = shown (stacked under the shared "Related" tab); 'primary' = core relationship, promoted to its own tab. Prominence intent, not a layout switch (ADR-0085).
relatedListTitlestringoptionalTitle for the detail-page related list
relatedListColumnsany[]optionalExplicit columns for the detail-page related list (derived from the child object when omitted)
displayFieldstringoptionalField shown as each candidate's label in the picker/popover (defaults to the referenced object's name/title).
descriptionFieldstringoptionalSecondary field shown under the label in the quick-select popover.
lookupColumns(string | { field: string; label?: string; width?: string; type?: string })[]optionalExplicit columns for the record-picker table; auto-derived from the referenced object when omitted.
lookupPageSizeintegeroptionalRows per page in the record-picker dialog (default 10).
lookupFilters{ field: string; operator: Enum<'eq' | 'ne' | 'gt' | 'lt' | 'gte' | 'lte' | 'contains' | 'in' | 'notIn'>; value: any }[]optionalBase filters restricting which records are selectable (e.g. only active). The structured, picker-honoured lookup filter.
dependsOn(string | { field: string; param?: string })[]optionalDeclares that this field's available values depend on the value of other field(s) on the same record — the form gates the field until they are set and re-evaluates as they change. For lookup/master_detail it scopes the candidate query (string = same local/remote key; {field,param} when the remote filter key differs — the {field,param} form is lookup-only). For select/multiselect/radio the actual per-option rule lives in each option's visibleWhen; list the referenced fields here (string form) so the option list gates and refreshes with the parent.
allowCreatebooleanoptionalAllow inline quick-create from the record picker: when no match exists the user can create a record from the typed text (optimistic dataSource.create with the display field). Best for simple objects whose only required field is the display field.
expressionstring | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object }optionalFormula expression (CEL). e.g. Frecord.amount * 0.1
returnTypeEnum<'number' | 'text' | 'boolean' | 'date'>optionalInferred value type of a formula field (number/text/boolean/date)
summaryOperations{ object: string; field: string; function: Enum<'count' | 'sum' | 'min' | 'max' | 'avg'>; relationshipField?: string; … }optionalRoll-up summary definition. The engine recomputes the value when child records are inserted/updated/deleted.
languagestringoptionalProgramming language for syntax highlighting (e.g., javascript, python, sql)
stepnumberoptionalStep increment for slider (default: 1)
currencyConfig{ precision?: integer; currencyMode?: Enum<'dynamic' | 'fixed'>; defaultCurrency?: string }optionalConfiguration for currency field type
dimensionsintegeroptionalVector dimensionality (e.g., 1536 for OpenAI embeddings)
trackHistorybooleanoptionalRender this field's value changes as human-readable entries on the record activity timeline (ADR-0052 §5b). Opt-in per field.
groupstringoptionalField group name for organizing fields in forms and layouts (e.g., "contact_info", "billing", "system")
visibleWhenstring | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object }optionalPredicate (CEL) — field is shown only when TRUE (else hidden). e.g. Precord.type == 'invoice'
readonlyWhenstring | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object }optionalPredicate (CEL) — field is read-only when TRUE. e.g. Precord.status == 'paid'
requiredWhenstring | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object }optionalPredicate (CEL) — field is required when TRUE. The only slot; the conditionalRequired alias was removed in protocol 17 (#3855).
conditionalRequiredneveroptional[REMOVED] conditionalRequired was removed in @objectstack/spec 17 (#3855) — use requiredWhen. Rename the key; the value (a CEL predicate) is unchanged. Run os migrate meta --from 16 to rewrite existing sources automatically.
widgetstringoptionalForm widget override — names a registered field component (resolved as field:<widget>) to render this field instead of the type default. Degrades to the type renderer when unregistered. e.g. "object-ref", "filter-condition", "recipient-picker".
hiddenbooleanoptionalHidden from default UI
internalbooleanoptional[#7728] Never return this field's value on the generic data path — the engine OMITS the key from find/findOne results, the 201 create body and the by-id update body, on the default projection AND when a client names the field in ?select=. Storage, filtering and indexing are untouched, so a server-side verifier can still match on the column and a purpose-built mint route can still return the value once at creation. The read protection for ADR-0100's third credential channel (auth-subsystem one-way hashes on text columns). Omission, not masking: a mask signals 'a value is set', which carries no information on a required column.
readonlybooleanoptionalRead-only — never editable in forms, AND server-enforced on BOTH write paths: a non-system write to this field is silently dropped from the payload on UPDATE (#2948/#3003) and on INSERT (#3043; a create can no longer directly seed e.g. approval_status: "approved"), symmetric with readonlyWhen. A stripped INSERT field still falls back to its defaultValue. Exempt from the strip on BOTH paths: isSystem writes (seed replay, migration). Exempt on the UPDATE path ONLY: an opt-in "historical" import (preserveAudit, #3493) — which admits a whitelist (the audit/timestamp family plus author-declared business readonly fields). On INSERT the exemption does NOT apply (#6640): a non-system create that requests preserveAudit still has its readonly fields stripped, and is warned loudly that the exemption is UPDATE-only — replaying archival readonly facts on create requires a system context. A normal (non-system) import is NOT system-context and still strips.
requiredPermissionsstring[]optional[ADR-0066 D3] Capabilities required to read/edit this field (mask on read, deny on write; AND-gate).
ackPlaintextMaskingbooleanoptional[ADR-0100] Affirm a generic password field's plaintext-at-rest / masked-on-read contract is intended, silencing the author-time warning (#3420). No effect on non-password fields.
systembooleanoptionalAuto-injected system/audit field (e.g. created_at, updated_by, organization_id). Tools that surface system fields separately from author-declared business fields should branch on this flag.
sortablebooleanoptionalWhether field is sortable in list views
inlineHelpTextstringoptionalHelp text displayed below the field in forms
autonumberFormatstringoptionalAuto-number format: literal text + {0000} counter, {YYYY}/{MM}/{DD}/{YYYYMMDD} date tokens (business tz), and {field_name} interpolation. Counter resets per rendered prefix (e.g. AD{YYYYMMDD}``{0000} resets daily). Omitted on an autonumber field ⇒ the contract default {0000} (#6555).
externalIdbooleanoptionalIs external ID for upsert operations
_lockEnum<'none' | 'no-overlay' | 'no-delete' | 'full'>optionalItem-level lock — controls overlay & delete (ADR-0010).
_lockReasonstringoptionalHuman-readable reason shown when a write is refused by _lock.
_lockSourceEnum<'artifact' | 'package' | 'env-forced'>optionalLayer that set _lock (artifact | package | env-forced).
_provenanceEnum<'package' | 'org' | 'env-forced'>optionalOrigin of the item (package | org | env-forced).
_packageIdstringoptionalOwning package machine id.
_packageVersionstringoptionalOwning package version.
_lockDocsUrlstringoptionalOptional documentation link surfaced next to _lockReason.

Allowed Values: Field.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

FieldType

Allowed Values

  • 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

LocationCoordinates

Properties

PropertyTypeRequiredDescription
latitudenumberLatitude coordinate
longitudenumberLongitude coordinate
altitudenumberoptionalAltitude in meters
accuracynumberoptionalAccuracy in meters

SelectOption

Properties

PropertyTypeRequiredDescription
labelstringDisplay label (human-readable, any case allowed)
valuestringStored value (lowercase machine identifier)
colorstringoptionalColor code for badges/charts
defaultbooleanoptionalIs default option
visibleWhenstring | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object }optionalPer-option visibility predicate (CEL) — option is offered only when TRUE (else omitted). Env: the live record plus the host predicate scope, which binds current_user — wider than field-level visibleWhen, which has no current_user. e.g. Precord.country == 'cn' or P'admin' in current_user.positions

UniqueScope

Union Options

This schema accepts one of the following structures:

Option 1

Type: boolean


Option 2

Type: 'global'


Option 3

Type: 'organization'



On this page