Skip to content

feat: add database transaction to createManagedOrganization flow to ensure atomicity#27979

Open
bandhan-majumder wants to merge 3 commits intocalcom:mainfrom
bandhan-majumder:fix-24384
Open

feat: add database transaction to createManagedOrganization flow to ensure atomicity#27979
bandhan-majumder wants to merge 3 commits intocalcom:mainfrom
bandhan-majumder:fix-24384

Conversation

@bandhan-majumder
Copy link
Contributor

@bandhan-majumder bandhan-majumder commented Feb 16, 2026

What does this PR do?

adds database transaction to createManagedOrganization flow to ensure atomicity. The previous db calls were sequential but not atomic. I have passed the client where it was needed to make sure same client is used. Client is a optional parameter which falls back to dbWrite or dbRead if not provided to make sure it does not totally break if transaction client is not provided.

Visual Demo (For contributors especially)

A visual demonstration is strongly recommended, for both the original and new change (video / image - any one).

Video Demo (if applicable):

N/A

Image Demo (if applicable):

N/A

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. If N/A, write N/A here and check the checkbox.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

https://cal.com/docs/platform/guides/managed-orgs

  • Are there environment variables that should be set?
  • What are the minimal test data to have?
  • What is expected (happy path) to have (input and output)?
  • Any other important info that could help to test that PR

Checklist

  • I haven't read the contributing guide
  • My code doesn't follow the style guidelines of this project
  • I haven't commented my code, particularly in hard-to-understand areas
  • I haven't checked if my changes generate no new warnings
  • My PR is too large (>500 lines or >10 files) and should be split into smaller PRs

Summary by cubic

Make createManagedOrganization atomic by wrapping org creation, membership, profile, billing, and API key creation in a single Prisma transaction with Serializable isolation. Prevents partial organizations and aligns with CAL-6555 and #24384.

  • Refactors
    • Threaded Prisma TransactionClient through managed orgs, memberships, billing, profiles, and API key services, plus TRPC api-keys create and auth middleware.
    • Checked slug uniqueness and created bootstrap membership (MembershipRole.OWNER) inside the transaction to avoid race conditions.
    • Set transaction options (Serializable isolation, maxWait, timeout) and added clearer failure messages.

Written for commit 2566dcb. Summary will update on new commits.

@github-actions github-actions bot added the api area: API, enterprise API, access token, OAuth label Feb 16, 2026
@bandhan-majumder bandhan-majumder changed the title feat: add database transaction to createManagedOrganization flow to e… feat: add database transaction to createManagedOrganization flow to ensure atomicity Feb 16, 2026
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 9 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/trpc/server/routers/viewer/apiKeys/_auth-middleware.ts">

<violation number="1" location="packages/trpc/server/routers/viewer/apiKeys/_auth-middleware.ts:15">
P2: Inefficient database query fetching full record for existence check</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

if (!teamId) return;
const team = await prisma.team.findFirst({
const client = prismaTransactionClient ?? prisma
const team = await client.team.findFirst({
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Inefficient database query fetching full record for existence check

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/trpc/server/routers/viewer/apiKeys/_auth-middleware.ts, line 15:

<comment>Inefficient database query fetching full record for existence check</comment>

<file context>
@@ -7,10 +7,12 @@ export async function checkPermissions(args: {
   if (!teamId) return;
-  const team = await prisma.team.findFirst({
+  const client = prismaTransactionClient ?? prisma
+  const team = await client.team.findFirst({
     where: {
       id: teamId,
</file context>
Fix with Cubic

@bandhan-majumder bandhan-majumder marked this pull request as ready for review February 16, 2026 16:22
@bandhan-majumder bandhan-majumder requested a review from a team as a code owner February 16, 2026 16:22
@graphite-app graphite-app bot added the community Created by Linear-GitHub Sync label Feb 16, 2026
isOrganization: true,
isPlatform: true,
metadata: organizationData.metadata,
if (existingManagedOrganization) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not send API response like previous, it just throws error. Open to change if reviewer thinks it can be better. Same goes to the over all catch block's error throw.

throw new Error(`Managed organization creation failed. ${error instanceof Error ? error.message : String(error)}`)
}
}, {
// @see: https://www.prisma.io/docs/orm/prisma-client/queries/transactions
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not required, but is mentioned in the prisma docs. Therefore, added it with docs link

...outputOrganization,
apiKey,
};
} catch (error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

managedOrgId: number,
prismaTransactionClient?: Prisma.TransactionClient
) {
const writeClient = prismaTransactionClient ?? this.dbWrite.prisma;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function require both the read and write db service. So added both of them falling back to the default.Open to suggestions here. A single client can also do the work but not appropriate usage I think as we use read,write services where they are appropriate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api area: API, enterprise API, access token, OAuth community Created by Linear-GitHub Sync size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] Add database transaction to createManagedOrganization flow to ensure atomicity

1 participant

Comments