Interfaces and components
An interface is a set of pages for a group of people. Pages are built from components, and everything a component shows or does is declared: there is no code and no expression language, so the server can check every reference and run every query as the person viewing it.
Interfaces
- An app has up to 10 interfaces, each with a name, an icon, a home page and up to 30 pages.
- An interface's audience is a list of roles. Leave it empty and everyone with access to the app sees it. Pages and actions have audiences too.
- Each interface declares its own actions (up to 40), which pages reference by id.
Pages
| Kind | What it is |
|---|---|
| Collection | Many records of one type: a table, a board, a list, a calendar or a map, with metrics above if you like. Bound to a record type (or a live source's entity). |
| Record | One record: its detail, related records, its timeline and actions. Rows in a collection open it. The record is available to components as $record. |
| Dashboard | Metrics, charts, reports and text across types. No bound type. |
| Form | A form that creates a record, with a submit action. |
Components
A page has up to 40 components. Each shows only the fields it declares, and only the ones the viewer's role may read.
| Component | What it shows |
|---|---|
| Table | Rows from a saved view or a query, with up to 30 columns. A row opens the record or runs a declared action. Carries a bounded total (up to 20,000 rows). |
| Board | Cards grouped by a field (a status, a stage), with the fields to show on each card. |
| List | A compact list with a title field and subtitle fields. |
| Form | Fields to fill in, each with a label, help, required and read-only flags, and the action that runs on submit. On a record page it loads the record's values. |
| Detail | The record's fields in one or two columns. Record pages only. |
| Related | Records linked to this one through a relation, with the columns to show. Record pages on Records types only. |
| Metric | One number: a count, sum, average, minimum or maximum over a query, formatted as a number, currency or percentage. |
| Chart | A bar, line or pie chart over an aggregate, grouped by a field or by day, week, month, quarter or year. |
| Timeline | The record's activity: every change, who made it and when. Record pages on Records types only. |
| Text | Markdown, up to 8,000 characters. |
| Actions | Buttons for declared actions. |
| Calendar | Items by a date field, with an optional end field, in the visible range. A multi-day item that began earlier still shows. |
| Map | Rows with a numeric latitude and longitude. OpenStreetMap tiles by default, with attribution; a coordinates list when tiles are off. Rows without valid coordinates are skipped and counted. |
| Report | Up to 20 aggregate rows, each labelled, with an optional note and a CSV export. Exporting needs the export capability on every type the report reads. |
| Custom block | Your own HTML in a sandbox, fed only by the operations it declares. Custom blocks. |
Queries and tokens
Tables, boards, lists, metrics, charts, calendars, maps and reports read through the same closed query grammar as Records:
- Up to 25 conditions, matched with and or or, using 11 operators: equals, not equals, contains, starts with, greater than, at least, less than, at most, in a list, is empty, is not empty.
- Up to 3 sort keys, and a limit of 1 to 500 rows per page.
- Values are literals, or one of the context tokens
$me(the viewer),$today,$nowand$record.<field>(a field of the record the page shows).
Clients never send a query. A page asks the server for a component by name, and the server resolves that component's view, query or aggregate from the published definition, substitutes the tokens, and runs it as the viewer, with their row scope and field access. Rows carry only the declared fields plus the names of linked records the viewer may read.
Actions
Actions are declared on the interface and referenced by forms, tables and action buttons. A destructive action always confirms; you can add a confirmation message to any action.
| Kind | What it does |
|---|---|
create | Creates a record of a type, from a form or from fields set to literals, tokens or prompted inputs. |
update | Sets the listed fields of the current record. Inputs ask the person for a value before the action runs. |
changeOwner | Changes the record's owner. |
archive | With fields to set, an update; without, it archives the record (a soft removal, like delete). |
delete | Removes the record. Records are soft-deleted and can be restored. |
runAutomation | Starts an existing automation, under the automation's own governance. The response carries the run id. |
askAgent | Asks the App assistant to work on the current record with a prompt. Defined in the contract and answered by the server; not yet offered in the designer or on pages. Agents in apps. |
Every action goes through the app's write rules. The response says what happened: applied, sent for approval, refused, or started (for an automation). A write sends an optional Idempotency-Key and the record's expected version, so a repeated click does not repeat the change and a stale page cannot overwrite a newer one.
On a phone
Every component is responsive and renders in a single column under 768 pixels, so an app works in the Android app and in a phone browser without a separate design.