Skip to content

UN-4283 [FEAT] Add role, member count and region to the organisation list - #2361

Merged
athul-rs merged 12 commits into
mainfrom
UN-4283-org-list-details
Oct 23, 2026
Merged

athul-rs merged 12 commits into
mainfrom
UN-4283-org-list-details

Conversation

@athul-rs

Copy link
Copy Markdown
Contributor

What

  • GET /api/v1/organization now returns three optional fields on each organization: role (the caller's role), member_count (the people the members page lists) and region (the deployment's region code).
  • Each field is absent, never null, where this deployment can't answer for that organization. In cloud, US and EU share one identity provider, so the list can name organizations with no data on the current deployment; those rows keep only id, display_name, name and metadata.
  • The contract is the organization_list @extend_schema annotation plus a new "Organization list contract" section in backend/account_v2/ReadMe.md, following the convention from UN-4398 [FEAT] Platform audit log: event store and admin read API #2342.

Why

  • The v1 organization switcher (P2-T02, UN-4290) shows the role, member count and region for each organization. This is backend task PB-T15 of the Frontend v1 epic (UN-4257).

How

  • New account_v2/organization_details.py: with_member_details() adds the fields with two queries for any number of organizations, one Count over member records (platform API key accounts excluded, as on the members page) and one role lookup for the caller. The role lookup uses OrganizationMember._base_manager, because the default manager filters to the request's organization.
  • region comes from settings.REGION. Only cloud settings define it; OSS and on-prem settings don't, so they never send it.
  • AuthenticationController.user_organizations() calls the helper inside a savepoint when a transaction is open. If it fails, the error is logged with the user id and organization count, and the list is returned without the three fields.

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • No. The change only adds keys. Existing fields keep their names, values and order (pinned by a test through the view), and the v0 frontend reads only id and display_name. A failure while adding the details still returns the list, with no logout. The 412 path is unchanged; it is now documented and tested. metadata is now marked required in the schema; on the wire it was already always sent (null when missing), and the legacy-payload test pins that.

Database Migrations

  • None.

Env Config

  • None. Cloud reads the existing REGION setting.

Relevant Docs

  • backend/account_v2/ReadMe.md, section "Organization list contract".

Related Issues or PRs

Dependencies Versions

  • None.

Notes on Testing

  • 24 new tests in account_v2/test_organization_details.py and account_v2/test_organization_list.py: role, count and region per organization; absent-not-null for an organization with no data here; API key accounts not counted; zero count; empty list; two queries for any number of organizations; exact legacy payload and key order through the view; the endpoint through the URL and auth middleware with a session organization; anonymous 401; the 412 body and logout; the fallback and its log; a failed query inside a transaction leaves it usable; the schema annotation.
  • account_v2, tenant_account_v2 and global_search suites: 153 passed locally against Postgres.
  • Role values differ by edition (admin/user in OSS, unstract_* in cloud), so P2-T02 needs to accept both.

Screenshots

  • N/A (backend only).

Checklist

I have read and understood the Contribution Guidelines.

🤖 Generated with Claude Code

athul-rs and others added 7 commits October 21, 2026 12:28
…rganisations

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…list

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the old payload

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tract

- Document the 412 body ({domain, code}) and every cause of a 412 (R1)
- Say absent means unknown, since a failed lookup returns the same rows (R2)
- Log the user and organisation count when the details fail (R3)
- metadata can be null in cloud too; it is required in the schema (R4, R9)
- Pin absent-not-null and the wire key order, including an organisation
  this deployment has no data for (R5, R6)
- Count an organisation with no people as 0 (R7)
- Build rows from attributes, not asdict, and type the input (R8)
- member_count is member records, not signed-in members (R10)
- Correct the user_organizations docstring (R11)
- Run the lookup in a savepoint when inside a transaction (R12)
- Test the endpoint through the URL and auth middleware

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y list

- Test the 412 body and logout for known and unknown listing errors (R16)
- Endpoint tests sign in to an organisation, as the browser does, and
  use OSS auth with no shared-cache write (R17, R18)
- Anonymous call: assert the body and that nothing was listed (R19)
- Fallback rows keep metadata in fourth place (R20)
- A user with no organisations lists none (R21)
- Other members hold a role the caller never has (R22)
- Cover the no-transaction branch of the savepoint guard (R13)
- 412 body: domain and code are required; Protocol says metadata is read (R23, R24)
- ReadMe: on-prem settings don't read REGION (R15)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Name the members-page rule the count copies, look up the operation id
directly, and share the API key account fixture. No behaviour change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed spec

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@athul-rs athul-rs left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review round 1 — unstract:review-deep (unstract plugin 2.1.73)

Mode: INITIAL. Tip 67c387b49, merge base 5a21d6252 (base fetched, 7 files / 711 lines, count verified against GitHub). Review agents ran on Sonnet.

Verdict — APPROVE WITH NITS

Summary — Critical: 0 · High: 0 · Medium: 1 · Low: 2 · Lenses run: 19/19

