137 lines
7.7 KiB
TypeScript
137 lines
7.7 KiB
TypeScript
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
|
|
export class CreateAdminTables1736600000000 implements MigrationInterface {
|
|
name = 'CreateAdminTables1736600000000'
|
|
|
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
// Extend users role enum with new roles
|
|
await queryRunner.query(`ALTER TYPE "public"."users_role_enum" ADD VALUE IF NOT EXISTS 'SUPER_ADMIN'`);
|
|
await queryRunner.query(`ALTER TYPE "public"."users_role_enum" ADD VALUE IF NOT EXISTS 'MODERATOR'`);
|
|
await queryRunner.query(`ALTER TYPE "public"."users_role_enum" ADD VALUE IF NOT EXISTS 'VIEWER'`);
|
|
|
|
// Create promotion type enum
|
|
await queryRunner.query(`CREATE TYPE "public"."promotions_type_enum" AS ENUM('PERCENTAGE', 'FIXED_CREDITS', 'MULTIPLIER')`);
|
|
|
|
// Create IA Providers table
|
|
await queryRunner.query(`CREATE TABLE "ia_providers" (
|
|
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
|
|
"name" character varying(100) NOT NULL,
|
|
"code" character varying(50) NOT NULL,
|
|
"description" text,
|
|
"costPerFrame" numeric(10,6) NOT NULL DEFAULT '0',
|
|
"costPerToken" numeric(10,8) NOT NULL DEFAULT '0',
|
|
"isActive" boolean NOT NULL DEFAULT true,
|
|
"isDefault" boolean NOT NULL DEFAULT false,
|
|
"config" jsonb,
|
|
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
|
|
"updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
|
|
CONSTRAINT "UQ_ia_providers_code" UNIQUE ("code"),
|
|
CONSTRAINT "PK_ia_providers" PRIMARY KEY ("id")
|
|
)`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_ia_providers_code" ON "ia_providers" ("code")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_ia_providers_active" ON "ia_providers" ("isActive")`);
|
|
|
|
// Create Promotions table
|
|
await queryRunner.query(`CREATE TABLE "promotions" (
|
|
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
|
|
"name" character varying(100) NOT NULL,
|
|
"code" character varying(50) NOT NULL,
|
|
"description" text,
|
|
"type" "public"."promotions_type_enum" NOT NULL,
|
|
"value" numeric(10,2) NOT NULL,
|
|
"minPurchaseAmount" numeric(10,2),
|
|
"maxDiscount" numeric(10,2),
|
|
"usageLimit" integer,
|
|
"usageCount" integer NOT NULL DEFAULT '0',
|
|
"perUserLimit" integer DEFAULT '1',
|
|
"startsAt" TIMESTAMP NOT NULL,
|
|
"endsAt" TIMESTAMP NOT NULL,
|
|
"isActive" boolean NOT NULL DEFAULT true,
|
|
"applicablePackageIds" uuid[],
|
|
"createdBy" uuid,
|
|
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
|
|
"updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
|
|
CONSTRAINT "UQ_promotions_code" UNIQUE ("code"),
|
|
CONSTRAINT "PK_promotions" PRIMARY KEY ("id")
|
|
)`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_promotions_code" ON "promotions" ("code")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_promotions_active_dates" ON "promotions" ("isActive", "startsAt", "endsAt")`);
|
|
|
|
// Create Audit Logs table
|
|
await queryRunner.query(`CREATE TABLE "audit_logs" (
|
|
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
|
|
"userId" uuid NOT NULL,
|
|
"action" character varying(100) NOT NULL,
|
|
"resource" character varying(100) NOT NULL,
|
|
"resourceId" uuid,
|
|
"previousValue" jsonb,
|
|
"newValue" jsonb,
|
|
"ipAddress" character varying(45),
|
|
"userAgent" text,
|
|
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
|
|
CONSTRAINT "PK_audit_logs" PRIMARY KEY ("id")
|
|
)`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_audit_logs_user" ON "audit_logs" ("userId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_audit_logs_action" ON "audit_logs" ("action")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_audit_logs_resource" ON "audit_logs" ("resource", "resourceId")`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_audit_logs_created" ON "audit_logs" ("createdAt")`);
|
|
|
|
// Add fraud detection columns to referrals
|
|
await queryRunner.query(`ALTER TABLE "referrals" ADD "fraudHold" boolean NOT NULL DEFAULT false`);
|
|
await queryRunner.query(`ALTER TABLE "referrals" ADD "fraudReason" character varying(255)`);
|
|
await queryRunner.query(`ALTER TABLE "referrals" ADD "reviewedBy" uuid`);
|
|
await queryRunner.query(`ALTER TABLE "referrals" ADD "reviewedAt" TIMESTAMP`);
|
|
await queryRunner.query(`CREATE INDEX "IDX_referrals_fraud" ON "referrals" ("fraudHold")`);
|
|
|
|
// Foreign Keys
|
|
await queryRunner.query(`ALTER TABLE "promotions" ADD CONSTRAINT "FK_promotions_creator" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "audit_logs" ADD CONSTRAINT "FK_audit_logs_user" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
await queryRunner.query(`ALTER TABLE "referrals" ADD CONSTRAINT "FK_referrals_reviewer" FOREIGN KEY ("reviewedBy") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
|
|
|
|
// Seed initial IA providers
|
|
await queryRunner.query(`
|
|
INSERT INTO "ia_providers" ("name", "code", "description", "costPerFrame", "costPerToken", "isActive", "isDefault")
|
|
VALUES
|
|
('OpenAI GPT-4 Vision', 'openai-gpt4v', 'OpenAI GPT-4 con capacidades de vision', 0.01, 0.00003, true, true),
|
|
('Claude 3 Sonnet', 'claude-sonnet', 'Anthropic Claude 3 Sonnet para analisis de imagenes', 0.003, 0.000015, true, false),
|
|
('Claude 3 Haiku', 'claude-haiku', 'Anthropic Claude 3 Haiku - rapido y economico', 0.00025, 0.00000125, true, false)
|
|
`);
|
|
}
|
|
|
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
// Drop Foreign Keys
|
|
await queryRunner.query(`ALTER TABLE "referrals" DROP CONSTRAINT IF EXISTS "FK_referrals_reviewer"`);
|
|
await queryRunner.query(`ALTER TABLE "audit_logs" DROP CONSTRAINT "FK_audit_logs_user"`);
|
|
await queryRunner.query(`ALTER TABLE "promotions" DROP CONSTRAINT "FK_promotions_creator"`);
|
|
|
|
// Remove fraud columns from referrals
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_referrals_fraud"`);
|
|
await queryRunner.query(`ALTER TABLE "referrals" DROP COLUMN "reviewedAt"`);
|
|
await queryRunner.query(`ALTER TABLE "referrals" DROP COLUMN "reviewedBy"`);
|
|
await queryRunner.query(`ALTER TABLE "referrals" DROP COLUMN "fraudReason"`);
|
|
await queryRunner.query(`ALTER TABLE "referrals" DROP COLUMN "fraudHold"`);
|
|
|
|
// Drop Audit Logs table
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_audit_logs_created"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_audit_logs_resource"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_audit_logs_action"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_audit_logs_user"`);
|
|
await queryRunner.query(`DROP TABLE "audit_logs"`);
|
|
|
|
// Drop Promotions table
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_promotions_active_dates"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_promotions_code"`);
|
|
await queryRunner.query(`DROP TABLE "promotions"`);
|
|
|
|
// Drop IA Providers table
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_ia_providers_active"`);
|
|
await queryRunner.query(`DROP INDEX "public"."IDX_ia_providers_code"`);
|
|
await queryRunner.query(`DROP TABLE "ia_providers"`);
|
|
|
|
// Drop ENUMs
|
|
await queryRunner.query(`DROP TYPE "public"."promotions_type_enum"`);
|
|
|
|
// Note: Cannot remove enum values in PostgreSQL, they remain but are unused
|
|
}
|
|
}
|