Files
edr-platform/apps/edr-freight-api/src/migrations/2310000000000-CreateSupportChat.ts
2026-07-17 10:59:25 +00:00

79 lines
2.9 KiB
TypeScript

import { MigrationInterface, QueryRunner } from "typeorm";
/**
* Customer-support chat. A `support_conversations` row is the single ongoing
* thread with a company; `support_messages` are its text messages. There is no
* lifecycle column — a thread is opened by whichever side speaks first and
* stays open. Enum-like columns are varchar (no PG enum churn).
*
* The unique index on `company_id` is load-bearing, not just an optimization:
* the get-or-create path depends on it to settle concurrent first-messages.
* It is partial on `deleted_at IS NULL` so a soft-deleted thread doesn't block
* a fresh one.
*/
export class CreateSupportChat2310000000000 implements MigrationInterface {
name = "CreateSupportChat2310000000000";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TABLE IF NOT EXISTS freight.support_conversations (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
company_id uuid NOT NULL,
company_name varchar(200),
created_by_user_id uuid,
last_message_at timestamptz,
last_message_preview varchar(280),
last_message_author_role varchar(12),
customer_last_read_at timestamptz,
agent_last_read_at timestamptz,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
deleted_at timestamptz
)
`);
await queryRunner.query(`
CREATE UNIQUE INDEX IF NOT EXISTS "IDX_SUPPORT_CONV_COMPANY"
ON freight.support_conversations (company_id)
WHERE deleted_at IS NULL
`);
await queryRunner.query(`
CREATE INDEX IF NOT EXISTS "IDX_SUPPORT_CONV_LASTMSG"
ON freight.support_conversations (last_message_at)
`);
await queryRunner.query(`
CREATE TABLE IF NOT EXISTS freight.support_messages (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id uuid NOT NULL,
author_user_id uuid NOT NULL,
author_role varchar(12) NOT NULL,
author_name varchar(200),
body text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
deleted_at timestamptz
)
`);
await queryRunner.query(`
CREATE INDEX IF NOT EXISTS "IDX_SUPPORT_MSG_CONV_CREATED"
ON freight.support_messages (conversation_id, created_at)
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`DROP INDEX IF EXISTS freight."IDX_SUPPORT_MSG_CONV_CREATED"`,
);
await queryRunner.query(`DROP TABLE IF EXISTS freight.support_messages`);
await queryRunner.query(
`DROP INDEX IF EXISTS freight."IDX_SUPPORT_CONV_LASTMSG"`,
);
await queryRunner.query(
`DROP INDEX IF EXISTS freight."IDX_SUPPORT_CONV_COMPANY"`,
);
await queryRunner.query(
`DROP TABLE IF EXISTS freight.support_conversations`,
);
}
}