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 (ProjectDiscipline model). 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 the any_role escape 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 ProjectPeople flags 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:

  1. Open the project.
  2. Open the People tab.
  3. Click the kebab next to a project person → Edit the Relationship.
  4. 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 (or any_role is set): full transition rights.
  • Match readonly_roles only: see but can't transition.
  • Match commentonly_roles only: 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:

  1. Draft → Review, transition_roles = {Author}
  2. Review → Approved, transition_roles = {Reviewer}

An event sits in Draft. Visibility:

  • The Author (matches T1's transition_roles at from=Draft) sees it. ✓
  • The Reviewer (matches T2's transition_roles at from=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 from state (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_roles at from=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 ProjectPeople has both the discipline AND role_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):

  1. U is a superuser. ✓
  2. U is project_admin=True on their ProjectPeople for P. ✓
  3. U is the event's owner. ✓
  4. U is the event's assigned_to. ✓
  5. The event's workflow is set, AND for some transition T in or out of the event's current status:
  6. T.any_role = True AND U has at least one discipline in P. ✓
  7. OR U's disciplines ∩ T.transition_roles is non-empty. ✓
  8. OR U's disciplines ∩ T.readonly_roles is non-empty. ✓
  9. OR U's disciplines ∩ T.commentonly_roles is non-empty. ✓
  10. (For requires_role_leader transitions, the matching discipline must come paired with role_leader=True for transition rights; bare visibility still passes.)
  11. 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 with disciplines (M2M), project_admin (bool), role_leader (bool).
  • apps.workflow.models.WorkflowTransition — transition_roles, readonly_roles, commentonly_roles, any_role, requires_role_leader, plus the notify_* 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.py walks ProjectPeople filtered 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.