This commit is contained in:
Nông Đức Huy
2026-08-13 23:20:23 +07:00
parent 1e356a2578
commit d9f159a8c3
84 changed files with 7992 additions and 180 deletions
@@ -0,0 +1,122 @@
-- CreateEnum
CREATE TYPE "DiscountTrigger" AS ENUM ('AUTOMATIC', 'CODE');
-- CreateEnum
CREATE TYPE "DiscountType" AS ENUM ('PERCENTAGE', 'FIXED_AMOUNT');
-- CreateEnum
CREATE TYPE "DiscountScope" AS ENUM ('ORDER', 'PRODUCT');
-- NOTE: Prisma wanted to drop `search_documents_document_idx` and strip the
-- default from `search_documents.document` here. Both were removed by hand.
--
-- `document` is a GENERATED column (see 20260812130938_add_search_documents),
-- which Prisma cannot express — it sees `Unsupported("tsvector")?` and assumes a
-- plain column that has drifted. Letting it "fix" that would drop the GIN index
-- search depends on and fail on the generated column anyway, which is exactly
-- what happened the first time this migration ran.
--
-- Expect this diff on every future `migrate dev`. Delete those two statements.
-- CreateTable
CREATE TABLE "discounts" (
"id" UUID NOT NULL,
"code" VARCHAR(40),
"trigger" "DiscountTrigger" NOT NULL,
"type" "DiscountType" NOT NULL,
"scope" "DiscountScope" NOT NULL DEFAULT 'ORDER',
"value" INTEGER NOT NULL,
"min_subtotal_amount" INTEGER,
"starts_at" TIMESTAMPTZ(3),
"ends_at" TIMESTAMPTZ(3),
"is_active" BOOLEAN NOT NULL DEFAULT true,
"usage_limit" INTEGER,
"usage_count" INTEGER NOT NULL DEFAULT 0,
"stackable" BOOLEAN NOT NULL DEFAULT false,
"priority" INTEGER NOT NULL DEFAULT 100,
"created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ(3) NOT NULL,
"deleted_at" TIMESTAMPTZ(3),
CONSTRAINT "discounts_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "discount_translations" (
"discount_id" UUID NOT NULL,
"locale" "Locale" NOT NULL,
"name" VARCHAR(120) NOT NULL,
"description" VARCHAR(500),
CONSTRAINT "discount_translations_pkey" PRIMARY KEY ("discount_id","locale")
);
-- CreateTable
CREATE TABLE "discount_products" (
"discount_id" UUID NOT NULL,
"product_id" UUID NOT NULL,
CONSTRAINT "discount_products_pkey" PRIMARY KEY ("discount_id","product_id")
);
-- CreateTable
CREATE TABLE "discount_collections" (
"discount_id" UUID NOT NULL,
"collection_id" UUID NOT NULL,
CONSTRAINT "discount_collections_pkey" PRIMARY KEY ("discount_id","collection_id")
);
-- CreateTable
CREATE TABLE "discount_redemptions" (
"id" UUID NOT NULL,
"discount_id" UUID NOT NULL,
"order_id" UUID NOT NULL,
"amount" INTEGER NOT NULL,
"code" VARCHAR(40),
"created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "discount_redemptions_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "discounts_code_key" ON "discounts"("code");
-- CreateIndex
CREATE INDEX "discounts_trigger_is_active_idx" ON "discounts"("trigger", "is_active");
-- CreateIndex
CREATE INDEX "discounts_code_idx" ON "discounts"("code");
-- CreateIndex
CREATE INDEX "discount_products_product_id_idx" ON "discount_products"("product_id");
-- CreateIndex
CREATE INDEX "discount_collections_collection_id_idx" ON "discount_collections"("collection_id");
-- CreateIndex
CREATE INDEX "discount_redemptions_discount_id_idx" ON "discount_redemptions"("discount_id");
-- CreateIndex
CREATE UNIQUE INDEX "discount_redemptions_order_id_discount_id_key" ON "discount_redemptions"("order_id", "discount_id");
-- AddForeignKey
ALTER TABLE "discount_translations" ADD CONSTRAINT "discount_translations_discount_id_fkey" FOREIGN KEY ("discount_id") REFERENCES "discounts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "discount_products" ADD CONSTRAINT "discount_products_discount_id_fkey" FOREIGN KEY ("discount_id") REFERENCES "discounts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "discount_products" ADD CONSTRAINT "discount_products_product_id_fkey" FOREIGN KEY ("product_id") REFERENCES "products"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "discount_collections" ADD CONSTRAINT "discount_collections_discount_id_fkey" FOREIGN KEY ("discount_id") REFERENCES "discounts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "discount_collections" ADD CONSTRAINT "discount_collections_collection_id_fkey" FOREIGN KEY ("collection_id") REFERENCES "collections"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "discount_redemptions" ADD CONSTRAINT "discount_redemptions_discount_id_fkey" FOREIGN KEY ("discount_id") REFERENCES "discounts"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "discount_redemptions" ADD CONSTRAINT "discount_redemptions_order_id_fkey" FOREIGN KEY ("order_id") REFERENCES "orders"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,57 @@
-- CreateEnum
CREATE TYPE "ReviewStatus" AS ENUM ('PENDING', 'APPROVED', 'REJECTED');
-- NOTE: Prisma's diff wanted to DROP INDEX "search_documents_document_idx" and
-- ALTER "search_documents"."document" DROP DEFAULT here. Both are removed on
-- purpose and must be removed from every future migration too.
--
-- `document` is a GENERATED tsvector column created by raw SQL in the M6
-- migration. Prisma's schema cannot express a generated column, so it sees one
-- it does not know about and proposes undoing it. Applying that drops the GIN
-- index behind every search query and silently degrades /search to nothing.
-- AlterTable
ALTER TABLE "products" ADD COLUMN "rating_count" INTEGER NOT NULL DEFAULT 0,
ADD COLUMN "rating_sum" INTEGER NOT NULL DEFAULT 0;
-- CreateTable
CREATE TABLE "reviews" (
"id" UUID NOT NULL,
"product_id" UUID NOT NULL,
"order_line_id" UUID NOT NULL,
"rating" INTEGER NOT NULL,
"title" VARCHAR(140),
"body" VARCHAR(2000),
"author_name" VARCHAR(120) NOT NULL,
"status" "ReviewStatus" NOT NULL DEFAULT 'PENDING',
"moderated_at" TIMESTAMPTZ(3),
"moderated_by_user_id" UUID,
"moderation_note" VARCHAR(500),
"created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ(3) NOT NULL,
CONSTRAINT "reviews_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "reviews_order_line_id_key" ON "reviews"("order_line_id");
-- CreateIndex
CREATE INDEX "reviews_product_id_status_created_at_idx" ON "reviews"("product_id", "status", "created_at");
-- CreateIndex
CREATE INDEX "reviews_status_created_at_idx" ON "reviews"("status", "created_at");
-- AddForeignKey
ALTER TABLE "reviews" ADD CONSTRAINT "reviews_product_id_fkey" FOREIGN KEY ("product_id") REFERENCES "products"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "reviews" ADD CONSTRAINT "reviews_order_line_id_fkey" FOREIGN KEY ("order_line_id") REFERENCES "order_lines"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "reviews" ADD CONSTRAINT "reviews_moderated_by_user_id_fkey" FOREIGN KEY ("moderated_by_user_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- Validation belongs in the schema as well as the DTO: `rating` feeds a stored
-- SUM, so one bad row silently skews a product's average forever. Zod checks
-- the request; this checks the table.
ALTER TABLE "reviews" ADD CONSTRAINT "reviews_rating_range" CHECK ("rating" BETWEEN 1 AND 5);
@@ -0,0 +1,55 @@
-- CreateEnum
CREATE TYPE "ContentType" AS ENUM ('PAGE', 'POST');
-- CreateEnum
CREATE TYPE "ContentStatus" AS ENUM ('DRAFT', 'PUBLISHED');
-- NOTE: Prisma's diff wanted to DROP INDEX "search_documents_document_idx" and
-- ALTER "search_documents"."document" DROP DEFAULT here. Removed on purpose —
-- `document` is a GENERATED tsvector column created by raw SQL in the M6
-- migration, which Prisma's schema cannot express, so it proposes undoing it in
-- every migration from now on. Applying it destroys full-text search.
-- CreateTable
CREATE TABLE "content_entries" (
"id" UUID NOT NULL,
"type" "ContentType" NOT NULL,
"status" "ContentStatus" NOT NULL DEFAULT 'DRAFT',
"published_at" TIMESTAMPTZ(3),
"cover_image_id" UUID,
"author_user_id" UUID,
"created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ(3) NOT NULL,
"deleted_at" TIMESTAMPTZ(3),
CONSTRAINT "content_entries_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "content_entry_translations" (
"entry_id" UUID NOT NULL,
"locale" "Locale" NOT NULL,
"slug" VARCHAR(200) NOT NULL,
"title" VARCHAR(255) NOT NULL,
"excerpt" VARCHAR(500),
"body" TEXT NOT NULL,
"meta_title" VARCHAR(255),
"meta_description" TEXT,
CONSTRAINT "content_entry_translations_pkey" PRIMARY KEY ("entry_id","locale")
);
-- CreateIndex
CREATE INDEX "content_entries_type_status_published_at_idx" ON "content_entries"("type", "status", "published_at");
-- CreateIndex
CREATE UNIQUE INDEX "content_entry_translations_locale_slug_key" ON "content_entry_translations"("locale", "slug");
-- AddForeignKey
ALTER TABLE "content_entries" ADD CONSTRAINT "content_entries_cover_image_id_fkey" FOREIGN KEY ("cover_image_id") REFERENCES "media_assets"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "content_entries" ADD CONSTRAINT "content_entries_author_user_id_fkey" FOREIGN KEY ("author_user_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "content_entry_translations" ADD CONSTRAINT "content_entry_translations_entry_id_fkey" FOREIGN KEY ("entry_id") REFERENCES "content_entries"("id") ON DELETE CASCADE ON UPDATE CASCADE;