Skip to content

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

Open
jp-agenta wants to merge 2 commits into
feat/oss-membership-tablesfrom
feat/oss-org-creation
Open

feat(api): Add OSS org-creation path and EE-shaped signup flow#4673
jp-agenta wants to merge 2 commits into
feat/oss-membership-tablesfrom
feat/oss-org-creation

Conversation

@jp-agenta

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

Copy link
Copy Markdown
Member

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 14, 2026 6:09pm

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

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: b87fa133-a0aa-4afa-a974-5d965aa8fcfe

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-e01b.up.railway.app/w
Image tag pr-4673-0ace64b
Status Failed
Railway logs Open logs
Logs View workflow run
Updated at 2026-06-14T17:25:09.048Z

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.
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.

1 participant