Skip to content

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:

  • aiActions are automatically hidden for LEGAL_ADVISOR and READ_ONLY
  • createAction is automatically hidden for LEGAL_ADVISOR and READ_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_ADVISOR and READ_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_ADVISOR and READ_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

  1. Central control: Permissions in one place only (src/lib/permissions.ts)
  2. Automatic: Components hide themselves
  3. Less code: No manual permission checks in pages
  4. Fewer errors: No forgotten permission checks
  5. Easy to extend: Add new roles only in permissions.ts

Adding a New Role

Example: New role VIEWER should NOT see Create buttons

  1. Prisma Schema (prisma/schema.prisma):
prisma
enum Role {
  ADMIN
  MANAGEMENT
  STAFF
  READ_ONLY
  LEGAL_ADVISOR
  VIEWER  // ← NEW
}
  1. Permission Helper (src/lib/permissions.ts):
typescript
export function canCreate(role: Role): boolean {
  return !isReadOnly(role) && !isLegalAdvisor(role) && role !== 'VIEWER';
}
  1. DONE! All buttons automatically hide for VIEWER

Component Overview

ComponentAuto-permissionUsage
PageHeader✅ YesPage header with AI + create actions
CreateButton✅ YesStandalone create button
AIEditButtonV2✅ YesAI edit button on detail pages
AIActionButton✅ YesAI action dropdown
AIActionButtonV2✅ YesAI action button V2

Further Documentation

  • Permission helpers: src/lib/permissions.ts
  • Role types: src/types/index.ts
  • Prisma schema: prisma/schema.prisma