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-zhuang and 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

vercel Bot commented Jul 9, 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 Jul 9, 2026 5:08am

Request Review

@github-actions github-actions Bot 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

github-actions Bot commented Jul 9, 2026

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 main Jul 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 free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant