Refactor EdrOrgSeeder

This commit is contained in:
Marshal
2026-07-29 06:28:42 +00:00
parent b17a72c280
commit dfde6b9021
3 changed files with 39 additions and 17 deletions

View File

@@ -164,20 +164,25 @@ export class EdrOrgSeeder {
manager: EntityManager,
applicationId: string,
) {
const permissionRepository = manager.getRepository(Permission);
// Upsert by key so reruns are idempotent; applicationId ties every
// permission to the EDR Freight application (also backfills rows that
// were previously seeded without the relation).
await permissionRepository.upsert(
EDR_FREIGHT_PERMISSIONS.map((permission) => ({
id: permission.id,
key: permission.key,
name: { ...permission.name },
applicationId,
})),
{ conflictPaths: { key: true } },
);
// iam.permissions has TWO unique columns (PK id, UQ key) but ON CONFLICT
// can only target one. Seeding a hand-minted id that some older/retired key
// already owns in an environment slips past ON CONFLICT (key) and dies on
// the PK. The key is the identity every consumer resolves by (positions
// seeder maps key -> id at runtime), so ids are left to the column default
// and never sent — no id can collide.
await manager
.createQueryBuilder()
.insert()
.into(Permission)
.values(
EDR_FREIGHT_PERMISSIONS.map((permission) => ({
key: permission.key,
name: { ...permission.name },
applicationId,
})),
)
.orUpdate(["name", "application_id"], ["key"])
.execute();
this.logger.log(
`Ensured ${EDR_FREIGHT_PERMISSIONS.length} permissions on application '${EDR_FREIGHT_APPLICATION.key}'`,

View File

@@ -0,0 +1,13 @@
import { EDR_FREIGHT_PERMISSIONS } from './edr-freight.seed';
describe('EDR_FREIGHT_PERMISSIONS', () => {
// The seeder inserts the whole catalog in one ON CONFLICT (key) DO UPDATE
// statement — a duplicated key there is a Postgres 21000 at boot, not a
// silent no-op.
it('has no duplicate keys', () => {
const keys = EDR_FREIGHT_PERMISSIONS.map((permission) => permission.key);
const duplicates = [...new Set(keys.filter((key, i) => keys.indexOf(key) !== i))];
expect(duplicates).toEqual([]);
});
});

View File

@@ -109,8 +109,12 @@ export const CONTRACT_PERMISSIONS: FreightPermissionSeed[] = [
perm('a3000001-0001-4000-8000-00000000001b', 'edr_freight_app:contracts:suspend', 'Suspend / resume a signed contract'),
];
// Existing per-slug view ids are kept as-is: position-type grants reference
// them by id, so re-minting would orphan those rows.
// Historical ids. EdrOrgSeeder no longer sends them — it upserts on `key` and
// lets the column default mint the uuid — so these are kept only as a record of
// which ids each environment already holds. A hand-picked id must still never
// be recycled from a retired key: `edr_freight_app:rule_engine:truck_types:manage`
// owned …001b, and reusing it for transit-agents crashed boot with a PK 23505
// on every environment that still had the retired row.
const RULE_ENGINE_VIEW_IDS: Record<RuleEngineResourceSlug, string> = {
'cargo-types': 'b2000001-0001-4000-8000-000000000001',
'container-types': 'b2000001-0001-4000-8000-000000000003',
@@ -124,7 +128,7 @@ const RULE_ENGINE_VIEW_IDS: Record<RuleEngineResourceSlug, string> = {
rates: 'b2000001-0001-4000-8000-000000000011',
'approval-rules': 'b2000001-0001-4000-8000-000000000013',
'yard-distances': 'b2000001-0001-4000-8000-000000000018',
'transit-agents': 'b2000001-0001-4000-8000-00000000001b',
'transit-agents': 'b2000003-0001-4000-8000-000000000001',
};
// CRUD replaces the retired coarse `:manage`. New ids live in a fresh block