Skip to main content

Introduction

The Cajas admin panel provides administrators with powerful tools to manage cases, items, and monitor platform activity. Access is restricted to users with the admin role.

Admin Roles and Permissions

Role Types

Cajas uses a simple role-based access control system defined in the profiles table:
role: 'user' | 'admin'
  • user: Standard user with access to public features (browsing cases, opening cases, managing inventory)
  • admin: Administrator with full access to create/edit cases, manage items, and view audit logs

Permission System

Admin permissions are enforced at multiple levels:

Database Level (Row Level Security)

PostgreSQL RLS policies ensure data security:
-- Only admins can insert cases
CREATE POLICY "Admins insert cases" ON cases FOR INSERT WITH CHECK (
  EXISTS (SELECT 1 FROM profiles WHERE id = auth.uid() AND role = 'admin')
);

-- Only admins can update cases
CREATE POLICY "Admins update cases" ON cases FOR UPDATE USING (
  EXISTS (SELECT 1 FROM profiles WHERE id = auth.uid() AND role = 'admin')
);

-- Only admins can delete cases
CREATE POLICY "Admins delete cases" ON cases FOR DELETE USING (
  EXISTS (SELECT 1 FROM profiles WHERE id = auth.uid() AND role = 'admin')
);
Reference: /home/daytona/workspace/source/supabase/migrations/0000_create_cases_system.sql:42-50

Application Level (Server Actions)

Server actions verify admin status before executing privileged operations:
export async function createCase(prevState: CreateCaseState, formData: FormData) {
  const supabase = await createClient()
  
  // Check authentication
  const { data: { user }, error: authError } = await supabase.auth.getUser()
  if (authError || !user) {
    return { error: 'Unauthorized' }
  }
  
  // Verify admin role
  const { data: profile } = await supabase
    .from('profiles')
    .select('role')
    .eq('id', user.id)
    .single()
  
  if (profile?.role !== 'admin') {
    return { error: 'Forbidden: Admin access required' }
  }
  
  // Proceed with admin action...
}
Reference: /home/daytona/workspace/source/app/actions/create-case.ts:37-51

Page Level (Route Protection)

Admin pages check role before rendering:
export default async function CreateCasePage() {
  const supabase = await createClient()
  const { data: { user } } = await supabase.auth.getUser()
  
  if (!user) {
    redirect('/')
  }
  
  const { data: profile } = await supabase
    .from('profiles')
    .select('role')
    .eq('id', user.id)
    .single()
  
  if (profile?.role !== 'admin') {
    redirect('/')
  }
  
  return <CreateCaseForm />
}
Reference: /home/daytona/workspace/source/app/admin/create-case/page.tsx:5-28

Admin Capabilities

Admins have access to the following features:

Case Management

  • Create new cases with custom pricing
  • Configure case images and descriptions
  • Update existing cases
  • Delete cases

Item Management

  • Add items to cases
  • Set item values and rarities
  • Configure drop probabilities
  • Manage item images

Monitoring & Audit

  • View all admin actions in audit logs
  • Track case creation and modifications
  • Monitor system activity

Database Schema

Profiles Table

interface Profile {
  id: string
  updated_at: string | null
  full_name: string | null
  avatar_url: string | null
  dni: string | null
  phone: string | null
  address: string | null
  role: 'user' | 'admin'  // Role determines access level
}
Reference: /home/daytona/workspace/source/types/supabase.ts:12-42

Admin Logs Table

All admin actions are logged for audit purposes:
interface AdminLog {
  id: string
  admin_id: string | null       // References auth.users
  action: string                 // Action type (e.g., 'CREATE_CASE')
  details: Json | null           // Additional context
  created_at: string
}
Reference: /home/daytona/workspace/source/types/supabase.ts:102-124

Best Practices

Security

  1. Never expose admin endpoints publicly: Always verify user role on the server side
  2. Use RLS policies: Leverage PostgreSQL’s Row Level Security for defense in depth
  3. Log all actions: Maintain an audit trail via the admin_logs table
  4. Validate input: Use Zod schemas to validate all admin inputs

Access Control

  1. Check role at multiple levels: Verify admin status in routes, actions, and database
  2. Use server components: Perform role checks in Server Components to prevent client-side bypasses
  3. Redirect unauthorized users: Always redirect non-admins attempting to access admin pages

Audit Trail

Log important admin actions:
// Example from create-case action
await supabase.from('admin_logs').insert({
  admin_id: user.id,
  action: 'CREATE_CASE',
  details: { case_id: newCase.id, name: newCase.name },
})
Reference: /home/daytona/workspace/source/app/actions/create-case.ts:128-132

Getting Started

To grant admin access to a user:
  1. Access your Supabase database
  2. Update the user’s profile:
    UPDATE profiles SET role = 'admin' WHERE id = 'user-uuid';
    
  3. The user will now have access to admin features

Next Steps

Build docs developers (and LLMs) love