Runtime
Reference for each part of an application model. If you are new, start with Getting started instead.
An application is a directory
myapp/
app.yaml what it is called, who may log in
modules/sales/
module.yaml the module's manifest
domain.yaml what is stored
security.yaml who may see and change it
flows.yaml logic the model cannot express
flows/approve-order.lua ...and the script
metrics.yaml what to count
Only app.yaml and one module.yaml are required. Everything else is added
when you need it.
| File | Reference |
|---|---|
domain.yaml | Modelling a domain |
security.yaml | Security |
flows.yaml | Flows |
metrics.yaml | Metrics |
| — | The API the runtime serves |
Modules
A module is a bounded context: its own entities, its own roles, its own flows.
app.yaml lists the modules that make up an application and maps module roles
onto the roles your organisation actually has.
The indirection earns its keep — a module ships with a sensible permission model without knowing anything about the organisation deploying it.
Point your editor at the schema
Do this before writing a line. Every file starts with a modeline:
# yaml-language-server: $schema=../../runtime/assets/schema/app-model.schema.json
With the YAML extension installed you get completion on every field, inline
errors, and the documentation for each option as you type. The schema is
generated from the same types that parse your model, so it cannot drift from
what the runtime actually accepts. runtime model schema prints it.
Read the errors
They are the product, not an afterthought:
$ runtime model validate myapp
error[M203]: `precision` is not a parameter of type `string`
--> modules/sales/domain.yaml (entities[0].attributes[1])
help: remove it, or change the type to `decimal`
Validation runs in three passes and which one fails determines the message: parse (is it YAML, does it match the schema), resolve (does that entity exist, does that attribute exist on it), check (is this expression well-typed against the model).
Every diagnostic has a stable code, and Diagnostics
lists all of them. M2xx is a semantic problem; M9xx is a warning — legal, and
nearly always unfinished.
Two things that surprise people
Money is never a number. decimal crosses every boundary as a string — in
JSON and in Lua. A binary float cannot represent 0.10, and a total that is out
by a cent is a total nobody trusts. Sending 12.10 as a JSON number is an
error, not a rounding.
Writes need an If-Match. PATCH and DELETE without one are refused with
428. Two people editing the same record is not a race condition, it is a
Tuesday, and last-write-wins loses one of the two changes with no error at all.