Remotehost Docs

Backends

Declare an app's record types once and sync them through the same engine as Issues

A backend is a set of record types an app keeps in a workspace. You declare it in one file, its declaration; the sync service makes its tables, validates every write against it, and syncs its records to every client over the sync protocol. The TypeScript SDK types its records from it.

Issues is a backend too: Atlas's own, declared native and written through its own ops. Every other backend is written with three generic record ops (put_record, update_record, delete_record), validated from its declaration by the same code.

A declaration

{
  "backend": "checklist",
  "version": 1,
  "kind": "declared",
  "title": "Checklist",
  "permissions": { "read": "atlas.read", "write": "atlas.write" },
  "types": {
    "list": {
      "fields": {
        "title": { "type": "text", "required": true, "max": 280 },
        "archived": { "type": "bool", "default": false }
      }
    },
    "item": {
      "fields": {
        "list_id": { "type": "ref", "to": "list", "required": true, "on_delete": "cascade" },
        "text": { "type": "text", "required": true, "max": 2000 },
        "done": { "type": "bool", "default": false },
        "sort_key": { "type": "sort_key" }
      },
      "index": [["list_id", "sort_key"]]
    }
  }
}

Its JSON Schema is schema/declaration.json in @remotehost/sync-protocol.

Names

  • A backend's name matches ^[a-z][a-z0-9_]{1,30}$; a type's or a field's, ^[a-z][a-z0-9_]{0,62}$.
  • issues, atlas, public, core, api, internal and private are reserved backend names.
  • id, org_id, workspace_id, rev, created_at, updated_at and deleted_at belong to every record and are never a type's or a field's.

Kinds

KindWho stores the records
declaredThe sync service, in the workspace's database
adapterYour own server, through a backend adapter; it declares changes: "ordered" (it reports changes in order, and syncs live) or "none"
nativeIssues alone; it lists its ops

Permissions

permissions.read and permissions.write name registered permissions: atlas.read and atlas.write. A client sees a backend's records only while it holds the read permission, and writes them only with the write one.

Field types

TypeValueOptions
textA stringmax characters, at most 8,192
long_textA stringmax characters, at most 1 MiB
intA 64-bit integer
realA number
booltrue or false
dateYYYY-MM-DD
timeYYYY-MM-DDTHH:MM:SS.sssZ
enumOne of valuesvalues, each once
uuidA UUID
refAnother record's idto (a type of the same backend), on_delete: cascade, set_null or restrict
sort_keyAn ordering key
jsonAny JSON valuemax_bytes, at most 64 KiB
blob{sha256, size, content_type}max_bytes, required, at most 5 GiB
actorWho actedFilled by the service; a client never sends one

Every field may also have:

  • required: a record must have it (a set_null reference never is);
  • default: a value of the field's type (none for uuid, ref, blob or actor);
  • unique: no two records share it (text, int, date, time, enum, uuid, ref and sort_key only).

A type's unique lists unique fields too, and its index lists the field lists to index, each once.

Writing records

{"op": "put_record", "backend": "checklist", "type": "list", "id": "0190f6b0-…", "fields": {"title": "Groceries"}}
{"op": "update_record", "backend": "checklist", "type": "list", "id": "0190f6b0-…",
 "set": {"title": "Shopping"}, "expect": {"title": "Groceries"}}
{"op": "delete_record", "backend": "checklist", "type": "list", "id": "0190f6b0-…"}

id is a UUIDv7 the client makes. expect applies the update only while those fields hold those values. A delete applies each reference's on_delete; a cascade over 1,000 records is refused cascade_too_large. The sync protocol lists every refusal.

Versions

A declaration's version starts at 1, and a new version only adds. It may add types, optional fields, enum values and indexes, raise a max, or make a field optional. It never removes or renames a type or field, narrows one, retargets a reference, or changes unique, a default, the kind or the permissions. Each earlier version is kept beside it (history/<n>.json), and each is checked against the one before it. Clients on an older version keep working.

Enabling a backend

A backend is off in a workspace until it is enabled: POST /v1/workspaces/{id}/backends/{name}/enable on the sync service, by someone who manages the workspace (workspaces.manage). It answers 200 with workspace_id, backend and group_id, the same again once it is on. A client then names it in hello's backends to receive its records; a connection that asked for it before it was enabled is sent its group in groups {add} once it has records.

On this page