feat(rbac): GDPR export becomes a toggleable clients.gdpr_export permission
Previously the GDPR export trigger + download routes were gated by admin.manage_settings, so sales roles couldn't run a client data export. Per request, make it a dedicated, toggleable permission that's on by default for sales-capable roles and hides the button when withheld. - New RolePermissions leaf clients.gdpr_export (+ PERMISSION_CATALOG entry); strict type forces every role map + fixture to declare it. - Granted true for super_admin / director / sales_manager / sales_agent; false for viewer / residential_partner. - GDPR export POST (trigger) and [exportId] GET (download) re-gated from admin.manage_settings -> clients.gdpr_export. - GdprExportButton visibility now keys off clients.gdpr_export, so toggling it off per-user hides the function entirely. - Migration 0098 backfills the key onto existing role rows (idempotent). Verified end-to-end as a Sales user: trigger (202) -> worker build (ready) -> list (200) -> download (200). 1664 vitest pass; tsc + eslint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,15 @@
|
||||
import type { RolePermissions } from './schema/users';
|
||||
|
||||
export const ALL_PERMISSIONS: RolePermissions = {
|
||||
clients: { view: true, create: true, edit: true, delete: true, merge: true, export: true },
|
||||
clients: {
|
||||
view: true,
|
||||
create: true,
|
||||
edit: true,
|
||||
delete: true,
|
||||
merge: true,
|
||||
export: true,
|
||||
gdpr_export: true,
|
||||
},
|
||||
interests: {
|
||||
view: true,
|
||||
create: true,
|
||||
@@ -104,7 +112,15 @@ export const ALL_PERMISSIONS: RolePermissions = {
|
||||
// reference the sales map directly.
|
||||
|
||||
export const SALES_MANAGER_PERMISSIONS: RolePermissions = {
|
||||
clients: { view: true, create: true, edit: true, delete: false, merge: true, export: true },
|
||||
clients: {
|
||||
view: true,
|
||||
create: true,
|
||||
edit: true,
|
||||
delete: false,
|
||||
merge: true,
|
||||
export: true,
|
||||
gdpr_export: true,
|
||||
},
|
||||
interests: {
|
||||
view: true,
|
||||
create: true,
|
||||
@@ -196,7 +212,15 @@ export const SALES_MANAGER_PERMISSIONS: RolePermissions = {
|
||||
export const DIRECTOR_PERMISSIONS: RolePermissions = SALES_MANAGER_PERMISSIONS;
|
||||
|
||||
export const SALES_AGENT_PERMISSIONS: RolePermissions = {
|
||||
clients: { view: true, create: true, edit: true, delete: false, merge: false, export: true },
|
||||
clients: {
|
||||
view: true,
|
||||
create: true,
|
||||
edit: true,
|
||||
delete: false,
|
||||
merge: false,
|
||||
export: true,
|
||||
gdpr_export: true,
|
||||
},
|
||||
interests: {
|
||||
view: true,
|
||||
create: true,
|
||||
@@ -283,7 +307,15 @@ export const SALES_AGENT_PERMISSIONS: RolePermissions = {
|
||||
};
|
||||
|
||||
export const VIEWER_PERMISSIONS: RolePermissions = {
|
||||
clients: { view: true, create: false, edit: false, delete: false, merge: false, export: false },
|
||||
clients: {
|
||||
view: true,
|
||||
create: false,
|
||||
edit: false,
|
||||
delete: false,
|
||||
merge: false,
|
||||
export: false,
|
||||
gdpr_export: false,
|
||||
},
|
||||
interests: {
|
||||
view: true,
|
||||
create: false,
|
||||
@@ -379,7 +411,15 @@ export const VIEWER_PERMISSIONS: RolePermissions = {
|
||||
// inquiries on the marina's behalf. Sees only the residential pages and
|
||||
// nothing else; can't see marina clients, yachts, berths, EOIs, etc.
|
||||
export const RESIDENTIAL_PARTNER_PERMISSIONS: RolePermissions = {
|
||||
clients: { view: false, create: false, edit: false, delete: false, merge: false, export: false },
|
||||
clients: {
|
||||
view: false,
|
||||
create: false,
|
||||
edit: false,
|
||||
delete: false,
|
||||
merge: false,
|
||||
export: false,
|
||||
gdpr_export: false,
|
||||
},
|
||||
interests: {
|
||||
view: false,
|
||||
create: false,
|
||||
|
||||
Reference in New Issue
Block a user