Permissions and roles
State Usergroup Rules has no module-specific privilege. Its admin API routes sit in the same privilege group as vendor management, so access follows the vendor privileges.
Privileges in play
| Privilege | Grants |
|---|---|
view_vendors | Read the rule list (GET /api/v1/admin/state-usergroup-rules). |
manage_vendors | Everything in view_vendors, plus create/upsert (POST) and delete (DELETE). |
manage_modules or manage_settings | Turn the module on or off at /admin/modules. |
There is no manage_state_rules privilege today. Tenants that need a stricter audit surface should grant manage_vendors only to a small admin team.
Typical role mapping
| Role | What they should be able to do | Privileges to grant |
|---|---|---|
| Platform admin | Everything | all privileges |
| Finance ops | Read rules to debug pricing issues | view_vendors |
| Marketing | Define which states go to which campaign group | manage_vendors (broad, but it's the lever the routes use) |
| Customer support | Look up which group a user got assigned to | user read access — they read /admin/users/<id> |
| Vendor | No access | (vendors don't see this page at all) |
Vendor isolation
Vendors do NOT see this page. State Usergroup Rules is platform-level — the rules are tenant-wide, not per-vendor. A marketplace running multiple vendors shares one rule set; per-vendor regional segmentation must be done at the catalog level rather than via this module.
Page-level gating
The admin page /admin/state-usergroup-rules is gated by:
- Module enabled? Disabled module → the API returns
403 module_disabledand the page shows "module not enabled". - Admin signed in? Signed-out → redirect to the admin login.
- Privileges —
view_vendorsfor reads,manage_vendorsfor writes. The backend checks on every request; hiding buttons in the UI is not a security boundary.
Runtime auto-assign privilege
The rule fires from users.Service.ApplyStateUsergroups regardless of who triggered the address write. That means:
- A customer saving their own address → fires.
- An admin creating an address on the customer's behalf → fires.
- A script creating addresses through the API → fires (the service is called per address).
There is no per-actor permission gate inside ApplyStateUsergroups. The assumption is that anyone authorised to write an address row is implicitly authorised to fire the rule.
Audit trail
Every assignment writes a log line. There is no DB audit table for state usergroup decisions specifically — if you need a paper trail beyond the log, query usergroup_links filtered by the rule's target group and cross-reference with the customer's address changes. Imperfect; a dedicated audit log is on the roadmap.
Multi-tenant boundary
Rules are stored in the tenant database. One tenant's CA → wholesale-ca rule does not leak into another tenant's data. The runtime check IsEnabled(tenant, "state-usergroup-rules") re-confirms the tenant before any read, so a misconfigured request that lands on the wrong tenant still gets gated.