Files
edr-platform/apps/edr-freight-api/src/seed/freight-permission-key-migration.seeder.ts
Nathnael b0d5b2191f feat(auth): seed granular permission keys, retire unused ones
Adds the support, procurement, compliance, facilities, trade-access,
overview, reports and staff-users keys, plus the split action keys for
bookings, contracts, train scheduling and settings. Retires eight seeded
keys that no feature ever enforced, revoking their grants first.
2026-08-07 07:32:25 +00:00

94 lines
2.9 KiB
TypeScript

import { Injectable, Logger } from '@nestjs/common';
import {
Permission,
PositionPermission,
PositionTypePermission,
RolePermission,
} from '@tria-plc/iamapi-common';
import { DataSource } from 'typeorm';
/** Renamed rule-engine resources: old key -> new key (same permission id). */
const PERMISSION_KEY_RENAMES: ReadonlyArray<{ from: string; to: string }> = [
{
from: 'edr_freight_app:rule_engine:priority_rules:view',
to: 'edr_freight_app:rule_engine:priority_configs:view',
},
{
from: 'edr_freight_app:rule_engine:priority_rules:manage',
to: 'edr_freight_app:rule_engine:priority_configs:manage',
},
];
/**
* Keys retired by the permission-system redesign (docs/permission-system/01):
* seeded but never enforced anywhere, and no matching feature exists. Grants
* referencing them are revoked before the permission row is deleted.
*/
const RETIRED_PERMISSION_KEYS: ReadonlyArray<string> = [
'edr_freight_app:payments:verify',
'edr_freight_app:payments:refund',
'edr_freight_app:invoices:create',
'edr_freight_app:invoices:cancel',
'edr_freight_app:fuel:approve',
'edr_freight_app:maintenance:complete',
'edr_freight_app:bookings:payment_pnr',
'edr_freight_app:bookings:payment_verify',
];
@Injectable()
export class FreightPermissionKeyMigrationSeeder {
private readonly logger = new Logger(FreightPermissionKeyMigrationSeeder.name);
constructor(private readonly dataSource: DataSource) {}
async run() {
const permissionRepository = this.dataSource.getRepository(Permission);
for (const { from, to } of PERMISSION_KEY_RENAMES) {
const existing = await permissionRepository.findOne({
where: { key: from },
select: { id: true, key: true },
});
if (!existing) {
continue;
}
const targetExists = await permissionRepository.existsBy({ key: to });
if (targetExists) {
this.logger.warn(
`Skipping permission key rename ${from} -> ${to}: target key already exists`,
);
continue;
}
await permissionRepository.update({ id: existing.id }, { key: to });
this.logger.log(`Renamed permission key ${from} -> ${to}`);
}
for (const key of RETIRED_PERMISSION_KEYS) {
const existing = await permissionRepository.findOne({
where: { key },
select: { id: true },
});
if (!existing) {
continue;
}
// Revoke every grant first, then drop the permission row itself.
const permissionId = existing.id as string;
await this.dataSource
.getRepository(RolePermission)
.delete({ permissionId });
await this.dataSource
.getRepository(PositionPermission)
.delete({ permissionId });
await this.dataSource
.getRepository(PositionTypePermission)
.delete({ permissionId });
await permissionRepository.delete({ id: permissionId });
this.logger.log(`Retired permission key ${key}`);
}
}
}