#Core Concepts

This page is the mental model. Each concept links to the guide that covers it in depth.

#Entities, types, and relationships

  • An entity is a single data object. It has a name, an attributes JSON blob, and belongs to exactly one entity type.
  • An entity type defines the shape: a JSON schema that validates attributes, an identifier key (for upsert + de-duplication), and which attributes are indexed (sortable/searchable for queries).
  • A relationship rule declares that two types may relate (e.g. Project → Task). A relationship is a concrete link between two entities under a rule.

Why flexible types? You evolve your data model without migrations — add a type, extend a schema, declare a new relationship rule, and start writing data.

Entities & Data Model

#Querying

Two complementary read paths over the same data:

  • REST query (POST /entity/query) — composite filters, sorting, keyset/offset pagination, relationship include trees, and counts.
  • GraphQL (POST /entity/graphql) — a typed graph view with Relay-style edges/node, where, and orderBy.

The two share the same underlying engine; a GraphQL query maps to the same filter/sort/include primitives a REST query uses. (You can convert one to a workflow step — see Querying & GraphQL and the converter at /graphql/.)

#Workflows, jobs, and actions

  • A workflow is an ordered set of steps. Each step runs an action (create an entity, call HTTP, publish an event, …).
  • A step can run an action inline, or invoke a referenced job — a reusable unit of work defined separately and called by name. Inline keeps small logic local; referenced jobs share logic across workflows.
  • Smart values ({{ … }}, $jsonata, $literal, $if) thread data between steps and from the trigger payload.

Definitions live in the definition surface (/definition); a tenant activates a definition (config + triggers) on the workflow surface (/workflows), which runs it and records runs you can inspect.

Workflows · Smart Values

#Triggers

A workflow doesn't run by itself — a trigger starts it:

  • Event triggers fire on published events.
  • Cron triggers fire on a schedule.
  • Webhook triggers fire on an inbound HTTP call (with a per-trigger secret).

Triggers

#Bridge apps, specs, and widgets

A bridge app is the UI runtime. Its app spec defines dashboards → pages → widgets (config-driven UI building blocks). The spec is a definition; a tenant activates it on the app surface (/apps) with config, integrations, principal overrides, and a token. At run time the spec renders to a widget tree (POST /apps/run).

Apps (Bridge) · App spec structure · Widget Catalogue

#Principals, policies, grants, and shares

Access control has two tiers:

  • Grants are intra-tenant: a tenant authorizes one of its principals (user / team / policy) to act on a resource, optionally narrowed by an attribute filter.
  • Shares are inter-tenant and read-only: a tenant that owns a resource declares that another tenant may see it. A share never lets the other tenant write your data.

Cross-tenant data access needs both a share (from the owner) and a grant (in the consumer). This is what lets one tenant build on another's shared definitions or types without ever exposing the owner's rows to writes.

Shares & Grants · Provisioning

#Secrets

Tenant secrets hold credentials (API keys, tokens) that workflows and apps reference by name. Values are stored centrally and fetched by the engines at run time — never inlined into a definition.

Secrets

#Putting it together

The Canonical Example walks the whole chain on a single Tasks domain: model → workflow (inline + referenced job) → activation + monitoring → app spec (every widget) → app activation → provisioning → shares & grants → GraphQL→workflow conversion.