Project team: editable member roles + new 'Admin' role inheritable down the project tree #48

Open
opened 2026-05-20 11:38:17 +00:00 by mAi · 1 comment
Collaborator

Trigger

m 2026-05-20 13:33:

In the team view of a project it should be possible to edit member roles (at least for admins). And we need a Project Role 'Admin' that is inherited down the tree... So specific users can change things for that project (and subprojects).

Current state (verified 2026-05-20)

  • paliad.project_teams.responsibility is the team-level role on a project. CHECK constraint: ('lead', 'member', 'observer', 'external') (mig 059).
  • paliad.users.profession is the firm-level tier (partner / of_counsel / associate / senior_pa / pa / paralegal) — orthogonal to responsibility.
  • Team is rendered on the project detail page (frontend/src/projects-detail.tsx + frontend/src/client/projects-detail.ts). Add/remove members exists; editing an existing member's responsibility does not appear in the UI today.
  • Team membership inherits down the project tree via the visibility / can_see_project predicate (children inherit parent team membership for view + approve gates).
  • Profession-vs-responsibility duality is well-trodden — see docs//migrations around 059_profession_vs_responsibility.up.sql for the rationale.

What m wants

1. Editable team-member roles

  • On a project's team panel (/projects/{id} Team section), a user with appropriate authority can change another member's responsibility (e.g. promote a member to lead, demote a lead to member, etc.).
  • 'Appropriate authority' minimum: global_admin. Better: any user with the new Admin project-role (see #2) on that project or an ancestor.

2. New project-role 'Admin'

  • Add 'admin' to the responsibility CHECK constraint (or to a separate per-project role column — design call).
  • Inherits down the project tree: a user marked Admin on a Client-level project is implicitly Admin on every Litigation / Patent / Case child below it.
  • An Admin can:
    • Add / remove team members on the project + descendants.
    • Change responsibilities of existing team members (the #1 capability).
    • Edit project metadata (subject to existing approval gates for fields that need 4-eye).
    • Other write-side actions that today require global_admin scope.
  • Design call: does Admin override the 4-eye approval requirement on the project? Inventor's recommendation: NO. 4-eye stays a separate gating axis; Admin is about WHO can change WHO's roles, not what's exempt from approval. Approval policies remain governed by paliad.approval_policies per project + the profession ladder.

Design considerations

  • Inheritance shape. Add a derived predicate effective_project_admin(user_id, project_id) that returns true iff the user is responsibility='admin' on this project OR any ancestor in the ltree path. Reuse the existing path-walk used by can_see_project.
  • RLS. UPDATE policy on paliad.project_teams for editing roles: caller must be effective_project_admin OR global_admin.
  • Audit. Role changes emit a project_team_member_role_changed event (project_events) per existing audit convention.
  • Idempotency / safety. Changing a member's responsibility is a single-row UPDATE; no orphans, no constraint cascades.
  • UI. Inline <select> per row in the team table for users with edit authority, read-only for everyone else. Save-on-change with toast feedback. Confirm modal only on demote-from-Admin or remove-self.

Acceptance

  • The responsibility CHECK allows 'admin' (or schema chosen alternative).
  • effective_project_admin(user_id, project_id) returns true for the user on the project AND every descendant.
  • A user with effective_project_admin can change other members' responsibilities in the team UI.
  • A user without it sees the team but can't edit roles.
  • Role changes are audited as project_team_member_role_changed.
  • Removing the last admin from a project + all ancestors is blocked (org-level safeguard).

Out of scope

  • Reshaping the existing visibility / can_see_project predicate (Admin is additive, not a replacement).
  • Changing the 4-eye approval policy plumbing (separate concern).
  • A separate org-level 'Org Admin' tier above project-level Admin (we already have global_admin).

Role recommendation

inventor → coder — small but with RLS implications + inheritance design. 3-4 questions for m to batch: (a) admin-as-responsibility vs admin-as-separate-column, (b) admin overrides approval gate yes/no (inventor recommends no), (c) UI shape inline-select vs dropdown-modal, (d) safeguard against last-admin removal.

## Trigger m 2026-05-20 13:33: > In the team view of a project it should be possible to edit member roles (at least for admins). And we need a Project Role 'Admin' that is inherited down the tree... So specific users can change things for that project (and subprojects). ## Current state (verified 2026-05-20) - `paliad.project_teams.responsibility` is the team-level role on a project. CHECK constraint: `('lead', 'member', 'observer', 'external')` (mig 059). - `paliad.users.profession` is the firm-level tier (`partner / of_counsel / associate / senior_pa / pa / paralegal`) — orthogonal to responsibility. - Team is rendered on the project detail page (`frontend/src/projects-detail.tsx` + `frontend/src/client/projects-detail.ts`). Add/remove members exists; **editing an existing member's responsibility does not appear in the UI today**. - Team membership inherits down the project tree via the visibility / can_see_project predicate (children inherit parent team membership for view + approve gates). - Profession-vs-responsibility duality is well-trodden — see `docs/`/migrations around `059_profession_vs_responsibility.up.sql` for the rationale. ## What m wants ### 1. Editable team-member roles - On a project's team panel (`/projects/{id}` Team section), a user with appropriate authority can change another member's responsibility (e.g. promote a member to lead, demote a lead to member, etc.). - 'Appropriate authority' minimum: global_admin. Better: any user with the new Admin project-role (see #2) on that project or an ancestor. ### 2. New project-role 'Admin' - Add `'admin'` to the `responsibility` CHECK constraint (or to a separate per-project role column — design call). - Inherits down the project tree: a user marked Admin on a Client-level project is implicitly Admin on every Litigation / Patent / Case child below it. - An Admin can: - Add / remove team members on the project + descendants. - Change responsibilities of existing team members (the #1 capability). - Edit project metadata (subject to existing approval gates for fields that need 4-eye). - Other write-side actions that today require global_admin scope. - Design call: does Admin override the 4-eye approval requirement on the project? **Inventor's recommendation: NO**. 4-eye stays a separate gating axis; Admin is about WHO can change WHO's roles, not what's exempt from approval. Approval policies remain governed by `paliad.approval_policies` per project + the profession ladder. ## Design considerations - **Inheritance shape.** Add a derived predicate `effective_project_admin(user_id, project_id)` that returns true iff the user is `responsibility='admin'` on this project OR any ancestor in the ltree path. Reuse the existing path-walk used by `can_see_project`. - **RLS.** UPDATE policy on `paliad.project_teams` for editing roles: caller must be `effective_project_admin` OR `global_admin`. - **Audit.** Role changes emit a `project_team_member_role_changed` event (project_events) per existing audit convention. - **Idempotency / safety.** Changing a member's responsibility is a single-row UPDATE; no orphans, no constraint cascades. - **UI.** Inline `<select>` per row in the team table for users with edit authority, read-only for everyone else. Save-on-change with toast feedback. Confirm modal only on demote-from-Admin or remove-self. ## Acceptance - The `responsibility` CHECK allows `'admin'` (or schema chosen alternative). - `effective_project_admin(user_id, project_id)` returns true for the user on the project AND every descendant. - A user with `effective_project_admin` can change other members' responsibilities in the team UI. - A user without it sees the team but can't edit roles. - Role changes are audited as `project_team_member_role_changed`. - Removing the last admin from a project + all ancestors is blocked (org-level safeguard). ## Out of scope - Reshaping the existing visibility / can_see_project predicate (Admin is additive, not a replacement). - Changing the 4-eye approval policy plumbing (separate concern). - A separate org-level 'Org Admin' tier above project-level Admin (we already have `global_admin`). ## Role recommendation **inventor → coder** — small but with RLS implications + inheritance design. 3-4 questions for m to batch: (a) admin-as-responsibility vs admin-as-separate-column, (b) admin overrides approval gate yes/no (inventor recommends no), (c) UI shape inline-select vs dropdown-modal, (d) safeguard against last-admin removal.
mAi self-assigned this 2026-05-20 11:38:17 +00:00
Author
Collaborator

Shipped via gauss on mai/gauss/inventorcoder-team-admin — merged into main; commit https://mgit.msbls.de/m/paliad/commit/111c7c3. Live after next Dokploy deploy. (m/paliad#49 Add User slice still parked pending m's credential go-ahead.)

Shipped via gauss on `mai/gauss/inventorcoder-team-admin` — merged into main; commit https://mgit.msbls.de/m/paliad/commit/111c7c3. Live after next Dokploy deploy. (m/paliad#49 Add User slice still parked pending m's credential go-ahead.)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: m/paliad#48
No description provided.