Security Rules

Control who can read, write, and delete records in each collection. Rules are enforced server-side on every request — your app cannot bypass them.

Rule types

publicAnyone can access — no authentication required.
authenticatedAny logged-in user can access.
ownerOnly the user who created the record can access it.
scopedAccess is granted if record.data[owner_field] matches the user's value for that field. Ideal for multi-tenant apps.
conditionalAccess is granted based on a set of conditions evaluated against record data and user context.

Rules apply per operation

Each collection has three independent rules — read, write, and delete. You can mix them freely. For example: read_rule: public, write_rule: authenticated, delete_rule: owner.

Scoped rule

The scoped rule is designed for multi-tenant apps. Set an owner_field on the collection — access is granted when the record's value for that field matches the authenticated user's value.

{
  "name": "projects",
  "read_rule": "scoped",
  "write_rule": "scoped",
  "delete_rule": "owner",
  "owner_field": "org_id"
}

With this setup, a user with org_id: "org_123" can only read and write records where data.org_id == "org_123".

Auto-injection on write

When writing with a scoped rule, the SDK automatically injects the owner_field value from the user context into the record data. You don't need to set it manually.

Conditional rule

The conditional rule evaluates a list of conditions against the record data and user context. Use mode: "all" to require all conditions (AND), or mode: "any" to require at least one (OR).

{
  "name": "documents",
  "read_rule": "conditional",
  "write_rule": "authenticated",
  "delete_rule": "owner",
  "rule_mode": "any",
  "rule_conditions": [
    {
      "type": "equals",
      "field": "org_id",
      "source": "user"
    },
    {
      "type": "equals",
      "field": "visibility",
      "value": "public"
    }
  ]
}

This allows access if org_id == user.org_id OR visibility == "public".

Condition types

equalsrecord.data[field] == value or user[field]
not_equalsrecord.data[field] != value or user[field]
inrecord.data[field] is in the provided list
not_inrecord.data[field] is not in the provided list
// Compare record field to user field
{ "type": "equals", "field": "org_id", "source": "user" }

// Compare record field to literal value
{ "type": "equals", "field": "status", "value": "active" }

// Check record field is in a list
{ "type": "in", "field": "role", "value": ["admin", "manager"] }

Creating collections with rules

Rules are set when creating a collection from the dashboard or via the API. The Flutter SDK reads are automatic — rules are invisible to the developer.

lib/posts_screen.dartDart
// Rules are enforced server-side — your query code stays the same
final result = await Koolbase.db
  .collection('documents')
  .get();

// Records are automatically filtered by the collection's rules
for (final doc in result.records) {
  print(doc.data['title']);
}

Current limitations

Nested conditions

Not supported — all conditions are a flat list.

Mixed modes

A collection has one mode (all/any) applied to all conditions.

User fields available

id, org_id, email, role — these are the fields you can compare against.

Conflict resolution

Not applicable — rules gate access, not conflict resolution.