Skip to content

fix(platform-objects): hide org/membership surfaces in single-org mode#2348

Merged
os-zhuang merged 2 commits into
mainfrom
fix/single-org-gate-membership-surfaces
Jun 26, 2026
Merged

fix(platform-objects): hide org/membership surfaces in single-org mode#2348
os-zhuang merged 2 commits into
mainfrom
fix/single-org-gate-membership-surfaces

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Problem

The platform gates multi-org features two ways — nav entries on requiresService: 'org-scoping' (e.g. setup-nav Organizations/Invitations) and object actions on visible: 'features.multiOrgEnabled != false' (e.g. sys_organization.create_organization). That convention had only been wired in a handful of spots, so a wide band of org/membership surface leaked into single-org deployments (OS_MULTI_ORG_ENABLED unset/false) where it is pure UX noise or a broken affordance.

Triggering example: …/_console/apps/com.objectstack.account/sys_member/view/mine ("My Organizations") shows even in single-org, where there are no sys_organization rows and no auto-stamped memberships — so the view is always empty for every user.

Changes (metadata-only)

Nav (P1)

  • Account app nav_account_memberships (sys_member/mine): was gated on requiresObject: 'sys_member', which never fires (system object is always registered). Re-gated on requiresService: 'org-scoping'.
  • setup-nav nav_teams (sys_team): had no gate while sibling Organizations/Invitations were service-gated. Added requiresService: 'org-scoping'.

Actions — gated on features.multiOrgEnabled != false (P0)

  • sys_user.invite_user (most exposed — the Users list is always reachable in single-org)
  • sys_member: add_member / update_member_role / remove_member, and transfer_ownership (combined with its existing record.role != 'owner' condition)
  • sys_team: create_team / update_team / remove_team
  • sys_team_member: add_team_member / remove_team_member
  • sys_invitation: invite_user / resend_invitation / cancel_invitation (recipient-side accept/reject stay record-gated — unreachable in single-org anyway)

Remaining rough edges (P2)

  • sys_organization admin actions (update / delete / set_active / leave / change_slug) now all gated too — previously only create_organization was.
  • titleFormat no longer renders a null organization: sys_member{user_id} ({role}), sys_invitationInvitation for {email} (org_id is null in single-org → old formats read "… null").

sys_team's by_org view left as-is: the teams list is empty in single-org (create is gated) so the grouping never degenerates in practice, and the nav entry is hidden anyway.

Scope / safety

No behavior change in multi-org deployments (OS_MULTI_ORG_ENABLED=true): features.multiOrgEnabled is true and the org-scoping service is present, so every gate evaluates to visible exactly as before. No schema, API, or runtime changes.

Not in scope (follow-up): single-sourcing the multi-org flag resolution (driver-sql reads the env var directly instead of the resolved flag; ~8 scattered detection sites) and a regression gate asserting org-scoped surfaces are hidden in single-org.

Verification

  • @objectstack/platform-objects build + DTS succeed
  • Package tests 63/63 pass

🤖 Generated with Claude Code

os-zhuang and others added 2 commits June 26, 2026 21:39
Apply the platform's existing multi-org gating convention consistently
across the org/membership surface, which had only been wired in a handful
of spots:
- nav entries -> requiresService: 'org-scoping'
- object actions -> visible: 'features.multiOrgEnabled != false'

Nav (P1):
- account.app "My Organizations" (sys_member/mine): was gated on
  requiresObject: 'sys_member', which never fires (system object always
  registered) and left the always-empty view visible in single-org.
  Re-gated on requiresService: 'org-scoping'.
- setup-nav "Teams" (sys_team): had no gate while sibling Organizations/
  Invitations were service-gated. Added requiresService: 'org-scoping'.

Actions (P0) — gated on features.multiOrgEnabled != false:
- sys_user.invite_user (most exposed: Users list always reachable)
- sys_member add_member/update_member_role/remove_member + transfer_ownership
- sys_team create_team/update_team/remove_team
- sys_team_member add_team_member/remove_team_member
- sys_invitation invite_user/resend_invitation/cancel_invitation

Recipient-side invitation accept/reject stay record-gated (unreachable in
single-org anyway). No behavior change in multi-org. Metadata-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Gate the remaining sys_organization admin actions (update/delete/
  set_active/leave/change_slug) on features.multiOrgEnabled != false, so
  every org action matches the already-gated create_organization.
- Stop rendering a null organization in titleFormat:
  - sys_member: '{user_id} in {organization_id}' -> '{user_id} ({role})'
  - sys_invitation: 'Invitation to {organization_id}' -> 'Invitation for {email}'
  organization_id is null in single-org mode, so the old formats read
  "... null"; the new fields identify the record in both modes.

sys_team's by_org view was left as-is: the teams list is empty in single-org
(create is gated) so the grouping never degenerates in practice, and the nav
entry is hidden anyway.

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

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 26, 2026 1:55pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling size/m labels Jun 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/platform-objects.

3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/packages.mdx (via @objectstack/platform-objects)
  • content/docs/concepts/setup-app.mdx (via @objectstack/platform-objects)
  • content/docs/guides/packages.mdx (via @objectstack/platform-objects)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang merged commit f44c1bd into main Jun 26, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the fix/single-org-gate-membership-surfaces branch June 26, 2026 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant