Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/EdgarJr30/proyecto-de-grado-cms/llms.txt

Use this file to discover all available pages before exploring further.

Row-Level Security Policies

MLM CMMS uses PostgreSQL Row-Level Security (RLS) to enforce permission-based access control at the database level. This page documents the RLS policies defined in sql/modules/core_cmms/09_policies.sql.

RLS Overview

All core tables have RLS enabled. Policies use the public.me_has_permission() function to check user permissions before allowing access to rows.

Permission-Based Policy Pattern

Most tables follow this standard pattern:
-- Enable RLS
ALTER TABLE public.table_name ENABLE ROW LEVEL SECURITY;

-- SELECT policy
CREATE POLICY "Users with read permission can view"
  ON public.table_name FOR SELECT
  USING (public.me_has_permission('resource:read'));

-- INSERT policy
CREATE POLICY "Users with create permission can insert"
  ON public.table_name FOR INSERT
  WITH CHECK (public.me_has_permission('resource:create'));

-- UPDATE policy
CREATE POLICY "Users with update permission can modify"
  ON public.table_name FOR UPDATE
  USING (public.me_has_permission('resource:update'));

-- DELETE policy
CREATE POLICY "Users with delete permission can remove"
  ON public.table_name FOR DELETE
  USING (public.me_has_permission('resource:delete'));

Table-Specific Policies

tickets

Work requests and work orders with hierarchical permissions.
ALTER TABLE public.tickets ENABLE ROW LEVEL SECURITY;

-- Read: full access or read permission
CREATE POLICY "tickets_select_policy"
  ON public.tickets FOR SELECT
  USING (
    public.me_has_permission('work_orders:read') OR
    public.me_has_permission('work_orders:full_access') OR
    (public.me_has_permission('work_orders:read_own') AND created_by = auth.uid())
  );

-- Insert: create permission
CREATE POLICY "tickets_insert_policy"
  ON public.tickets FOR INSERT
  WITH CHECK (
    public.me_has_permission('work_orders:create') OR
    public.me_has_permission('work_orders:full_access')
  );

-- Update: full access permission
CREATE POLICY "tickets_update_policy"
  ON public.tickets FOR UPDATE
  USING (public.me_has_permission('work_orders:full_access'));

-- Delete: delete or full access permission
CREATE POLICY "tickets_delete_policy"
  ON public.tickets FOR DELETE
  USING (
    public.me_has_permission('work_orders:delete') OR
    public.me_has_permission('work_orders:full_access')
  );
Key Features:
  • read_own permission allows users to view only tickets they created
  • full_access grants all operations
  • Separate delete permission for destructive operations
Source: sql/modules/core_cmms/09_policies.sql

users

User profile management with self-update capability.
ALTER TABLE public.users ENABLE ROW LEVEL SECURITY;

-- Read: users:read permission
CREATE POLICY "users_select_policy"
  ON public.users FOR SELECT
  USING (public.me_has_permission('users:read'));

-- Insert: users:create or full_access
CREATE POLICY "users_insert_policy"
  ON public.users FOR INSERT
  WITH CHECK (
    public.me_has_permission('users:create') OR
    public.me_has_permission('users:full_access')
  );

-- Update: full_access OR self-update (own profile)
CREATE POLICY "users_update_policy"
  ON public.users FOR UPDATE
  USING (
    public.me_has_permission('users:full_access') OR
    (id = auth.uid()) -- Users can update their own profile
  );

-- Delete: users:delete permission
CREATE POLICY "users_delete_policy"
  ON public.users FOR DELETE
  USING (public.me_has_permission('users:delete'));
Key Features:
  • Any authenticated user can update their own profile
  • Admin permissions required for creating/deleting users
Source: sql/modules/core_cmms/09_policies.sql

assignees

Technician/assignee management.
ALTER TABLE public.assignees ENABLE ROW LEVEL SECURITY;

CREATE POLICY "assignees_select_policy"
  ON public.assignees FOR SELECT
  USING (public.me_has_permission('assignees:read'));

CREATE POLICY "assignees_insert_policy"
  ON public.assignees FOR INSERT
  WITH CHECK (public.me_has_permission('assignees:full_access'));

CREATE POLICY "assignees_update_policy"
  ON public.assignees FOR UPDATE
  USING (public.me_has_permission('assignees:full_access'));

CREATE POLICY "assignees_delete_policy"
  ON public.assignees FOR DELETE
  USING (public.me_has_permission('assignees:delete'));
Source: sql/modules/core_cmms/09_policies.sql

roles and permissions

RBAC management tables with admin-only access.
ALTER TABLE public.roles ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.permissions ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.role_permissions ENABLE ROW LEVEL SECURITY;

-- Only users with manage_permissions can view/modify
CREATE POLICY "roles_all_policy"
  ON public.roles FOR ALL
  USING (public.me_has_permission('rbac:manage_permissions'));

CREATE POLICY "permissions_all_policy"
  ON public.permissions FOR ALL
  USING (public.me_has_permission('rbac:manage_permissions'));

CREATE POLICY "role_permissions_all_policy"
  ON public.role_permissions FOR ALL
  USING (public.me_has_permission('rbac:manage_permissions'));
