fix conflict

This commit is contained in:
hagiye
2026-06-25 11:31:50 +03:00
168 changed files with 8445 additions and 2583 deletions

View File

@@ -0,0 +1,31 @@
import { MigrationInterface, QueryRunner } from "typeorm";
/**
* Company-profile references are now minted only when a profile is approved
* (status → Active); pending profiles carry NULL. Drop the NOT NULL constraint
* on freight.company_profiles.reference. The existing unique index is kept —
* Postgres treats NULLs as distinct, so multiple pending (NULL) profiles don't
* collide.
*/
export class MakeCompanyProfileReferenceNullable1810000000002
implements MigrationInterface
{
name = "MakeCompanyProfileReferenceNullable1810000000002";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "freight"."company_profiles" ALTER COLUMN "reference" DROP NOT NULL`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
// Reinstating NOT NULL requires every row to have a reference; any pending
// (NULL) profiles get a placeholder so the constraint can be re-applied.
await queryRunner.query(
`UPDATE "freight"."company_profiles" SET "reference" = 'PENDING-' || left(replace("id"::text, '-', ''), 12) WHERE "reference" IS NULL`,
);
await queryRunner.query(
`ALTER TABLE "freight"."company_profiles" ALTER COLUMN "reference" SET NOT NULL`,
);
}
}

View File

@@ -0,0 +1,42 @@
import { MigrationInterface, QueryRunner, Table } from "typeorm";
/**
* Create the public.otp_verifications table backing the OTP module
* (OtpVerification entity). One row per phone, holding the latest server-issued
* code and whether that phone has been verified.
*/
export class CreateOtpVerifications1810000000003
implements MigrationInterface
{
name = "CreateOtpVerifications1810000000003";
public async up(queryRunner: QueryRunner): Promise<void> {
const exists = await queryRunner.hasTable("otp_verifications");
if (exists) return;
await queryRunner.createTable(
new Table({
name: "otp_verifications",
columns: [
{
name: "id",
type: "uuid",
isPrimary: true,
default: "gen_random_uuid()",
},
{ name: "phone", type: "varchar", isUnique: true },
{ name: "otp", type: "varchar" },
{ name: "verified", type: "boolean", default: false },
{ name: "created_at", type: "timestamptz", default: "now()" },
{ name: "updated_at", type: "timestamptz", default: "now()" },
{ name: "deleted_at", type: "timestamptz", isNullable: true },
],
}),
true,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable("otp_verifications", true);
}
}

View File

@@ -0,0 +1,59 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
/**
* Multi-locomotive train sets: a train set is now pulled by 2+ locomotives.
*
* Adds the `freight.train_set_locomotives` link table (train set ⇄ locomotive,
* with an order index) and backfills one row per existing train set from its
* current `locomotive_id`, so existing read paths keep resolving locomotives.
* The `train_sets.locomotive_id` column is retained as the "primary" locomotive.
*
* NOTE: the shared dev DB has no applied migration history, so this is also
* hand-applied there. IF NOT EXISTS keeps that idempotent.
*/
export class AddTrainSetLocomotives1820000000011 implements MigrationInterface {
name = 'AddTrainSetLocomotives1820000000011';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TABLE IF NOT EXISTS freight.train_set_locomotives (
id uuid NOT NULL DEFAULT uuid_generate_v4(),
train_set_id uuid NOT NULL,
locomotive_id uuid NOT NULL,
sequence_no int NOT NULL DEFAULT 0,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
deleted_at timestamptz,
CONSTRAINT "PK_train_set_locomotives" PRIMARY KEY (id),
CONSTRAINT "FK_train_set_locomotives_train_set" FOREIGN KEY (train_set_id)
REFERENCES freight.train_sets (id) ON DELETE CASCADE,
CONSTRAINT "FK_train_set_locomotives_locomotive" FOREIGN KEY (locomotive_id)
REFERENCES freight.locomotives (id)
);
`);
await queryRunner.query(`
CREATE UNIQUE INDEX IF NOT EXISTS "UQ_train_set_locomotives_set_loco"
ON freight.train_set_locomotives (train_set_id, locomotive_id);
`);
// Backfill: one link row per existing train set, from its current primary loco.
await queryRunner.query(`
INSERT INTO freight.train_set_locomotives (train_set_id, locomotive_id, sequence_no)
SELECT ts.id, ts.locomotive_id, 0
FROM freight.train_sets ts
WHERE ts.locomotive_id IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM freight.train_set_locomotives tsl
WHERE tsl.train_set_id = ts.id AND tsl.locomotive_id = ts.locomotive_id
);
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`DROP INDEX IF EXISTS freight."UQ_train_set_locomotives_set_loco";`,
);
await queryRunner.query(`DROP TABLE IF EXISTS freight.train_set_locomotives;`);
}
}

View File

@@ -0,0 +1,33 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
/**
* Contact email/phone for an external profile is sourced from IAM (the user's
* identity) and from the company record, so the duplicated `email`/`phone`
* columns on external_profiles are redundant and are dropped. Dropping `email`
* also removes its UNIQUE constraint.
*/
export class DropEmailPhoneFromExternalProfiles1820000000011
implements MigrationInterface
{
name = 'DropEmailPhoneFromExternalProfiles1820000000011';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE freight.external_profiles DROP COLUMN IF EXISTS email;`,
);
await queryRunner.query(
`ALTER TABLE freight.external_profiles DROP COLUMN IF EXISTS phone;`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
// Re-added as nullable (the original email was UNIQUE NOT NULL) since the
// dropped values cannot be recovered to satisfy those constraints.
await queryRunner.query(
`ALTER TABLE freight.external_profiles ADD COLUMN IF NOT EXISTS email varchar(150);`,
);
await queryRunner.query(
`ALTER TABLE freight.external_profiles ADD COLUMN IF NOT EXISTS phone varchar(20);`,
);
}
}

View File

@@ -0,0 +1,26 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
/**
* The booking wizard now captures a NON-BINDING estimated shipment date instead
* of the binding scheduledDate. The binding scheduledDate (validated against
* open train departures) is set later, at the operation-request step.
*/
export class AddEstimatedShipmentDate1820000000012
implements MigrationInterface
{
name = 'AddEstimatedShipmentDate1820000000012';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE freight.bookings
ADD COLUMN IF NOT EXISTS estimated_shipment_date timestamptz NULL;
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE freight.bookings
DROP COLUMN IF EXISTS estimated_shipment_date;
`);
}
}