Skip to content

Comments

fix: Issues observed when inviting members to organization either through teams migration during onboarding or explicit user invite#22901

Merged
hariombalhara merged 5 commits intomainfrom
fix-member-pending-but-profile
Aug 13, 2025
Merged

fix: Issues observed when inviting members to organization either through teams migration during onboarding or explicit user invite#22901
hariombalhara merged 5 commits intomainfrom
fix-member-pending-but-profile

Conversation

@hariombalhara
Copy link
Member

@hariombalhara hariombalhara commented Aug 5, 2025

What does this PR do?

  • Fixes PRI-299

Fixes following issues

  • A user(having autoAcceptEmail as per org) who had pending membership with a team and that team got moved to an Organization. Then, the user had an accepted membership with organization, but pending membership with the Team(existing membership). In this case, the pending membership should have been automatically accepted.
  • Teams in organization were being moved in parallel to organization and if they had common users, some of the records might conflict and error in that case. One such case was seen on Axiom and is linked in the Linear ticket. Now, we move the teams in sequence to completely avoid these issues. We expect a small delay in moving teams to organization but it happens through an asynchronous flow and should take a few seconds only.
  • A user who had a Profile record with organization wasn't allowed to be invited via Invite Member flow. A very wrong error that 'User is part of another organization' was thrown. This has been fixed now.
  • Unhandled promise rejection error in inviteMember flow

Tests

  • Introduced integration tests for inviteMembers flow which should give much needed confidence when tests pass

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • N/A 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.

Instead of processing team migrations in parallel using Promise.all,
process them sequentially to avoid race conditions when creating
profiles and memberships for team members.

This simplifies the implementation and avoids the need for complex
retry logic or database-level concurrency controls.
…in it as the first item. This fixes the issue where these promises were unhandled
…nding even though theorganization membership gets created as accepted
@vercel
Copy link

vercel bot commented Aug 5, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
cal ⬜️ Ignored Aug 13, 2025 10:19am
cal-eu ⬜️ Ignored Aug 13, 2025 10:19am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 5, 2025

Walkthrough

This change set modifies the logic for migrating teams to process them sequentially rather than in parallel, addressing unique constraint issues during membership and profile creation. It introduces a new integration test suite for the invite member handler, focusing on organizational membership and profile scenarios, and expands unit tests with additional fields and organizational state coverage. The canBeInvited utility is refactored to clarify profile and organization checks, and the invitation logic is updated to ensure that when a user is auto-accepted into an organization, their pending sub-team memberships are also accepted. No changes are made to public API signatures.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~18 minutes

Assessment against linked issues

Objective Addressed Explanation
Handle users who have a profile with the organization but no membership (PRI-299)
Prevent errors during organization creation and user migration related to membership/profile state (PRI-299)
Add or update tests covering invitation, membership, and profile logic for organizations (PRI-299)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes were found. All code changes are relevant to the objectives in the linked issue, focusing on membership/profile handling and organizational invite logic.

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-member-pending-but-profile

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Contributor

github-actions bot commented Aug 5, 2025

Hey there and thank you for opening this pull request! 👋🏼

We require pull request titles to follow the Conventional Commits specification and it looks like your proposed title needs to be adjusted.

Details:

No release type found in pull request title "Fix-member-pending-but-profile". Add a prefix to indicate what kind of release this pull request corresponds to. For reference, see https://www.conventionalcommits.org/

Available types:
 - feat: A new feature
 - fix: A bug fix
 - docs: Documentation only changes
 - style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
 - refactor: A code change that neither fixes a bug nor adds a feature
 - perf: A code change that improves performance
 - test: Adding missing tests or correcting existing tests
 - build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
 - ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
 - chore: Other changes that don't modify src or test files
 - revert: Reverts a previous commit

@keithwillcode keithwillcode added core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO labels Aug 5, 2025
@linear
Copy link

linear bot commented Aug 5, 2025

PRI-299

