Skip to content

Code Review Bench PR #26801 - feat: add scope configuration for feature opt-in#14

Open
tomerqodo wants to merge 8 commits intobase_pr_26801_20260125_1768from
corrupted_pr_26801_20260125_1768
Open

Code Review Bench PR #26801 - feat: add scope configuration for feature opt-in#14
tomerqodo wants to merge 8 commits intobase_pr_26801_20260125_1768from
corrupted_pr_26801_20260125_1768

Conversation

@tomerqodo
Copy link

Code Review Bench PR calcom#26801

Original PR Title: feat: add scope configuration for feature opt-in
Original PR Description: ## What does this PR do?

Follow-up to calcom#25892 as discussed in this review comment.

Adds a scope field to OptInFeatureConfig that allows features to be scoped to specific levels (org, team, user). This enables features to be shown only at certain settings pages rather than all three.

Example configuration:

export const OPT_IN_FEATURES: OptInFeatureConfig[] = [
  {
    slug: "bookings-v3",
    titleI18nKey: "bookings_v3_title",
    descriptionI18nKey: "bookings_v3_description",
    policy: "permissive",
    scope: ["org", "team", "user"], // Optional: defaults to all scopes if not specified
  },
];

Changes

  • Add OptInFeatureScope type with values "org", "team", "user"
  • Add optional scope field to OptInFeatureConfig interface
  • Add getOptInFeaturesForScope() helper function to filter features by scope
  • Add isFeatureAllowedForScope() helper function to validate scope access
  • Update FeatureOptInService to filter features based on scope
  • Update tRPC router to pass scope parameter for org/team endpoints
  • Scope validation on mutations: setUserFeatureState and setTeamFeatureState now reject requests with ErrorWithCode(ErrorCode.BadRequest) if the feature is not allowed for the specified scope
  • Scope-aware menu visibility: Features menu items in settings sidebar now use scope-specific constants (HAS_USER_OPT_IN_FEATURES, HAS_TEAM_OPT_IN_FEATURES, HAS_ORG_OPT_IN_FEATURES) to only show when features exist for that scope

Features without a scope field default to all scopes for backward compatibility.

Updates since last revision

  • Replaced raw Error with ErrorWithCode using ErrorCode.BadRequest for scope validation errors
  • Added comprehensive unit tests for scope validation in setUserFeatureState and setTeamFeatureState
  • Tests cover: enabled/disabled states, inherit state, error code and message validation
  • Improved Features menu visibility: Updated SettingsLayoutAppDirClient.tsx to use scope-specific constants instead of generic HAS_OPT_IN_FEATURES, so the Features menu item only appears when features are available for that specific scope (user/team/org)

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. N/A - internal feature configuration change
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  1. Since OPT_IN_FEATURES is currently empty, the changes won't have visible effects until features are added
  2. To test manually:
    • Add a feature to OPT_IN_FEATURES with scope: ["user"] only
    • Verify it appears on /settings/my-account/features but not on team/org settings pages
    • Verify attempting to set the feature state at team/org level throws an ErrorWithCode with BadRequest code
    • Add a feature with scope: ["org"] only
    • Verify it appears on /settings/organizations/features but not on user/team settings pages
  3. Run type checks: yarn type-check:ci --force --filter=@calcom/features --filter=@calcom/trpc
  4. Run unit tests: TZ=UTC yarn test packages/features/feature-opt-in/services/FeatureOptInService.test.ts

Human Review Checklist

  • Verify ErrorWithCode with ErrorCode.BadRequest is appropriate for scope validation failures
  • Verify scope filtering logic: features without scope should appear in all scopes (backward compatible)
  • Review test coverage for scope validation edge cases (16 tests total)
  • Verify the default scope value of "team" in listFeaturesForTeam is appropriate
  • Verify scope-specific constants (HAS_USER_OPT_IN_FEATURES, etc.) are used correctly in SettingsLayoutAppDirClient.tsx

Checklist

  • My code follows the style guidelines of this project
  • I have commented my code, particularly in hard-to-understand areas
  • I have checked if my changes generate no new warnings

Link to Devin run: https://app.devin.ai/sessions/4d62343634ba4f44819cff9c8d0cb83a
Requested by: @eunjae-lee
Original PR URL: calcom#26801

devin-ai-integration bot and others added 8 commits January 25, 2026 12:03
Add scope field to OptInFeatureConfig that allows features to be scoped
to specific levels (org, team, user). This enables features to be shown
only at certain settings pages rather than all three.

Changes:
- Add OptInFeatureScope type with values 'org', 'team', 'user'
- Add optional scope field to OptInFeatureConfig interface
- Add getOptInFeaturesForScope helper function to filter features by scope
- Update FeatureOptInService to filter features based on scope
- Update tRPC router to pass scope parameter for org/team endpoints

Features without a scope field default to all scopes for backward compatibility.

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
…tate

- Add isFeatureAllowedForScope helper function to check if a feature is allowed for a scope
- Update setUserFeatureState to reject if feature is not scoped to 'user'
- Update setTeamFeatureState to accept scope parameter and reject if feature is not allowed
- Update tRPC router to pass scope parameter for team and org endpoints
- Fix unit test mock to include new config exports

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
- Replace raw Error with ErrorWithCode using ErrorCode.BadRequest
- Add comprehensive tests for setUserFeatureState scope validation
- Add comprehensive tests for setTeamFeatureState scope validation
- Test both enabled/disabled and inherit state scenarios
- Test error messages include feature ID and scope name

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
…on tests

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant