Skip to content

feat(api): Add OSS org-creation path and EE-shaped signup flow - #4673

Merged
junaway merged 4 commits into
release/v0.104.0from
feat/oss-org-creation
Jun 17, 2026
Merged

junaway merged 4 commits into
release/v0.104.0from
feat/oss-org-creation

Conversation

@jp-agenta

@jp-agenta jp-agenta commented Jun 12, 2026 •

Copy link
Copy Markdown
Contributor

Context

OSS has no way to mint a second organization: signup hard-codes a first-user bootstrap of one singleton org (slug oss-default), later users must hold an invitation to that org, and POST /organizations/ exists only in EE. This PR is sequencing step 2 of the convergence plan (docs/designs/oss-ee-convergence/assessment-a-oss-multi-org.md): give OSS the same org-creation path and signup semantics as EE.

Changes

The org-creation core moves into shared OSS code. New oss/src/services/commoners.py holds can_create_organization (the AGENTA_ACCESS_ALLOWED_OWNER_EMAILS check, moved verbatim from EE), the creation core (org row + owner membership + default workspace + default project + seeded testsets/evaluators/environments), create_organization_for_signup, create_organization_for_user, and an OSS create_accounts that mirrors the EE flow minus billing, demos, and marketing emails. EE's commoners.py now wraps the shared core with subscription provisioning and entitlement checks; its duplicated creation code in db_manager_ee.py is deleted, and the membership writers (add_user_to_organization/workspace/project, add_user_to_workspace_and_org), transfer_organization_ownership, count_organizations_by_owner, and delete_organization move to OSS db_manager with re-exports in place.

Signup: the OSS branch of _create_account (first-user bootstrap, invite-only check for everyone else) collapses to the same create_accounts(payload) call EE makes. Behavior change: a fresh signup now gets a personal org when the allowlist permits, instead of joining the singleton; users not allowed to create an org sign in org-less and join via invitation. Accepting an invitation now writes org/workspace/project membership rows (before, OSS only flipped the invitation's used flag).

Endpoints: OSS mounts POST /organizations/, PUT/PATCH /organizations/{id}, DELETE /organizations/{id}, and POST /organizations/{id}/transfer/{new_owner_id} with plain owner checks (no RBAC/entitlements). They register only when is_ee() is false, since the OSS router is mounted first and would otherwise shadow EE's gated versions.

Admin API: the OssMultiOrgNotSupportedError block is gone; OSS accepts explicit org/workspace/project/memberships like EE, and membership rows are written through the shared models (the EE-only admin_manager indirection is gone).

Removed from OSS db_manager: is_first_user_signup, get_or_bootstrap_oss_organization, setup_oss_organization_for_first_user, _assign_user_to_organization_oss, create_accounts, check_if_user_invitation_exists, and the INSERT ... ON CONFLICT (slug) singleton branch of create_organization (slugs now stay NULL at creation, matching EE).

Tests / notes

  • New acceptance suite oss/tests/pytest/acceptance/accounts/test_organizations.py: create, list, rename, empty-update 400, delete, ownership transfer (and transfer-to-non-member rejection) through the new endpoints with an ApiKey-authed account.

  • New unit tests for can_create_organization (unit/services/test_commoners.py).

  • Follow-up commit also lifts the leftover is_ee gates on the simple membership-create admin endpoints; they wrap the graph path this PR already ungated.

  • ruff format and ruff check pass; all touched files compile.

  • get_default_workspace_id_oss() loses its oss-default slug filter (it would break fresh deployments whose first org has no slug) but still picks the oldest workspace; the full membership-aware resolution of its callers is sequencing step 4.

  • The remaining OSS_SINGLETON_ORG_SLUG guards in the admin delete paths (refuse to delete the legacy singleton org/workspace) are left in place; they protect migrated deployments and go away with the step-4 sweep.

  • Release note for operators: upgrading flips OSS from invite-only to open signup. Set AGENTA_ACCESS_ALLOWED_OWNER_EMAILS / AGENTA_ACCESS_ALLOWED_DOMAINS (or block lists) before upgrading to keep a closed instance (access vars are enforced by the step-3 PR).

What to QA

  • Fresh OSS deployment: sign up. You land in your own org named after your username. Sign up a second user from another browser; they get their own org, not an invitation error.
  • OSS with AGENTA_ACCESS_ALLOWED_OWNER_EMAILS=you@x.com: a different email can still sign up but gets no org; inviting them to a project and accepting works and grants access (membership rows now exist).
  • In the org sidebar API: create a new organization via POST /organizations/, rename it, transfer it to a member, delete it (deleting your last org is refused).
  • Regression (EE): cloud signup still provisions the trial subscription, and org creation via the EE endpoint still enforces entitlements.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jun 12, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment Jun 16, 2026 1:30pm

Request Review

@jp-agenta
jp-agenta changed the base branch from main to feat/oss-membership-tables June 12, 2026 12:25
@dosubot dosubot Bot added size:XXL This PR changes 1000+ lines, ignoring generated files. backend feature request New feature or request labels Jun 12, 2026
@coderabbitai

coderabbitai Bot commented Jun 12, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 843da34e-ed40-45ff-aa7b-75b378093f3f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR consolidates organization and membership management across OSS and EE by introducing a unified membership table schema (organization_members, workspace_members, project_members), refactoring shared organization creation and lifecycle helpers into OSS implementations, unifying account provisioning logic, and removing OSS-specific multi-organization restrictions. EE re-exports the OSS implementations where applicable.

Changes

Membership and Organization Management Consolidation

Layer / File(s) Summary
Membership database schema and models
api/oss/databases/postgres/migrations/core/versions/0a1b2c3d4e5f_add_membership_tables_and_account_parity.py, api/oss/databases/postgres/migrations/core/versions/1b2c3d4e5f6a_backfill_membership_rows.py, api/oss/databases/postgres/migrations/core/data_migrations/memberships.py, api/oss/src/models/db_models.py
Creates three membership tables with cascading foreign keys and role fields; defines OrganizationMemberDB, WorkspaceMemberDB, ProjectMemberDB models; provides backfill logic to seed memberships for org/workspace/project owners and invited users.
Organization service foundations
api/oss/src/core/organizations/exceptions.py, api/oss/src/models/api/organization_models.py, api/oss/src/services/commoners.py (partial)
Introduces OrganizationError base and OrganizationCreationNotAllowedError/LastOrganizationError subclasses; adds CreateOrganizationPayload and UpdateOrganizationPayload models; implements can_create_organization allowlist check and create_organization function that seeds default memberships and related records.
Organization lifecycle and user membership operations
api/oss/src/services/db_manager.py, api/oss/src/services/commoners.py (continuation), api/oss/src/services/organization_service.py
Adds membership row creators for org/workspace/project; implements add_user_to_workspace_and_org with project backfill; provides organization counting, deletion, and ownership transfer with role swapping; wraps creation with signup/user provisioning helpers; updates invitation acceptance to establish membership relationships.
Organization management API endpoints
api/oss/src/routers/organization_router.py
Adds OSS-only create/update/transfer/delete organization endpoints with ownership validation; handles OrganizationCreationNotAllowedError (403), validation errors (400), and server errors (500).
Account creation and membership support unification
api/oss/src/core/accounts/service.py, api/oss/src/core/auth/supertokens/overrides.py
Removes OSS multi-org restrictions; adds direct membership row creators; implements unified _create_memberships method; scaffolds owner defaults for all accounts; updates SuperTokens to use commoners create_accounts; adds lock-protected account creation with user provisioning and domain policy enforcement.
Enterprise Edition consolidation and schema alignment
api/ee/src/core/organizations/exceptions.py, api/ee/src/models/db_models.py, api/ee/src/services/commoners.py, api/ee/src/services/db_manager_ee.py, api/ee/databases/postgres/migrations/core/versions/2c3d4e5f6a7b_account_schema_parity.py
EE re-exports organization exceptions, membership models, and org/workspace/project helpers from OSS; removes local implementations; updates organization creation to call OSS create_organization directly; adds EE migration for api_keys created_by_id nullability and projects schema constraints with cascading workspace FK.
Error handling and multi-org restriction cleanup
api/oss/src/apis/fastapi/accounts/router.py, api/oss/src/core/accounts/errors.py
Removes OssMultiOrgNotSupportedError exception class and its error handler; removes OSS branching that previously rejected multi-entity account inputs.

🎯 4 (Complex) | ⏱️ ~75 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly summarizes the main changes: adding OSS organization-creation capability and converging signup semantics with EE.
Description check ✅ Passed The PR description is comprehensive and directly related to the changeset, explaining context, changes, behavior shifts, endpoints, and QA guidance.
Docstring Coverage ✅ Passed Docstring coverage is 61.67% which is sufficient. The required threshold is 60.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/oss-org-creation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 12, 2026 •

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Preview URL https://gateway-production-178c.up.railway.app/w
Project agenta-oss-pr-4673
Image tag pr-4673-27c7099
Status Deployed
Railway logs Open logs
Workflow logs View workflow run
Updated at 2026-06-16T13:36:31.513Z

Moves the org-creation core (org + owner membership + default workspace/
project + seeded defaults) into shared OSS code (oss commoners + db_manager);
EE commoners slims to subscription/entitlement wrappers over it. OSS signup
converges on the EE flow: personal org per allowed user, no first-user
bootstrap, no invite-only gate. Mounts create/update/delete/transfer
organization endpoints in OSS, lifts the admin-API multi-org block, and
writes membership rows on invitation accept.
Adds acceptance tests for the OSS create/rename/transfer/delete organization
endpoints and unit tests for can_create_organization. Lifts the leftover
is_ee gates on the simple membership-create endpoints — they wrap the graph
path, which already creates memberships in both editions.
…ation

The old `if invitation is not None:` block was left inside the open
parentheses of the `invitation = (...)` call; the incoming branch
correctly closed the paren and the new error-class-based handling
(InviteNotFoundError, InviteEmailMismatchError, etc.) already sat below
the conflict marker on the current branch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@junaway
junaway changed the base branch from feat/oss-membership-tables to release/v0.104.0 June 17, 2026 08:41
@junaway
junaway merged commit 63a32f7 into release/v0.104.0 Jun 17, 2026
32 of 34 checks passed

This branch was successfully deployed

1 active deployment
Preview — 1c820c5d Deployed Jun 16, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend feature request New feature or request size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants