Skip to content

feat(core): RoleAssignmentPlugin (WIP)#4937

Draft
BibiSebi wants to merge 14 commits into
minorfrom
bsebestianova/oss-300-cannot-share-roles-across-multiple-channels-in-multi-vendor
Draft

feat(core): RoleAssignmentPlugin (WIP)#4937
BibiSebi wants to merge 14 commits into
minorfrom
bsebestianova/oss-300-cannot-share-roles-across-multiple-channels-in-multi-vendor

Conversation

@BibiSebi

@BibiSebi BibiSebi commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Description

First slice of channel-scoped role assignments for multi-vendor setups (design discussion in #3779): a skeleton RoleAssignmentPlugin shipped inside @vendure/core, activated only via a new experimental.roleAssignments.enabled config flag.

  • New RoleAssignment entity: (user, role, channel) bridge with a unique constraint on the triple, non-nullable FK columns (@EntityId()), CASCADE deletes, and indexes on roleId/channelId (userId lookups are covered by the unique constraint's leftmost column)
  • Minimal @VendurePlugin shell that registers the entity — no permission resolution, services, or API extensions yet
  • New experimental section on VendureConfig; when roleAssignments.enabled is set, preBootstrapConfig registers the plugin internally (users never touch plugins: [])
  • Legacy-data backfill (RoleAssignmentMigrationService), run on server bootstrap only while the role_assignment table is empty (run-once semantics; deleting all rows re-triggers it, and the service can be invoked manually):
    • Candidate rows come from a single join across the legacy tables: user_roles_rolerole_channels_channel, one row per (user, role, channel). All users are treated alike — this mirrors legacy permission resolution exactly (a customer holds the Customer role, which is assigned to every channel, just as getUserChannelsPermissions() grants Authenticated everywhere today). Row count therefore scales with users × channels-per-role
    • Memory-bounded regardless of store size: rows are processed in keyset-paginated batches, with already-migrated rows excluded DB-side via an anti-join instead of being loaded and diffed in memory; the whole run is one transaction so a mid-run failure cannot leave the table partially populated (which would defeat the empty-table check on next boot)
    • Additive and idempotent (INSERT ... orIgnore); legacy relations are never modified, so disabling the flag stays non-destructive
    • Server process only; soft-deleted users excluded; if the flag is on but the table is missing, a clear "generate and run a migration" error is logged instead of an opaque SQL failure
  • Commented-out flag in the dev-server config for local testing

With the flag disabled (default) there is zero schema or behavior change. With it enabled, the effects are the new role_assignment table (requires a migration, same as DefaultJobQueuePlugin) and the one-time backfill. Permission resolution still uses only the legacy relations — the rows are inert until the resolver-strategy pass, which follows in subsequent PRs per the plan on the linked issue.

Relates to #3779

TODOs

Migration tooling
  • Consider exporting the backfill as a standalone migrateRoleAssignmentData(queryRunner) helper in migration-utils/ (the v3.6 migrateProductOptionGroupData() pattern), so it can run inside the same TypeORM migration that creates the table instead of boot-time run-once logic
  • Equivalence check: recompute per-user-per-channel permissions before/after migration and assert they match
  • Phase 2: dry-run CLI for consolidating duplicated per-channel roles (vendorX-* copies)

Breaking changes

None. The feature is opt-in via an experimental flag; disabled by default.

Screenshots

N/A

Checklist

📌 Always:

  • I have set a clear title
  • My PR is small and contains a single feature
  • I have checked my own PR

👍 Most of the time:

  • I have added or updated test cases
  • I have updated the README if needed

@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
vendure-storybook Ready Ready Preview, Comment Jul 10, 2026 11:34am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fa30e53e-d112-462a-b5f6-fcb89cfacc7d

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bsebestianova/oss-300-cannot-share-roles-across-multiple-channels-in-multi-vendor

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.

@BibiSebi BibiSebi changed the title feat(core): add experimental RoleAssignmentPlugin skeleton feat(core): RoleAssignmentPlugin (WIP) Jul 9, 2026
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Dashboard Preview: https://admin-dashboard-1kgkuw5s4-vendure.vercel.app

@BibiSebi
BibiSebi force-pushed the bsebestianova/oss-300-cannot-share-roles-across-multiple-channels-in-multi-vendor branch from 1c45377 to f1e5070 Compare July 9, 2026 15:01
@BibiSebi
BibiSebi marked this pull request as ready for review July 9, 2026 15:02
@BibiSebi
BibiSebi marked this pull request as draft July 9, 2026 15:04
@BibiSebi
BibiSebi force-pushed the bsebestianova/oss-300-cannot-share-roles-across-multiple-channels-in-multi-vendor branch from 53bfd10 to f1e5070 Compare July 9, 2026 15:07
@sonarqubecloud

Copy link
Copy Markdown

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