Start here

Concepts

Aaly has no backend code layer — everything below is data, held as your project's definition, and Aaly serves the API from it directly.

Project

An independent backend: its own definition, data, and REST API at https://api.aaly.io/<your-slug>/<project>. Every project is multi-tenant capable from creation — see Multi-tenancy for what the multiTenant and publicSignup flags actually control.

Entity

A collection of records — the closest analogy is a database table, but an entity is defined, not migrated. Each entity has a key (a short prefix like TSK) used to generate readable record IDs (TSK1, TSK2, ...), and a set of fields.

Fields and types

TypeNotes
textSupports pattern (regex), min/max length.
numbermin/max value.
boolean—
dateYYYY-MM-DD.
datetimeISO 8601 with milliseconds.
enumSet values; validated on write.
referenceLinks to another entity — see below.
listAn array of primitives; set valueType. Not for relationships.
objectA nested, unvalidated JSON blob.

Common to every field: required (enforced on create only), unique (case-insensitive), and search (makes the field filterable — see REST API).

References — model relationships with these, not text or list

A reference field links one entity to another:

{ "name": "assignee", "type": "reference", "targets": [{ "entity": "users", "projection": ["name", "email"] }] }

Write a value as {"id": "<recordId>"}; the projected target fields are inlined automatically when you read the record back. Set multiple: true for an array of links. References can nest up to three levels deep.

Validation

Enforced at write time, from the field definition: required (create only), unique, min/max (length or value), enum membership, regex pattern (text fields), and type checks. A violation returns a 400 with a ValidationErrorResponse — see REST API for the shape.

The immutability rule — model relationships correctly the first time

Once a field is created, its type, unique, search, multiple, targets, and valueType cannot change. Changing one of those after records exist would leave old data inconsistent with the new shape, so update_field rejects the whole call if it touches any of them — even mixed with mutable attributes in the same call.

required, hidden, min, max, pattern, and values (enum options) are mutable at any time — they only affect future validation, never rewrite existing records.

If you need to change one of the immutable attributes: create a new field under a different name with the correct shape, migrate data into it through the REST API (once per tenant — data is partitioned per tenant), then remove the old field once every tenant is verified migrated. Don't try to reuse the old field's name — a field's old data isn't purged when you remove it, and a same-named field created later reads it back inconsistently.

What's next

REST API for endpoints, filtering, and errors · Auth for signup/signin and API keys · Multi-tenancy for the isolation model.