@hariombalhara hariombalhara changed the title Fix-member-pending-but-profile fix: Issues observed when inviting members to organization either through teams migration during onboarding or explicit user invite Aug 5, 2025
@hariombalhara hariombalhara self-assigned this Aug 5, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Aug 5, 2025

E2E results are ready!

@hariombalhara hariombalhara marked this pull request as ready for review August 7, 2025 16:59
@graphite-app graphite-app bot requested a review from a team August 7, 2025 16:59
@graphite-app
Copy link

graphite-app bot commented Aug 7, 2025

Graphite Automations

"Add consumer team as reviewer" took an action on this PR • (08/07/25)

1 reviewer was added to this PR based on Keith Williams's automation.

"Add platform team as reviewer" took an action on this PR • (08/07/25)

1 reviewer was added to this PR based on Keith Williams's automation.

@dosubot dosubot bot added platform Anything related to our platform plan teams area: teams, round robin, collective, managed event-types 🐛 bug Something isn't working labels Aug 7, 2025
@graphite-app graphite-app bot requested a review from a team August 7, 2025 17:00
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts (1)

177-177: Use strict equality for consistency

For consistency with the rest of the codebase and to avoid potential type coercion issues, use strict equality.

-    return profile.organizationId != team.parentId;
+    return profile.organizationId !== team.parentId;
packages/trpc/server/routers/viewer/organizations/createTeams.handler.ts (1)

98-109: Correct fix for race condition issues!

Changing from parallel to sequential processing effectively prevents unique constraint violations when users belong to multiple teams being migrated. This is a necessary trade-off for data consistency.

Consider monitoring the performance impact of sequential processing for organizations with many teams. If this becomes a bottleneck, you could batch teams in smaller groups or implement a queue-based approach.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5d0dc3f and af669f1.

📒 Files selected for processing (5)
  • packages/trpc/server/routers/viewer/organizations/createTeams.handler.ts (1 hunks)
  • packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts (1 hunks)
  • packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.test.ts (4 hunks)
  • packages/trpc/server/routers/viewer/teams/inviteMember/inviteMemberUtils.test.ts (6 hunks)
  • packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.ts

📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.test.ts
  • packages/trpc/server/routers/viewer/organizations/createTeams.handler.ts
  • packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
  • packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts
  • packages/trpc/server/routers/viewer/teams/inviteMember/inviteMemberUtils.test.ts
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.test.ts
  • packages/trpc/server/routers/viewer/organizations/createTeams.handler.ts
  • packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
  • packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts
  • packages/trpc/server/routers/viewer/teams/inviteMember/inviteMemberUtils.test.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: sean-brydon
PR: calcom/cal.com#22618
File: packages/trpc/server/routers/viewer/eventTypes/utils/transformUtils.ts:113-113
Timestamp: 2025-08-05T07:42:06.335Z
Learning: In Cal.com's getUserEventGroups handler refactor (PR #22618), the membershipCount field for team event groups is intentionally set to 0 in the new createTeamEventGroup function, as confirmed by sean-brydon (PR author). This preserves the same behavior as the old implementation that was being refactored, maintaining backward compatibility. While other parts of the codebase may use actual member counts, this specific implementation maintains the previous behavior.
📚 Learning: 2025-08-05T12:04:29.037Z
Learnt from: din-prajapati
PR: calcom/cal.com#21854
File: packages/app-store/office365calendar/__tests__/unit_tests/SubscriptionManager.test.ts:0-0
Timestamp: 2025-08-05T12:04:29.037Z
Learning: In packages/app-store/office365calendar/lib/CalendarService.ts, the fetcher method in Office365CalendarService class is public, not private. It was specifically changed from private to public in this PR to support proper testing and external access patterns.

Applied to files:

  • packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.test.ts
