Permission System — Systematic Button Control
Executive Overview — all summaries for decision-makers.
Goal
Buttons (Create, AI Edit, AI Generate) should automatically be hidden for certain roles without manually updating every page.
Systematic Solution
1. Permission Helper (src/lib/permissions.ts)
typescript
/**
* Checks whether a user may see "Create" buttons
* LEGAL_ADVISOR and READ_ONLY must NOT see Create buttons
*/
export function canCreate(role: Role): boolean {
return !isReadOnly(role) && !isLegalAdvisor(role);
}Usage:
- Central logic for all create/edit permissions
- Easy to extend for new roles
2. PageHeader Component (src/components/layout/page-header.tsx)
AUTOMATIC PERMISSION CHECK:
aiActionsare automatically hidden forLEGAL_ADVISORandREAD_ONLYcreateActionis automatically hidden forLEGAL_ADVISORandREAD_ONLY
Usage:
tsx
<PageHeader
title="Policies"
description="Manage all policies"
aiActions={aiActions} // ← Automatically hidden for LEGAL_ADVISOR
createAction={{ // ← Automatically hidden for LEGAL_ADVISOR
label: "New Policy",
onClick: () => setShowForm(true)
}}
/>No manual permission check required!
3. CreateButton Component (src/components/ui/create-button.tsx)
AUTOMATIC PERMISSION CHECK:
- Automatically hides itself for
LEGAL_ADVISORandREAD_ONLY
Usage:
tsx
import { CreateButton } from '@/components/ui/create-button';
<CreateButton
onClick={() => setShowForm(true)}
label="New Entity"
/>No manual permission check required!
4. AIEditButtonV2 Component (src/components/ai/ai-edit-button-v2.tsx)
AUTOMATIC PERMISSION CHECK:
- Automatically hides itself for
LEGAL_ADVISORandREAD_ONLY
Usage:
tsx
import { AIEditButtonV2 } from '@/components/ai';
<AIEditButtonV2
entityType="Chapter"
entityId={chapter.id}
entityCode={chapter.slug}
/>No manual permission check required!
Migration Guide
OLD (Manual):
tsx
// ❌ DO NOT DO THIS ANYMORE:
const { user } = useAuth();
{user && canCreate(user.role) && (
<Button onClick={() => setShowForm(true)}>
<Plus className="h-4 w-4 mr-2" />
New Entity
</Button>
)}NEW (Automatic):
tsx
// ✅ DO THIS:
import { CreateButton } from '@/components/ui/create-button';
<CreateButton onClick={() => setShowForm(true)} label="New Entity" />Benefits
- Central control: Permissions in one place only (
src/lib/permissions.ts) - Automatic: Components hide themselves
- Less code: No manual permission checks in pages
- Fewer errors: No forgotten permission checks
- Easy to extend: Add new roles only in
permissions.ts
Adding a New Role
Example: New role VIEWER should NOT see Create buttons
- Prisma Schema (
prisma/schema.prisma):
prisma
enum Role {
ADMIN
MANAGEMENT
STAFF
READ_ONLY
LEGAL_ADVISOR
VIEWER // ← NEW
}- Permission Helper (
src/lib/permissions.ts):
typescript
export function canCreate(role: Role): boolean {
return !isReadOnly(role) && !isLegalAdvisor(role) && role !== 'VIEWER';
}- DONE! All buttons automatically hide for
VIEWER
Component Overview
| Component | Auto-permission | Usage |
|---|---|---|
PageHeader | ✅ Yes | Page header with AI + create actions |
CreateButton | ✅ Yes | Standalone create button |
AIEditButtonV2 | ✅ Yes | AI edit button on detail pages |
AIActionButton | ✅ Yes | AI action dropdown |
AIActionButtonV2 | ✅ Yes | AI action button V2 |
Further Documentation
- Permission helpers:
src/lib/permissions.ts - Role types:
src/types/index.ts - Prisma schema:
prisma/schema.prisma