202 lines
14 KiB
TypeScript
202 lines
14 KiB
TypeScript
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
|
|
export class CreateFeedbackTables1736502000000 implements MigrationInterface {
|
|
name = 'CreateFeedbackTables1736502000000'
|
|
|
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
// ENUMs
|
|
await queryRunner.query(`CREATE TYPE "public"."corrections_type_enum" AS ENUM('QUANTITY', 'SKU', 'CONFIRMATION')`);
|
|
await queryRunner.query(`CREATE TYPE "public"."ground_truth_status_enum" AS ENUM('PENDING', 'APPROVED', 'REJECTED')`);
|
|
await queryRunner.query(`CREATE TYPE "public"."product_submissions_status_enum" AS ENUM('PENDING', 'APPROVED', 'REJECTED')`);
|
|
await queryRunner.query(`CREATE TYPE "public"."validation_requests_status_enum" AS ENUM('PENDING', 'COMPLETED', 'SKIPPED', 'EXPIRED')`);
|
|
|
|
// Corrections table - Historial de correcciones de usuario
|
|
await queryRunner.query(`CREATE TABLE "corrections" (
|
|
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
|
|
"inventoryItemId" uuid NOT NULL,
|
|
"userId" uuid NOT NULL,
|
|
"storeId" uuid NOT NULL,
|
|
"type" "public"."corrections_type_enum" NOT NULL,
|
|
"previousValue" jsonb NOT NULL,
|
|
"newValue" jsonb NOT NULL,
|
|
"reason" character varying(255),
|
|
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
|
|
CONSTRAINT "PK_corrections" PRIMARY KEY ("id")
|
|
)`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_corrections_item" ON "corrections" ("inventoryItemId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_corrections_user" ON "corrections" ("userId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_corrections_store" ON "corrections" ("storeId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_corrections_type" ON "corrections" ("type", "createdAt")`);
|
|
|
|
// Ground Truth table - Datos validados para entrenamiento
|
|
await queryRunner.query(`CREATE TABLE "ground_truth" (
|
|
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
|
|
"inventoryItemId" uuid NOT NULL,
|
|
"videoId" uuid NOT NULL,
|
|
"storeId" uuid NOT NULL,
|
|
"originalDetection" jsonb NOT NULL,
|
|
"correctedData" jsonb NOT NULL,
|
|
"frameTimestamp" integer,
|
|
"boundingBox" jsonb,
|
|
"status" "public"."ground_truth_status_enum" NOT NULL DEFAULT 'PENDING',
|
|
"validatedBy" uuid,
|
|
"validationScore" numeric(5,2),
|
|
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
|
|
"updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
|
|
CONSTRAINT "PK_ground_truth" PRIMARY KEY ("id")
|
|
)`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_ground_truth_item" ON "ground_truth" ("inventoryItemId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_ground_truth_video" ON "ground_truth" ("videoId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_ground_truth_status" ON "ground_truth" ("status")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_ground_truth_store" ON "ground_truth" ("storeId")`);
|
|
|
|
// Product Submissions table - Nuevos productos etiquetados por usuarios
|
|
await queryRunner.query(`CREATE TABLE "product_submissions" (
|
|
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
|
|
"userId" uuid NOT NULL,
|
|
"storeId" uuid NOT NULL,
|
|
"videoId" uuid,
|
|
"name" character varying(255) NOT NULL,
|
|
"category" character varying(100),
|
|
"barcode" character varying(50),
|
|
"imageUrl" character varying(500),
|
|
"frameTimestamp" integer,
|
|
"boundingBox" jsonb,
|
|
"status" "public"."product_submissions_status_enum" NOT NULL DEFAULT 'PENDING',
|
|
"reviewedBy" uuid,
|
|
"reviewNotes" text,
|
|
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
|
|
"updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
|
|
CONSTRAINT "PK_product_submissions" PRIMARY KEY ("id")
|
|
)`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_product_submissions_user" ON "product_submissions" ("userId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_product_submissions_store" ON "product_submissions" ("storeId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_product_submissions_status" ON "product_submissions" ("status")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_product_submissions_barcode" ON "product_submissions" ("barcode")`);
|
|
|
|
// Validation Requests table - Solicitudes de micro-auditoria
|
|
await queryRunner.query(`CREATE TABLE "validation_requests" (
|
|
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
|
|
"videoId" uuid NOT NULL,
|
|
"userId" uuid NOT NULL,
|
|
"storeId" uuid NOT NULL,
|
|
"totalItems" integer NOT NULL DEFAULT '0',
|
|
"itemsValidated" integer NOT NULL DEFAULT '0',
|
|
"triggerReason" character varying(100) NOT NULL,
|
|
"probabilityScore" numeric(5,2) NOT NULL,
|
|
"status" "public"."validation_requests_status_enum" NOT NULL DEFAULT 'PENDING',
|
|
"expiresAt" TIMESTAMP NOT NULL,
|
|
"completedAt" TIMESTAMP,
|
|
"creditsRewarded" integer NOT NULL DEFAULT '0',
|
|
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
|
|
"updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
|
|
CONSTRAINT "PK_validation_requests" PRIMARY KEY ("id")
|
|
)`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_validation_requests_video" ON "validation_requests" ("videoId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_validation_requests_user" ON "validation_requests" ("userId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_validation_requests_store" ON "validation_requests" ("storeId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_validation_requests_status" ON "validation_requests" ("status", "expiresAt")`);
|
|
|
|
// Validation Responses table - Respuestas de validacion por item
|
|
await queryRunner.query(`CREATE TABLE "validation_responses" (
|
|
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
|
|
"requestId" uuid NOT NULL,
|
|
"inventoryItemId" uuid NOT NULL,
|
|
"userId" uuid NOT NULL,
|
|
"isCorrect" boolean,
|
|
"correctedQuantity" integer,
|
|
"correctedName" character varying(255),
|
|
"responseTimeMs" integer,
|
|
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
|
|
CONSTRAINT "PK_validation_responses" PRIMARY KEY ("id")
|
|
)`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_validation_responses_request" ON "validation_responses" ("requestId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_validation_responses_item" ON "validation_responses" ("inventoryItemId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_validation_responses_user" ON "validation_responses" ("userId")`);
|
|
|
|
// Foreign Keys
|
|
await queryRunner.query(`ALTER TABLE "corrections" ADD CONSTRAINT "FK_corrections_item" FOREIGN KEY ("inventoryItemId") REFERENCES "inventory_items"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "corrections" ADD CONSTRAINT "FK_corrections_user" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "corrections" ADD CONSTRAINT "FK_corrections_store" FOREIGN KEY ("storeId") REFERENCES "stores"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
|
|
await queryRunner.query(`ALTER TABLE "ground_truth" ADD CONSTRAINT "FK_ground_truth_item" FOREIGN KEY ("inventoryItemId") REFERENCES "inventory_items"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "ground_truth" ADD CONSTRAINT "FK_ground_truth_video" FOREIGN KEY ("videoId") REFERENCES "videos"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "ground_truth" ADD CONSTRAINT "FK_ground_truth_store" FOREIGN KEY ("storeId") REFERENCES "stores"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "ground_truth" ADD CONSTRAINT "FK_ground_truth_validator" FOREIGN KEY ("validatedBy") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
|
|
await queryRunner.query(`ALTER TABLE "product_submissions" ADD CONSTRAINT "FK_product_submissions_user" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "product_submissions" ADD CONSTRAINT "FK_product_submissions_store" FOREIGN KEY ("storeId") REFERENCES "stores"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "product_submissions" ADD CONSTRAINT "FK_product_submissions_video" FOREIGN KEY ("videoId") REFERENCES "videos"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "product_submissions" ADD CONSTRAINT "FK_product_submissions_reviewer" FOREIGN KEY ("reviewedBy") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
|
|
await queryRunner.query(`ALTER TABLE "validation_requests" ADD CONSTRAINT "FK_validation_requests_video" FOREIGN KEY ("videoId") REFERENCES "videos"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "validation_requests" ADD CONSTRAINT "FK_validation_requests_user" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "validation_requests" ADD CONSTRAINT "FK_validation_requests_store" FOREIGN KEY ("storeId") REFERENCES "stores"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
|
|
await queryRunner.query(`ALTER TABLE "validation_responses" ADD CONSTRAINT "FK_validation_responses_request" FOREIGN KEY ("requestId") REFERENCES "validation_requests"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "validation_responses" ADD CONSTRAINT "FK_validation_responses_item" FOREIGN KEY ("inventoryItemId") REFERENCES "inventory_items"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "validation_responses" ADD CONSTRAINT "FK_validation_responses_user" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
}
|
|
|
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
// Drop Foreign Keys
|
|
await queryRunner.query(`ALTER TABLE "validation_responses" DROP CONSTRAINT "FK_validation_responses_user"`);
|
|
await queryRunner.query(`ALTER TABLE "validation_responses" DROP CONSTRAINT "FK_validation_responses_item"`);
|
|
await queryRunner.query(`ALTER TABLE "validation_responses" DROP CONSTRAINT "FK_validation_responses_request"`);
|
|
|
|
await queryRunner.query(`ALTER TABLE "validation_requests" DROP CONSTRAINT "FK_validation_requests_store"`);
|
|
await queryRunner.query(`ALTER TABLE "validation_requests" DROP CONSTRAINT "FK_validation_requests_user"`);
|
|
await queryRunner.query(`ALTER TABLE "validation_requests" DROP CONSTRAINT "FK_validation_requests_video"`);
|
|
|
|
await queryRunner.query(`ALTER TABLE "product_submissions" DROP CONSTRAINT "FK_product_submissions_reviewer"`);
|
|
await queryRunner.query(`ALTER TABLE "product_submissions" DROP CONSTRAINT "FK_product_submissions_video"`);
|
|
await queryRunner.query(`ALTER TABLE "product_submissions" DROP CONSTRAINT "FK_product_submissions_store"`);
|
|
await queryRunner.query(`ALTER TABLE "product_submissions" DROP CONSTRAINT "FK_product_submissions_user"`);
|
|
|
|
await queryRunner.query(`ALTER TABLE "ground_truth" DROP CONSTRAINT "FK_ground_truth_validator"`);
|
|
await queryRunner.query(`ALTER TABLE "ground_truth" DROP CONSTRAINT "FK_ground_truth_store"`);
|
|
await queryRunner.query(`ALTER TABLE "ground_truth" DROP CONSTRAINT "FK_ground_truth_video"`);
|
|
await queryRunner.query(`ALTER TABLE "ground_truth" DROP CONSTRAINT "FK_ground_truth_item"`);
|
|
|
|
await queryRunner.query(`ALTER TABLE "corrections" DROP CONSTRAINT "FK_corrections_store"`);
|
|
await queryRunner.query(`ALTER TABLE "corrections" DROP CONSTRAINT "FK_corrections_user"`);
|
|
await queryRunner.query(`ALTER TABLE "corrections" DROP CONSTRAINT "FK_corrections_item"`);
|
|
|
|
// Drop Tables
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_validation_responses_user"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_validation_responses_item"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_validation_responses_request"`);
|
|
await queryRunner.query(`DROP TABLE "validation_responses"`);
|
|
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_validation_requests_status"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_validation_requests_store"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_validation_requests_user"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_validation_requests_video"`);
|
|
await queryRunner.query(`DROP TABLE "validation_requests"`);
|
|
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_product_submissions_barcode"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_product_submissions_status"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_product_submissions_store"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_product_submissions_user"`);
|
|
await queryRunner.query(`DROP TABLE "product_submissions"`);
|
|
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_ground_truth_store"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_ground_truth_status"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_ground_truth_video"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_ground_truth_item"`);
|
|
await queryRunner.query(`DROP TABLE "ground_truth"`);
|
|
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_corrections_type"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_corrections_store"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_corrections_user"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_corrections_item"`);
|
|
await queryRunner.query(`DROP TABLE "corrections"`);
|
|
|
|
// Drop ENUMs
|
|
await queryRunner.query(`DROP TYPE "public"."validation_requests_status_enum"`);
|
|
await queryRunner.query(`DROP TYPE "public"."product_submissions_status_enum"`);
|
|
await queryRunner.query(`DROP TYPE "public"."ground_truth_status_enum"`);
|
|
await queryRunner.query(`DROP TYPE "public"."corrections_type_enum"`);
|
|
}
|
|
}
|