📚 Learning: 2025-08-05T07:42:06.335Z
Learnt from: sean-brydon
PR: calcom/cal.com#22618
File: packages/trpc/server/routers/viewer/eventTypes/utils/transformUtils.ts:113-113
Timestamp: 2025-08-05T07:42:06.335Z
Learning: In Cal.com's getUserEventGroups handler refactor (PR #22618), the membershipCount field for team event groups is intentionally set to 0 in the new createTeamEventGroup function, as confirmed by sean-brydon (PR author). This preserves the same behavior as the old implementation that was being refactored, maintaining backward compatibility. While other parts of the codebase may use actual member counts, this specific implementation maintains the previous behavior.

Applied to files:

  • packages/trpc/server/routers/viewer/organizations/createTeams.handler.ts
  • packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
  • packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts
📚 Learning: 2025-07-21T21:33:23.371Z
Learnt from: Anshumancanrock
PR: calcom/cal.com#22570
File: apps/web/modules/signup-view.tsx:253-253
Timestamp: 2025-07-21T21:33:23.371Z
Learning: In signup-view.tsx, when checking if redirectUrl contains certain strings, using explicit && checks (redirectUrl && redirectUrl.includes()) is preferred over optional chaining (redirectUrl?.includes()) to ensure the result is always a boolean rather than potentially undefined. This approach provides cleaner boolean contracts for downstream conditional logic.

Applied to files:

  • packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
🪛 GitHub Actions: PR Update
packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts

[error] 119-119: TypeScript error TS2322: Type 'string | undefined' is not assignable to type 'string'.

🔇 Additional comments (8)
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts (3)

163-178: Good refactoring for improved readability!

The extraction of profile checking logic into hasDifferentOrganizationProfile makes the code more maintainable and easier to understand. The three distinct cases are now clearly documented.


848-862: Promise.all handles empty arrays correctly

Passing the mapped promise array directly to Promise.all (instead of wrapping it in [...]) does not change behavior—when the array is empty, Promise.all([]) resolves immediately with []. This is consistent with how Promise.all is used elsewhere in the codebase, so no further changes are needed.


897-912: Confirm correct targeting of sub-team memberships

The updateMany call in packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts uses the filter

team: { parentId: organization.id }

to accept only pending memberships for direct sub-teams when shouldAutoAccept is true. This aligns with existing patterns and ensures membership state consistency.

• File: packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
• Lines: 900–907

packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.test.ts (1)

1-5: Good practice to deprecate in favor of integration tests!

The deprecation notice clearly directs developers to the integration test file, which provides better test coverage with less mocking.

packages/trpc/server/routers/viewer/teams/inviteMember/inviteMemberUtils.test.ts (1)

471-489: Good test coverage for profile edge case!

This test case covers an important scenario where a user has a profile with an organization but no team membership, ensuring they can still be invited.

packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts (3)

54-79: Well-structured test helper with proper cleanup!

The createTestUser helper properly handles unique ID generation and pre-emptive cleanup to avoid conflicts. The error handling with empty catch blocks is appropriate for cleanup operations.


160-193: Excellent test cleanup strategy!

The cleanup in afterEach follows the correct dependency order and uses transactions for atomicity. This ensures test isolation and prevents data leakage between tests.


358-436: Comprehensive test for the key fix!

This test effectively validates the PR's main objective - ensuring that pending sub-team memberships are auto-accepted when a user with matching email domain is invited to the organization. Great coverage of the critical path.

Copy link
Contributor

@volnei volnei left a comment

Choose a reason for hiding this comment

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

Nice tests! 🚀
LGTM

@hariombalhara hariombalhara enabled auto-merge (squash) August 13, 2025 10:19
@hariombalhara hariombalhara merged commit b7fda31 into main Aug 13, 2025
36 checks passed
@hariombalhara hariombalhara deleted the fix-member-pending-but-profile branch August 13, 2025 10:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛 bug Something isn't working core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO platform Anything related to our platform plan ready-for-e2e teams area: teams, round robin, collective, managed event-types

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants