Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
ae9b3c3
Close every spec schema object and reject removed keys through schema…
sebastiaoteixeira Oct 21, 2026
9998cf2
Run repository operations and handlers through one runtime shared by …
sebastiaoteixeira Oct 21, 2026
60a5c59
Share one access runtime across the dev server and generated backends
sebastiaoteixeira Oct 21, 2026
72962bd
Validate payloads with one shared field validator in every consumer
sebastiaoteixeira Oct 21, 2026
69b385b
Layer controller access, conventions and overrides into every route a…
sebastiaoteixeira Oct 21, 2026
480cf09
Enforce platform keys in every consumer
sebastiaoteixeira Oct 21, 2026
f971220
Test nested array payloads and the payload scenario on MongoDB develo…
sebastiaoteixeira Oct 23, 2026
e804c29
Generate abstract services as base classes and run custom operations …
sebastiaoteixeira Oct 23, 2026
dbeb321
Reject service forwarding to an operation without a query
sebastiaoteixeira Oct 23, 2026
d68cfec
Test services over HTTP against the dev server and generated backends
sebastiaoteixeira Oct 23, 2026
4e4f0a1
Enforce role grants, readonly fields, login exposure and row filters …
sebastiaoteixeira Oct 23, 2026
a188789
Register the 0.1 mongo block as the default datastore
sebastiaoteixeira Oct 24, 2026
7850b80
Keep non-identity role fields, keep record ids on raw replace and ret…
sebastiaoteixeira Oct 24, 2026
b7eccdf
Serve declared login routes, honour api.port in DRF and UI, echo requ…
sebastiaoteixeira Oct 24, 2026
7acb78d
Store datetimes as canonical UTC strings, fill and reject readonly fi…
sebastiaoteixeira Oct 24, 2026
fe684a5
Serve generated DRF views on adrf with async principal lookups, a loo…
sebastiaoteixeira Oct 24, 2026
a514f05
Default explicit controller routes to public and let operations overr…
sebastiaoteixeira Oct 24, 2026
507aba0
Reject services and routes bound to abstract repositories or services
sebastiaoteixeira Oct 24, 2026
001399c
Drop unimplemented pagination modes from the schema and their name-sp…
sebastiaoteixeira Oct 24, 2026
3632a77
Reject handlers naming undefined vendored functions and services decl…
sebastiaoteixeira Oct 24, 2026
8950acd
Reject repository queries targeting an undeclared collection
sebastiaoteixeira Oct 24, 2026
41c0d92
Merge branch 'grammar/models' into grammar/access
sebastiaoteixeira Oct 24, 2026
cad072e
Keep the FastAPI repository mixin import on its own line when the rep…
sebastiaoteixeira Oct 24, 2026
838ec43
Route literal path segments ahead of parameters at the same position
sebastiaoteixeira Oct 24, 2026
9c61d55
Name raw ASGI route handlers by method and path so controllers sharin…
sebastiaoteixeira Oct 24, 2026
86c4d84
Type field keys per field type in every schema and check bounds, defa…
sebastiaoteixeira Oct 24, 2026
b35c40b
Merge branch 'grammar/models' into grammar/services
sebastiaoteixeira Oct 24, 2026
48d9c70
Store every field default in the canonical form its own field gives a…
sebastiaoteixeira Oct 24, 2026
c076d69
Run the payload scenario on generated FastAPI over MongoDB, on Postgr…
sebastiaoteixeira Oct 24, 2026
128456f
Generate abstract service and repository bases on raw and DRF, route …
sebastiaoteixeira Oct 24, 2026
e167b5d
Locate route records and path scopes in the IR and admit anonymous ca…
sebastiaoteixeira Oct 24, 2026
1577a95
Reject operation names that shadow generated repository or service me…
sebastiaoteixeira Oct 24, 2026
d19f78b
Send typed, writable-only bodies from every generated form through a …
sebastiaoteixeira Oct 25, 2026
7896b47
Implement SAML login in the dev server and apply SAML binding relations
sebastiaoteixeira Oct 25, 2026
e635229
Validate FastAPI page parameters with the shared pagination contract
sebastiaoteixeira Oct 25, 2026
bba7d86
Limit role grants to the caller's held roles, write access-rule binds…
sebastiaoteixeira Oct 25, 2026
160a1a5
Return SQL NUMERIC operation results as JSON numbers and run the SQL …
sebastiaoteixeira Oct 25, 2026
c6a37cc
Read number and boolean service inputs from their path parameters
sebastiaoteixeira Oct 25, 2026
0461b0d
Give documents that operations insert the collection id and leave uns…
sebastiaoteixeira Oct 25, 2026
c54eed3
Soft-delete and expire repository rows in the dev server and every ge…
sebastiaoteixeira Oct 25, 2026
140be98
Name DRF path views after their path segments
sebastiaoteixeira Oct 25, 2026
0b5f070
Share identity sign-in across dev and generated apps, reject replayed…
sebastiaoteixeira Oct 25, 2026
3923f5c
Route generated UI requests through declared routes, pagination, role…
sebastiaoteixeira Oct 25, 2026
58ceeec
Validate the ui block against the pack manifest and route example pac…
sebastiaoteixeira Oct 25, 2026
8476b15
Type-check identity claims, refuse unusable or conflicting sign-ins w…
sebastiaoteixeira Oct 25, 2026
d97aed1
Merge branch 'grammar/models' into grammar/ui
sebastiaoteixeira Oct 25, 2026
5e3758c
Merge branch 'grammar/services' into grammar/lifecycle
sebastiaoteixeira Oct 25, 2026
1f15a86
Merge branch 'grammar/access' into grammar/ui
sebastiaoteixeira Oct 25, 2026
29c8fb1
Export every generic pack component by default and type-check a front…
sebastiaoteixeira Oct 25, 2026
dbcad57
Send typed sign-up fields and a password field when creating identiti…
sebastiaoteixeira Oct 25, 2026
e9ab809
Break offset pagination sort ties on the id
sebastiaoteixeira Oct 25, 2026
927e8ff
Keep 0.1 collection roles and their hierarchy, and give a 0.1 replace…
sebastiaoteixeira Oct 25, 2026
4d7bc0d
Project UI collections through referenced records the caller may not …
sebastiaoteixeira Oct 25, 2026
b201ab7
Choose the save operation of a UI record in the shared records layer …
sebastiaoteixeira Oct 25, 2026
3f4c995
Test role assignment on 0.2 specs and declared defaults on every Mong…
sebastiaoteixeira Oct 25, 2026
9dc37eb
Merge branch 'grammar/access' into fix/grammar-enforcement
sebastiaoteixeira Oct 25, 2026
b562aeb
Merge branch 'grammar/models' into fix/grammar-enforcement
sebastiaoteixeira Oct 25, 2026
777079b
Exercise soft deletion and expiry on grammar 0.3 as well as 0.2 on ev…
sebastiaoteixeira Oct 25, 2026
7a51292
Test IdP-trusted sign-in on Mongo, SAML minimal identities on 0.3 and…
sebastiaoteixeira Oct 25, 2026
32924e2
Send cleared fields as null, render FastAPI validation errors, and ga…
sebastiaoteixeira Oct 25, 2026
e985a44
Merge branch 'grammar/services' into fix/grammar-enforcement
sebastiaoteixeira Oct 25, 2026
07c6f05
Answer anonymous callers with 401 unless an allow rule can admit them
sebastiaoteixeira Oct 25, 2026
7fd9733
Merge branch 'grammar/platform' into fix/grammar-enforcement
sebastiaoteixeira Oct 25, 2026
5889e4d
Exercise the v0.1 constraint check with bounds the schema cannot reject
sebastiaoteixeira Oct 25, 2026
8af5b20
Enable register and login and bind documents by collection in the ide…
sebastiaoteixeira Oct 25, 2026
454aae7
Start the DRF entry point with the interpreter holding its requirements
sebastiaoteixeira Oct 25, 2026
be5c8e8
Merge branch 'grammar/identity' into fix/grammar-enforcement
sebastiaoteixeira Oct 25, 2026
071b98b
Reference the organization record type from the SAML fixture
sebastiaoteixeira Oct 25, 2026
982d992
Merge grammar/lifecycle into fix/grammar-enforcement
sebastiaoteixeira Oct 25, 2026
bc59afc
Merge grammar/ui into fix/grammar-enforcement
sebastiaoteixeira Oct 25, 2026
9996676
Accept session.refresh on SQL-only specs in the FastAPI generator
sebastiaoteixeira Oct 25, 2026
6bcd0f1
Stub the DRF handler principal in the where-authorization test
sebastiaoteixeira Oct 25, 2026
3b854e5
Bind typed request symbols to the whole request and check path parame…
sebastiaoteixeira Oct 25, 2026
74b9bce
Bind owners to the caller, admit only admins to user deletion and fil…
sebastiaoteixeira Oct 25, 2026
a44e549
Describe the enforced grammar in the user docs and drop pages about r…
sebastiaoteixeira Oct 25, 2026
5e2cd8d
Describe the v0.1 grammar and behaviour in the v0.1 docs
sebastiaoteixeira Oct 26, 2026
beef365
Document lifecycle, inheritance, session, deploy, SQL queries and the…
sebastiaoteixeira Oct 26, 2026
b8145d9
Document every v0.3 spec key, the handler request contract and file p…
sebastiaoteixeira Oct 26, 2026
4a5cba3
Test policies, explicit-controller access and operations, and custom-…
sebastiaoteixeira Oct 27, 2026
0cba8da
Validate DTO bodies against the entity and on handler and custom-oper…
sebastiaoteixeira Oct 27, 2026
b7d15a8
Enforce abstract repository and service inheritance, operation shape …
sebastiaoteixeira Oct 27, 2026
8be8912
Document that mongo and a record datastore cannot be declared together
sebastiaoteixeira Oct 27, 2026
69b13dc
Test security headers over HTTP on the generated DRF app
sebastiaoteixeira Oct 27, 2026
dc31833
Test entity-level role hierarchy over HTTP on 0.2 and 0.3 in every se…
sebastiaoteixeira Oct 28, 2026
9f8439b
Build 0.1 providers into the IR so SAML sign-in is served by the dev …
sebastiaoteixeira Oct 28, 2026
e256360
Serve password login only when api.operations.auth.login is true or a…
sebastiaoteixeira Oct 28, 2026
c299ea6
Drop the unreachable AUTH_IDENTIFIER_REQUIRED check; schema validatio…
sebastiaoteixeira Oct 28, 2026
716b9f9
Test session.ttl token lifetime over HTTP on MongoDB in the dev serve…
sebastiaoteixeira Oct 28, 2026
4607e4f
Test external-provider sign-in in the generated UI and the SAML provi…
sebastiaoteixeira Oct 28, 2026
7fb7a6e
Scope soft delete and ttl across identities, joins, inherited and bul…
sebastiaoteixeira Oct 28, 2026
a27b3c1
Report the signed-in roles from login and code exchange and gate the …
sebastiaoteixeira Oct 28, 2026
138f846
Test that the UI neither offers nor writes a declared soft-delete tim…
sebastiaoteixeira Oct 28, 2026
c5242af
Render the crud delete slot and make every generic pack prop change t…
sebastiaoteixeira Oct 31, 2026
e477242
Drive the generated data layer against every server on MongoDB and re…
sebastiaoteixeira Oct 31, 2026
69cdea7
Document role gating in the UI, the crud delete slot and the generic …
sebastiaoteixeira Nov 1, 2026
de2425b
Let the dev server decide a record route before the fetch only when t…
sebastiaoteixeira Nov 1, 2026
412b576
Document that includeDeleted requires query and that the raw ASGI bac…
sebastiaoteixeira Nov 1, 2026
b431546
Check every schema location for a consumer by changing its value in e…
sebastiaoteixeira Nov 1, 2026
4cd0755
Report a key whose value fails its schema at the value instead of as …
sebastiaoteixeira Nov 1, 2026
a7ae751
Test that every record in the spec and UI schemas is closed
sebastiaoteixeira Nov 1, 2026
05c6fb7
Rewrite the contributing guide for outside contributors
sebastiaoteixeira Nov 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
194 changes: 147 additions & 47 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,83 +1,183 @@
# Contributing to Stackform

