Documentation Index
Fetch the complete documentation index at: https://mintlify.com/tailor-platform/sdk/llms.txt
Use this file to discover all available pages before exploring further.
TailorDB uses a secure-by-default permission system. All operations are denied unless explicitly allowed through permission configuration.
Permission Levels
TailorDB has two levels of permissions:
- Record-level permissions (
.permission()) - Controls CRUD operations on individual records
- GraphQL permissions (
.gqlPermission()) - Controls access to GraphQL operations and queries
Record-Level Permissions
Record-level permissions control create, read, update, and delete operations on individual records.
Basic Syntax
.permission({
create: [conditions],
read: [conditions],
update: [conditions],
delete: [conditions],
})
create
ActionPermission[]
required
Array of permission conditions for creating records.
read
ActionPermission[]
required
Array of permission conditions for reading records.
update
ActionPermission[]
required
Array of permission conditions for updating records. Use newRecord and oldRecord operands.
delete
ActionPermission[]
required
Array of permission conditions for deleting records.
Permission Conditions
Conditions are expressed as tuples comparing operands:
[leftOperand, operator, rightOperand]
Operands:
{ user: "fieldName" } - User attribute (from auth config)
{ user: "_loggedIn" } - Special: is user logged in?
{ user: "id" } - User ID
{ record: "fieldName" } - Record field value
{ newRecord: "fieldName" } - New record value (update only)
{ oldRecord: "fieldName" } - Old record value (update only)
- Literal values: strings, booleans, arrays
Operators:
"=", "!=" - Equality/inequality
"in", "not in" - Contains in array
"hasAny", "not hasAny" - Arrays have any common elements
Use the object format for better readability:
{
conditions: [[{ user: "role" }, "=", "admin"]],
permit: true,
description: "Allow admins to perform this action",
}
Example: Role-Based Permissions
import { db } from "@tailor-platform/sdk";
import type { TailorTypePermission, TailorTypeGqlPermission } from "@tailor-platform/sdk";
const adminOnly = [
{ user: "role" },
"=",
"MANAGER",
] as const;
const loggedIn = [
{ user: "_loggedIn" },
"=",
true,
] as const;
export const defaultPermission: TailorTypePermission = {
create: [adminOnly],
read: [adminOnly, loggedIn], // Admin OR logged in
update: [adminOnly],
delete: [adminOnly],
};
export const user = db.type("User", {
name: db.string(),
email: db.string().unique(),
role: db.enum(["MANAGER", "STAFF"]),
...db.fields.timestamps(),
})
.permission(defaultPermission);
How it works:
- Managers can create, read, update, and delete
- Any logged-in user can read
- Staff members cannot create, update, or delete
Example: Owner-Based Permissions
export const document = db.type("Document", {
title: db.string(),
ownerId: db.uuid(),
isPublic: db.bool(),
})
.permission({
create: [{ conditions: [[{ user: "_loggedIn" }, "=", true]], permit: true }],
read: [
{ conditions: [[{ record: "isPublic" }, "=", true]], permit: true },
{ conditions: [[{ record: "ownerId" }, "=", { user: "id" }]], permit: true },
],
update: [
{ conditions: [[{ record: "ownerId" }, "=", { user: "id" }]], permit: true },
],
delete: [
{ conditions: [[{ record: "ownerId" }, "=", { user: "id" }]], permit: true },
],
});
How it works:
- Any logged-in user can create documents
- Anyone can read public documents
- Only owners can read their private documents
- Only owners can update or delete their documents
Example: Update with Old/New Record
For update operations, use oldRecord and newRecord to compare values:
export const article = db.type("Article", {
title: db.string(),
status: db.enum(["draft", "published"]),
authorId: db.uuid(),
})
.permission({
create: [{ conditions: [[{ user: "_loggedIn" }, "=", true]], permit: true }],
read: [{ conditions: [], permit: true }], // Public read
update: [
// Author can update their own drafts
{
conditions: [
[{ oldRecord: "authorId" }, "=", { user: "id" }],
[{ oldRecord: "status" }, "=", "draft"],
],
permit: true,
},
// Admin can update anything
{
conditions: [[{ user: "role" }, "=", "admin"]],
permit: true,
},
],
delete: [
{ conditions: [[{ user: "role" }, "=", "admin"]], permit: true },
],
});
GraphQL Permissions
GraphQL permissions control access to GraphQL operations and queries.
Basic Syntax
.gqlPermission([
{
conditions: [[{ user: "role" }, "=", "admin"]],
actions: ["create", "read", "update", "delete", "aggregate", "bulkUpsert"],
permit: true,
},
])
conditions
PermissionCondition[]
required
Array of conditions that must be met.
actions
'all' | GqlPermissionAction[]
required
Which GraphQL operations to allow. Use "all" for all operations or specify individual actions.
Whether to permit (true) or deny (false) access.
Available actions:
"read" - Query operations (get, list)
"create" - Create mutations
"update" - Update mutations
"delete" - Delete mutations
"aggregate" - Aggregation queries
"bulkUpsert" - Bulk upsert operations
"all" - All of the above
Example: Role-Based GraphQL Permissions
const adminCondition = [{ user: "role" }, "=", "MANAGER"] as const;
const loggedInCondition = [{ user: "_loggedIn" }, "=", true] as const;
export const defaultGqlPermission: TailorTypeGqlPermission = [
{
conditions: [adminCondition],
actions: ["create", "read", "update", "delete", "aggregate", "bulkUpsert"],
permit: true,
},
{
conditions: [loggedInCondition],
actions: ["read"],
permit: true,
},
];
export const user = db.type("User", {
name: db.string(),
role: db.enum(["MANAGER", "STAFF"]),
})
.permission(defaultPermission)
.gqlPermission(defaultGqlPermission);
How it works:
- Managers can perform all GraphQL operations
- Logged-in users can only perform read queries
- Non-logged-in users cannot access any operations
Complete Example
Here’s a complete example with both permission types:
import { db } from "@tailor-platform/sdk";
import type {
PermissionCondition,
TailorTypePermission,
TailorTypeGqlPermission,
} from "@tailor-platform/sdk";
const adminCondition = [
{ user: "role" },
"=",
"MANAGER",
] as const satisfies PermissionCondition;
const loggedInCondition = [
{ user: "_loggedIn" },
"=",
true,
] as const satisfies PermissionCondition;
const permission: TailorTypePermission = {
create: [adminCondition],
read: [adminCondition, loggedInCondition],
update: [adminCondition],
delete: [adminCondition],
};
const gqlPermission: TailorTypeGqlPermission = [
{
conditions: [adminCondition],
actions: ["create", "read", "update", "delete", "aggregate", "bulkUpsert"],
permit: true,
},
{
conditions: [loggedInCondition],
actions: ["read"],
permit: true,
},
];
export const customer = db.type("Customer", {
name: db.string(),
email: db.string(),
country: db.string(),
...db.fields.timestamps(),
})
.permission(permission)
.gqlPermission(gqlPermission);
User Attributes in Permissions
User attributes come from your auth configuration:
// tailor.config.ts
export const auth = defineAuth("my-auth", {
userProfile: {
type: user,
attributes: {
role: true, // Available as { user: "role" }
department: true, // Available as { user: "department" }
},
},
});
These attributes are automatically typed and available in permission conditions.
Built-in user attributes:
{ user: "id" } - User ID (always available)
{ user: "_loggedIn" } - Whether user is logged in (always available)
Development Helpers
For local development and testing, you can use unsafe helpers that grant full access:
import {
db,
unsafeAllowAllTypePermission,
unsafeAllowAllGqlPermission,
} from "@tailor-platform/sdk";
export const user = db.type("User", {
name: db.string(),
})
.permission(unsafeAllowAllTypePermission)
.gqlPermission(unsafeAllowAllGqlPermission);
Warning: Do NOT use these in production. They disable all authorization checks.
Permission Evaluation
Permissions are evaluated as follows:
- All conditions must match: Within a single permission object, all conditions must be true (AND logic)
- Any permission can grant access: Multiple permissions are evaluated with OR logic
- First match wins: The first matching permission determines access
- Default deny: If no permissions match, access is denied
Example: Complex Permissions
export const project = db.type("Project", {
name: db.string(),
ownerId: db.uuid(),
teamIds: db.uuid({ array: true }),
isPublic: db.bool(),
})
.permission({
create: [{ conditions: [[{ user: "_loggedIn" }, "=", true]], permit: true }],
read: [
// Public projects
{ conditions: [[{ record: "isPublic" }, "=", true]], permit: true },
// Owner
{ conditions: [[{ record: "ownerId" }, "=", { user: "id" }]], permit: true },
// Team member
{ conditions: [[{ user: "id" }, "in", { record: "teamIds" }]], permit: true },
],
update: [
// Only owner can update
{ conditions: [[{ record: "ownerId" }, "=", { user: "id" }]], permit: true },
],
delete: [
// Only owner can delete
{ conditions: [[{ record: "ownerId" }, "=", { user: "id" }]], permit: true },
],
});
Best Practices
- Start restrictive: Begin with minimal permissions and add access as needed
- Use typed conditions: Import
PermissionCondition type and use satisfies for type safety
- Reuse permission configs: Define common permissions once and reuse across types
- Test permissions: Always test permission logic with different user roles
- Document complex rules: Use the
description field for complex permission logic
- Avoid unsafe helpers in production: Never deploy with
unsafeAllowAll* permissions
See Also