Core Concepts
Before diving into the API, it helps to understand the four core building blocks of the platform.
Collections
A collection is a database table (or view). Every collection has a name, a primary key, and zero or more fields.
daas_users ← system collection (managed by the platform)
daas_roles ← system collection
posts ← custom collection you create
products ← custom collection you createYou interact with any collection’s data through the Items API:
GET /api/items/posts → list posts
POST /api/items/posts → create a post
GET /api/items/posts/:id → get one post
PATCH /api/items/posts/:id → update a post
DELETE /api/items/posts/:id → delete a postFields
A field maps to a database column. Each field has a name, a data type, and optional metadata (interface type, display options, validation rules).
| Field type | PostgreSQL type |
|---|---|
string | text / varchar |
integer | int4 |
bigInteger | int8 |
float | float8 |
boolean | bool |
json | jsonb |
dateTime | timestamptz |
uuid | uuid |
Additional types such as text, decimal, date, time, csv, hash, and binary are also supported.
Relational patterns — M2O (many-to-one), O2M (one-to-many), and M2M (many-to-many) — are local types that describe how a field relates to other collections. At the storage level, they use uuid columns with foreign key constraints.
Fields also carry interface metadata that drives the Data Studio’s form renderer (e.g., show a <input>, a rich-text editor, a file picker, etc.).
Items
An item is a single row in a collection. The platform treats every table the same way — system tables and user-defined tables share the same CRUD API surface.
Items support:
- Filtering —
?filter[status][_eq]=active - Field selection —
?fields=id,title,author - Sorting —
?sort=-created_at - Pagination —
?limit=20&page=2 - Relational data —
?fields=*,author.*(deep reads) - Aggregates —
?aggregate[count]=*
See Filter Rules for the complete filter syntax.
Access Control Model
Access control is built on four layers that compose from the most granular to the broadest:
┌─────────────────────────────────────────────────────────────┐
│ PERMISSIONS (what can be done on a collection) │
│ │
│ Read Posts Read Users Create Posts │
│ (public=true) (name & id only) │
│ │
│ Edit Posts Delete Posts Edit All Posts │
│ (own rows only) │
└──────────────────────────┬──────────────────────────────────┘
│ grouped into
┌──────────────────────────▼──────────────────────────────────┐
│ POLICIES (reusable bundles of permissions) │
│ │
│ Read Public Data │ Manage Own Posts │ Full Moderator │
└──────────────────────────┬──────────────────────────────────┘
│ assigned to
┌──────────────────────────▼──────────────────────────────────┐
│ ROLES (organisational groups) │
│ │
│ Viewer │ User │ Moderator │
└──────────────────────────┬──────────────────────────────────┘
│ assigned to
┌──────────────────────────▼──────────────────────────────────┐
│ USERS │
│ │
│ User 1 │ User 2 │ User 3 │ User 4 │ User 5 │
└─────────────────────────────────────────────────────────────┘Permissions
A permission is the most granular unit of access control. It is always scoped to a collection and an action (create, read, update, delete, share), and can further restrict:
- Item filter — which rows the rule applies to, using the same filter syntax as the API (e.g., only rows where
user_created = $CURRENT_USER) - Field access — which columns are readable or writable for that action
- Field validation — value constraints that must pass before a write is accepted
- Field presets — default values automatically injected on create or update
A permission can grant all access, no access, or custom access for its collection/action pair.
Collection: posts
Action: read
Item filter: { "status": { "_eq": "published" } }
Fields: id, title, slug, published_atPolicies
A policy is a named bundle of permissions that can be assigned to any number of roles or users. Instead of configuring permissions per-role, you define them once in a policy and reuse that policy wherever it applies.
Each policy also carries three top-level flags:
- Admin access — bypasses all permission checks entirely
- App access — allows the user to log in to the DaaS Studio
- Delegate access — allows a service account to act on behalf of another user via the
X-On-Behalf-Ofrequest header
When a user has multiple policies (through multiple roles, or ones attached directly), their effective access is the additive union of all applicable policies:
- Field access is merged — if Policy A exposes
titleand Policy B exposesbody, the user sees both. - Item filters are combined with
OR— a user matching either policy’s row condition can access those rows.
Policies only expand access — they can never revoke access granted by another policy. Design each policy around the minimum access it needs, then layer policies up to build more permissive roles.
Roles
A role is an organisational group (e.g., viewer, editor, moderator). Roles hold one or more policies and can be assigned to any number of users. Users can belong to multiple roles simultaneously — their effective permissions are the union of all policies across all their roles.
Two roles are seeded by default:
| Role | Linked policy | Behaviour |
|---|---|---|
| Administrator | Admin Policy (admin_access = true) | Full system access — bypasses all permission checks. |
| User | User Policy (admin_access = false) | Standard user access — subject to all permission rules. |
You can create additional roles and attach any combination of policies to them.
Public access applies to every authenticated user regardless of role. It is represented by policy entries in daas_access with no role and no user set. Any policy linked this way grants its permissions to all logged-in users as a default layer. Unauthenticated access is not supported — every data API route requires authentication. All access is off by default — opt-in only.