Pulse/docs/release-control/v6/internal/subsystems/organization-settings.md
2026-03-19 19:30:34 +00:00

6.1 KiB

Organization Settings Contract

Contract Metadata

{
  "subsystem_id": "organization-settings",
  "lane": "L14",
  "contract_file": "docs/release-control/v6/internal/subsystems/organization-settings.md",
  "status_file": "docs/release-control/v6/internal/status.json",
  "registry_file": "docs/release-control/v6/internal/subsystems/registry.json",
  "dependency_subsystem_ids": [
    "api-contracts"
  ]
}

Purpose

Own organization role/share semantics and the canonical settings surfaces that let users review organization metadata, manage membership, assign roles, and create cross-organization shares.

Canonical Files

  1. internal/models/organization.go
  2. frontend-modern/src/components/Settings/OrganizationAccessPanel.tsx
  3. frontend-modern/src/components/Settings/OrganizationOverviewPanel.tsx
  4. frontend-modern/src/components/Settings/OrganizationSharingPanel.tsx
  5. frontend-modern/src/components/Settings/RolesPanel.tsx
  6. frontend-modern/src/components/Settings/UserAssignmentsPanel.tsx
  7. frontend-modern/src/utils/orgUtils.ts
  8. frontend-modern/src/utils/organizationRolePresentation.ts
  9. frontend-modern/src/utils/organizationSettingsPresentation.ts

Shared Boundaries

  1. None.

Extension Points

  1. Add or change organization role and share semantics through internal/models/organization.go
  2. Add or change organization access, overview, sharing, role-management, or user-assignment presentation through frontend-modern/src/components/Settings/OrganizationAccessPanel.tsx, frontend-modern/src/components/Settings/OrganizationOverviewPanel.tsx, frontend-modern/src/components/Settings/OrganizationSharingPanel.tsx, frontend-modern/src/components/Settings/RolesPanel.tsx, and frontend-modern/src/components/Settings/UserAssignmentsPanel.tsx
  3. Route organization transport changes through frontend-modern/src/api/orgs.ts and frontend-modern/src/api/rbac.ts
  4. Keep backend organization and RBAC handler changes aligned through internal/api/org_handlers.go, internal/api/org_lifecycle_handlers.go, and internal/api/enterprise_extension_rbac_admin.go

Forbidden Paths

  1. Duplicating organization role normalization or badge styling outside the canonical organization presentation helpers
  2. Reintroducing organization settings copy, validation, or empty-state strings directly inside feature panels instead of the shared organization presentation helpers
  3. Letting share-role, RBAC role-assignment, or membership semantics drift between internal/models/organization.go and the governed organization settings surfaces

Completion Obligations

  1. Update the organization model, settings surfaces, and proof files together when role/share semantics move
  2. Keep organization settings copy and validation inside the canonical organization presentation helpers
  3. Update this contract whenever a new organization settings, role-management, or organization-domain helper entry point becomes canonical runtime surface area

Current State

This subsystem now sits under the dedicated security, identity, and privacy lane so role boundaries, organization membership semantics, and cross-org sharing behavior stay governed as a first-class trust surface.

Organization overview, access, sharing, roles, and user-assignment surfaces had been sitting outside the governed subsystem map even though they define real runtime expectations around membership management, least-privilege role assignment, and cross-organization resource sharing. This contract now makes that boundary explicit while leaving transport payload ownership in api-contracts. Canonical organization role ordering is now part of that owned model as well: owner outranks admin, which outranks editor, which outranks viewer, and runtime checks must resolve that ordering through shared organization-role comparison helpers rather than ad hoc equality checks scattered across model and handler code. That same hierarchy governs inbound share visibility and organization management gates: a user may only see or accept a share when their effective membership role satisfies the share's requested access role, and admin-capable operations must continue to derive from the canonical role comparator instead of duplicating owner/admin special cases. The comparator itself is now part of the owned runtime boundary: helpers such as CanUserManage and any share-filtering logic must route through the shared organization-role ordering function so viewer/editor/admin/owner semantics stay identical across model checks, handler authorization, and settings-surface presentation. That same canonical comparator now governs live membership transitions too: promoting or demoting a member must immediately change whether that user can manage organization settings, and organization listing must not leak non-member tenants just because another org with the same user exists in the system. Incoming share visibility is part of that same boundary as well: a recipient must only see inbound shares whose requested accessRole is satisfied by the user's effective membership role in the target organization, using the shared role comparator instead of handler-local owner/admin shortcuts. Hosted organization membership and billing routes now also follow this owned semantics boundary: for hosted tenant orgs, internal/api/org_handlers.go must authorize organization operations from the seeded org membership and the hosted subscription state rather than requiring the self-hosted multi_tenant feature flag. Provisioned hosted workspaces must therefore keep org.OwnerUserID aligned with the authenticated creator when that actor is known, so organization-owner checks stay consistent across runtime auth and the settings surfaces. The organization settings panels now also normalize org scope through frontend-modern/src/utils/orgScope.ts instead of carrying their own getOrgID() || 'default' fallbacks, so access, overview, and sharing views stay aligned with the shared multi-tenant org context contract. The organization sharing surface now also sources resource quick-pick labels from the shared preferred resource display helper, so governed resources do not fall back to raw names inside share creation.