AppSpring Docs

Properties (PropertyDecl)

Generated from the doc schema (CatalogDocSchema, @canonify/kernel-catalog/doc): each field’s type, default and description are the schema’s own, and each example is a bundle file that readBundle decodes. A field’s Example is its value in one of those examples.

PropertyDecl

A property of a type.

One of, told apart by kind:

PropertyDecl.stored

A stored value.

Field Type Required Default Example Description
kind "stored" yes — "stored" A stored property: a value in its own column.
id PropId yes (propose assigns it; a new declaration leaves it out) — "pr_2h6k8m4q0z" A property id (pr_…); renames keep it.
name Ident yes — "name" The property name.
label Text yes (a draft may leave it out: propose writes a default made from the name, catalog.label_defaulted) — "Name" The words shown for it.
type ValueType yes — {"t":"text"} What the property holds.
required boolean no false true Whether every row must have a value; default false.
default Expr | SequenceDefault no — "today()" The value of a new row whose create leaves it blank: a constant of the type, today() / now(), or a sequence (a text or integer property).
history boolean no — true Whether every change of the value is kept as history.
searchable SearchSpec no — {"weight":"body"} Whether and how the property is searched.
sensitive "personal" | "secret" no — "personal" Personal data is masked for readers without the right; a secret is never shown (authz).
migrate PropertyDecl.stored.migrate no (a draft’s only: propose takes it out before the hash, and a stored doc refuses it) — (see the example) How this change converts the rows that exist; absent = the change needs no transform.

An item of properties in a type file (types/<name>.json).

{
  "kind": "stored",
  "name": "email",
  "label": "Email",
  "type": { "t": "text", "format": "email" },
  "required": true
}

An item of properties in a type file (types/<name>.json).

{
  "kind": "stored",
  "name": "placed_on",
  "label": "Placed on",
  "type": { "t": "date" },
  "required": true,
  "default": "today()",
  "history": true,
  "searchable": { "weight": "body" },
  "sensitive": "personal"
}

An item of properties in a type file (types/<name>.json).

{
  "kind": "stored",
  "name": "priority",
  "label": "Priority",
  "type": { "t": "integer" },
  "required": true,
  "migrate": {
    "fill": "band_rank",
    "convert": "band_rank",
    "map": { "urgent": "high" },
    "inverse": "band_rank"
  }
}

PropertyDecl.ref

A reference to another row.

Field Type Required Default Example Description
kind "ref" yes — "ref" A reference to one row of another type.
id PropId yes (propose assigns it; a new declaration leaves it out) — "pr_2d4f6h8k0m" A property id (pr_…); renames keep it.
name Ident yes — "customer" The property name.
label Text yes (a draft may leave it out: propose writes a default made from the name, catalog.label_defaulted) — "Customer" The words shown for it.
target TypeId yes — "ty_7k2m9q4z1a" The type it refers to.
required boolean no false true Whether every row must have a value; default false.
onDelete "restrict" | "cascade" | "set_null" yes — "cascade" What deleting the target row does: refuse, delete this row too, or clear the reference.
history boolean no — true Whether every change of the value is kept as history.
searchable SearchSpec no — {"weight":"title"} Whether and how the property is searched.
inverse PropertyDecl.ref.inverse no — {"name":"orders","label":"Orders"} The reverse reference on the target (C22); default name = this type’s name.
settles boolean no true true Whether a terminal state of the target locks this row (runtime); default true.
sensitive "personal" | "secret" no — "personal" Personal data is masked for readers without the right; a secret is never shown (authz).
migrate PropertyDecl.ref.migrate no (a draft’s only: propose takes it out before the hash, and a stored doc refuses it) — (see the example) How this change converts the rows that exist; absent = the change needs no transform.

An item of properties in a type file (types/<name>.json).

{
  "kind": "ref",
  "name": "customer",
  "label": "Customer",
  "target": "ty_7k2m9q4z1a",
  "required": true,
  "onDelete": "restrict",
  "history": true,
  "searchable": { "weight": "title" },
  "inverse": { "name": "orders", "label": "Orders" },
  "settles": false,
  "sensitive": "personal",
  "migrate": {
    "fill": "first_customer",
    "convert": "first_customer",
    "inverse": "customer"
  }
}

