Skip to content

ADR-0081 (cloud): open org-management basics + retire plugin-org-scoping to enterprise - #2699

Merged
os-zhuang merged 5 commits into
mainfrom
feat/org-mgmt-basics
Jul 9, 2026
Merged

ADR-0081 (cloud): open org-management basics + retire plugin-org-scoping to enterprise#2699
os-zhuang merged 5 commits into
mainfrom
feat/org-mgmt-basics

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Implements the framework side of cloud ADR-0081 (org management: open basics, enterprise multi-org). Two commits, reviewable independently:

1. Open single-org basics (D1)

Single-org deployments had no way to add a user at all — invite affordances hid behind features.multiOrgEnabled, and nothing ever created an org (no activeOrganizationId → better-auth invite-member unresolvable).

  • plugin-auth now owns ensureDefaultOrganization (the multi-org seed-ownership step became an injectable option) and runs it in single-org mode on kernel:ready + after every admin grant (autoDefaultOrganization opt-out).
  • plugin-auth adds a default session.create.before hook stamping activeOrganizationId from the caller's membership (owner-preferred; host hooks — e.g. the cloud's — chain first and win; autoActiveOrganization opt-out).
  • platform-objects re-gates member/invitation/team actions from features.multiOrgEnabled to features.organization (the capability is always mounted); sys_organization's own create/leave/delete keep the multi-org gate so the single-org default org stays protected.
  • Setup nav: new nav_organization entry deep-links to the ACTIVE org's record page ({current_org_id}); Teams/Invitations drop the org-scoping service gate; the Organizations LIST keeps it.

2. Retire plugin-org-scoping (D2, BREAKING)

