Files
edr-platform/apps/edr-freight-api/src/migrations/2300000000000-CreateRateChangeRequests.ts
2026-07-17 10:15:26 +00:00

48 lines
1.9 KiB
TypeScript

import { MigrationInterface, QueryRunner } from 'typeorm';
/**
* Approval workflow for edits to LIVE rates. A LIVE rate is what pricing
* charges, so it is never edited in place: the edit is filed here as PENDING
* and the live row keeps its value until an approver applies it.
*
* `payload` holds the changed fields only; `previous_values` snapshots what
* they were at submit time so the approver sees a real before→after diff.
*/
export class CreateRateChangeRequests2300000000000 implements MigrationInterface {
name = 'CreateRateChangeRequests2300000000000';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TABLE IF NOT EXISTS freight.rate_change_requests (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
rate_id uuid NOT NULL REFERENCES freight.rates (id),
payload jsonb NOT NULL,
previous_values jsonb NOT NULL,
status varchar(10) NOT NULL DEFAULT 'PENDING',
requested_by_user_id uuid NULL,
decided_by_user_id uuid NULL,
decided_at timestamptz NULL,
decision_note text NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
deleted_at timestamptz NULL
)
`);
await queryRunner.query(`
CREATE INDEX IF NOT EXISTS idx_rcr_status
ON freight.rate_change_requests (status)
`);
// At most one pending edit per rate — two racing requests would both pass
// validation and the second would silently overwrite the first on approval.
await queryRunner.query(`
CREATE UNIQUE INDEX IF NOT EXISTS uq_rcr_one_pending_per_rate
ON freight.rate_change_requests (rate_id)
WHERE status = 'PENDING' AND deleted_at IS NULL
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE IF EXISTS freight.rate_change_requests`);
}
}