PropertyDecl.ref.inverse

The reverse reference on the target (C22); default name = this type’s name.

Field Type Required Default Example Description
name Ident yes — "orders" The name CX reads the reverse collection by, on the target.
label Text yes (a draft may leave it out: propose writes a default made from the name, catalog.label_defaulted) — "Orders" The words shown for the reverse collection.

PropertyDecl.derived

A value computed from the row.

Field Type Required Default Example Description
kind "derived" yes — "derived" A derived property: a CX expression over the row, never stored.
id PropId yes (propose assigns it; a new declaration leaves it out) — — A property id (pr_…); renames keep it.
name Ident yes — "total" The property name.
label Text yes (a draft may leave it out: propose writes a default made from the name, catalog.label_defaulted) — "Total" The words shown for it.
params ParamDecl[] no — [{"name":"day","type":"date"}] The parameters a reader passes (cx.md §2.10).
expr Expr yes — "lines.sum(l => l.amount)" The CX expression it computes.
type ValueType no — {"t":"money","currency":"DKK"} The asserted type; compile checks it equals the inferred type (derived.type_mismatch).
visibility "over_readable" | "whole_or_withheld" yes — "over_readable" Over the rows the reader may read, or withheld unless the reader may read every row it uses.
searchable SearchSpec no — {"weight":"body"} Whether and how the property is searched.

An item of properties in a type file (types/<name>.json).

{
  "kind": "derived",
  "name": "total",
  "label": "Total",
  "expr": "lines.sum(l => l.amount)",
  "type": { "t": "money", "currency": "DKK" },
  "visibility": "over_readable",
  "searchable": { "weight": "body" }
}

An item of properties in a type file (types/<name>.json).

{
  "kind": "derived",
  "name": "open_on",
  "label": "Open on",
  "params": [{ "name": "day", "type": "date" }],
  "expr": "placed_on <= day",
  "visibility": "whole_or_withheld"
}

PropertyDecl.state

The row’s lifecycle state.

Field Type Required Default Example Description
kind "state" yes — "state" A state property: the row’s state in a lifecycle.
id PropId yes (propose assigns it; a new declaration leaves it out) — — A property id (pr_…); renames keep it.
name Ident yes — "status" The property name.
label Text yes (a draft may leave it out: propose writes a default made from the name, catalog.label_defaulted) — "Status" The words shown for it.
lifecycle FsmId yes — "lc_2k4m6p8r0t" The lifecycle it follows.
history true no — true A state always keeps its history.

An item of properties in a type file (types/<name>.json).

{
  "kind": "state",
  "name": "status",
  "label": "Status",
  "lifecycle": "lc_2k4m6p8r0t",
  "history": true
}

PropertyDecl.stored.migrate

How this change converts the rows that exist; absent = the change needs no transform.

Field Type Required Default Example Description
fill Expr no — "band_rank" The value of each existing row when the property is added as required.
convert Expr no — "band_rank" The new value of each row when the property is retyped; null means the row cannot be converted.
inverse Expr no — "band_rank" The old value of each row, which makes a retype exact on rewind.
map Record<Ident, Ident> no — {"urgent":"high"} Old enum code to new code, for rows that hold a value this change drops.

PropertyDecl.ref.migrate

How this change converts the rows that exist; absent = the change needs no transform.

Field Type Required Default Example Description
fill Expr no — "first_customer" The value of each existing row when the property is added as required.
convert Expr no — "first_customer" The new value of each row when the property is retyped; null means the row cannot be converted.
inverse Expr no — "customer" The old value of each row, which makes a retype exact on rewind.

SequenceDefault

A number the write engine allocates when a create leaves the property blank: gap-free per scope, in the write transaction.

Field Type Required Default Example Description
sequence string yes — "FV/{year}/" The template the number follows: literal text and the date parts {year} and {month}, which set the scope (one counter per year, per month, or one for the property).
start integer (greater than or equal to 0) no 1 1001 The first number of each scope; default 1.
digits integer (between 1 and 12) no — 4 Writes the number with at least this many digits, zero-padded (a text property only).

The default of a stored text or integer property.

{ "sequence": "FV/{year}/", "start": 1001, "digits": 4 }

This page as Markdown