Docs

Team Workspace RLS

Team Workspace RLS This example models shared workspaces where a user can see records only when they are a member of the workspace. Tables Create workspace . Field or relation Type Notes name string Required owner many-to-one relation to enfyra_user Required Create workspace_memb

Team Workspace RLS

This example models shared workspaces where a user can see records only when they are a member of the workspace.

Tables

Create workspace.

Field or relation Type Notes
name string Required
owner many-to-one relation to enfyra_user Required

Create workspace_member.

Field or relation Type Notes
workspace many-to-one relation to workspace Required
member many-to-one relation to enfyra_user Required
role select owner, admin, member

Create workspace_task.

Field or relation Type Notes
workspace many-to-one relation to workspace Required
title string Required
status select open, done
assignee many-to-one relation to enfyra_user Optional

Add a unique constraint on workspace_member.workspace,member.

Scope Workspace Tasks

Add a GET /workspace_task pre-hook.

if (@USER?.isRootAdmin) {
  return;
}

if (!@USER?.id) {
  @THROW401();
}

@QUERY.filter = {
  _and: [
    @QUERY.filter || {},
    {
      workspace: {
        members: {
          member: {
            id: { _eq: @USER.id }
          }
        }
      }
    }
  ]
};

The relation path must match your inverse relation names. If your metadata does not expose workspace.members, query workspace_member first and filter tasks by the resulting workspace ids.

Require Admin Role To Create Tasks

Add a pre-hook to POST /workspace_task.

if (@USER?.isRootAdmin) {
  return;
}

const workspaceId = @BODY.workspace?.id || @BODY.workspace || @QUERY.filter?.workspace?._eq;
if (!workspaceId) {
  @THROW400('workspace is required');
}

const membership = await #workspace_member.find({
  filter: {
    workspace: { id: { _eq: workspaceId } },
    member: { id: { _eq: @USER.id } },
    role: { _in: ['owner', 'admin'] }
  },
  fields: 'id',
  limit: 1
});

if (!membership.data?.[0]) {
  @THROW403();
}

For PATCH /workspace_task/:id and DELETE /workspace_task/:id, load the target task by @PARAMS.id, read its workspace, and run the same membership check before allowing the write.

Create A Workspace

A custom POST /workspaces handler can create the workspace and owner membership together.

if (!@USER?.id) {
  @THROW401();
}

const created = await #workspace.create({
  data: {
    name: @BODY.name,
    owner: { id: @USER.id }
  }
});

const workspace = created.data?.[0];
if (!workspace) {
  @THROW500('workspace was not created');
}

await #workspace_member.create({
  data: {
    workspace: { id: workspace.id },
    member: { id: @USER.id },
    role: 'owner'
  }
});

return workspace;