import { MigrationInterface, QueryRunner } from 'typeorm'; export class PhaseF12ActAdministration1789581600000 implements MigrationInterface { name = 'PhaseF12ActAdministration1789581600000'; public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(`CREATE TABLE inspection_act_deadline_events ( id uuid PRIMARY KEY, act_id uuid NOT NULL REFERENCES inspection_acts(id) ON DELETE RESTRICT, response_due_on date NOT NULL, reason text NOT NULL, created_by uuid NULL REFERENCES users(id) ON DELETE SET NULL, created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP )`); await queryRunner.query(`CREATE INDEX idx_act_deadline_events_act_created ON inspection_act_deadline_events (act_id, created_at DESC)`); await queryRunner.query(`CREATE INDEX idx_act_deadline_events_due ON inspection_act_deadline_events (response_due_on)`); await queryRunner.query(`CREATE TABLE inspection_act_company_responses ( id uuid PRIMARY KEY, act_id uuid NOT NULL REFERENCES inspection_acts(id) ON DELETE RESTRICT, received_on date NOT NULL, details text NULL, committed_correction_on date NULL, contact_name varchar(200) NULL, contact_email varchar(320) NULL, original_name varchar(255) NULL, stored_name varchar(100) NULL, mime_type varchar(120) NULL, size_bytes bigint NULL, sha256 char(64) NULL, created_by uuid NULL REFERENCES users(id) ON DELETE SET NULL, created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_act_company_response_file CHECK ((stored_name IS NULL AND original_name IS NULL AND mime_type IS NULL AND size_bytes IS NULL AND sha256 IS NULL) OR (stored_name IS NOT NULL AND original_name IS NOT NULL AND mime_type = 'application/pdf' AND size_bytes > 0 AND sha256 IS NOT NULL)) )`); await queryRunner.query(`CREATE INDEX idx_act_company_responses_act_received ON inspection_act_company_responses (act_id, received_on DESC, created_at DESC)`); await queryRunner.query(`CREATE INDEX idx_act_company_responses_commitment ON inspection_act_company_responses (committed_correction_on)`); await queryRunner.query(`INSERT INTO inspection_act_deadline_events (id, act_id, response_due_on, reason, created_by, created_at) SELECT gen_random_uuid(), act_id, MIN(correction_due_on), 'Migrado desde plazo histórico coincidente de hallazgos', NULL, CURRENT_TIMESTAMP FROM inspection_findings WHERE correction_due_on IS NOT NULL GROUP BY act_id HAVING COUNT(DISTINCT correction_due_on) = 1`); await queryRunner.query(`CREATE OR REPLACE FUNCTION prevent_f12_append_only_mutation() RETURNS trigger AS $$ BEGIN RAISE EXCEPTION 'F1.2 append-only: update/delete no permitido'; END; $$ LANGUAGE plpgsql`); await queryRunner.query(`CREATE TRIGGER trg_act_deadline_events_append_only BEFORE UPDATE OR DELETE ON inspection_act_deadline_events FOR EACH ROW EXECUTE FUNCTION prevent_f12_append_only_mutation()`); await queryRunner.query(`CREATE TRIGGER trg_act_company_responses_append_only BEFORE UPDATE OR DELETE ON inspection_act_company_responses FOR EACH ROW EXECUTE FUNCTION prevent_f12_append_only_mutation()`); } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query(`DROP TRIGGER IF EXISTS trg_act_company_responses_append_only ON inspection_act_company_responses`); await queryRunner.query(`DROP TRIGGER IF EXISTS trg_act_deadline_events_append_only ON inspection_act_deadline_events`); await queryRunner.query(`DROP FUNCTION IF EXISTS prevent_f12_append_only_mutation()`); await queryRunner.query(`DROP TABLE inspection_act_company_responses`); await queryRunner.query(`DROP TABLE inspection_act_deadline_events`); } }