The multi-org runtime moves to the closed-source @objectstack/organizations package (cloud repo), which keeps registering the historical org-scoping service (plugin-security probe + nav gates unaffected). serve / plugin-dev / verify mount it best-effort by name; missing package = loud warn (or an actionable error for verify's explicit multiTenant opt-in). The dogfood multi-org RLS gate skips (loudly) when the package isn't linked.

Verification

  • Unit: plugin-auth 252 ✓, plugin-security 183 ✓, platform-objects 63 ✓, org-scoping wrapper 20 ✓ (pre-migration).
  • Browser E2E (single-org, real signup): first-run wizard → default org (CJK rename) + owner membership + active-org session; invite → accept → change role → remove, all through better-auth.
  • Browser E2E (multi-org with the enterprise package linked): bootstrap, second-org create, {current_org_id} nav following org switch; missing-package downgrade warning verified.

Pairs with objectstack-ai/objectui feat/team-org-context and objectstack-ai/cloud feat/console-team-page (cloud#738).

🤖 Generated with Claude Code

os-zhuangand others added 3 commits July 8, 2026 21:56
feat(studio): match form designer/preview column density to the runtime form (#2345)
objectui@195121ade6ec921e5786030093f0b23fc58d02f7
…loud ADR-0081 D1)
Single-org deployments had NO way to add a user at all: the invite
affordances hid behind 'features.multiOrgEnabled' gates, and nothing ever
created an organization (OrgScopingPlugin and its default-org bootstrap are
multi-org-gated), so sessions carried no activeOrganizationId and better-auth
organization/invite-member had no org to resolve.
- plugin-auth: ensureDefaultOrganization moves here (open home; the
multi-org seed-ownership step becomes an injectable option that
plugin-org-scoping's wrapper keeps providing), wired in single-org mode on
kernel:ready + after every sys_user_permission_set insert
(autoDefaultOrganization opt-out).
- plugin-auth: default session.create.before hook stamps
activeOrganizationId from the caller's sys_member row (owner-preferred);
host-supplied hooks chain first and win (autoActiveOrganization opt-out).
- platform-objects: member/invitation/team actions re-gate from
'features.multiOrgEnabled' to 'features.organization' (the capability is
always mounted); sys_organization's own create/leave/delete keep the
multi-org gate so the single-org default org stays protected.
- setup nav: new nav_organization entry deep-links to the ACTIVE org's
record page ({current_org_id}); nav_teams / nav_invitations drop the
org-scoping service gate; the Organizations LIST keeps it (multi-org only).
Live-verified single-org via browser: first-run wizard -> default org
(renamed, CJK name) + owner membership + active-org session; invite ->
accept -> change role -> remove, all through better-auth endpoints.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…erprise @objectstack/organizations package (cloud ADR-0081 D2)
BREAKING: the open @objectstack/plugin-org-scoping package is removed. The
multi-org runtime (organization_id auto-stamp, per-org seed replay, multi-org
default-org bootstrap) is now the closed-source @objectstack/organizations
package, which keeps registering the historical 'org-scoping' service — the
plugin-security RLS probe and the requiresService nav gates are unaffected.
- cli serve / plugin-dev / verify harness mount it best-effort by name when
OS_MULTI_ORG_ENABLED=true; a missing package WARNS loudly (serve/dev) or
throws an actionable error (verify's explicit multiTenant opt-in) instead
of silently downgrading the RLS posture.
- The open member-management basics are unaffected: plugin-auth's single-org
default-org bootstrap + better-auth invitations (ADR-0081 D1) keep working
without the enterprise package.
- dogfood multi-org RLS gate skips (loudly) when the package isn't linked;
enterprise/cloud CI runs it.
Live-verified: multi-org stack with the enterprise package linked (bootstrap,
second-org create, {current_org_id} nav following org switch) and the
missing-package single-org downgrade warning.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercelBot commented Jul 9, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJul 9, 2026 5:08am

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file tests tooling size/xl labels Jul 9, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 9 package(s): @objectstack/cli, @objectstack/dogfood, @objectstack/platform-objects, @objectstack/plugin-auth, @objectstack/plugin-dev, packages/plugins/plugin-org-scoping, @objectstack/plugin-security, @objectstack/runtime, @objectstack/verify.

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

  • content/docs/ai/skills-reference.mdx(via packages/cli)
  • content/docs/api/client-sdk.mdx(via @objectstack/cli)
  • content/docs/api/data-flow.mdx(via @objectstack/cli)
  • content/docs/api/environment-routing.mdx(via @objectstack/cli)
  • content/docs/api/error-catalog.mdx(via @objectstack/cli)
  • content/docs/api/index.mdx(via @objectstack/runtime)
  • content/docs/api/wire-format.mdx(via @objectstack/runtime)
  • content/docs/automation/hook-bodies.mdx(via packages/cli, @objectstack/runtime)
  • content/docs/concepts/north-star.mdx(via packages/runtime)
  • content/docs/data-modeling/drivers.mdx(via @objectstack/runtime)
  • content/docs/deployment/index.mdx(via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx(via @objectstack/plugin-auth, @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx(via @objectstack/runtime)
  • content/docs/deployment/vercel.mdx(via @objectstack/runtime)
  • content/docs/getting-started/cli.mdx(via @objectstack/cli, @objectstack/plugin-auth, @objectstack/plugin-security)
  • content/docs/kernel/runtime-services/data-service.mdx(via packages/cli)
  • content/docs/kernel/runtime-services/index.mdx(via packages/cli)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/plugin-auth)
  • content/docs/permissions/access-recipes.mdx(via packages/plugins/plugin-security)
  • content/docs/permissions/authentication.mdx(via @objectstack/cli, @objectstack/plugin-auth, @objectstack/runtime)
  • content/docs/permissions/authorization.mdx(via packages/dogfood, packages/plugins/plugin-security)
  • content/docs/permissions/permission-sets.mdx(via packages/plugins/plugin-org-scoping, packages/plugins/plugin-security)
  • content/docs/permissions/permissions-matrix.mdx(via packages/plugins/plugin-security)
  • content/docs/permissions/sharing-rules.mdx(via @objectstack/plugin-security)
  • content/docs/permissions/sso.mdx(via @objectstack/plugin-auth)
  • content/docs/plugins/index.mdx(via @objectstack/plugin-auth, @objectstack/plugin-security)
  • content/docs/plugins/packages.mdx(via @objectstack/cli, @objectstack/platform-objects, @objectstack/plugin-auth, @objectstack/plugin-dev, packages/plugins/plugin-org-scoping, @objectstack/plugin-security, @objectstack/runtime)
  • content/docs/protocol/objectos/http-protocol.mdx(via @objectstack/runtime)
  • content/docs/protocol/objectos/index.mdx(via @objectstack/runtime)
  • content/docs/protocol/objectos/lifecycle.mdx(via @objectstack/runtime)
  • content/docs/protocol/objectos/plugin-spec.mdx(via @objectstack/cli)
  • content/docs/protocol/objectos/realtime-protocol.mdx(via @objectstack/cli)
  • content/docs/releases/implementation-status.mdx(via @objectstack/cli, @objectstack/plugin-auth, @objectstack/plugin-security, @objectstack/runtime, @objectstack/verify)
  • content/docs/releases/v9.mdx(via @objectstack/plugin-auth)
  • content/docs/ui/dashboards.mdx(via @objectstack/plugin-security)
  • content/docs/ui/role-based-interfaces.mdx(via packages/plugins/plugin-security)
  • content/docs/ui/setup-app.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.

…op deleted package from changeset fixed group
- verify harness: pass autoDefaultOrganization: false to AuthPlugin. The
single-org default-org bootstrap (ADR-0081 D1) is a product onboarding
convenience for objectstack dev/serve; running it inside the harness minted
a Default Organization + bound the dev admin as owner, giving every
'single-tenant' fixture an active org — which switched on org-scoped RLS and
reparented seeded rows, breaking the pure single-tenant baseline the dogfood
proofs assert (ADR-0057 identity create, ADR-0062 federation, ADR-0086
two-doors). The bootstrap stays covered by plugin-auth unit tests + browser E2E.
- .changeset/config.json: remove @objectstack/plugin-org-scoping from the
fixed group (package deleted in this branch).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@os-zhuang
os-zhuang merged commit 54e43db into mainJul 9, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the feat/org-mgmt-basics branch July 9, 2026 05:17
os-zhuang added a commit that referenced this pull request Jul 19, 2026
…eld (#3304) (#3313)
The flow designer generates a node's config form from its published
`configSchema` (ADR-0018). Introduce an `xExpression: 'expression' | 'template'`
marker on string properties — riding the same Zod `.meta()` → JSON-Schema
channel as `xRef` / `xEnumDeprecated` — that declares whether a string is bare
CEL or an `interpolate()` single-brace `{var}` template.
Apply it to the `loop` node's `collection` (a `{tasks}` template):
• LoopConfigSchema.collection — the canonical Zod source (control-flow.zod.ts),
emitted via z.toJSONSchema.
• the shipped descriptor's configSchema literal (service-automation
loop-node.ts) — the JSON objectui actually reads. loop's configSchema is a
hand-written literal that doesn't derive from the Zod schema, so both are
annotated so they agree.
Closes the live divergence: without the marker the designer rendered
`collection` as plain text online while the offline hardcoded form rendered it
as a mono expression editor, and the CEL brace-trap false-flagged `{tasks}`.
objectui #2670 Phase 3 (#2699) already consumes the marker.
Additive + backward-compatible: an unknown value is ignored, runtime unchanged.
Follow-up (tracked in #3304): the same marker on map/decision/script and the
node types that publish no configSchema yet.
Tests: LoopConfigSchema emits xExpression through z.toJSONSchema (spec); the
registered loop descriptor's configSchema.collection carries it (service-automation).
Claude-Session: https://claude.ai/code/session_01VuvxWgoadqryqBcjs7TpVi
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/xlteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@os-zhuang