-- CreateEnum CREATE TYPE "UserType" AS ENUM ('CUSTOMER', 'STAFF', 'ADMIN', 'SUPER_ADMIN'); -- CreateEnum CREATE TYPE "UserStatus" AS ENUM ('ACTIVE', 'INVITED', 'SUSPENDED'); -- CreateEnum CREATE TYPE "MediaKind" AS ENUM ('IMAGE', 'VIDEO', 'DOCUMENT'); -- CreateEnum CREATE TYPE "CollectionType" AS ENUM ('MANUAL', 'AUTOMATED'); -- CreateEnum CREATE TYPE "ProductStatus" AS ENUM ('DRAFT', 'ACTIVE', 'ARCHIVED'); -- CreateEnum CREATE TYPE "VariantStatus" AS ENUM ('ACTIVE', 'ARCHIVED'); -- CreateEnum CREATE TYPE "Currency" AS ENUM ('VND', 'USD'); -- CreateEnum CREATE TYPE "GenderTarget" AS ENUM ('MEN', 'WOMEN', 'KIDS', 'UNISEX'); -- CreateEnum CREATE TYPE "SportType" AS ENUM ('RUNNING', 'FOOTBALL', 'TRAINING', 'GYM', 'BADMINTON', 'LIFESTYLE'); -- CreateEnum CREATE TYPE "StockMovementReason" AS ENUM ('PURCHASE_RECEIPT', 'SALE', 'RETURN', 'MANUAL_ADJUSTMENT', 'STOCK_TAKE', 'TRANSFER_IN', 'TRANSFER_OUT', 'DAMAGE'); -- CreateTable CREATE TABLE "users" ( "id" UUID NOT NULL, "email" VARCHAR(255) NOT NULL, "password_hash" TEXT, "type" "UserType" NOT NULL, "status" "UserStatus" NOT NULL DEFAULT 'ACTIVE', "first_name" VARCHAR(80), "last_name" VARCHAR(80), "phone" VARCHAR(20), "avatar_id" UUID, "email_verified_at" TIMESTAMPTZ(3), "last_login_at" TIMESTAMPTZ(3), "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ(3) NOT NULL, "deleted_at" TIMESTAMPTZ(3), CONSTRAINT "users_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "roles" ( "id" UUID NOT NULL, "key" VARCHAR(64) NOT NULL, "name" VARCHAR(120) NOT NULL, "description" TEXT, "is_system" BOOLEAN NOT NULL DEFAULT false, "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ(3) NOT NULL, CONSTRAINT "roles_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "permissions" ( "id" UUID NOT NULL, "key" VARCHAR(64) NOT NULL, "resource" VARCHAR(40) NOT NULL, "action" VARCHAR(40) NOT NULL, "description" TEXT, CONSTRAINT "permissions_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "role_permissions" ( "role_id" UUID NOT NULL, "permission_id" UUID NOT NULL, CONSTRAINT "role_permissions_pkey" PRIMARY KEY ("role_id","permission_id") ); -- CreateTable CREATE TABLE "user_roles" ( "user_id" UUID NOT NULL, "role_id" UUID NOT NULL, "assigned_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "user_roles_pkey" PRIMARY KEY ("user_id","role_id") ); -- CreateTable CREATE TABLE "sessions" ( "id" UUID NOT NULL, "user_id" UUID NOT NULL, "refresh_token_hash" VARCHAR(64) NOT NULL, "family_id" UUID NOT NULL, "replaced_by_id" UUID, "expires_at" TIMESTAMPTZ(3) NOT NULL, "revoked_at" TIMESTAMPTZ(3), "user_agent" TEXT, "ip_address" VARCHAR(45), "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "sessions_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "audit_logs" ( "id" UUID NOT NULL, "actor_user_id" UUID, "action" VARCHAR(80) NOT NULL, "resource_type" VARCHAR(60) NOT NULL, "resource_id" TEXT, "changes" JSONB, "ip_address" VARCHAR(45), "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "audit_logs_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "customers" ( "id" UUID NOT NULL, "user_id" UUID NOT NULL, "accepts_marketing" BOOLEAN NOT NULL DEFAULT false, "date_of_birth" DATE, "note" TEXT, "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ(3) NOT NULL, CONSTRAINT "customers_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "addresses" ( "id" UUID NOT NULL, "customer_id" UUID NOT NULL, "full_name" VARCHAR(160) NOT NULL, "phone" VARCHAR(20) NOT NULL, "line1" VARCHAR(255) NOT NULL, "line2" VARCHAR(255), "ward" VARCHAR(120), "ward_code" VARCHAR(20), "district" VARCHAR(120), "district_code" VARCHAR(20), "province" VARCHAR(120) NOT NULL, "province_code" VARCHAR(20), "country_code" CHAR(2) NOT NULL DEFAULT 'VN', "postal_code" VARCHAR(20), "is_default_shipping" BOOLEAN NOT NULL DEFAULT false, "is_default_billing" BOOLEAN NOT NULL DEFAULT false, "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ(3) NOT NULL, CONSTRAINT "addresses_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "media_assets" ( "id" UUID NOT NULL, "kind" "MediaKind" NOT NULL DEFAULT 'IMAGE', "storage_key" VARCHAR(512) NOT NULL, "mime_type" VARCHAR(120) NOT NULL, "size_bytes" INTEGER NOT NULL, "width" INTEGER, "height" INTEGER, "blur_data_url" TEXT, "alt_text" VARCHAR(255), "metadata" JSONB, "uploaded_by_user_id" UUID, "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "media_assets_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "brands" ( "id" UUID NOT NULL, "name" VARCHAR(160) NOT NULL, "slug" VARCHAR(180) NOT NULL, "description" TEXT, "logo_id" UUID, "is_active" BOOLEAN NOT NULL DEFAULT true, "meta_title" VARCHAR(255), "meta_description" TEXT, "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ(3) NOT NULL, CONSTRAINT "brands_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "categories" ( "id" UUID NOT NULL, "parent_id" UUID, "name" VARCHAR(160) NOT NULL, "slug" VARCHAR(180) NOT NULL, "path" VARCHAR(512) NOT NULL, "depth" INTEGER NOT NULL DEFAULT 0, "position" INTEGER NOT NULL DEFAULT 0, "description" TEXT, "image_id" UUID, "is_active" BOOLEAN NOT NULL DEFAULT true, "meta_title" VARCHAR(255), "meta_description" TEXT, "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ(3) NOT NULL, CONSTRAINT "categories_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "collections" ( "id" UUID NOT NULL, "name" VARCHAR(160) NOT NULL, "slug" VARCHAR(180) NOT NULL, "type" "CollectionType" NOT NULL DEFAULT 'MANUAL', "description" TEXT, "banner_id" UUID, "rules" JSONB, "starts_at" TIMESTAMPTZ(3), "ends_at" TIMESTAMPTZ(3), "is_active" BOOLEAN NOT NULL DEFAULT true, "position" INTEGER NOT NULL DEFAULT 0, "meta_title" VARCHAR(255), "meta_description" TEXT, "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ(3) NOT NULL, CONSTRAINT "collections_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "product_collections" ( "product_id" UUID NOT NULL, "collection_id" UUID NOT NULL, "position" INTEGER NOT NULL DEFAULT 0, CONSTRAINT "product_collections_pkey" PRIMARY KEY ("product_id","collection_id") ); -- CreateTable CREATE TABLE "products" ( "id" UUID NOT NULL, "name" VARCHAR(255) NOT NULL, "slug" VARCHAR(280) NOT NULL, "description" TEXT, "short_description" VARCHAR(500), "status" "ProductStatus" NOT NULL DEFAULT 'DRAFT', "published_at" TIMESTAMPTZ(3), "brand_id" UUID, "primary_category_id" UUID, "gender_targets" "GenderTarget"[], "sport_types" "SportType"[], "meta_title" VARCHAR(255), "meta_description" TEXT, "metadata" JSONB, "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ(3) NOT NULL, "deleted_at" TIMESTAMPTZ(3), CONSTRAINT "products_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "product_options" ( "id" UUID NOT NULL, "product_id" UUID NOT NULL, "name" VARCHAR(60) NOT NULL, "key" VARCHAR(40) NOT NULL, "position" INTEGER NOT NULL DEFAULT 0, CONSTRAINT "product_options_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "product_option_values" ( "id" UUID NOT NULL, "option_id" UUID NOT NULL, "label" VARCHAR(80) NOT NULL, "value" VARCHAR(80) NOT NULL, "position" INTEGER NOT NULL DEFAULT 0, "swatch_hex" VARCHAR(9), "swatch_image_id" UUID, CONSTRAINT "product_option_values_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "product_variants" ( "id" UUID NOT NULL, "product_id" UUID NOT NULL, "sku" VARCHAR(64) NOT NULL, "barcode" VARCHAR(64), "title" VARCHAR(255) NOT NULL, "currency" "Currency" NOT NULL DEFAULT 'VND', "price_amount" INTEGER NOT NULL, "sale_price_amount" INTEGER, "compare_at_amount" INTEGER, "cost_amount" INTEGER, "weight_grams" INTEGER, "length_mm" INTEGER, "width_mm" INTEGER, "height_mm" INTEGER, "status" "VariantStatus" NOT NULL DEFAULT 'ACTIVE', "position" INTEGER NOT NULL DEFAULT 0, "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ(3) NOT NULL, "deleted_at" TIMESTAMPTZ(3), CONSTRAINT "product_variants_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "product_variant_option_values" ( "variant_id" UUID NOT NULL, "option_id" UUID NOT NULL, "option_value_id" UUID NOT NULL, CONSTRAINT "product_variant_option_values_pkey" PRIMARY KEY ("variant_id","option_id") ); -- CreateTable CREATE TABLE "product_images" ( "id" UUID NOT NULL, "product_id" UUID NOT NULL, "media_id" UUID NOT NULL, "option_value_id" UUID, "position" INTEGER NOT NULL DEFAULT 0, CONSTRAINT "product_images_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "product_attributes" ( "id" UUID NOT NULL, "product_id" UUID NOT NULL, "key" VARCHAR(60) NOT NULL, "label" VARCHAR(120) NOT NULL, "value" VARCHAR(500) NOT NULL, "group" VARCHAR(60), "position" INTEGER NOT NULL DEFAULT 0, "is_filterable" BOOLEAN NOT NULL DEFAULT false, CONSTRAINT "product_attributes_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "inventory_locations" ( "id" UUID NOT NULL, "name" VARCHAR(120) NOT NULL, "code" VARCHAR(40) NOT NULL, "is_default" BOOLEAN NOT NULL DEFAULT false, "is_active" BOOLEAN NOT NULL DEFAULT true, "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ(3) NOT NULL, CONSTRAINT "inventory_locations_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "stock_levels" ( "variant_id" UUID NOT NULL, "location_id" UUID NOT NULL, "on_hand" INTEGER NOT NULL DEFAULT 0, "reserved" INTEGER NOT NULL DEFAULT 0, "reorder_point" INTEGER, "updated_at" TIMESTAMPTZ(3) NOT NULL, CONSTRAINT "stock_levels_pkey" PRIMARY KEY ("variant_id","location_id") ); -- CreateTable CREATE TABLE "stock_movements" ( "id" UUID NOT NULL, "variant_id" UUID NOT NULL, "location_id" UUID NOT NULL, "quantity_delta" INTEGER NOT NULL, "reason" "StockMovementReason" NOT NULL, "reference_id" TEXT, "note" TEXT, "created_by_user_id" UUID, "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "stock_movements_pkey" PRIMARY KEY ("id") ); -- CreateIndex CREATE UNIQUE INDEX "users_email_key" ON "users"("email"); -- CreateIndex CREATE INDEX "users_type_status_idx" ON "users"("type", "status"); -- CreateIndex CREATE INDEX "users_created_at_idx" ON "users"("created_at"); -- CreateIndex CREATE UNIQUE INDEX "roles_key_key" ON "roles"("key"); -- CreateIndex CREATE UNIQUE INDEX "permissions_key_key" ON "permissions"("key"); -- CreateIndex CREATE INDEX "permissions_resource_idx" ON "permissions"("resource"); -- CreateIndex CREATE INDEX "role_permissions_permission_id_idx" ON "role_permissions"("permission_id"); -- CreateIndex CREATE INDEX "user_roles_role_id_idx" ON "user_roles"("role_id"); -- CreateIndex CREATE UNIQUE INDEX "sessions_refresh_token_hash_key" ON "sessions"("refresh_token_hash"); -- CreateIndex CREATE UNIQUE INDEX "sessions_replaced_by_id_key" ON "sessions"("replaced_by_id"); -- CreateIndex CREATE INDEX "sessions_user_id_revoked_at_idx" ON "sessions"("user_id", "revoked_at"); -- CreateIndex CREATE INDEX "sessions_family_id_idx" ON "sessions"("family_id"); -- CreateIndex CREATE INDEX "sessions_expires_at_idx" ON "sessions"("expires_at"); -- CreateIndex CREATE INDEX "audit_logs_resource_type_resource_id_idx" ON "audit_logs"("resource_type", "resource_id"); -- CreateIndex CREATE INDEX "audit_logs_actor_user_id_created_at_idx" ON "audit_logs"("actor_user_id", "created_at"); -- CreateIndex CREATE UNIQUE INDEX "customers_user_id_key" ON "customers"("user_id"); -- CreateIndex CREATE INDEX "addresses_customer_id_idx" ON "addresses"("customer_id"); -- CreateIndex CREATE UNIQUE INDEX "media_assets_storage_key_key" ON "media_assets"("storage_key"); -- CreateIndex CREATE INDEX "media_assets_kind_created_at_idx" ON "media_assets"("kind", "created_at"); -- CreateIndex CREATE UNIQUE INDEX "brands_slug_key" ON "brands"("slug"); -- CreateIndex CREATE UNIQUE INDEX "categories_path_key" ON "categories"("path"); -- CreateIndex CREATE INDEX "categories_path_idx" ON "categories"("path"); -- CreateIndex CREATE INDEX "categories_parent_id_position_idx" ON "categories"("parent_id", "position"); -- CreateIndex CREATE UNIQUE INDEX "categories_parent_id_slug_key" ON "categories"("parent_id", "slug"); -- CreateIndex CREATE UNIQUE INDEX "collections_slug_key" ON "collections"("slug"); -- CreateIndex CREATE INDEX "collections_is_active_starts_at_ends_at_idx" ON "collections"("is_active", "starts_at", "ends_at"); -- CreateIndex CREATE INDEX "product_collections_collection_id_position_idx" ON "product_collections"("collection_id", "position"); -- CreateIndex CREATE UNIQUE INDEX "products_slug_key" ON "products"("slug"); -- CreateIndex CREATE INDEX "products_status_published_at_idx" ON "products"("status", "published_at"); -- CreateIndex CREATE INDEX "products_brand_id_idx" ON "products"("brand_id"); -- CreateIndex CREATE INDEX "products_primary_category_id_idx" ON "products"("primary_category_id"); -- CreateIndex CREATE INDEX "products_gender_targets_idx" ON "products" USING GIN ("gender_targets"); -- CreateIndex CREATE INDEX "products_sport_types_idx" ON "products" USING GIN ("sport_types"); -- CreateIndex CREATE INDEX "product_options_product_id_position_idx" ON "product_options"("product_id", "position"); -- CreateIndex CREATE UNIQUE INDEX "product_options_product_id_key_key" ON "product_options"("product_id", "key"); -- CreateIndex CREATE INDEX "product_option_values_option_id_position_idx" ON "product_option_values"("option_id", "position"); -- CreateIndex CREATE UNIQUE INDEX "product_option_values_option_id_value_key" ON "product_option_values"("option_id", "value"); -- CreateIndex CREATE UNIQUE INDEX "product_variants_sku_key" ON "product_variants"("sku"); -- CreateIndex CREATE UNIQUE INDEX "product_variants_barcode_key" ON "product_variants"("barcode"); -- CreateIndex CREATE INDEX "product_variants_product_id_position_idx" ON "product_variants"("product_id", "position"); -- CreateIndex CREATE INDEX "product_variants_status_idx" ON "product_variants"("status"); -- CreateIndex CREATE INDEX "product_variant_option_values_option_value_id_idx" ON "product_variant_option_values"("option_value_id"); -- CreateIndex CREATE INDEX "product_images_product_id_position_idx" ON "product_images"("product_id", "position"); -- CreateIndex CREATE UNIQUE INDEX "product_images_product_id_media_id_option_value_id_key" ON "product_images"("product_id", "media_id", "option_value_id"); -- CreateIndex CREATE INDEX "product_attributes_key_value_idx" ON "product_attributes"("key", "value"); -- CreateIndex CREATE UNIQUE INDEX "product_attributes_product_id_key_key" ON "product_attributes"("product_id", "key"); -- CreateIndex CREATE UNIQUE INDEX "inventory_locations_code_key" ON "inventory_locations"("code"); -- CreateIndex CREATE INDEX "stock_levels_location_id_idx" ON "stock_levels"("location_id"); -- CreateIndex CREATE INDEX "stock_movements_variant_id_created_at_idx" ON "stock_movements"("variant_id", "created_at"); -- CreateIndex CREATE INDEX "stock_movements_reference_id_idx" ON "stock_movements"("reference_id"); -- AddForeignKey ALTER TABLE "users" ADD CONSTRAINT "users_avatar_id_fkey" FOREIGN KEY ("avatar_id") REFERENCES "media_assets"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "role_permissions" ADD CONSTRAINT "role_permissions_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "roles"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "role_permissions" ADD CONSTRAINT "role_permissions_permission_id_fkey" FOREIGN KEY ("permission_id") REFERENCES "permissions"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "roles"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "sessions" ADD CONSTRAINT "sessions_replaced_by_id_fkey" FOREIGN KEY ("replaced_by_id") REFERENCES "sessions"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "audit_logs" ADD CONSTRAINT "audit_logs_actor_user_id_fkey" FOREIGN KEY ("actor_user_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "customers" ADD CONSTRAINT "customers_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "addresses" ADD CONSTRAINT "addresses_customer_id_fkey" FOREIGN KEY ("customer_id") REFERENCES "customers"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "brands" ADD CONSTRAINT "brands_logo_id_fkey" FOREIGN KEY ("logo_id") REFERENCES "media_assets"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "categories" ADD CONSTRAINT "categories_parent_id_fkey" FOREIGN KEY ("parent_id") REFERENCES "categories"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "categories" ADD CONSTRAINT "categories_image_id_fkey" FOREIGN KEY ("image_id") REFERENCES "media_assets"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "collections" ADD CONSTRAINT "collections_banner_id_fkey" FOREIGN KEY ("banner_id") REFERENCES "media_assets"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "product_collections" ADD CONSTRAINT "product_collections_product_id_fkey" FOREIGN KEY ("product_id") REFERENCES "products"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "product_collections" ADD CONSTRAINT "product_collections_collection_id_fkey" FOREIGN KEY ("collection_id") REFERENCES "collections"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "products" ADD CONSTRAINT "products_brand_id_fkey" FOREIGN KEY ("brand_id") REFERENCES "brands"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "products" ADD CONSTRAINT "products_primary_category_id_fkey" FOREIGN KEY ("primary_category_id") REFERENCES "categories"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "product_options" ADD CONSTRAINT "product_options_product_id_fkey" FOREIGN KEY ("product_id") REFERENCES "products"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "product_option_values" ADD CONSTRAINT "product_option_values_option_id_fkey" FOREIGN KEY ("option_id") REFERENCES "product_options"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "product_option_values" ADD CONSTRAINT "product_option_values_swatch_image_id_fkey" FOREIGN KEY ("swatch_image_id") REFERENCES "media_assets"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "product_variants" ADD CONSTRAINT "product_variants_product_id_fkey" FOREIGN KEY ("product_id") REFERENCES "products"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "product_variant_option_values" ADD CONSTRAINT "product_variant_option_values_variant_id_fkey" FOREIGN KEY ("variant_id") REFERENCES "product_variants"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "product_variant_option_values" ADD CONSTRAINT "product_variant_option_values_option_id_fkey" FOREIGN KEY ("option_id") REFERENCES "product_options"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "product_variant_option_values" ADD CONSTRAINT "product_variant_option_values_option_value_id_fkey" FOREIGN KEY ("option_value_id") REFERENCES "product_option_values"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "product_images" ADD CONSTRAINT "product_images_product_id_fkey" FOREIGN KEY ("product_id") REFERENCES "products"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "product_images" ADD CONSTRAINT "product_images_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "media_assets"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "product_images" ADD CONSTRAINT "product_images_option_value_id_fkey" FOREIGN KEY ("option_value_id") REFERENCES "product_option_values"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "product_attributes" ADD CONSTRAINT "product_attributes_product_id_fkey" FOREIGN KEY ("product_id") REFERENCES "products"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "stock_levels" ADD CONSTRAINT "stock_levels_variant_id_fkey" FOREIGN KEY ("variant_id") REFERENCES "product_variants"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "stock_levels" ADD CONSTRAINT "stock_levels_location_id_fkey" FOREIGN KEY ("location_id") REFERENCES "inventory_locations"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "stock_movements" ADD CONSTRAINT "stock_movements_variant_id_fkey" FOREIGN KEY ("variant_id") REFERENCES "product_variants"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "stock_movements" ADD CONSTRAINT "stock_movements_location_id_fkey" FOREIGN KEY ("location_id") REFERENCES "inventory_locations"("id") ON DELETE RESTRICT ON UPDATE CASCADE;