feat(permissions): add inquiries resource (view/manage) + idempotent role backfill
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -103,6 +103,10 @@ const DEFAULT_PERMISSIONS: Record<string, Record<string, boolean>> = {
|
||||
delete: false,
|
||||
change_stage: false,
|
||||
},
|
||||
inquiries: {
|
||||
view: false,
|
||||
manage: false,
|
||||
},
|
||||
};
|
||||
|
||||
const GROUP_LABELS: Record<string, string> = {
|
||||
@@ -126,6 +130,7 @@ const GROUP_LABELS: Record<string, string> = {
|
||||
admin: 'Administration',
|
||||
residential_clients: 'Residential Clients',
|
||||
residential_interests: 'Residential Interests',
|
||||
inquiries: 'Inquiries',
|
||||
};
|
||||
|
||||
function formatAction(action: string): string {
|
||||
|
||||
@@ -69,6 +69,7 @@ export const PERMISSION_CATALOG = {
|
||||
],
|
||||
residential_clients: ['view', 'create', 'edit', 'delete'],
|
||||
residential_interests: ['view', 'create', 'edit', 'delete', 'change_stage'],
|
||||
inquiries: ['view', 'manage'],
|
||||
} as const satisfies {
|
||||
[R in PermissionResource]: ReadonlyArray<PermissionAction<R> & string>;
|
||||
};
|
||||
|
||||
25
src/lib/db/migrations/0092_inquiries_permission.sql
Normal file
25
src/lib/db/migrations/0092_inquiries_permission.sql
Normal file
@@ -0,0 +1,25 @@
|
||||
-- 0092_inquiries_permission.sql
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- New `inquiries` permission resource (view/manage) backing the top-level
|
||||
-- Inquiries workbench (previously the inbox lived under /admin and was gated on
|
||||
-- admin.view_audit_log, which sales roles don't have).
|
||||
--
|
||||
-- Existing role rows are backfilled so the resource defaults to whatever the
|
||||
-- role's `clients` access is: view ⟵ clients.view, manage ⟵ clients.create.
|
||||
-- This lights up the right roles (anyone who can see/create clients) without a
|
||||
-- manual per-role edit, and defaults to deny for read-only roles.
|
||||
--
|
||||
-- New-key only and idempotent via the `? 'inquiries'` guard, so re-running is a
|
||||
-- no-op. Per-user / port-role override tables are intentionally left untouched:
|
||||
-- the deep-merge resolver fills missing leaves from the base role (same
|
||||
-- reasoning as 0041).
|
||||
|
||||
UPDATE roles
|
||||
SET permissions = permissions || jsonb_build_object(
|
||||
'inquiries', jsonb_build_object(
|
||||
'view', COALESCE((permissions->'clients'->>'view')::boolean, false),
|
||||
'manage', COALESCE((permissions->'clients'->>'create')::boolean, false)
|
||||
)
|
||||
)
|
||||
WHERE permissions IS NOT NULL
|
||||
AND NOT (permissions ? 'inquiries');
|
||||
@@ -162,6 +162,10 @@ export type RolePermissions = {
|
||||
delete: boolean;
|
||||
change_stage: boolean;
|
||||
};
|
||||
inquiries: {
|
||||
view: boolean;
|
||||
manage: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -88,6 +88,10 @@ export const ALL_PERMISSIONS: RolePermissions = {
|
||||
delete: true,
|
||||
change_stage: true,
|
||||
},
|
||||
inquiries: {
|
||||
view: true,
|
||||
manage: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const DIRECTOR_PERMISSIONS: RolePermissions = {
|
||||
@@ -167,6 +171,10 @@ export const DIRECTOR_PERMISSIONS: RolePermissions = {
|
||||
delete: true,
|
||||
change_stage: true,
|
||||
},
|
||||
inquiries: {
|
||||
view: true,
|
||||
manage: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const SALES_MANAGER_PERMISSIONS: RolePermissions = {
|
||||
@@ -246,6 +254,10 @@ export const SALES_MANAGER_PERMISSIONS: RolePermissions = {
|
||||
delete: false,
|
||||
change_stage: false,
|
||||
},
|
||||
inquiries: {
|
||||
view: true,
|
||||
manage: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const SALES_AGENT_PERMISSIONS: RolePermissions = {
|
||||
@@ -325,6 +337,10 @@ export const SALES_AGENT_PERMISSIONS: RolePermissions = {
|
||||
delete: false,
|
||||
change_stage: false,
|
||||
},
|
||||
inquiries: {
|
||||
view: true,
|
||||
manage: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const VIEWER_PERMISSIONS: RolePermissions = {
|
||||
@@ -410,6 +426,10 @@ export const VIEWER_PERMISSIONS: RolePermissions = {
|
||||
delete: false,
|
||||
change_stage: false,
|
||||
},
|
||||
inquiries: {
|
||||
view: true,
|
||||
manage: false,
|
||||
},
|
||||
};
|
||||
|
||||
// Residential Partner - for an outside party who handles residential
|
||||
@@ -498,4 +518,8 @@ export const RESIDENTIAL_PARTNER_PERMISSIONS: RolePermissions = {
|
||||
delete: false,
|
||||
change_stage: true,
|
||||
},
|
||||
inquiries: {
|
||||
view: false,
|
||||
manage: false,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -384,6 +384,7 @@ export function makeFullPermissions(): RolePermissions {
|
||||
delete: true,
|
||||
change_stage: true,
|
||||
},
|
||||
inquiries: { view: true, manage: true },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -472,6 +473,7 @@ export function makeViewerPermissions(): RolePermissions {
|
||||
delete: false,
|
||||
change_stage: false,
|
||||
},
|
||||
inquiries: { view: true, manage: false },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -560,6 +562,7 @@ export function makeSalesAgentPermissions(): RolePermissions {
|
||||
delete: false,
|
||||
change_stage: false,
|
||||
},
|
||||
inquiries: { view: true, manage: true },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -648,6 +651,7 @@ export function makeSalesManagerPermissions(): RolePermissions {
|
||||
delete: true,
|
||||
change_stage: true,
|
||||
},
|
||||
inquiries: { view: true, manage: true },
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user