Roles & Module Permissions
Overview
This domain has four tables: system_role (roles), system_module (system features/modules),
system_role_module (what each role may do in each module) and organization_module (which
modules an organization has been granted). A user's effective permissions are the intersection of
their role grants and the modules enabled for their organization.
Table system_role
| Column | Type | Nullable | Default | Description |
|---|
id | INTEGER | NOT NULL | nextval (serial) | Primary key of the role |
name | TEXT | NOT NULL | – | Role name, e.g. admin, editor, viewer |
total | INTEGER | NOT NULL | 5 | Maximum number of users allowed to hold this role |
type | UserType (enum) | NOT NULL | – | Which user type the role applies to: onemoby or customer |
status | CommonStatus (enum) | NOT NULL | – | Role status (active, inactive, etc.) |
created_date | TIMESTAMPTZ(3) | NOT NULL | CURRENT_TIMESTAMP | Creation timestamp |
created_by | INTEGER | NOT NULL | 0 | User id of the creator |
updated_date | TIMESTAMPTZ(3) | NULL | – | Last update timestamp |
updated_by | INTEGER | NULL | 0 | User id of the last editor |
deleted_date | TIMESTAMPTZ(3) | NULL | – | Soft-delete timestamp |
Table system_module
| Column | Type | Nullable | Default | Description |
|---|
id | INTEGER | NOT NULL | nextval (serial) | Primary key of the module |
name | TEXT | NOT NULL | – | Module/feature name, e.g. import-mapping, campaign |
actions | TEXT | NOT NULL | – | Comma-separated list of actions the module supports, e.g. readAll,read,create,update,delete |
status | CommonStatus (enum) | NOT NULL | – | Module status (active = enabled in the system) |
created_date | TIMESTAMPTZ(3) | NOT NULL | CURRENT_TIMESTAMP | Creation timestamp |
created_by | INTEGER | NOT NULL | 0 | User id of the creator |
updated_date | TIMESTAMPTZ(3) | NULL | – | Last update timestamp |
updated_by | INTEGER | NULL | 0 | User id of the last editor |
deleted_date | TIMESTAMPTZ(3) | NULL | – | Soft-delete timestamp |
Table system_role_module
| Column | Type | Nullable | Default | Description |
|---|
id | INTEGER | NOT NULL | nextval (serial) | Primary key |
role_id | INTEGER | NOT NULL | – | Role (FK to system_role.id) |
module_id | INTEGER | NOT NULL | – | Module (FK to system_module.id) |
actions | TEXT | NOT NULL | – | Actions this role may perform on this module (a subset of system_module.actions) |
created_date | TIMESTAMPTZ(3) | NOT NULL | CURRENT_TIMESTAMP | Creation timestamp |
created_by | INTEGER | NOT NULL | 0 | User id of the creator |
updated_date | TIMESTAMPTZ(3) | NULL | – | Last update timestamp |
updated_by | INTEGER | NULL | 0 | User id of the last editor |
Table organization_module
| Column | Type | Nullable | Default | Description |
|---|
id | INTEGER | NOT NULL | nextval (serial) | Primary key |
organization_id | INTEGER | NOT NULL | – | Organization (FK to organization.id, ON DELETE CASCADE) |
module_id | INTEGER | NOT NULL | – | Module (FK to system_module.id, ON DELETE CASCADE) |
actions | TEXT | NOT NULL | – | Actions this organization is granted on this module |
created_date | TIMESTAMPTZ | NOT NULL | now() | Creation timestamp |
updated_date | TIMESTAMPTZ | NULL | – | Last update timestamp |
Notes
organization_module is absent from schema.prisma and has no tracked migration file — the
table was created directly on the database. The structure above comes from the preprod pg_dump
(schema-dumps/2026-07-24/schema.sql), which is why it lacks the
created_by/updated_by/deleted_date columns the other tables in this domain have, and why
its timestamps are plain TIMESTAMPTZ (no precision 3).
- Unique constraint:
organization_module (organization_id, module_id) — one row per module per
organization.
- Foreign keys:
system_role_module.role_id -> system_role.id,
system_role_module.module_id -> system_module.id,
organization_module.organization_id -> organization.id,
organization_module.module_id -> system_module.id
system_role has an index on deleted_date.
- The
actions column in all three tables is a comma-separated string, not an array or JSON, e.g.
readAll,read,create,update,delete. readAll means "see all records in the organization" while
read means "see only your own records".
- Registering a new module requires inserts into
system_module, system_role_module (for the
relevant roles) and organization_module (for customer organizations that already have
overrides). See manual-sql/9.import_mapping.sql for a worked example.