Thanks for your interest in the project. This guide covers the development setup, the test suite,
and what a reviewable change looks like.
Thank you for your interest in Stackform. Bug reports, documentation fixes and code changes are all
welcome. This guide explains how to get in touch, how to set up a development environment, and what
a pull request needs before it can be merged.

For what Stackform does and how to use it, read the [README](README.md) and the
[manual](https://sebastiaoteixeira.github.io/yaml-framework-docs/).

## Questions, bugs and ideas

All conversation happens in [GitHub issues](https://github.com/ieeta-pt/stackform/issues). Search
the open and closed issues first; your question or bug may already have an answer.

- **Questions.** Open an issue and describe what you are trying to do.
- **Bug reports.** Include:
- the Stackform commit or version and your Python version;
- the smallest YAML spec that reproduces the problem, including its `version:` line;
- the exact command you ran (for example `stackform build spec.yaml --target drf`);
- what you expected and what happened, with the full error output.
- **Feature proposals.** Describe the problem first, then the change you suggest. For a change to
the specification language, show the YAML a user would write.

## Before you write code

Small fixes such as typos, broken links or an obvious one-line bug can go straight to a pull
request. For anything larger, open an issue first and wait for a maintainer to agree on the
approach. This applies in particular to new spec keys or changes to existing ones, which every
backend target has to support. Issues labelled
[`good first issue`](https://github.com/ieeta-pt/stackform/labels/good%20first%20issue) or
[`help wanted`](https://github.com/ieeta-pt/stackform/labels/help%20wanted) are open for anyone to
take; leave a comment saying you are working on one.

## Development setup

The project is managed with [uv](https://docs.astral.sh/uv/). A locked environment for the
supported interpreters is created with:
You need:

- Python 3.11 or newer (CI tests 3.11 and 3.13);
- [uv](https://docs.astral.sh/uv/), which installs the locked dependencies;
- Docker, for the integration tests;
- Node.js 18 or newer, only for frontend generation and the tests that run generated frontend code.

Fork the repository, then clone your fork and install the project with its development
dependencies:

```bash
uv sync --locked --all-extras
git clone https://github.com/<your-username>/stackform.git
cd stackform
uv sync --all-extras
```

A plain virtual environment works too:
The `stackform` command is now available through `uv run`:

```bash
pip install -e ".[dev]"
uv run stackform --help
```

Python 3.11 or newer is required. The integration suite additionally needs a MongoDB instance:
## Running the tests

The suite has two parts. Tests marked `integration` start real services; everything else runs
without them.

Run the unit suite, as CI does:

```bash
docker run -d --name stackform-mongodb -p 27017:27017 mongo:8
uv run pytest -m "not integration"
```

## Running the tests
Run the integration suite:

```bash
uv run pytest -m "not integration" # unit suite, no services required
uv run pytest -m integration # integration suite, needs MongoDB
uv run pytest # everything
uv run pytest -m integration
```

GitHub Actions runs the unit suite on Python 3.11 and 3.13 for every push to `main` and every pull
request. A pull request whose unit suite is red is not reviewed.
Each integration test starts a throwaway Docker container for the service it needs (`mongo:7`,
`postgres:16` or `minio/minio`). To use a service you already run, set its environment variable
instead:

| Service | Variable |
| ---------- | ---------------------------- |
| MongoDB | `YAML_API_TEST_MONGO_URI` |
| PostgreSQL | `YAML_API_TEST_POSTGRES_URI` |
| S3 (MinIO) | `YAML_API_TEST_S3_ENDPOINT` |

Some tests are skipped instead of failing when a tool is missing:

- without Docker and without the variable above, the tests that need that service;
- without `node` or `npm` on the `PATH`, the tests that run generated frontend code;
- without `YAML_API_TEST_DRF_PYTHON`, the tests that serve a generated Django REST Framework
backend. Set it to a Python interpreter that has the generated DRF project's requirements
installed.

## Where the code lives
CI runs only the unit suite. If your change touches generated backends, datastores or
authentication, run the integration suite locally as well.

| Path | Responsibility |
| --- | --- |
| `src/yaml_api_generator/parsers/` | JSON Schema validation, desugaring, and version transformers that read a spec into the IR |
| `src/yaml_api_generator/ir/` | the intermediate representation every generator consumes |
| `src/yaml_api_generator/generators/` | backend, frontend and deploy emitters |
| `src/yaml_api_generator/server/` | the development server that runs a spec without compiling it |
| `src/yaml_api_generator/cli/` | the `stackform` command |
| `examples/` | the specification corpus; `valid/` and `invalid/` are consumed by the tests |
| `docs/` | the manual, published to the documentation site on merge |
To run one file or one test, pass it to pytest as usual:

```bash
uv run pytest tests/unit/test_parser.py -k <name>
```

## Where things live

| Path | Contents |
| ---------------------------------------- | ---------------------------------------------------------- |
| `src/yaml_api_generator/cli/` | The `stackform` command |
| `src/yaml_api_generator/parsers/` | Spec loading and validation; JSON Schemas in `schemas/` |
| `src/yaml_api_generator/ir/` | The intermediate representation the generators consume |
| `src/yaml_api_generator/generators/` | `backend/` (`fastapi`, `drf`, `raw`), `frontend/`, `deploy/` |
| `src/yaml_api_generator/server/` | The development server behind `stackform run` |
| `src/yaml_api_generator/runtime/` | Modules shared by the development server and generated applications |
| `tests/unit/`, `tests/integration/` | The two test suites |
| `tests/fixtures/valid/`, `tests/fixtures/invalid/` | Specs that must load and specs that must be rejected |
| `examples/` | Example specs, grouped by spec version |
| `docs/` | The manual, one directory per spec version |

The Python package keeps the name `yaml_api_generator`; the distribution and the command are
named `stackform`.

## Changing the specification language

The language is versioned, and each version has its own schema under
`src/yaml_api_generator/parsers/schemas/`. A change to the language is only complete when all of
the following land together:
A spec file selects its grammar with its `version:` key. Each version has a JSON Schema in
`src/yaml_api_generator/parsers/schemas/` (for example `yaml-spec-v0.3.schema.json`). A pull
request that adds or changes a spec key carries:

- the schema change and the parser change for the affected version;
- a spec in `tests/fixtures/valid/` that uses the key, and specs in `tests/fixtures/invalid/` for
each way it can be misused, with unit tests that load them;
- the generator change for every backend target that supports the feature;
- the manual page for the key in `docs/<version>/`, and an entry in that version's
`grammar-reference.md`.

1. the schema for the version that introduces it,
2. a transformer under `parsers/transformers/` if an older version must keep parsing,
3. an example under `examples/valid/` (and, where the change adds a rejection, one under
`examples/invalid/`),
4. unit tests covering both the accepted and the rejected shapes,
5. the manual page under `docs/` for that version.
## Documentation

A specification feature with no example is treated as undocumented and will be asked for in review.
The manual is written in Markdown under `docs/`, with one directory per spec version. Each page
starts with front matter that sets `title` and `description`, and each directory's `meta.json`
sets the page order. When you add a page, add it to `meta.json`.

The site is built with Fumadocs from the separate
[yaml-framework-docs](https://github.com/sebastiaoteixeira/yaml-framework-docs) repository. A push
to `main` that changes `docs/` triggers a rebuild. To preview your changes locally, clone that
repository next to this one and link the content in:

```bash
git clone https://github.com/sebastiaoteixeira/yaml-framework-docs.git
cd yaml-framework-docs
mkdir -p content
ln -s "$(pwd)/../stackform/docs" content/docs
npm install
npm run dev
```

The site is then served at <http://localhost:3000/yaml-framework-docs/docs>.

## Pull requests

- Branch from `main`, named `<type>/<subject>` — for example `fix/login-route-404` or
`feat/field-level-scoping`.
- One concern per pull request. A refactor bundled with a behaviour change is split before review.
- The title states the change in the imperative, and the body says what a reviewer should check.
- Keep generated output, local scratch files and client material out of the commit; `git status`
should be clean of them before you stage.
1. Create a branch named `<type>/<short-description>`, where the type is `feat`, `fix`, `docs`,
`refactor`, `ci` or `chore`. If the branch implements an issue, put its number after the type,
for example `feat/83-pagination`.
2. Keep each pull request to one change. Unrelated fixes go in separate pull requests.
3. Add or update tests for the behaviour you change, and update the manual if users will notice
the change.
4. Run the unit suite, and the integration suite where it applies.
5. Open the pull request against `main`. In the description, say what changes and how you tested
it, and link the issue it resolves (for example `Closes #83`).

Pull requests are squash-merged, so the pull request title becomes the commit message on `main`.
Write the title as a single sentence in the imperative mood that states the change, without a type
prefix or a trailing period. For example:

- `Reject deploy build contexts that enclose the spec or output directory`
- `Await pymongo async aggregate and list_indexes cursors`
- `Add file datastores and file field type`

## Reporting issues
No formatter or linter is enforced; follow the style of the code around your change.

Open an issue with the specification that reproduces the problem, the command you ran, and the
observed against the expected output. A minimal spec that still fails is worth more than a large
one that fails for several reasons at once.
CI runs the unit suite on Python 3.11 and 3.13 for every pull request. A maintainer reviews the pull
request once CI passes and may ask for changes before merging.

## Licence

Stackform is released under the MIT licence. By contributing you agree that your contribution is
licensed under the same terms.
Stackform is released under the [MIT License](LICENSE.txt). By submitting a contribution, you agree
that it is licensed under the same terms.
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,5 @@ YAML Spec --> Parser --> Intermediate Representation --> Code Generator --> Fast

### Spec Documents

- [YAML Specification v0.1](./YAML-Specification-v0.1.md)
- [YAML Structure Spec v0.1](./YAML-Structure-Spec-v0.1.md)
- [v0.1 Specification](./v0.1/specification)
- [v0.1 Grammar Reference](./v0.1/grammar-reference)
156 changes: 156 additions & 0 deletions docs/v0.1/grammar-reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
---
title: Grammar Reference
description: Every key a v0.1 spec accepts, with its type, in one tree.
---

This tree lists every key a v0.1 spec accepts. Every object is closed: a key
that does not appear here fails the build with `SCHEMA_VALIDATION_ERROR`
(`'<key>' was unexpected`). The [specification](./specification.md) describes
what each key does.

Notation:

- `!` = required
- `?` = optional
- `map<K,V>` = mapping from names to values
- `enum(...)` = one of the listed values
- `array<T>` = list of values
- `oneOf(...)` = one of the listed forms

```yaml
YAML-SPEC:
version!: "0.1"

api?:
basePath?: string # default: /api
version?: string
pagination?:
defaultPageSize?: integer >= 1 # default: the smaller of 20 and maxPageSize
maxPageSize?: integer >= 1 # default: 100
operations?:
defaults?: OperationFlags

mongo?:
uri?: string # default: mongodb://localhost:27017
database?: string # default: yaml_api

security?:
cors?:
allowedOrigins?: array<string> # no "*" when allowCredentials is true
allowCredentials?: boolean # default: false
allowedMethods?: array<string> # default: ["*"]
headers?:
enableStandard?: boolean # default: true

providers?: map<string, ProviderConfig>

collections!: map<string, CollectionConfig>

ui?: UiConfig # see the UI reference


OperationFlags:
list?: boolean
get?: boolean
create?: boolean
update?: boolean
replace?: boolean
delete?: boolean


ProviderConfig: oneOf(OIDCProvider, SAMLProvider)

OIDCProvider:
type!: oidc
client_id!: string
client_secret!: string

SAMLProvider:
type!: saml
idp_metadata_url!: string
sp_entity_id!: string


CollectionConfig:
type?: enum(base, auth) # default: base
fields!: map<string, FieldConfig> # exactly one field of type id
auth?: AuthConfig # required when type is auth
roles?: RolesConfig # only when type is auth
operations?: OperationFlags
access?:
list?: Access
get?: Access
create?: Access
update?: Access
replace?: Access # default: the update access
delete?: Access
softDelete?: boolean # default: false


AuthConfig:
identifier!: string # a field of the collection
via!: oneOf(string, array<string>) # password, apiKey or a providers key


RolesConfig:
values!: array<string> # at least one role
default!: string # one of values
hierarchy?: map<string, array<string>> # role -> roles it includes


FieldConfig: # a top-level collection field
<the keys of its type, below>
unique?: boolean

NestedFieldConfig: # an object property
<the keys of its type, below>

ItemConfig: # the items of an array
type!: <a field type>
<the keys added by its type, below>

Keys of every type, except in ItemConfig:
type!: enum(string, number, boolean, datetime, enum, array, object, ref, id)
required?: boolean
default?: any # must satisfy the field's own keys

Keys added by type:
string:
minLength?: integer >= 0
maxLength?: integer >= 0
format?: enum(email, e164, uri, uuidv7, uuidv4)
number:
min?: number
max?: number
enum:
values!: array<string> # at least one value
array:
items!: ItemConfig
object:
properties?: map<string, NestedFieldConfig>
additionalProperties?: boolean # default: false with properties, true without
ref:
ref!: string # a declared collection
id:
format?: enum(uuidv7, uuidv4) # default: uuidv7
boolean, datetime: no further keys


Access: oneOf(Principal, array<AccessRule>)

Principal: oneOf(
public,
"*",
<authCollection>:*,
<authCollection>:<role>,
<role> # only with a single auth collection
)

AccessRule:
principal!: Principal
when?: string # when expression
reason?: string # 403 detail when the rule refuses
```

The `ui` block has the same shape in every spec version; see the
[UI reference](../v0.2/Reference/ui/overview.md).
Loading
Loading