Permissions
RBAC matrix with 143 granular permissions across 7 roles.
Contents
Overview
HeartCo uses a role-based access control (RBAC) system defined in a single file that acts as the source of truth.
File: src/lib/permissions/matrix.ts
Role hierarchy
ADMIN (0) ─── Full access
│
DIRECTION (1) ─── Extended read access, approval
│
MANAGER (2) ─── Operational management
│
HR (3) / ACCOUNTANT (3) ─── Specialized functions
│
COLLABORATOR (4) ─── Limited access (own data)
│
CLIENT (99) ─── Portal only (0 permissions)
HR and ACCOUNTANT share the same hierarchy level but have different permission sets.
Full matrix by category
Invoicing (9 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
facturation:read | ✅ | ✅ | ✅ | — | ✅ | — |
facturation:read_own | ✅ | ✅ | ✅ | — | ✅ | ✅ |
facturation:create | ✅ | — | ✅ | — | — | — |
facturation:edit | ✅ | — | ✅ | — | — | — |
facturation:delete | ✅ | — | — | — | — | — |
facturation:send | ✅ | — | ✅ | — | — | — |
facturation:mark_paid | ✅ | ✅ | ✅ | — | ✅ | — |
facturation:export | ✅ | ✅ | — | — | ✅ | — |
facturation:void | ✅ | — | — | — | — | — |
Quotes (6 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
devis:read | ✅ | ✅ | ✅ | — | — | — |
devis:create | ✅ | — | ✅ | — | — | — |
devis:edit | ✅ | — | ✅ | — | — | — |
devis:delete | ✅ | — | — | — | — | — |
devis:send | ✅ | — | ✅ | — | — | — |
devis:convert_to_invoice | ✅ | — | ✅ | — | — | — |
Accounting (3 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
comptabilite:read | ✅ | ✅ | — | — | ✅ | — |
comptabilite:export_fec | ✅ | — | — | — | ✅ | — |
comptabilite:reconcile | ✅ | — | — | — | ✅ | — |
Clients (5 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
clients:read | ✅ | ✅ | ✅ | — | — | ✅ |
clients:create | ✅ | — | ✅ | — | — | — |
clients:edit | ✅ | — | ✅ | — | — | — |
clients:delete | ✅ | — | — | — | — | — |
clients:export | ✅ | ✅ | — | — | — | — |
CRM (5 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
crm:read | ✅ | ✅ | ✅ | — | — | ✅ |
crm:create | ✅ | — | ✅ | — | — | — |
crm:edit | ✅ | — | ✅ | — | — | — |
crm:delete | ✅ | — | — | — | — | — |
crm:assign | ✅ | — | ✅ | — | — | — |
Expense reports (6 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
notes_frais:read_own | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
notes_frais:read_all | ✅ | ✅ | ✅ | — | ✅ | — |
notes_frais:create | ✅ | ✅ | ✅ | ✅ | — | ✅ |
notes_frais:edit_own | ✅ | ✅ | ✅ | ✅ | — | ✅ |
notes_frais:approve | ✅ | ✅ | ✅ | — | — | — |
notes_frais:export | ✅ | ✅ | — | — | ✅ | — |
Projects (4 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
project:read | ✅ | ✅ | ✅ | — | — | ✅ |
project:create | ✅ | — | ✅ | — | — | — |
project:edit | ✅ | — | ✅ | — | — | — |
project:delete | ✅ | — | — | — | — | — |
Work orders (4 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
workorder:read | ✅ | ✅ | ✅ | — | — | ✅ |
workorder:create | ✅ | — | ✅ | — | — | — |
workorder:edit | ✅ | — | ✅ | — | — | — |
workorder:delete | ✅ | — | — | — | — | — |
Field reports (6 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
rapports:read_own | ✅ | ✅ | ✅ | — | — | ✅ |
rapports:read_all | ✅ | ✅ | ✅ | — | — | — |
rapports:create | ✅ | — | ✅ | — | — | ✅ |
rapports:edit_own | ✅ | — | ✅ | — | — | ✅ |
rapports:finalize | ✅ | — | ✅ | — | — | — |
rapports:sign | ✅ | ✅ | — | — | — | — |
HR (6 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
rh:read_own | ✅ | ✅ | ✅ | ✅ | — | ✅ |
rh:read_all | ✅ | ✅ | — | ✅ | — | — |
rh:manage_leaves | ✅ | — | — | ✅ | — | — |
rh:manage_payslips | ✅ | — | — | ✅ | — | — |
rh:manage_profiles | ✅ | — | — | ✅ | — | — |
rh:export_dsn | ✅ | — | — | ✅ | — | — |
Members (4 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
membres:read | ✅ | ✅ | ✅ | ✅ | — | — |
membres:invite | ✅ | — | ✅ | — | — | — |
membres:edit_roles | ✅ | — | — | — | — | — |
membres:deactivate | ✅ | — | — | — | — | — |
Timesheets (4 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
timesheets:read_own | ✅ | ✅ | ✅ | ✅ | — | ✅ |
timesheets:read_all | ✅ | ✅ | ✅ | ✅ | — | — |
timesheets:create | ✅ | ✅ | ✅ | ✅ | — | ✅ |
timesheets:approve | ✅ | ✅ | ✅ | ✅ | — | — |
Settings (6 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
settings:read | ✅ | ✅ | ✅ | — | — | — |
settings:edit_org | ✅ | — | — | — | — | — |
settings:edit_billing | ✅ | — | — | — | — | — |
settings:manage_webhooks | ✅ | — | — | — | — | — |
settings:view_audit_log | ✅ | ✅ | — | — | — | — |
settings:manage_permissions | ✅ | — | — | — | — | — |
Marketing (3 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
marketing:read | ✅ | ✅ | ✅ | — | — | — |
marketing:create | ✅ | — | ✅ | — | — | — |
marketing:send_campaigns | ✅ | — | — | — | — | — |
E-invoicing (2 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
e_invoicing:read | ✅ | ✅ | — | — | ✅ | — |
e_invoicing:submit | ✅ | — | — | — | — | — |
AI & Copilot (3 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
ia:use_basic | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
ia:use_advanced | ✅ | ✅ | ✅ | — | — | — |
ia:view_insights | ✅ | ✅ | — | — | — | — |
Automations (2 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
automation:read | ✅ | ✅ | ✅ | — | — | — |
automation:manage | ✅ | — | — | — | — | — |
Inventory (3 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
stock:read | ✅ | ✅ | ✅ | — | — | — |
stock:write | ✅ | — | ✅ | — | — | — |
stock:export | ✅ | ✅ | — | — | — | — |
Analytics (2 permissions)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
analytics:read_own | ✅ | ✅ | ✅ | — | — | ✅ |
analytics:read_org | ✅ | ✅ | — | — | — | — |
Superadmin (1 permission)
| Permission | ADMIN | DIRECTION | MANAGER | HR | ACCOUNTANT | COLLAB |
|---|
superadmin:access | — | — | — | — | — | — |
superadmin:access is not granted to any role by default. It is reserved for platform administration.
Summary by role
| Role | Number of permissions |
|---|
| ADMIN | ~60+ (everything except superadmin) |
| DIRECTION | ~26 (extended read access + approval) |
| MANAGER | ~36 (operational CRUD) |
| HR | ~14 (HR, time, leave) |
| ACCOUNTANT | ~13 (accounting, exports) |
| COLLABORATOR | ~12 (their own data) |
| CLIENT | 0 (portal only) |
Utility functions
import {
hasPermission,
hasAnyPermission,
hasAllPermissions,
getRolePermissions,
isRoleAtLeast,
canManageRole,
} from "~/lib/permissions/matrix";
// Check a permission
hasPermission("MANAGER", "facturation:create"); // true
hasPermission("COLLABORATOR", "facturation:create"); // false
// Check for at least one permission among several
hasAnyPermission("MANAGER", ["facturation:read", "devis:read"]); // true
// Check the hierarchy
isRoleAtLeast("MANAGER", "COLLABORATOR"); // true (2 ≤ 4)
isRoleAtLeast("COLLABORATOR", "MANAGER"); // false (4 > 2)
// Check whether a role can manage another
canManageRole("ADMIN", "MANAGER"); // true
canManageRole("MANAGER", "ADMIN"); // false
Usage in tRPC routers
Single permission
export const facturationRouter = createTRPCRouter({
create: requirePermission("facturation:create")
.input(schema)
.mutation(async ({ ctx, input }) => {
// Only ADMIN and MANAGER reach this point
}),
});
Multiple permissions (at least one)
export const analyticsRouter = createTRPCRouter({
overview: requireAnyPermission(["analytics:read_own", "analytics:read_org"])
.query(async ({ ctx }) => {
// ADMIN, DIRECTION, MANAGER or COLLABORATOR
}),
});
Adding a new permission
1. Define the permission
In src/lib/permissions/matrix.ts, add the string to the Permission type and to each role's matrix:
// Permission type — add the new entry
type Permission = ... | "my_module:read" | "my_module:create" | "my_module:edit" | "my_module:delete";
// ADMIN matrix — add the permissions
ADMIN: [..., "my_module:read", "my_module:create", "my_module:edit", "my_module:delete"],
MANAGER: [..., "my_module:read", "my_module:create", "my_module:edit"],
// etc.
2. Use it in the router
requirePermission("my_module:create")
3. (Optional) Check on the client
const { data: session } = useSession();
const canCreate = hasPermission(session?.user.role, "my_module:create");
◀ Modules · Contents · Payments ▶