Files
edr-platform/apps/edr-freight-api/src/seed/freight-permissions.registry.ts
Hagernesh 59f06a9bd1 feat(warehouses): enforce yard/zone capacity limits; broaden dispatcher perms
Yard create/update now rejects capacities that overflow the parent warehouse,
and zone create/update rejects capacities that overflow the parent yard, via
BadRequestException. Dispatcher permission preset expanded to full CRUD on
warehouse and fleet management; allocation and fee rules remain view-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 12:15:47 +00:00

859 lines
47 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const EDR_FREIGHT_APP_KEY = 'edr_freight_app';
export type FreightPermissionSeed = {
id: string;
key: string;
name: { am: string; en: string };
applicationKey: string;
};
export const RULE_ENGINE_RESOURCE_SLUGS = [
'cargo-types',
'container-types',
'wagon-types',
'service-types',
'yards',
'shipping-lines',
'weight-limit-rules',
'priority-configs',
'rates',
'approval-rules',
'yard-distances',
] as const;
export type RuleEngineResourceSlug = (typeof RULE_ENGINE_RESOURCE_SLUGS)[number];
const slugToResourceKey = (slug: RuleEngineResourceSlug): string =>
slug.replace(/-/g, '_');
const perm = (
id: string,
key: string,
en: string,
): FreightPermissionSeed => ({
id,
key,
name: { am: en, en },
applicationKey: EDR_FREIGHT_APP_KEY,
});
export const BOOKING_PERMISSIONS: FreightPermissionSeed[] = [
perm('a1000001-0001-4000-8000-000000000001', 'edr_freight_app:bookings:view', 'View bookings'),
perm('a1000001-0001-4000-8000-000000000002', 'edr_freight_app:bookings:staff_accept', 'Accept booking intake'),
perm('a1000001-0001-4000-8000-000000000003', 'edr_freight_app:bookings:request_changes', 'Request booking changes'),
perm('a1000001-0001-4000-8000-000000000004', 'edr_freight_app:bookings:reject', 'Reject booking submission'),
perm('a1000001-0001-4000-8000-000000000005', 'edr_freight_app:bookings:approve_line_staff', 'Approve as line staff'),
perm('a1000001-0001-4000-8000-000000000006', 'edr_freight_app:bookings:approve_director', 'Approve as director'),
perm('a1000001-0001-4000-8000-000000000007', 'edr_freight_app:bookings:approve_ceo', 'Approve as CEO'),
perm('a1000001-0001-4000-8000-000000000008', 'edr_freight_app:bookings:reject_approval', 'Reject at approval step'),
perm('a1000001-0001-4000-8000-000000000009', 'edr_freight_app:bookings:generate_contract', 'Generate contract'),
perm('a1000001-0001-4000-8000-00000000000a', 'edr_freight_app:bookings:sign_staff', 'Staff contract signature'),
perm('a1000001-0001-4000-8000-00000000000b', 'edr_freight_app:bookings:payment_pnr', 'Generate PNR'),
perm('a1000001-0001-4000-8000-00000000000c', 'edr_freight_app:bookings:payment_verify', 'Verify payment'),
perm('a1000001-0001-4000-8000-00000000000d', 'edr_freight_app:bookings:operations', 'Booking operations'),
perm('a1000001-0001-4000-8000-00000000000e', 'edr_freight_app:bookings:cancel', 'Cancel booking'),
perm('a1000001-0001-4000-8000-000000000023', 'edr_freight_app:bookings:clearance_view', 'View customs-clearance queue'),
perm('a1000001-0001-4000-8000-000000000020', 'edr_freight_app:bookings:review_documents', 'Review clearance documents'),
perm('a1000001-0001-4000-8000-000000000021', 'edr_freight_app:bookings:upload_clearance_output', 'Upload customs output documents'),
perm('a1000001-0001-4000-8000-000000000022', 'edr_freight_app:bookings:finalize_clearance', 'Finalize document clearance'),
perm('a1000001-0001-4000-8000-00000000000f', 'edr_freight_app:train_scheduling:view', 'View train scheduling'),
perm('a1000001-0001-4000-8000-000000000010', 'edr_freight_app:train_scheduling:manage', 'Manage train scheduling'),
perm('a1000001-0001-4000-8000-000000000011', 'edr_freight_app:fleet:view', 'View fleet'),
perm('a1000001-0001-4000-8000-000000000012', 'edr_freight_app:fleet:manage', 'Manage fleet'),
perm('a1000001-0001-4000-8000-000000000013', 'edr_freight_app:admin', 'Freight administration'),
perm('a1000001-0001-4000-8000-000000000024', 'edr_freight_app:bookings:create', 'Create booking'),
];
/**
* Contract-phase permissions (contractbooking separation). Mirror the booking
* approval/sign/clearance permissions but scoped to the new contracts module.
*/
export const CONTRACT_PERMISSIONS: FreightPermissionSeed[] = [
perm('a3000001-0001-4000-8000-000000000001', 'edr_freight_app:contracts:view', 'View contracts'),
perm('a3000001-0001-4000-8000-000000000002', 'edr_freight_app:contracts:staff_accept', 'Accept contract intake'),
perm('a3000001-0001-4000-8000-000000000003', 'edr_freight_app:contracts:request_changes', 'Request contract changes'),
perm('a3000001-0001-4000-8000-000000000004', 'edr_freight_app:contracts:reject', 'Reject contract'),
perm('a3000001-0001-4000-8000-000000000005', 'edr_freight_app:contracts:approve_line_staff', 'Approve contract as line staff'),
perm('a3000001-0001-4000-8000-000000000006', 'edr_freight_app:contracts:approve_director', 'Approve contract as director'),
perm('a3000001-0001-4000-8000-000000000007', 'edr_freight_app:contracts:approve_ceo', 'Approve contract as CEO'),
perm('a3000001-0001-4000-8000-000000000008', 'edr_freight_app:contracts:generate_contract', 'Generate contract document'),
perm('a3000001-0001-4000-8000-000000000009', 'edr_freight_app:contracts:sign_staff', 'Staff contract signature'),
perm('a3000001-0001-4000-8000-00000000000a', 'edr_freight_app:contracts:clearance_review', 'Review pre-booking clearance docs'),
perm('a3000001-0001-4000-8000-00000000000b', 'edr_freight_app:contracts:finalize_clearance', 'Finalize pre-booking clearance'),
perm('a3000001-0001-4000-8000-00000000000c', 'edr_freight_app:contracts:create_booking', 'GL ET create booking under contract'),
perm('a3000001-0001-4000-8000-00000000000d', 'edr_freight_app:contracts:ops_clearance_review', 'Operations review of self-clearance docs (Path A)'),
perm('a3000001-0001-4000-8000-00000000000e', 'edr_freight_app:contracts:clearance_et_actions', 'GL Ethiopia phased clearance actions'),
perm('a3000001-0001-4000-8000-00000000000f', 'edr_freight_app:contracts:clearance_dj_actions', 'GL Djibouti phased clearance actions'),
perm('a3000001-0001-4000-8000-000000000010', 'edr_freight_app:contracts:clearance_duty_advise', 'Advise contract duty/tax'),
];
const RULE_ENGINE_PERMISSION_IDS: Record<RuleEngineResourceSlug, { view: string; manage: string }> = {
'cargo-types': { view: 'b2000001-0001-4000-8000-000000000001', manage: 'b2000001-0001-4000-8000-000000000002' },
'container-types': { view: 'b2000001-0001-4000-8000-000000000003', manage: 'b2000001-0001-4000-8000-000000000004' },
'wagon-types': { view: 'b2000001-0001-4000-8000-000000000015', manage: 'b2000001-0001-4000-8000-000000000016' },
'service-types': { view: 'b2000001-0001-4000-8000-000000000005', manage: 'b2000001-0001-4000-8000-000000000006' },
yards: { view: 'b2000001-0001-4000-8000-000000000007', manage: 'b2000001-0001-4000-8000-000000000008' },
'shipping-lines': { view: 'b2000001-0001-4000-8000-000000000009', manage: 'b2000001-0001-4000-8000-00000000000a' },
'weight-limit-rules': { view: 'b2000001-0001-4000-8000-00000000000b', manage: 'b2000001-0001-4000-8000-00000000000c' },
'priority-configs': { view: 'b2000001-0001-4000-8000-00000000000f', manage: 'b2000001-0001-4000-8000-000000000010' },
rates: { view: 'b2000001-0001-4000-8000-000000000011', manage: 'b2000001-0001-4000-8000-000000000012' },
'approval-rules': { view: 'b2000001-0001-4000-8000-000000000013', manage: 'b2000001-0001-4000-8000-000000000014' },
'yard-distances': { view: 'b2000001-0001-4000-8000-000000000018', manage: 'b2000001-0001-4000-8000-000000000019' },
};
/**
* Slugs whose changes go through a separate approver. `manage` lets a staff
* member propose a change; only `approve` lets someone put it into effect.
* Only listed slugs get the permission — the rest are manage-only.
*/
const RULE_ENGINE_APPROVE_PERMISSION_IDS: Partial<Record<RuleEngineResourceSlug, string>> = {
rates: 'b2000001-0001-4000-8000-000000000017',
};
export type RuleEngineApprovableSlug = 'rates';
export const RULE_ENGINE_PERMISSIONS: FreightPermissionSeed[] = RULE_ENGINE_RESOURCE_SLUGS.flatMap(
(slug) => {
const resource = slugToResourceKey(slug);
const ids = RULE_ENGINE_PERMISSION_IDS[slug];
const approveId = RULE_ENGINE_APPROVE_PERMISSION_IDS[slug];
return [
perm(ids.view, `edr_freight_app:rule_engine:${resource}:view`, `View ${slug}`),
perm(ids.manage, `edr_freight_app:rule_engine:${resource}:manage`, `Manage ${slug}`),
...(approveId
? [perm(approveId, `edr_freight_app:rule_engine:${resource}:approve`, `Approve ${slug} changes`)]
: []),
];
},
);
/**
* Container-allocation permission for the previously-unguarded
* booking allocate-containers endpoint.
*/
export const GAP_CONTROLLER_PERMISSIONS: FreightPermissionSeed[] = [
perm('c1000001-0001-4000-8000-000000000001', 'edr_freight_app:allocation:manage', 'Allocate containers to vehicles'),
];
/**
* Advanced backoffice resources — full CRUD + workflow-action keys.
* See docs/rbac/freight-backoffice-permissions.md. Additive only: the existing
* bookings/contracts/rule-engine/allocation keys above are unchanged.
*/
// C. Customers
export const CUSTOMER_PERMISSIONS: FreightPermissionSeed[] = [
perm('d1a00001-0001-4000-8000-000000000001', 'edr_freight_app:customers:view', 'View customers'),
perm('d1a00001-0001-4000-8000-000000000002', 'edr_freight_app:customers:create', 'Create customer'),
perm('d1a00001-0001-4000-8000-000000000003', 'edr_freight_app:customers:update', 'Update customer'),
perm('d1a00001-0001-4000-8000-000000000004', 'edr_freight_app:customers:deactivate', 'Deactivate customer'),
perm('d1a00001-0001-4000-8000-000000000005', 'edr_freight_app:customers:verify', 'Verify customer (KYC/Fayda)'),
perm('d1a00001-0001-4000-8000-000000000006', 'edr_freight_app:customers:reset-password', 'Trigger customer password reset'),
];
// D. Finance — payments + invoices
export const FINANCE_PERMISSIONS: FreightPermissionSeed[] = [
perm('d2a00001-0001-4000-8000-000000000001', 'edr_freight_app:payments:view', 'View payments'),
perm('d2a00001-0001-4000-8000-000000000002', 'edr_freight_app:payments:verify', 'Verify/settle payment'),
perm('d2a00001-0001-4000-8000-000000000003', 'edr_freight_app:payments:refund', 'Refund payment'),
perm('d2b00001-0001-4000-8000-000000000001', 'edr_freight_app:invoices:view', 'View invoices'),
perm('d2b00001-0001-4000-8000-000000000002', 'edr_freight_app:invoices:create', 'Generate invoice'),
perm('d2b00001-0001-4000-8000-000000000003', 'edr_freight_app:invoices:cancel', 'Cancel invoice'),
perm('d2b00001-0001-4000-8000-000000000004', 'edr_freight_app:invoices:export', 'Download invoice document'),
];
// E. First / last mile operations
export const MILE_PERMISSIONS: FreightPermissionSeed[] = [
perm('d3a00001-0001-4000-8000-000000000001', 'edr_freight_app:first_mile:view', 'View first-mile'),
perm('d3a00001-0001-4000-8000-000000000002', 'edr_freight_app:first_mile:accept', 'Accept first-mile request'),
perm('d3a00001-0001-4000-8000-000000000003', 'edr_freight_app:first_mile:create', 'Create first-mile'),
perm('d3a00001-0001-4000-8000-000000000004', 'edr_freight_app:first_mile:update', 'Update first-mile'),
perm('d3a00001-0001-4000-8000-000000000005', 'edr_freight_app:first_mile:delete', 'Delete first-mile'),
perm('d3a00001-0001-4000-8000-000000000006', 'edr_freight_app:first_mile:assign_vehicles', 'Assign first-mile vehicles'),
perm('d3a00001-0001-4000-8000-000000000007', 'edr_freight_app:first_mile:set_distances', 'Set first-mile distances'),
perm('d3a00001-0001-4000-8000-000000000008', 'edr_freight_app:first_mile:generate_invoice', 'Generate first-mile invoice'),
perm('d3b00001-0001-4000-8000-000000000001', 'edr_freight_app:last_mile:view', 'View last-mile'),
perm('d3b00001-0001-4000-8000-000000000002', 'edr_freight_app:last_mile:accept', 'Accept last-mile request'),
perm('d3b00001-0001-4000-8000-000000000003', 'edr_freight_app:last_mile:create', 'Create last-mile'),
perm('d3b00001-0001-4000-8000-000000000004', 'edr_freight_app:last_mile:update', 'Update last-mile'),
perm('d3b00001-0001-4000-8000-000000000005', 'edr_freight_app:last_mile:delete', 'Delete last-mile'),
perm('d3b00001-0001-4000-8000-000000000006', 'edr_freight_app:last_mile:assign_vehicles', 'Assign last-mile vehicles'),
perm('d3b00001-0001-4000-8000-000000000007', 'edr_freight_app:last_mile:set_distances', 'Set last-mile distances'),
perm('d3b00001-0001-4000-8000-000000000008', 'edr_freight_app:last_mile:generate_invoice', 'Generate last-mile invoice'),
];
// F. Fleet — rail assets (splits the flat fleet:view/manage)
export const FLEET_RAIL_PERMISSIONS: FreightPermissionSeed[] = [
perm('e1a00001-0001-4000-8000-000000000001', 'edr_freight_app:locomotives:view', 'View locomotives'),
perm('e1a00001-0001-4000-8000-000000000002', 'edr_freight_app:locomotives:create', 'Create locomotive'),
perm('e1a00001-0001-4000-8000-000000000003', 'edr_freight_app:locomotives:update', 'Update locomotive'),
perm('e1a00001-0001-4000-8000-000000000004', 'edr_freight_app:locomotives:delete', 'Delete locomotive'),
perm('e1b00001-0001-4000-8000-000000000001', 'edr_freight_app:wagons:view', 'View wagons'),
perm('e1b00001-0001-4000-8000-000000000002', 'edr_freight_app:wagons:create', 'Create wagon'),
perm('e1b00001-0001-4000-8000-000000000003', 'edr_freight_app:wagons:update', 'Update wagon'),
perm('e1b00001-0001-4000-8000-000000000004', 'edr_freight_app:wagons:delete', 'Delete wagon'),
perm('e1b00001-0001-4000-8000-000000000005', 'edr_freight_app:wagons:transfer_request', 'Request wagon transfer'),
perm('e1b00001-0001-4000-8000-000000000006', 'edr_freight_app:wagons:transfer_fulfill', 'Fulfil wagon transfer (OCC)'),
perm('e1b00001-0001-4000-8000-000000000007', 'edr_freight_app:wagons:transfer_history_all', "View all staff's transfer history"),
perm('e1c00001-0001-4000-8000-000000000001', 'edr_freight_app:trains:view', 'View trains'),
perm('e1c00001-0001-4000-8000-000000000002', 'edr_freight_app:trains:create', 'Create train'),
perm('e1c00001-0001-4000-8000-000000000003', 'edr_freight_app:trains:update', 'Update train'),
perm('e1c00001-0001-4000-8000-000000000004', 'edr_freight_app:trains:delete', 'Delete train'),
perm('e1c00001-0001-4000-8000-000000000005', 'edr_freight_app:trains:assign_wagons', 'Assign wagons to train'),
perm('e1d00001-0001-4000-8000-000000000001', 'edr_freight_app:routes:view', 'View routes'),
perm('e1d00001-0001-4000-8000-000000000002', 'edr_freight_app:routes:create', 'Create route'),
perm('e1d00001-0001-4000-8000-000000000003', 'edr_freight_app:routes:update', 'Update route'),
perm('e1d00001-0001-4000-8000-000000000004', 'edr_freight_app:routes:delete', 'Delete route'),
perm('e1e00001-0001-4000-8000-000000000001', 'edr_freight_app:containers:view', 'View containers'),
perm('e1e00001-0001-4000-8000-000000000002', 'edr_freight_app:containers:create', 'Create container'),
perm('e1e00001-0001-4000-8000-000000000003', 'edr_freight_app:containers:update', 'Update container'),
perm('e1e00001-0001-4000-8000-000000000004', 'edr_freight_app:containers:delete', 'Delete container'),
perm('e1f00001-0001-4000-8000-000000000001', 'edr_freight_app:cargoes:view', 'View cargoes'),
perm('e1f00001-0001-4000-8000-000000000002', 'edr_freight_app:cargoes:create', 'Create cargo'),
perm('e1f00001-0001-4000-8000-000000000003', 'edr_freight_app:cargoes:update', 'Update cargo'),
perm('e1f00001-0001-4000-8000-000000000004', 'edr_freight_app:cargoes:delete', 'Delete cargo'),
];
// G. Fleet — road & telemetry
export const FLEET_ROAD_PERMISSIONS: FreightPermissionSeed[] = [
perm('e2a00001-0001-4000-8000-000000000001', 'edr_freight_app:vehicles:view', 'View vehicles'),
perm('e2a00001-0001-4000-8000-000000000002', 'edr_freight_app:vehicles:create', 'Create vehicle'),
perm('e2a00001-0001-4000-8000-000000000003', 'edr_freight_app:vehicles:update', 'Update vehicle'),
perm('e2a00001-0001-4000-8000-000000000004', 'edr_freight_app:vehicles:delete', 'Delete vehicle'),
perm('e2b00001-0001-4000-8000-000000000001', 'edr_freight_app:drivers:view', 'View drivers'),
perm('e2b00001-0001-4000-8000-000000000002', 'edr_freight_app:drivers:create', 'Create driver'),
perm('e2b00001-0001-4000-8000-000000000003', 'edr_freight_app:drivers:update', 'Update driver'),
perm('e2b00001-0001-4000-8000-000000000004', 'edr_freight_app:drivers:delete', 'Delete driver'),
perm('e2c00001-0001-4000-8000-000000000001', 'edr_freight_app:tracking:view', 'Track vehicles'),
perm('e2c00001-0001-4000-8000-000000000002', 'edr_freight_app:tracking:manage', 'Manage GPS trackers'),
perm('e2d00001-0001-4000-8000-000000000001', 'edr_freight_app:fuel:view', 'View fuel purchases'),
perm('e2d00001-0001-4000-8000-000000000002', 'edr_freight_app:fuel:create', 'Create fuel purchase'),
perm('e2d00001-0001-4000-8000-000000000003', 'edr_freight_app:fuel:update', 'Update fuel purchase'),
perm('e2d00001-0001-4000-8000-000000000004', 'edr_freight_app:fuel:delete', 'Delete fuel purchase'),
perm('e2d00001-0001-4000-8000-000000000005', 'edr_freight_app:fuel:approve', 'Approve fuel purchase'),
perm('e2e00001-0001-4000-8000-000000000001', 'edr_freight_app:maintenance:view', 'View maintenance'),
perm('e2e00001-0001-4000-8000-000000000002', 'edr_freight_app:maintenance:create', 'Create maintenance'),
perm('e2e00001-0001-4000-8000-000000000003', 'edr_freight_app:maintenance:update', 'Update maintenance'),
perm('e2e00001-0001-4000-8000-000000000004', 'edr_freight_app:maintenance:delete', 'Delete maintenance'),
perm('e2e00001-0001-4000-8000-000000000005', 'edr_freight_app:maintenance:complete', 'Complete maintenance'),
perm('e2f00001-0001-4000-8000-000000000001', 'edr_freight_app:fleet_reports:view', 'View fleet financial reports'),
perm('e2f00001-0001-4000-8000-000000000002', 'edr_freight_app:fleet_reports:export', 'Export fleet financial reports'),
perm('e2000001-0001-4000-8000-000000000001', 'edr_freight_app:fleet_dashboard:view', 'View fleet dashboard'),
];
// H. Warehouse management
export const WAREHOUSE_PERMISSIONS: FreightPermissionSeed[] = [
perm('f1000001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_dashboard:view', 'View warehouse dashboard'),
perm('f1a00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouses:view', 'View warehouses'),
perm('f1a00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouses:create', 'Create warehouse'),
perm('f1a00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouses:update', 'Update warehouse'),
perm('f1a00001-0001-4000-8000-000000000004', 'edr_freight_app:warehouses:delete', 'Delete warehouse'),
perm('f1b00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_yards:view', 'View warehouse yards'),
perm('f1b00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_yards:create', 'Create warehouse yard'),
perm('f1b00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_yards:update', 'Update warehouse yard'),
perm('f1b00001-0001-4000-8000-000000000004', 'edr_freight_app:warehouse_yards:delete', 'Delete warehouse yard'),
perm('f1c00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_zones:view', 'View warehouse zones'),
perm('f1c00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_zones:create', 'Create warehouse zone'),
perm('f1c00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_zones:update', 'Update warehouse zone'),
perm('f1d00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_allocation_rules:view', 'View allocation rules'),
perm('f1d00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_allocation_rules:create', 'Create allocation rule'),
perm('f1d00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_allocation_rules:update', 'Update allocation rule'),
perm('f1d00001-0001-4000-8000-000000000004', 'edr_freight_app:warehouse_allocation_rules:delete', 'Delete allocation rule'),
perm('f1e00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_fee_rules:view', 'View fee rules'),
perm('f1e00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_fee_rules:create', 'Create fee rule'),
perm('f1e00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_fee_rules:update', 'Update fee rule'),
perm('f1e00001-0001-4000-8000-000000000004', 'edr_freight_app:warehouse_fee_rules:delete', 'Delete fee rule'),
perm('f1f00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_inspection_reports:view', 'View inspection reports'),
perm('f1f00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_inspection_reports:create', 'Create inspection report'),
perm('f1f00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_inspection_reports:update', 'Update inspection report'),
];
// I. Port & terminal — inventory movement + interchange + fee invoices
export const PORT_TERMINAL_PERMISSIONS: FreightPermissionSeed[] = [
perm('f2a00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_inventory:view', 'View terminal inventory'),
perm('f2a00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_inventory:receive', 'Receive inventory'),
perm('f2a00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_inventory:move', 'Move/store/reserve inventory'),
perm('f2a00001-0001-4000-8000-000000000004', 'edr_freight_app:warehouse_inventory:load', 'Load inventory'),
perm('f2a00001-0001-4000-8000-000000000005', 'edr_freight_app:warehouse_inventory:unload', 'Unload inventory'),
perm('f2a00001-0001-4000-8000-000000000006', 'edr_freight_app:warehouse_inventory:dispatch', 'Dispatch inventory'),
perm('f2a00001-0001-4000-8000-000000000007', 'edr_freight_app:warehouse_inventory:gate_pass', 'Gate-clearance inventory'),
perm('f2a00001-0001-4000-8000-000000000008', 'edr_freight_app:warehouse_inventory:release', 'Release inventory'),
perm('f2a00001-0001-4000-8000-000000000009', 'edr_freight_app:warehouse_inventory:deliver', 'Deliver inventory'),
perm('f2a00001-0001-4000-8000-00000000000a', 'edr_freight_app:warehouse_inventory:inspect', 'Inspect inventory'),
perm('f2b00001-0001-4000-8000-000000000001', 'edr_freight_app:interchange_documents:view', 'View interchange documents'),
perm('f2b00001-0001-4000-8000-000000000002', 'edr_freight_app:interchange_documents:generate', 'Generate interchange document'),
perm('f2b00001-0001-4000-8000-000000000003', 'edr_freight_app:interchange_documents:acknowledge', 'Acknowledge interchange document'),
perm('f2b00001-0001-4000-8000-000000000004', 'edr_freight_app:interchange_documents:dispute', 'Dispute interchange document'),
perm('f2b00001-0001-4000-8000-000000000005', 'edr_freight_app:interchange_documents:cancel', 'Cancel interchange document'),
perm('f2c00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_fee_invoices:view', 'View warehouse fee invoices'),
perm('f2c00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_fee_invoices:generate', 'Generate warehouse fee invoice'),
perm('f2c00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_fee_invoices:cancel', 'Cancel warehouse fee invoice'),
perm('f2c00001-0001-4000-8000-000000000004', 'edr_freight_app:warehouse_fee_invoices:pay', 'Pay warehouse fee invoice'),
];
// E'. Train-scheduling finer actions (augment existing view/manage)
export const SCHEDULING_EXTRA_PERMISSIONS: FreightPermissionSeed[] = [
perm('a2a00001-0001-4000-8000-000000000001', 'edr_freight_app:train_scheduling:create', 'Create train schedule'),
perm('a2a00001-0001-4000-8000-000000000002', 'edr_freight_app:train_scheduling:update', 'Update train schedule'),
perm('a2a00001-0001-4000-8000-000000000003', 'edr_freight_app:train_scheduling:cancel', 'Cancel train schedule'),
perm('a2a00001-0001-4000-8000-000000000004', 'edr_freight_app:train_scheduling:reschedule', 'Reschedule train'),
perm('a2a00001-0001-4000-8000-000000000005', 'edr_freight_app:train_scheduling:rules_manage', 'Manage global scheduling rules'),
];
// L. Administration & settings (split from the coarse admin umbrella)
export const CONFIG_SETTINGS_PERMISSIONS: FreightPermissionSeed[] = [
perm('b3a00001-0001-4000-8000-000000000001', 'edr_freight_app:config:contract_validity:view', 'View contract validity periods'),
perm('b3a00001-0001-4000-8000-000000000002', 'edr_freight_app:config:contract_validity:manage', 'Manage contract validity periods'),
perm('b4a00001-0001-4000-8000-000000000001', 'edr_freight_app:settings:file_upload:view', 'View file-upload settings'),
perm('b4a00001-0001-4000-8000-000000000002', 'edr_freight_app:settings:file_upload:manage', 'Manage file-upload settings'),
perm('b4b00001-0001-4000-8000-000000000001', 'edr_freight_app:settings:dropdown:view', 'View dropdown settings'),
perm('b4b00001-0001-4000-8000-000000000002', 'edr_freight_app:settings:dropdown:manage', 'Manage dropdown settings'),
];
// M. Staff / IAM admin — NEW keys only. The employee_registration / role_assignment
// / hierarchy_* / position_types:view keys are seeded separately in edr-freight.seed.ts.
export const STAFF_IAM_PERMISSIONS: FreightPermissionSeed[] = [
perm('c2a00001-0001-4000-8000-000000000001', 'edr_freight_app:staff:roles:view', 'View roles'),
perm('c2a00001-0001-4000-8000-000000000002', 'edr_freight_app:staff:roles:create', 'Create role'),
perm('c2a00001-0001-4000-8000-000000000003', 'edr_freight_app:staff:roles:update', 'Update role'),
perm('c2a00001-0001-4000-8000-000000000004', 'edr_freight_app:staff:roles:delete', 'Delete role'),
perm('c2b00001-0001-4000-8000-000000000001', 'edr_freight_app:staff:permissions:view', 'View permission assignments'),
perm('c2b00001-0001-4000-8000-000000000002', 'edr_freight_app:staff:permissions:assign', 'Assign permissions'),
perm('c2c00001-0001-4000-8000-000000000001', 'edr_freight_app:position_types:create', 'Create position type'),
perm('c2c00001-0001-4000-8000-000000000002', 'edr_freight_app:position_types:update', 'Update position type'),
perm('c2c00001-0001-4000-8000-000000000003', 'edr_freight_app:position_types:delete', 'Delete position type'),
];
export const ADVANCED_BACKOFFICE_PERMISSIONS: FreightPermissionSeed[] = [
...CUSTOMER_PERMISSIONS,
...FINANCE_PERMISSIONS,
...MILE_PERMISSIONS,
...FLEET_RAIL_PERMISSIONS,
...FLEET_ROAD_PERMISSIONS,
...WAREHOUSE_PERMISSIONS,
...PORT_TERMINAL_PERMISSIONS,
...SCHEDULING_EXTRA_PERMISSIONS,
...CONFIG_SETTINGS_PERMISSIONS,
...STAFF_IAM_PERMISSIONS,
];
export const BOOKING_RULE_ENGINE_PERMISSIONS = [
...BOOKING_PERMISSIONS,
...CONTRACT_PERMISSIONS,
...RULE_ENGINE_PERMISSIONS,
...GAP_CONTROLLER_PERMISSIONS,
...ADVANCED_BACKOFFICE_PERMISSIONS,
];
export const BOOKING_RULE_ENGINE_PERMISSION_KEYS = BOOKING_RULE_ENGINE_PERMISSIONS.map(
(p) => p.key,
);
export const FREIGHT_PERMS = {
bookings: {
view: 'edr_freight_app:bookings:view',
create: 'edr_freight_app:bookings:create',
clearanceView: 'edr_freight_app:bookings:clearance_view',
staffAccept: 'edr_freight_app:bookings:staff_accept',
requestChanges: 'edr_freight_app:bookings:request_changes',
reject: 'edr_freight_app:bookings:reject',
approveLineStaff: 'edr_freight_app:bookings:approve_line_staff',
approveDirector: 'edr_freight_app:bookings:approve_director',
approveCeo: 'edr_freight_app:bookings:approve_ceo',
rejectApproval: 'edr_freight_app:bookings:reject_approval',
generateContract: 'edr_freight_app:bookings:generate_contract',
signStaff: 'edr_freight_app:bookings:sign_staff',
operations: 'edr_freight_app:bookings:operations',
cancel: 'edr_freight_app:bookings:cancel',
reviewDocuments: 'edr_freight_app:bookings:review_documents',
uploadClearanceOutput: 'edr_freight_app:bookings:upload_clearance_output',
finalizeClearance: 'edr_freight_app:bookings:finalize_clearance',
},
contracts: {
view: 'edr_freight_app:contracts:view',
staffAccept: 'edr_freight_app:contracts:staff_accept',
requestChanges: 'edr_freight_app:contracts:request_changes',
reject: 'edr_freight_app:contracts:reject',
approveLineStaff: 'edr_freight_app:contracts:approve_line_staff',
approveDirector: 'edr_freight_app:contracts:approve_director',
approveCeo: 'edr_freight_app:contracts:approve_ceo',
generateContract: 'edr_freight_app:contracts:generate_contract',
signStaff: 'edr_freight_app:contracts:sign_staff',
clearanceReview: 'edr_freight_app:contracts:clearance_review',
finalizeClearance: 'edr_freight_app:contracts:finalize_clearance',
createBooking: 'edr_freight_app:contracts:create_booking',
opsClearanceReview: 'edr_freight_app:contracts:ops_clearance_review',
clearanceEtActions: 'edr_freight_app:contracts:clearance_et_actions',
clearanceDjActions: 'edr_freight_app:contracts:clearance_dj_actions',
clearanceDutyAdvise: 'edr_freight_app:contracts:clearance_duty_advise',
},
trainScheduling: {
view: 'edr_freight_app:train_scheduling:view',
manage: 'edr_freight_app:train_scheduling:manage',
create: 'edr_freight_app:train_scheduling:create',
update: 'edr_freight_app:train_scheduling:update',
cancel: 'edr_freight_app:train_scheduling:cancel',
reschedule: 'edr_freight_app:train_scheduling:reschedule',
rulesManage: 'edr_freight_app:train_scheduling:rules_manage',
},
fleet: {
view: 'edr_freight_app:fleet:view',
manage: 'edr_freight_app:fleet:manage',
},
admin: 'edr_freight_app:admin',
ruleEngine: {
view: (slug: RuleEngineResourceSlug) =>
`edr_freight_app:rule_engine:${slugToResourceKey(slug)}:view`,
manage: (slug: RuleEngineResourceSlug) =>
`edr_freight_app:rule_engine:${slugToResourceKey(slug)}:manage`,
approve: (slug: RuleEngineApprovableSlug) =>
`edr_freight_app:rule_engine:${slugToResourceKey(slug)}:approve`,
},
allocation: {
manage: 'edr_freight_app:allocation:manage',
},
customers: {
view: 'edr_freight_app:customers:view',
create: 'edr_freight_app:customers:create',
update: 'edr_freight_app:customers:update',
deactivate: 'edr_freight_app:customers:deactivate',
verify: 'edr_freight_app:customers:verify',
resetPassword: 'edr_freight_app:customers:reset-password',
},
payments: {
view: 'edr_freight_app:payments:view',
verify: 'edr_freight_app:payments:verify',
refund: 'edr_freight_app:payments:refund',
},
invoices: {
view: 'edr_freight_app:invoices:view',
create: 'edr_freight_app:invoices:create',
cancel: 'edr_freight_app:invoices:cancel',
export: 'edr_freight_app:invoices:export',
},
firstMile: {
view: 'edr_freight_app:first_mile:view',
accept: 'edr_freight_app:first_mile:accept',
create: 'edr_freight_app:first_mile:create',
update: 'edr_freight_app:first_mile:update',
delete: 'edr_freight_app:first_mile:delete',
assignVehicles: 'edr_freight_app:first_mile:assign_vehicles',
setDistances: 'edr_freight_app:first_mile:set_distances',
generateInvoice: 'edr_freight_app:first_mile:generate_invoice',
},
lastMile: {
view: 'edr_freight_app:last_mile:view',
accept: 'edr_freight_app:last_mile:accept',
create: 'edr_freight_app:last_mile:create',
update: 'edr_freight_app:last_mile:update',
delete: 'edr_freight_app:last_mile:delete',
assignVehicles: 'edr_freight_app:last_mile:assign_vehicles',
setDistances: 'edr_freight_app:last_mile:set_distances',
generateInvoice: 'edr_freight_app:last_mile:generate_invoice',
},
locomotives: {
view: 'edr_freight_app:locomotives:view',
create: 'edr_freight_app:locomotives:create',
update: 'edr_freight_app:locomotives:update',
delete: 'edr_freight_app:locomotives:delete',
},
wagons: {
view: 'edr_freight_app:wagons:view',
create: 'edr_freight_app:wagons:create',
update: 'edr_freight_app:wagons:update',
delete: 'edr_freight_app:wagons:delete',
// Requester creates a transfer request; OCC fulfils it (picks the wagons and
// executes the move). Distinct keys so OCC can hold fulfil without request.
transferRequest: 'edr_freight_app:wagons:transfer_request',
transferFulfill: 'edr_freight_app:wagons:transfer_fulfill',
// Admin: read every staffer's transfer history. Without it, a user only sees
// their own (the /history endpoint uses the caller id, backend-enforced).
transferHistoryAll: 'edr_freight_app:wagons:transfer_history_all',
},
trains: {
view: 'edr_freight_app:trains:view',
create: 'edr_freight_app:trains:create',
update: 'edr_freight_app:trains:update',
delete: 'edr_freight_app:trains:delete',
assignWagons: 'edr_freight_app:trains:assign_wagons',
},
routes: {
view: 'edr_freight_app:routes:view',
create: 'edr_freight_app:routes:create',
update: 'edr_freight_app:routes:update',
delete: 'edr_freight_app:routes:delete',
},
containers: {
view: 'edr_freight_app:containers:view',
create: 'edr_freight_app:containers:create',
update: 'edr_freight_app:containers:update',
delete: 'edr_freight_app:containers:delete',
},
cargoes: {
view: 'edr_freight_app:cargoes:view',
create: 'edr_freight_app:cargoes:create',
update: 'edr_freight_app:cargoes:update',
delete: 'edr_freight_app:cargoes:delete',
},
vehicles: {
view: 'edr_freight_app:vehicles:view',
create: 'edr_freight_app:vehicles:create',
update: 'edr_freight_app:vehicles:update',
delete: 'edr_freight_app:vehicles:delete',
},
drivers: {
view: 'edr_freight_app:drivers:view',
create: 'edr_freight_app:drivers:create',
update: 'edr_freight_app:drivers:update',
delete: 'edr_freight_app:drivers:delete',
},
tracking: {
view: 'edr_freight_app:tracking:view',
manage: 'edr_freight_app:tracking:manage',
},
fuel: {
view: 'edr_freight_app:fuel:view',
create: 'edr_freight_app:fuel:create',
update: 'edr_freight_app:fuel:update',
delete: 'edr_freight_app:fuel:delete',
approve: 'edr_freight_app:fuel:approve',
},
maintenance: {
view: 'edr_freight_app:maintenance:view',
create: 'edr_freight_app:maintenance:create',
update: 'edr_freight_app:maintenance:update',
delete: 'edr_freight_app:maintenance:delete',
complete: 'edr_freight_app:maintenance:complete',
},
fleetReports: {
view: 'edr_freight_app:fleet_reports:view',
export: 'edr_freight_app:fleet_reports:export',
},
fleetDashboard: {
view: 'edr_freight_app:fleet_dashboard:view',
},
warehouseDashboard: {
view: 'edr_freight_app:warehouse_dashboard:view',
},
warehouses: {
view: 'edr_freight_app:warehouses:view',
create: 'edr_freight_app:warehouses:create',
update: 'edr_freight_app:warehouses:update',
delete: 'edr_freight_app:warehouses:delete',
},
warehouseYards: {
view: 'edr_freight_app:warehouse_yards:view',
create: 'edr_freight_app:warehouse_yards:create',
update: 'edr_freight_app:warehouse_yards:update',
delete: 'edr_freight_app:warehouse_yards:delete',
},
warehouseZones: {
view: 'edr_freight_app:warehouse_zones:view',
create: 'edr_freight_app:warehouse_zones:create',
update: 'edr_freight_app:warehouse_zones:update',
},
warehouseAllocationRules: {
view: 'edr_freight_app:warehouse_allocation_rules:view',
create: 'edr_freight_app:warehouse_allocation_rules:create',
update: 'edr_freight_app:warehouse_allocation_rules:update',
delete: 'edr_freight_app:warehouse_allocation_rules:delete',
},
warehouseFeeRules: {
view: 'edr_freight_app:warehouse_fee_rules:view',
create: 'edr_freight_app:warehouse_fee_rules:create',
update: 'edr_freight_app:warehouse_fee_rules:update',
delete: 'edr_freight_app:warehouse_fee_rules:delete',
},
warehouseInspectionReports: {
view: 'edr_freight_app:warehouse_inspection_reports:view',
create: 'edr_freight_app:warehouse_inspection_reports:create',
update: 'edr_freight_app:warehouse_inspection_reports:update',
},
warehouseInventory: {
view: 'edr_freight_app:warehouse_inventory:view',
receive: 'edr_freight_app:warehouse_inventory:receive',
move: 'edr_freight_app:warehouse_inventory:move',
load: 'edr_freight_app:warehouse_inventory:load',
unload: 'edr_freight_app:warehouse_inventory:unload',
dispatch: 'edr_freight_app:warehouse_inventory:dispatch',
gatePass: 'edr_freight_app:warehouse_inventory:gate_pass',
release: 'edr_freight_app:warehouse_inventory:release',
deliver: 'edr_freight_app:warehouse_inventory:deliver',
inspect: 'edr_freight_app:warehouse_inventory:inspect',
},
interchangeDocuments: {
view: 'edr_freight_app:interchange_documents:view',
generate: 'edr_freight_app:interchange_documents:generate',
acknowledge: 'edr_freight_app:interchange_documents:acknowledge',
dispute: 'edr_freight_app:interchange_documents:dispute',
cancel: 'edr_freight_app:interchange_documents:cancel',
},
warehouseFeeInvoices: {
view: 'edr_freight_app:warehouse_fee_invoices:view',
generate: 'edr_freight_app:warehouse_fee_invoices:generate',
cancel: 'edr_freight_app:warehouse_fee_invoices:cancel',
pay: 'edr_freight_app:warehouse_fee_invoices:pay',
},
config: {
contractValidity: {
view: 'edr_freight_app:config:contract_validity:view',
manage: 'edr_freight_app:config:contract_validity:manage',
},
},
settings: {
fileUpload: {
view: 'edr_freight_app:settings:file_upload:view',
manage: 'edr_freight_app:settings:file_upload:manage',
},
dropdown: {
view: 'edr_freight_app:settings:dropdown:view',
manage: 'edr_freight_app:settings:dropdown:manage',
},
},
staff: {
roles: {
view: 'edr_freight_app:staff:roles:view',
create: 'edr_freight_app:staff:roles:create',
update: 'edr_freight_app:staff:roles:update',
delete: 'edr_freight_app:staff:roles:delete',
},
permissions: {
view: 'edr_freight_app:staff:permissions:view',
assign: 'edr_freight_app:staff:permissions:assign',
},
// Seeded in edr-freight.seed.ts (EDR_FREIGHT_PERMISSIONS) — surfaced here for gating.
employeeRegistration: {
view: 'edr_freight_app:employee_registration:view',
create: 'edr_freight_app:employee_registration:create',
update: 'edr_freight_app:employee_registration:update',
activate: 'edr_freight_app:employee_registration:activate',
deactivate: 'edr_freight_app:employee_registration:deactivate',
},
roleAssignment: {
view: 'edr_freight_app:role_assignment:view',
assign: 'edr_freight_app:role_assignment:assign',
replace: 'edr_freight_app:role_assignment:replace',
},
hierarchyUnits: {
view: 'edr_freight_app:hierarchy_units:view',
create: 'edr_freight_app:hierarchy_units:create',
update: 'edr_freight_app:hierarchy_units:update',
delete: 'edr_freight_app:hierarchy_units:delete',
},
hierarchyPositions: {
view: 'edr_freight_app:hierarchy_positions:view',
create: 'edr_freight_app:hierarchy_positions:create',
update: 'edr_freight_app:hierarchy_positions:update',
delete: 'edr_freight_app:hierarchy_positions:delete',
changeParent: 'edr_freight_app:hierarchy_positions:change_parent',
},
hierarchyEmployeeAssignment: {
view: 'edr_freight_app:hierarchy_employee_assignment:view',
invite: 'edr_freight_app:hierarchy_employee_assignment:invite',
assign: 'edr_freight_app:hierarchy_employee_assignment:assign',
},
positionTypes: {
view: 'edr_freight_app:position_types:view',
create: 'edr_freight_app:position_types:create',
update: 'edr_freight_app:position_types:update',
delete: 'edr_freight_app:position_types:delete',
},
},
} as const;
const allRuleEngineViewKeys = () =>
RULE_ENGINE_RESOURCE_SLUGS.map((s) => FREIGHT_PERMS.ruleEngine.view(s));
export const ROLE_PERMISSION_PRESETS = {
// Marketing / line staff: drives a booking from intake through line-staff
// approval and contract generation/signing — i.e. until the contract is ready
// and signed. No director/CEO approval, no scheduling, no operations.
lineStaff: [
FREIGHT_PERMS.bookings.view,
FREIGHT_PERMS.bookings.staffAccept,
FREIGHT_PERMS.bookings.requestChanges,
FREIGHT_PERMS.bookings.reject,
FREIGHT_PERMS.bookings.approveLineStaff,
FREIGHT_PERMS.bookings.rejectApproval,
FREIGHT_PERMS.bookings.cancel,
FREIGHT_PERMS.contracts.view,
FREIGHT_PERMS.contracts.staffAccept,
FREIGHT_PERMS.contracts.requestChanges,
FREIGHT_PERMS.contracts.reject,
FREIGHT_PERMS.contracts.approveLineStaff,
...allRuleEngineViewKeys(),
],
// Operations Officer: train scheduling + wagon allocation + transit/complete
// + fleet management (wagons, trains, locomotives, routes, containers, cargo).
operationsOfficer: [
FREIGHT_PERMS.bookings.view,
FREIGHT_PERMS.bookings.operations,
FREIGHT_PERMS.trainScheduling.view,
FREIGHT_PERMS.trainScheduling.manage,
FREIGHT_PERMS.fleet.view,
FREIGHT_PERMS.fleet.manage,
// Path A (no customs): Operations reviews the customer's self-clearance docs
// — on the contract for ONE_TIME contracts, and PER BOOKING for GENERAL
// contracts (booking-level document review → finalize → CLEARANCE_READY).
FREIGHT_PERMS.contracts.view,
FREIGHT_PERMS.contracts.opsClearanceReview,
FREIGHT_PERMS.bookings.clearanceView,
FREIGHT_PERMS.bookings.reviewDocuments,
FREIGHT_PERMS.bookings.finalizeClearance,
...allRuleEngineViewKeys(),
],
director: [
FREIGHT_PERMS.bookings.view,
FREIGHT_PERMS.bookings.approveDirector,
FREIGHT_PERMS.bookings.rejectApproval,
FREIGHT_PERMS.bookings.generateContract,
FREIGHT_PERMS.contracts.view,
FREIGHT_PERMS.contracts.approveDirector,
FREIGHT_PERMS.contracts.generateContract,
...allRuleEngineViewKeys(),
],
ceo: [
FREIGHT_PERMS.bookings.view,
FREIGHT_PERMS.bookings.approveCeo,
FREIGHT_PERMS.bookings.rejectApproval,
FREIGHT_PERMS.contracts.view,
FREIGHT_PERMS.contracts.approveCeo,
...allRuleEngineViewKeys(),
],
finance: [FREIGHT_PERMS.bookings.view],
// Global Logistics: manages ONLY the customs-clearance queue. Scoped out of
// the general booking-request list (no bookings:view) — instead a dedicated
// clearance:view permission lists the clearance bookings. Reviews customer
// clearance documents, uploads customs output documents, and finalizes the
// clearance gate.
// GL Ethiopia (edr_gl_ethiopia): reviews pre-booking clearance docs on the
// contract, uploads ET output docs, finalizes clearance, and EXCLUSIVELY creates
// the booking under a customs contract (Path B). Also runs post-booking ET
// milestones + the legacy booking-clearance permissions during migration.
glEthiopia: [
FREIGHT_PERMS.contracts.view,
FREIGHT_PERMS.contracts.clearanceReview,
FREIGHT_PERMS.contracts.finalizeClearance,
FREIGHT_PERMS.contracts.createBooking,
FREIGHT_PERMS.contracts.clearanceEtActions,
FREIGHT_PERMS.contracts.clearanceDutyAdvise,
FREIGHT_PERMS.bookings.clearanceView,
FREIGHT_PERMS.bookings.reviewDocuments,
FREIGHT_PERMS.bookings.uploadClearanceOutput,
FREIGHT_PERMS.bookings.finalizeClearance,
FREIGHT_PERMS.bookings.operations,
],
// GL Djibouti (edr_gl_djibouti): DO/RO collection, gatepass, loading milestones,
// damage reports. Read-only on the contract; no booking creation.
glDjibouti: [
FREIGHT_PERMS.contracts.view,
FREIGHT_PERMS.contracts.clearanceDjActions,
FREIGHT_PERMS.bookings.clearanceView,
FREIGHT_PERMS.bookings.uploadClearanceOutput,
FREIGHT_PERMS.bookings.operations,
],
// Marketing handles intake through contract (same as line staff here) and,
// for non-customs bookings, reviews/finalizes the customer's clearance
// documents from the booking detail (customs bookings go to Global Logistics).
marketing: [
FREIGHT_PERMS.bookings.view,
FREIGHT_PERMS.bookings.staffAccept,
FREIGHT_PERMS.bookings.requestChanges,
FREIGHT_PERMS.bookings.reject,
FREIGHT_PERMS.bookings.approveLineStaff,
FREIGHT_PERMS.bookings.rejectApproval,
FREIGHT_PERMS.bookings.cancel,
FREIGHT_PERMS.bookings.generateContract,
FREIGHT_PERMS.bookings.signStaff,
FREIGHT_PERMS.bookings.reviewDocuments,
FREIGHT_PERMS.bookings.finalizeClearance,
FREIGHT_PERMS.contracts.view,
FREIGHT_PERMS.contracts.staffAccept,
FREIGHT_PERMS.contracts.requestChanges,
FREIGHT_PERMS.contracts.reject,
FREIGHT_PERMS.contracts.approveLineStaff,
FREIGHT_PERMS.contracts.generateContract,
FREIGHT_PERMS.contracts.signStaff,
],
orgManager: [...BOOKING_RULE_ENGINE_PERMISSION_KEYS],
} as const;
/**
* Position permission presets (positions-as-roles). Grants flow to users via
* Position → PositionPermission (NOT Role/RolePermission). Each reuses the
* matching ROLE_PERMISSION_PRESETS key-array as a building block and adds the
* gap-controller keys the position needs. Deduped via Set.
*/
const dedupe = (keys: string[]): string[] => [...new Set(keys)];
export const POSITION_PERMISSION_PRESETS = {
// Chief: senior operational role — intake/line-staff approval + director
// approval + scheduling/ops, plus container allocation.
chief: dedupe([
...ROLE_PERMISSION_PRESETS.lineStaff,
...ROLE_PERMISSION_PRESETS.director,
...ROLE_PERMISSION_PRESETS.operationsOfficer,
FREIGHT_PERMS.allocation.manage,
]),
director: dedupe([...ROLE_PERMISSION_PRESETS.director]),
ceo: dedupe([...ROLE_PERMISSION_PRESETS.ceo]),
ethiopianGl: dedupe([...ROLE_PERMISSION_PRESETS.glEthiopia]),
djiboutiGl: dedupe([...ROLE_PERMISSION_PRESETS.glDjibouti]),
marketer: dedupe([...ROLE_PERMISSION_PRESETS.marketing]),
operation: dedupe([
...ROLE_PERMISSION_PRESETS.operationsOfficer,
FREIGHT_PERMS.allocation.manage,
]),
// Operations Chief: full operational authority — the entire freight
// permission catalog (all CRUD across bookings, contracts, scheduling,
// fleet, warehouse, mile, finance, settings, staff).
operationsChief: dedupe([...BOOKING_RULE_ENGINE_PERMISSION_KEYS]),
// Dispatcher: full CRUD on warehouse management (incl. import/export/intercity
// inventory flows) and fleet management, plus truck dispatch on the mile legs
// and operational context. The ONE carve-out: allocation & fee rules stay
// VIEW-ONLY — a dispatcher never creates/updates/deletes those rules.
dispatcher: dedupe([
// Warehouse management — full CRUD.
FREIGHT_PERMS.warehouseDashboard.view,
...Object.values(FREIGHT_PERMS.warehouses),
...Object.values(FREIGHT_PERMS.warehouseYards),
...Object.values(FREIGHT_PERMS.warehouseZones),
...Object.values(FREIGHT_PERMS.warehouseInventory),
...Object.values(FREIGHT_PERMS.warehouseInspectionReports),
...Object.values(FREIGHT_PERMS.interchangeDocuments),
...Object.values(FREIGHT_PERMS.warehouseFeeInvoices),
// View-only on the rules that govern allocation and fees.
FREIGHT_PERMS.warehouseAllocationRules.view,
FREIGHT_PERMS.warehouseFeeRules.view,
// Fleet management — full CRUD.
...Object.values(FREIGHT_PERMS.fleet),
FREIGHT_PERMS.fleetDashboard.view,
...Object.values(FREIGHT_PERMS.fleetReports),
...Object.values(FREIGHT_PERMS.vehicles),
...Object.values(FREIGHT_PERMS.drivers),
...Object.values(FREIGHT_PERMS.tracking),
...Object.values(FREIGHT_PERMS.fuel),
...Object.values(FREIGHT_PERMS.maintenance),
...Object.values(FREIGHT_PERMS.locomotives),
...Object.values(FREIGHT_PERMS.wagons),
...Object.values(FREIGHT_PERMS.trains),
...Object.values(FREIGHT_PERMS.routes),
...Object.values(FREIGHT_PERMS.containers),
...Object.values(FREIGHT_PERMS.cargoes),
// Truck dispatch on the EDR mile legs + operational context.
...Object.values(FREIGHT_PERMS.firstMile),
...Object.values(FREIGHT_PERMS.lastMile),
FREIGHT_PERMS.trainScheduling.view,
FREIGHT_PERMS.bookings.operations,
]),
} as const;
/** Derive the module bucket from the resource segment of a permission key. */
const moduleOf = (key: string): string => key.split(':')[1] ?? 'other';
export const PERMISSIONS_CATALOG = BOOKING_RULE_ENGINE_PERMISSIONS.map((p) => ({
key: p.key,
label: p.name.en,
module: moduleOf(p.key),
}));