Key Features:
  • Single ALL policy covers SELECT, INSERT, UPDATE, DELETE
  • Only users with RBAC management permission can access
Source: sql/modules/core_cmms/09_policies.sql

user_roles

User-role assignments with self-view capability.
ALTER TABLE public.user_roles ENABLE ROW LEVEL SECURITY;

-- Users can view their own roles
CREATE POLICY "user_roles_select_policy"
  ON public.user_roles FOR SELECT
  USING (
    user_id = auth.uid() OR
    public.me_has_permission('rbac:manage_roles')
  );

-- Only RBAC managers can modify role assignments
CREATE POLICY "user_roles_insert_policy"
  ON public.user_roles FOR INSERT
  WITH CHECK (public.me_has_permission('rbac:manage_roles'));

CREATE POLICY "user_roles_delete_policy"
  ON public.user_roles FOR DELETE
  USING (public.me_has_permission('rbac:manage_roles'));
Key Features:
  • Users can view their own role assignments
  • Only admins can assign/revoke roles
Source: sql/modules/core_cmms/09_policies.sql

locations

Location management with read access for all authenticated users.
ALTER TABLE public.locations ENABLE ROW LEVEL SECURITY;

-- All authenticated users can read locations
CREATE POLICY "locations_select_policy"
  ON public.locations FOR SELECT
  USING (auth.uid() IS NOT NULL);

-- Admins with locations:full_access can modify
CREATE POLICY "locations_insert_policy"
  ON public.locations FOR INSERT
  WITH CHECK (public.me_has_permission('locations:full_access'));

CREATE POLICY "locations_update_policy"
  ON public.locations FOR UPDATE
  USING (public.me_has_permission('locations:full_access'));

CREATE POLICY "locations_delete_policy"
  ON public.locations FOR DELETE
  USING (public.me_has_permission('locations:delete'));
Key Features:
  • Locations are readable by all authenticated users (needed for dropdown selectors)
  • Modification requires admin permissions
Source: sql/modules/core_cmms/09_policies.sql

notifications

Notification delivery tables with user-specific access.
ALTER TABLE public.notification_deliveries ENABLE ROW LEVEL SECURITY;

-- Users can only see their own notifications
CREATE POLICY "notification_deliveries_select_policy"
  ON public.notification_deliveries FOR SELECT
  USING (recipient_user_id = auth.uid());

-- Users can mark their own notifications as read
CREATE POLICY "notification_deliveries_update_policy"
  ON public.notification_deliveries FOR UPDATE
  USING (recipient_user_id = auth.uid());
Key Features:
  • Strict user isolation - users can only access their own notifications
  • No INSERT/DELETE - managed by triggers and functions
Source: sql/modules/core_cmms/16_notifications.sql For more notification policies, see Notifications Database Schema.

Policy Testing

Verify policies are working correctly:
-- Check if RLS is enabled
SELECT tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'public'
  AND tablename IN ('tickets', 'users', 'assignees', 'roles');

-- List all policies on a table
SELECT policyname, cmd, qual, with_check
FROM pg_policies
WHERE tablename = 'tickets';

-- Test as specific user
SET LOCAL ROLE authenticated;
SET LOCAL "request.jwt.claim.sub" = 'user-uuid-here';
SELECT * FROM public.tickets; -- Should enforce policies

Common Permission Codes

ResourceActionCodeUsage
work_ordersreadwork_orders:readView all tickets
work_ordersread_ownwork_orders:read_ownView own tickets only
work_orderscreatework_orders:createCreate tickets
work_ordersfull_accesswork_orders:full_accessAll operations
usersreadusers:readView user list
usersfull_accessusers:full_accessManage users
assigneesreadassignees:readView technicians
assigneesfull_accessassignees:full_accessManage technicians
rbacmanage_rolesrbac:manage_rolesManage role assignments
rbacmanage_permissionsrbac:manage_permissionsSync permissions
For the complete permission registry, see RBAC System.

Security Considerations

Important Security Notes:
  • RLS policies are enforced at the database level - even direct SQL queries respect them
  • SECURITY DEFINER functions bypass RLS, so they must implement their own checks
  • The me_has_permission() function caches results for 5 minutes for performance
  • Always test policies with multiple user roles before deployment

Troubleshooting

  1. Verify RLS is enabled: SELECT tablename, rowsecurity FROM pg_tables WHERE tablename = 'your_table'
  2. Check policy exists: SELECT * FROM pg_policies WHERE tablename = 'your_table'
  3. Ensure user is authenticated: SELECT auth.uid()
  1. Verify user has required permission: SELECT public.me_has_permission('resource:action')
  2. Check role assignments: SELECT * FROM public.user_roles WHERE user_id = auth.uid()
  3. Verify permission is active: SELECT * FROM public.permissions WHERE code = 'resource:action'
  1. Check WITH CHECK clauses in INSERT/UPDATE policies
  2. Verify required permissions for the operation
  3. Ensure foreign key references exist and are accessible

Next Steps

Core Tables

Review the database schema

Database Functions

Learn about stored procedures

RBAC System

Understand the permission model

Frontend Permissions

Configure roles and permissions

Build docs developers (and LLMs) love