Recipes
Limit Documents to Their Owner
Enforce row-level access and assign ownership on the trusted server.
Owner scoping must protect reads, updates, and deletion, while create logic must prevent clients from choosing another owner.
Return a where constraint from access control so authenticated users only read their own records.
Use this when
- users should only see their own records
- add row level access
- scope documents by owner
- prevent users reading another user's data
Dyrected concepts
access.read, where, row-level access
Additional packages: No additional packages.
Complete recipe
This is the canonical source compiled and behavior-tested by @dyrected/knowledge.
import { defineCollection, defineRelationshipField, defineTextField } from "@dyrected/core";
export const Projects = defineCollection({
slug: "projects",
access: {
read: ({ user }) => (user ? { owner: { equals: user.sub } } : false),
create: ({ user }) => Boolean(user),
update: ({ user }) => (user ? { owner: { equals: user.sub } } : false),
delete: ({ user }) => (user ? { owner: { equals: user.sub } } : false),
},
hooks: {
beforeChange: [
({ data, operation, user }) => {
if (operation !== "create") return data;
if (!user) throw new Error("Authentication is required to create a project.");
return { ...data, owner: user.sub };
},
],
},
fields: [
defineTextField({ name: "name", label: "Project name", required: true }),
defineRelationshipField({
name: "owner",
label: "Owner",
relationTo: "users",
required: true,
admin: { readOnly: true },
}),
],
});Decisions and cautions
- Add create access requiring an authenticated user.
- Set or overwrite
ownerin a serverbeforeChangehook during creation. - Apply the same owner constraint to every operation that should be private.
- Decide whether administrators need an explicit bypass; do not grant it accidentally.
- Prefer hiding or making the owner field read-only in the Admin UI, but keep server enforcement regardless.
Test anonymous, owner, non-owner, and administrator cases for each operation.