What each action sees
$auth, $credential, $request, $env and $now are available everywhere.
create: constrain what may be written
Rules on $input let the server enforce business constraints the client can’t skip.
- All of these rules pass:
- Is signed in: yes
- Compare values:
$input.statusis one ofdraft, submitted - Compare values:
$input.quantityis at most10
update: old and new together
- All of these rules pass:
- Owns the record (field)
owner_id - Compare values:
$record.lockedequals no - Compare values:
$input.owner_iddoes not equalnull
- Owns the record (field)
delete: be conservative
Deleting is permanent. Common tightening:
Choose All of: Record owner; Signed in with 2FA in the rule picker.
or no delete at all plus a soft delete.
list and get should agree
If get is looser than list, people can read records they can’t list (by guessing ids); if list is looser than get, they see rows they can’t open. Use the same rule for both unless you have a reason. The Studio quick sets do this.
Designs
Rules and relations
Anexpand reads the related table under its own rules. Don’t rely on one table’s rule to protect another’s data; set rules on both.
Writes and side effects
Rules run before the write. A passing rule doesn’t mean the write will succeed: validation, unique constraints and database errors can still refuse it (ValidationError, ConflictError).
Test it
For every rule: allowed user, forbidden user, signed-out visitor, and the odd cases (missing owner, null org). See Testing.Database access
The Studio screen.
Ownership recipes
Ready-made.