Signals: lenses 4, 7, 16, 17 raised (auth/authz trigger and _base_manager in organization_details.py; serializer + @extend_schema in serializer.py/views.py; ReadMe.md and docstrings beside behaviour; the field-presence rules).

Lens checklist

  1. Spec & intent — Clean (code-reviewer; title follows UN-XXXX [FEAT] …)
  2. Architectural fit & precedent — Clean (code-reviewer)
  3. Correctness & edge cases — Clean (code-reviewer, silent-failure-hunter)
  4. Security — Clean (assessed by me; security deep-dive done, no finding ≥ 0.7; boundary sweep 3 sinks traced, clean)
  5. Data integrity & migrations — Clean (dispatched infra agent)
  6. Concurrency — N/A — no shared state, locks or async ordering (assessed by me)
  7. API & contract compatibility — See findings #3 (contract shape: type-design-analyzer clean; consumer search by me: v0 useSessionValid.js, TopNavBar.jsx, SetOrg.jsx read id/display_name only; serializer has no other callers)
  8. Reliability & resilience — Clean (dispatched infra agent)
  9. Performance & cost — Clean (code-reviewer; two queries for any number of organizations, indexed)
  10. Observability — Clean (code-reviewer)
  11. Operational safety — Clean — additive, no flags or rollout config, revert-only rollback (assessed by me)
  12. LLM/agent-specific — N/A — no model, prompt or tool path (assessed by me)
  13. Testing — See findings #1 (pr-test-analyzer; 24 tests ran green)
  14. Dependencies & build — N/A — no dependency or lockfile change (assessed by me)
  15. Code quality — Clean (code-reviewer; pinned ruff 0.3.4 check and format-check pass on the 6 changed Python files, run by me)
  16. Doc & comment accuracy — See findings #2, #3 (comment-analyzer)
  17. Cross-document rule consistency — Clean (assessed by me; merge-result sweep exit 1, hits classified: group member_count is a different entity; every other people-list excludes is_service_account, matching this PR)
  18. On-prem deployment experience — Clean (assessed by me; no chart, schema or on-prem settings touched; the ReadMe's on-prem claim checked against cloud settings/on-prem.py, which never reads REGION)
  19. Scaling & workload lifecycle — N/A — no worker, replica, pool or lifecycle config (assessed by me)

Security deep-dive: done

Open questions for the author

  • region is the answering deployment's code. Can an Organization row exist on a deployment other than the organization's home (for example one opened from another region's list)? If so, the switcher shows this deployment's region for it, which is what the contract says, but the design may expect the home region.

Assumptions made

  • Cloud CI or a cloud test run may load these tests under settings that define REGION; finding #1 is rated on that.

cost: agents=8 wall=04:17 lenses-examined=15 of 19 files=7 lines=711

Comment thread backend/account_v2/test_organization_details.py
Comment thread backend/account_v2/test_organization_list.py Outdated
Comment thread backend/account_v2/views.py
… notes

- WithMemberDetailsTests starts from REGION=None, so the exact key-list
  test no longer depends on the deployment's settings
- Drop the test docstring's claim that the contract is published
- Say beside the 412 serializer why its fields are required

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@athul-rs athul-rs left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review round 2 — unstract:review-deep (unstract plugin 2.1.73)

Verdict — APPROVE

Summary — Critical: 0 · High: 0 · Medium: 0 · Low: 0 · Lenses run: 19/19

Prior context fetched — my review 5596297587 and its three inline comments (4334128898, 4334128904, 4334128913). Since-boundary: 67c387b. Delta: git diff 67c387b49 ed7b34357 (3 files, 6 insertions, 5 deletions). Review agents ran on Sonnet.

Scope change — NO

Prior findings status

  • #1 [Medium] exact key-list test did not pin REGION → RESOLVED — backend/account_v2/test_organization_details.py:52-54 puts @override_settings(REGION=None) on the class; per-test REGION="US" overrides still apply (tests at :75, :107, :116, :130 assert "US" and pass). The test failed under REGION="US" before the fix and passes after.
  • #2 [Low] test docstring called the contract "published" → RESOLVED — backend/account_v2/test_organization_list.py:1 is one line with no such claim.
  • #3 [Low] 412 fields required though the body can be empty → RESOLVED as proposed — backend/account_v2/views.py:90-92 records why the fields stay required; it matches the controller's two 412 paths (authentication_controller.py:130-142) and the description's code list.

New findings — none.

Lens checklist

  1. Spec & intent — Clean (code-reviewer)
  2. Architectural fit & precedent — Clean (code-reviewer)
  3. Correctness & edge cases — Clean (code-reviewer)
  4. Security — Clean (assessed by me; delta has no attack surface; security deep-dive done in round 1, result stands)
  5. Data integrity & migrations — N/A — delta touches no query, transaction or schema (assessed by me)
  6. Concurrency — N/A — no shared state (assessed by me)
  7. API & contract compatibility — Clean (assessed by me; delta adds a comment only, wire unchanged)
  8. Reliability & resilience — N/A — delta touches no runtime path (assessed by me)
  9. Performance & cost — Clean (code-reviewer)
  10. Observability — Clean (code-reviewer)
  11. Operational safety — N/A — no rollout or config surface (assessed by me)
  12. LLM/agent-specific — N/A — no model path (assessed by me)
  13. Testing — Clean (pr-test-analyzer; 24 tests green)
  14. Dependencies & build — N/A — none touched (assessed by me)
  15. Code quality — Clean (code-reviewer; pinned ruff 0.3.4 check and format-check pass on the changed files, run by me)
  16. Doc & comment accuracy — Clean (comment-analyzer)
  17. Cross-document rule consistency — Clean (assessed by me; the delta changes no stated rule)
  18. On-prem deployment experience — N/A — no on-prem surface (assessed by me)
  19. Scaling & workload lifecycle — N/A — no workload config (assessed by me)

Security deep-dive: done

cost: agents=3 wall=02:06 lenses-examined=10 of 19 files=7 lines=711

@athul-rs
athul-rs marked this pull request as ready for review October 21, 2026 07:37
@greptile-apps

greptile-apps Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

via Greptile

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge with dependent PR #2370 supplying the home-region correction.

Summary

Adds optional role, member_count, and region fields to the organization list.

  • Organization lists can now show each caller’s role, member count, and region.

Reviews (5) · Last reviewed commit: "Merge branch 'main' into UN-4283-org-lis..." · Reviewed by Greptile

@ritwik-g ritwik-g left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. I ran the new tests locally against Postgres (24 pass, and the account_v2 and tenant_account_v2 suites stay green). I also broke each guard in turn: the caller filter on the role lookup, the base manager, the API key exclusion, the savepoint, and region only for organisations with data here. Each break fails at least one test. The existing response is unchanged for the current frontend. Login gets two extra queries however many organisations the user has, and OSS and on-prem never send region. One comment inline about organisations from the other region that have been copied onto this one. It's a follow-up, not a blocker.

Comment thread backend/account_v2/organization_details.py
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	backend/account_v2/ReadMe.md
#	backend/account_v2/authentication_controller.py
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Unstract test results

Per-group results

Status Group Tier Passed Failed Errors Skipped Duration (s)
⚪ e2e-agent-kv e2e 0 0 0 1 0.1
✅ e2e-api-deployment e2e 3 0 0 0 20.6
✅ e2e-coowners e2e 1 0 0 0 1.6
✅ e2e-etl e2e 1 0 0 0 14.7
✅ e2e-login e2e 2 0 0 0 1.2
✅ e2e-prompt-studio e2e 1 0 0 0 11.2
✅ e2e-smoke e2e 2 0 0 0 2.5
✅ e2e-workflow e2e 1 0 0 0 14.4
✅ frontend unit 629 0 0 0 19.1
✅ integration-backend integration 1196 0 0 26 67.7
✅ integration-connectors integration 1 0 0 7 8.3
✅ integration-workers integration 181 0 0 1 50.8
❌ ui e2e 0 1 0 0 0.0
✅ unit-agent-kv-schema unit 143 0 0 0 1.7
✅ unit-backend unit 2017 0 0 1 58.4
✅ unit-connectors unit 82 0 0 0 11.2
✅ unit-core unit 281 0 0 0 3.2
✅ unit-filesystem unit 1 0 0 0 4.4
✅ unit-platform-service unit 18 0 0 0 2.7
✅ unit-rig unit 120 0 0 0 4.5
✅ unit-runner unit 12 0 0 0 3.0
✅ unit-sdk1 unit 878 0 0 0 42.3
✅ unit-tool-sidecar unit 8 0 0 0 1.9
✅ unit-workers unit 1531 0 0 2 130.0
TOTAL 7109 1 0 38 475.3

Critical paths

⚠️ Critical paths not yet covered

  • workflow-execution-fan-out — Multi-file workflow execution fans out to file-processing workers and rejoins. (declared coverage: no groups declared)
✅ Covered critical paths
  • auth-login — covered by e2e-login
  • adapter-register-llm — covered by integration-backend
  • workflow-author — covered by integration-backend
  • co-owner-manage — covered by integration-backend, e2e-coowners
  • workflow-create-execute — covered by e2e-workflow
  • api-deployment-provision — covered by integration-backend
  • api-deployment-auth — covered by integration-backend
  • api-deployment-run — covered by e2e-api-deployment
  • mcp-server-auth — covered by integration-backend
  • mcp-platform-auth — covered by integration-backend
  • platform-key-whoami — covered by integration-backend
  • prompt-studio-author — covered by integration-backend
  • prompt-studio-fetch-response — covered by e2e-prompt-studio
  • connector-register-test — covered by integration-backend
  • pipeline-etl-execute — covered by e2e-etl
  • usage-aggregate-read — covered by integration-backend
  • usage-token-tracking — covered by e2e-api-deployment
  • callback-result-delivery — covered by e2e-api-deployment

@athul-rs
athul-rs merged commit 3c59e85 into main Oct 23, 2026
14 checks passed
@athul-rs
athul-rs deleted the UN-4283-org-list-details branch October 23, 2026 08:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants