Roles¶
Part of the user manual. Related: VISIBILITY · PERMISSIONS · TENANCY · NOTIFICATIONS · PROJECTS · WORKFLOWS. Roles are layer 4 of the five visibility layers.
Roles in REBIM are the trickiest piece of the workflow-event visibility puzzle. Most "Alice can see this event but Bob can't, same project" support questions resolve here.
This page covers the role mechanism end-to-end: what counts as a role, how they're assigned, how they grant or restrict visibility on workflow events, and the non-obvious from-state-not-to-state semantic that catches operators out.
TL;DR¶
- "Role" in REBIM = discipline (
ProjectDisciplinemodel). Architect, Mechanical, Electrical, Reviewer, etc. - Disciplines are assigned to project members via their
ProjectPeople.disciplines(many-to-many). - Workflow transitions can declare disciplines in four categories —
transition_roles,readonly_roles,commentonly_roles, plus theany_roleescape hatch. - A user holding any of those disciplines sees the workflow event when its status is the transition's FROM state — not the TO state. The non-obvious bit, and the source of most "I should see this!" confusion.
- Two
ProjectPeopleflags amplify the basic rule: project_admin— bypasses all role checks within the project.role_leader— broadens visibility within an assigned discipline; required for some transitions (requires_role_leader).- Ad-hoc (no-workflow) events have no role mechanism — visible only to owner / assignee / project admin / superuser.
What "role" means here¶
A role in REBIM is a ProjectDiscipline. The model is named
"Discipline" because it originated as a way to model architectural /
engineering disciplines (Architect, Mechanical, Electrical, Civil,
Structural, MEP, …), but in practice the mechanism is general — any
labeled grouping with workflow visibility implications can be modelled
as a discipline.
Disciplines have a code (short identifier, e.g. ARC) and a name
(human-readable, e.g. Architect). They live in a tenancy like other
configuration objects — so the set of available disciplines is shared
across all projects in that tenancy.
The workflow_role flag on a discipline¶
Each ProjectDiscipline has a workflow_role boolean. When set, the
discipline is treated as workflow-only — hidden from the EDMS
document create/edit form and from bulk-create. Useful for keeping
the EDMS form's role dropdown short by hiding disciplines that only
serve a workflow-routing purpose.
The flag is purely UX scoping — it doesn't affect how the role participates in visibility rules. A workflow-only discipline still grants workflow event visibility per the rules below.
How disciplines get assigned¶
A user holds a discipline per project. There's no global "Alice
is an Architect" — instead, Alice's ProjectPeople row for Project X
has disciplines = {Architect}, and her ProjectPeople row for
Project Y has disciplines = {Architect, Reviewer}.
Assignments are managed via the project's People tab:
- Open the project.
- Open the People tab.
- Click the kebab next to a project person → Edit the Relationship.
- Set / change the disciplines list.
A user can hold multiple disciplines per project (the field is M2M). The visibility rule is satisfied if any of the user's disciplines matches any of the transition's discipline categories.
A user with no disciplines at all in a project still has project membership and sees project-scoped things accordingly — but workflow events with role-restricted transitions are filtered out for them (unless they hold one of the bypass flags below).
How roles grant visibility on workflow events¶
A workflow event has a current status. Transitions go in and out of that status. Each transition can declare disciplines in three categories:
| Field on transition | Grants | Notes |
|---|---|---|
transition_roles |
See the event AND perform this transition | The standard "you're the X reviewer, here's an X-routed event" path |
readonly_roles |
See the event but cannot perform this transition | The "I want them aware but not authorised to advance" case |
commentonly_roles |
See the event with an explicit comment / @mention request | A weaker awareness — they're asked for input, not full review |
Plus one boolean escape hatch:
| Field on transition | Effect |
|---|---|
any_role |
When true, every project member who holds any discipline (i.e. any role at all) sees the event and can perform this transition. Bypasses the per-discipline matching entirely. Does not affect notifications — who is emailed is set by the notify_* toggles (see Notifications and roles); to email everyone on the project use notify_all_project_members. |
A user holding any matching discipline gets visibility. They get action rights according to which category matched:
- Match
transition_roles(orany_roleis set): full transition rights. - Match
readonly_rolesonly: see but can't transition. - Match
commentonly_rolesonly: see + comment, can't transition.
If the user matches multiple categories, the most permissive match wins.
The FROM-state semantic (the key non-obvious thing)¶
Workflow transitions are directional: each transition goes
status_from → status_to. When you assign roles to a transition, the
roles grant visibility at the status_from end, not the status_to
end.
Why: the role-holder needs to see the event in order to trigger the
transition. If a role only granted visibility once the event arrived
at status_to, the role-holder would never get a chance to act —
they'd see the event only AFTER someone else had advanced it past
them.
Worked example¶
Workflow: Draft → Review → Approved
Two transitions:
Draft → Review,transition_roles = {Author}Review → Approved,transition_roles = {Reviewer}
An event sits in Draft. Visibility:
- The Author (matches T1's
transition_rolesatfrom=Draft) sees it. ✓ - The Reviewer (matches T2's
transition_rolesatfrom=Review) does not see it yet — the event isn't in Review yet.
The Author advances Draft → Review. Now the event sits in Review.
Visibility:
- The Author no longer matches any in-progress transition's
fromstate (T1's from was Draft, but we've left Draft). They lose visibility — unless they're also the owner / assignee / project admin (any of which would keep them in). - The Reviewer (matches T2's
transition_rolesatfrom=Review) now sees it. ✓
The "role appears at the FROM" rule is what makes that handoff work.
Edge case: multiple transitions out of the same status¶
If two transitions both leave the same status — e.g.
Review → Approved (Reviewer) AND Review → Rejected (QA) — then
both role-holders see the event at Review. Either can act.
This is standard "approve or reject" behaviour. Worth knowing because adding a second outgoing transition with a different role widens visibility at that status to both roles.
The project_admin and role_leader flags¶
Two booleans on ProjectPeople modify the basic role rules:
project_admin¶
A user with project_admin=True on their ProjectPeople row for a
project bypasses all role checks within that project. They see
every workflow event regardless of role, and can perform every
transition.
In effect, project admin is the per-project equivalent of the global superuser — full visibility + action rights within their project's scope.
Use this for people who genuinely need cross-discipline oversight: project managers, principal engineers, anyone running the project end-to-end.
role_leader¶
A user with role_leader=True on their ProjectPeople row gets
broader visibility within their assigned disciplines. They see
events for their disciplines slightly earlier in the workflow than
non-leaders, and some transitions require role-leader status.
Use this for the "senior X" / "lead X" on a project where there are multiple X-discipline people but one of them is responsible for sign-off.
requires_role_leader on a transition¶
A WorkflowTransition can have requires_role_leader=True. When set:
- The user must hold a matching discipline AS A ROLE LEADER (i.e.
their
ProjectPeoplehas both the discipline ANDrole_leader=True). - A regular role-holder (matching discipline,
role_leader=False) loses transition rights on this transition — but still sees the event under the basic role rules.
Use this when a workflow step needs the senior person specifically (e.g. "any Architect can comment on a draft, only the Lead Architect can sign off").
The full visibility rule for workflow events¶
Given a workflow event in project P, a user U sees it if any of the following hold (checked in order, first match wins):
- U is a superuser. ✓
- U is
project_admin=Trueon theirProjectPeoplefor P. ✓ - U is the event's owner. ✓
- U is the event's
assigned_to. ✓ - The event's workflow is set, AND for some transition T in or out of the event's current status:
T.any_role = TrueAND U has at least one discipline in P. ✓- OR U's disciplines ∩
T.transition_rolesis non-empty. ✓ - OR U's disciplines ∩
T.readonly_rolesis non-empty. ✓ - OR U's disciplines ∩
T.commentonly_rolesis non-empty. ✓ - (For
requires_role_leadertransitions, the matching discipline must come paired withrole_leader=Truefor transition rights; bare visibility still passes.) - None of the above → U does not see the event.
This is then layered with the other visibility filters (VISIBILITY): tenancy first, project membership second, then this role check, then state-specific rules (completion gating, check-out locks).
Ad-hoc events (no workflow)¶
When WorkflowEvent.workflow_workflow is null, the event is "ad-hoc"
— it has no workflow definition, no transitions, no roles. The
visibility rule collapses to:
Superuser OR project admin OR owner OR assigned_to.
There's no role mechanism for ad-hoc events. To grant a non-admin visibility, add them as owner or assignee.
Notifications and roles¶
Each transition has fine-grained notification toggles for which role categories get notified when the transition fires:
| Toggle | Default | Who it notifies |
|---|---|---|
notify_role_members |
True | Users matching transition_roles (regular members of that discipline) |
notify_role_leaders |
True | Users matching transition_roles AND role_leader=True |
notify_project_admins |
True | All project_admin=True users in this project |
notify_readonly_members |
True | Users matching readonly_roles |
notify_commentonly_members |
True | Users matching commentonly_roles |
notify_all_project_members |
False | Everyone in the project's People list (with a login), whatever their roles — independent of the other toggles |
any_role plays no part in notifications: an any_role transition
notifies exactly who its notify_* toggles say, matched against its
roles as above. (Previously any_role also emailed everyone on the
project; that behaviour is now the explicit notify_all_project_members
toggle.) Anyone in the project's People list can be reached this way —
including people with no roles — but never anyone outside it.
Turning a toggle off prevents the email + livefeed notification for that category on this transition. Visibility is independent — turning off notifications doesn't hide the event from the matching users, it just stops them being actively pinged about it.
The recipient's role in the email¶
A workflow notification email is tailored to each recipient: the
subject leads with their role and the project (e.g. [For Action]
REBIM Workflow - Programme Euston), and the body repeats that role
at the top, so each person can see at a glance what's being asked of
them (the shared body follows):
The label comes from three buckets, which are the transition's own role
sets (the same transition_roles / commentonly_roles / readonly_roles
that drive the notify toggles above) — a recipient is "in" a bucket when one
of their disciplines is in that set:
| The recipient matched… | Default label shown |
|---|---|
a transition_roles discipline (an actor) |
For Action |
a commentonly_roles discipline (a reviewer) |
For Review |
a readonly_roles discipline (an explicit reader) |
For Information |
| no workflow discipline (e.g. an any-role notify, or a project admin with no role) | Notification |
Which label wins when a person has several disciplines: 1. Across buckets — most active wins: Action → Review → Information. Being in a higher bucket decides the tier; a labelled lower-tier role never overrides it (an unlabelled actor still shows For Action, not a reviewer's custom label). 2. Within the winning bucket — a labelled discipline wins: if any of the person's disciplines in that bucket has bespoke wording set, it's used (the first such, by role code); only if none is labelled do you get the bucket default. So a configured label is never dropped just because an unlabelled discipline sorts first.
A recipient with no role at all gets the neutral Notification rather than being labelled a reader.
To set bespoke wording for a role, fill workflow_email_label on the
role (Admin → Roles) — e.g. NSI-ELE-INF For Information, or a client's own
phrasing. Left blank (the default), the bucket labels above are used, so this
needs no configuration to work.
See NOTIFICATIONS for the broader notification system.
Practical operations¶
Assign a discipline to a project member¶
Project → People tab → kebab next to person → Edit the Relationship → Disciplines field → add or remove → Save.
Effect: the user gains / loses visibility on workflow events whose transitions reference that discipline.
Promote a member to role leader¶
Same path. Tick Is a Role Leader on the relationship form.
Effect: the user gains broader role-side visibility, and unlocks the
ability to perform transitions with requires_role_leader=True.
Promote a member to project admin¶
Same path. Tick Is a Project Administrator.
Effect: full visibility + action rights within this project. Bypasses role checks entirely for this user in this project.
Add or modify roles on a transition¶
Django admin → Workflow → Workflow Transitions → (pick transition) →
edit transition_roles / readonly_roles / commentonly_roles /
any_role / requires_role_leader.
Effect: changes who sees this transition's events + who can perform it. Effective immediately on existing events (no re-tagging needed — visibility is computed at view time).
Make a discipline workflow-only (hide from EDMS forms)¶
Django admin → Projects → Roles (Disciplines) → (pick) → tick Workflow role.
Effect: the discipline disappears from the EDMS document create / edit form and bulk-create dropdown. Still active in workflow visibility rules.
Troubleshooting¶
| Symptom | Likely cause | First check |
|---|---|---|
| Alice sees event, Bob doesn't, same project | Discipline mismatch on a transition in/out of the event's current status | Compare Alice's vs Bob's ProjectPeople.disciplines vs the transition's roles |
| User saw event yesterday, doesn't today | Workflow advanced past the user's role | Event's current status + transitions in/out of it vs user's disciplines |
| User sees event but no "Transition" button | Match was via readonly_roles or commentonly_roles only |
The transition's role fields — was the match a transition_role or one of the limited categories? |
| User has the discipline but transition button still missing | Transition has requires_role_leader=True and user is not a role leader |
ProjectPeople.role_leader for this user in this project |
| Project admin can't see event in a different project | project_admin is per-project |
They need project_admin=True on the OTHER project's ProjectPeople row too |
| Newly-added discipline doesn't grant visibility | Discipline added to the user but not referenced in any of the workflow's transitions | Workflow transitions' transition_roles etc. — does the new discipline appear? |
| Everyone in the project sees an event they shouldn't | Transition has any_role=True |
Transition's any_role flag |
| Workflow-only discipline shows in EDMS doc form | workflow_role flag not set |
The discipline's workflow_role boolean |
User mentioned via commentonly_roles got no email |
notify_commentonly_members is False on this transition |
Transition's notification toggles |
For developers¶
This page is for users and admins. Implementation pointers:
- Models:
apps.projects.models.ProjectDiscipline— the role model (verbose_name = "Role" in the admin).apps.projects.models.ProjectPeople— the membership row withdisciplines(M2M),project_admin(bool),role_leader(bool).apps.workflow.models.WorkflowTransition—transition_roles,readonly_roles,commentonly_roles,any_role,requires_role_leader, plus thenotify_*toggles.- Visibility evaluation: mostly client-side in
apps_workflow.js: can_user_perform_transition,is_owner_or_assignee. The backend serves rows; the frontend applies the role-side filter to hide rows the user shouldn't see. - Notification fan-out:
apps.workflow.signals.pywalksProjectPeoplefiltered by the matching disciplines per the notification toggles when a transition fires.
A practical consequence (same as for the broader VISIBILITY page): the backend may return a row that the frontend then hides. Logs showing "row served" doesn't mean "user saw it."
See devdocs/ for codebase-level material.