Skip to main content
← All notes
Building

The client toggle action proves ownership through the database relation chain, not a role check

software

The toggleActionItem server action in portal/actions.ts does not use a role-based guard. It uses data-scoped verification. The first query retrieves the client record from the Clerk user ID. The second query runs prisma.actionItem.findFirst with three simultaneous conditions — id matches the action item ID from the form, project.clientId matches the authenticated client, and assignedTo equals client. If any condition fails, the query returns null and the action returns an error. The client cannot toggle an item that belongs to another client's project because the clientId mismatch eliminates it. The client cannot toggle an item assigned to James because the assignedTo condition eliminates it. Two queries, three permission checks, zero role strings. The admin side works differently. The addAdminComment and createMilestone actions call requireAdmin at the top — one function, one role check, full access. The asymmetry is structural. The admin proves identity once and acts freely. The client proves ownership on every mutation through the shape of the database query itself. The Prisma relation chain does the authorization work. No manual join, no separate permission table, no middleware. The data model is the access model.

Comments coming soon

Sign in with TikTok to leave a comment. Coming soon.