12 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
internal/models/organization.gofrontend-modern/src/components/Settings/OrganizationAccessPanel.tsxfrontend-modern/src/components/Settings/OrganizationAccessLoadingState.tsxfrontend-modern/src/components/Settings/OrganizationAccessManagementSection.tsxfrontend-modern/src/components/Settings/OrganizationAccessMembersSection.tsxfrontend-modern/src/components/Settings/OrganizationOverviewPanel.tsxfrontend-modern/src/components/Settings/OrganizationOverviewLoadingState.tsxfrontend-modern/src/components/Settings/OrganizationOverviewDetailsSection.tsxfrontend-modern/src/components/Settings/OrganizationOverviewMembersSection.tsxfrontend-modern/src/components/Settings/OrganizationSharingPanel.tsxfrontend-modern/src/components/Settings/OrganizationSharingCreateSection.tsxfrontend-modern/src/components/Settings/OrganizationSharingLoadingState.tsxfrontend-modern/src/components/Settings/OrganizationOutgoingSharesSection.tsxfrontend-modern/src/components/Settings/OrganizationIncomingSharesSection.tsxfrontend-modern/src/components/Settings/useOrganizationAccessPanelState.tsfrontend-modern/src/components/Settings/useOrganizationOverviewPanelState.tsfrontend-modern/src/components/Settings/useOrganizationSharingPanelState.tsfrontend-modern/src/components/Settings/RolesPanel.tsxfrontend-modern/src/components/Settings/RBACFeatureGateSection.tsxfrontend-modern/src/components/Settings/RolesEditorDialog.tsxfrontend-modern/src/components/Settings/useRBACFeatureGateState.tsfrontend-modern/src/components/Settings/useRolesPanelState.tsfrontend-modern/src/components/Settings/UserAssignmentsPanel.tsxfrontend-modern/src/components/Settings/UserAssignmentsDialog.tsxfrontend-modern/src/components/Settings/useUserAssignmentsPanelState.tsfrontend-modern/src/utils/orgUtils.tsfrontend-modern/src/utils/organizationRolePresentation.tsfrontend-modern/src/utils/organizationSettingsPresentation.ts
Shared Boundaries
- None.
Extension Points
- Add or change organization role and share semantics through
internal/models/organization.go - Add or change organization access, overview, sharing, RBAC feature-gating, role-management, or user-assignment presentation through
frontend-modern/src/components/Settings/OrganizationAccessPanel.tsx,frontend-modern/src/components/Settings/OrganizationAccessLoadingState.tsx,frontend-modern/src/components/Settings/OrganizationAccessManagementSection.tsx,frontend-modern/src/components/Settings/OrganizationAccessMembersSection.tsx,frontend-modern/src/components/Settings/OrganizationOverviewPanel.tsx,frontend-modern/src/components/Settings/OrganizationOverviewLoadingState.tsx,frontend-modern/src/components/Settings/OrganizationOverviewDetailsSection.tsx,frontend-modern/src/components/Settings/OrganizationOverviewMembersSection.tsx,frontend-modern/src/components/Settings/OrganizationSharingPanel.tsx,frontend-modern/src/components/Settings/OrganizationSharingCreateSection.tsx,frontend-modern/src/components/Settings/OrganizationSharingLoadingState.tsx,frontend-modern/src/components/Settings/OrganizationOutgoingSharesSection.tsx,frontend-modern/src/components/Settings/OrganizationIncomingSharesSection.tsx,frontend-modern/src/components/Settings/useOrganizationAccessPanelState.ts,frontend-modern/src/components/Settings/useOrganizationOverviewPanelState.ts,frontend-modern/src/components/Settings/useOrganizationSharingPanelState.ts,frontend-modern/src/components/Settings/RBACFeatureGateSection.tsx,frontend-modern/src/components/Settings/RolesPanel.tsx,frontend-modern/src/components/Settings/RolesEditorDialog.tsx,frontend-modern/src/components/Settings/useRBACFeatureGateState.ts,frontend-modern/src/components/Settings/useRolesPanelState.ts,frontend-modern/src/components/Settings/UserAssignmentsPanel.tsx,frontend-modern/src/components/Settings/UserAssignmentsDialog.tsx, andfrontend-modern/src/components/Settings/useUserAssignmentsPanelState.ts - Route organization transport changes through
frontend-modern/src/api/orgs.tsandfrontend-modern/src/api/rbac.ts - Keep backend organization and RBAC handler changes aligned through
internal/api/org_handlers.go,internal/api/org_lifecycle_handlers.go, andinternal/api/enterprise_extension_rbac_admin.go
Forbidden Paths
- Duplicating organization role normalization or badge styling outside the canonical organization presentation helpers
- Reintroducing organization settings copy, validation, or empty-state strings directly inside feature panels instead of the shared organization presentation helpers
- Letting share-role, RBAC role-assignment, or membership semantics drift between
internal/models/organization.goand the governed organization settings surfaces
Completion Obligations
- Update the organization model, settings surfaces, and proof files together when role/share semantics move
- Keep organization settings copy and validation inside the canonical organization presentation helpers
- 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.
Organization settings empty, unavailable, and load-error states are part of
that same presentation boundary: the shared organization presentation helpers
must describe server capability and settings availability directly, rather than
falling back to generic feature not available or transport-style failed to load copy.
The same helper also owns organization action notifications and confirmations:
success and failure messages for renaming, membership changes, and sharing
operations should stay specific and customer-facing, not terse operator jargon
or bare transport wording.
The organization access surface now follows that extracted-owner pattern too:
the panel is the shell, useOrganizationAccessPanelState.ts owns the
membership runtime, and the loading, management, and members views each live
in dedicated section owners instead of collapsing API lifecycle, permission
gates, and table rendering into one file.
The organization overview surface now follows that same extracted-owner
pattern: the panel is the shell, useOrganizationOverviewPanelState.ts owns
the org/member load and display-name runtime, and the loading, details, and
membership views each live in dedicated section owners instead of mixing
summary cards, form actions, and table rendering into the shell.
The sharing surface now follows the same extracted-owner pattern: the panel is
the shell, useOrganizationSharingPanelState.ts owns the API-backed runtime,
and the loading, create, outgoing, and incoming views each live in dedicated
section owners instead of staying collapsed into one file.
The RBAC settings area now follows the same extracted-owner pattern as the
other modernized settings surfaces: RBACFeatureGateSection.tsx owns the
shared paywall CTA rendering, useRBACFeatureGateState.ts owns the shared
license and free-trial runtime, useRolesPanelState.ts plus
RolesEditorDialog.tsx own the roles runtime split, and
useUserAssignmentsPanelState.ts plus UserAssignmentsDialog.tsx own the
user-assignment runtime split. RolesPanel.tsx and UserAssignmentsPanel.tsx
remain the canonical render shells for those governed RBAC surfaces.
That shared RBAC free-trial runtime must also preserve backend denial reasons
through the canonical upgrade presentation helper instead of collapsing every
trial-start conflict into a generic already-used message. Organization settings
paywalls should only map the explicit canonical trial helper outputs, not
re-interpret status codes locally.
The RBAC feature-gate state now also depends on the shared
frontend-modern/src/utils/trialStartAction.ts owner for hosted handoff and
success/error orchestration. Organization settings paywalls must not keep a
lane-local startProTrial() branch once that shared helper covers the same
runtime contract.