diff --git a/Dockerfile b/Dockerfile index 385d03f..cf6b241 100644 --- a/Dockerfile +++ b/Dockerfile @@ -46,11 +46,12 @@ CMD ["node", "apps/api/dist/index.js"] FROM dependencies AS admin-builder -ARG VITE_API_BASE_URL=http://localhost:4000 +ARG VITE_API_BASE_URL ENV VITE_API_BASE_URL=$VITE_API_BASE_URL COPY apps/admin apps/admin -RUN npm run build:admin +RUN test -n "$VITE_API_BASE_URL" \ + && npm run build:admin FROM ${NGINX_IMAGE} AS admin diff --git a/apps/api/prisma/init.sql b/apps/api/prisma/init.sql new file mode 100644 index 0000000..4e87ae3 --- /dev/null +++ b/apps/api/prisma/init.sql @@ -0,0 +1,539 @@ +-- CreateSchema +CREATE SCHEMA IF NOT EXISTS "public"; + +-- CreateTable +CREATE TABLE "AdminUser" ( + "id" TEXT NOT NULL, + "email" TEXT NOT NULL, + "name" TEXT NOT NULL, + "passwordHash" TEXT NOT NULL, + "role" TEXT NOT NULL DEFAULT 'admin', + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "AdminUser_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "MediaAsset" ( + "id" TEXT NOT NULL, + "url" TEXT NOT NULL, + "name" TEXT, + "mimeType" TEXT, + "sizeBytes" INTEGER, + "group" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "MediaAsset_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "HeroSlide" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "kicker" TEXT, + "actionLabel" TEXT, + "image" TEXT NOT NULL, + "targetType" TEXT, + "targetValue" TEXT, + "sortOrder" INTEGER NOT NULL DEFAULT 0, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "HeroSlide_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Destination" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "region" TEXT, + "image" TEXT, + "isHot" BOOLEAN NOT NULL DEFAULT false, + "sortOrder" INTEGER NOT NULL DEFAULT 0, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Destination_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "DestinationAlias" ( + "id" TEXT NOT NULL, + "alias" TEXT NOT NULL, + "destinationId" TEXT NOT NULL, + + CONSTRAINT "DestinationAlias_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ThemeCard" ( + "id" TEXT NOT NULL, + "label" TEXT NOT NULL, + "image" TEXT NOT NULL, + "targetType" TEXT, + "targetValue" TEXT, + "sortOrder" INTEGER NOT NULL DEFAULT 0, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "ThemeCard_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "CtaBanner" ( + "id" TEXT NOT NULL, + "alt" TEXT NOT NULL, + "image" TEXT NOT NULL, + "targetType" TEXT NOT NULL, + "targetValue" TEXT, + "sortOrder" INTEGER NOT NULL DEFAULT 0, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "CtaBanner_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "DestinationPageConfig" ( + "id" TEXT NOT NULL DEFAULT 'destination-home', + "recommendedProductIds" JSONB NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "DestinationPageConfig_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "SearchPageConfig" ( + "id" TEXT NOT NULL DEFAULT 'search-page', + "title" TEXT NOT NULL, + "subtitle" TEXT NOT NULL, + "placeholder" TEXT NOT NULL, + "modules" JSONB NOT NULL DEFAULT '{}', + "popularKeywords" JSONB NOT NULL, + "groups" JSONB NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "SearchPageConfig_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "HomeModule" ( + "id" TEXT NOT NULL, + "label" TEXT NOT NULL, + "templateType" TEXT NOT NULL DEFAULT 'explore', + "content" JSONB, + "publishedConfig" JSONB, + "sortOrder" INTEGER NOT NULL DEFAULT 0, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "isSystem" BOOLEAN NOT NULL DEFAULT false, + "isDeleted" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "HomeModule_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Product" ( + "id" TEXT NOT NULL, + "sourceId" INTEGER, + "title" TEXT NOT NULL, + "subtitle" TEXT, + "destinationId" TEXT, + "priceAmount" INTEGER, + "priceUnit" TEXT NOT NULL DEFAULT '起/人', + "pricingTiers" JSONB, + "tags" TEXT[], + "coverImage" TEXT, + "summary" TEXT, + "durationDays" INTEGER, + "durationNights" INTEGER, + "departureDates" TEXT[] DEFAULT ARRAY[]::TEXT[], + "remainingSpots" INTEGER, + "recommendation" TEXT, + "keyFacts" JSONB, + "contentBlocks" JSONB, + "detailSections" JSONB, + "status" TEXT NOT NULL DEFAULT 'published', + "sortWeight" INTEGER NOT NULL DEFAULT 0, + "publishedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Product_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ProductImage" ( + "id" TEXT NOT NULL, + "productId" TEXT NOT NULL, + "url" TEXT NOT NULL, + "alt" TEXT, + "sortOrder" INTEGER NOT NULL DEFAULT 0, + + CONSTRAINT "ProductImage_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Campaign" ( + "id" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "coverImage" TEXT, + "status" TEXT NOT NULL DEFAULT 'published', + "startsAt" TIMESTAMP(3), + "endsAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Campaign_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "CampaignProduct" ( + "campaignId" TEXT NOT NULL, + "productId" TEXT NOT NULL, + "sortOrder" INTEGER NOT NULL DEFAULT 0, + + CONSTRAINT "CampaignProduct_pkey" PRIMARY KEY ("campaignId","productId") +); + +-- CreateTable +CREATE TABLE "Lead" ( + "id" TEXT NOT NULL, + "requestType" TEXT NOT NULL DEFAULT 'custom', + "userId" TEXT, + "wecomContactId" TEXT, + "destination" TEXT, + "phone" TEXT NOT NULL, + "contactName" TEXT, + "wechat" TEXT, + "travelDate" TIMESTAMP(3), + "peopleCount" INTEGER, + "adultCount" INTEGER, + "childCount" INTEGER, + "roomType" TEXT, + "plan" TEXT, + "addOns" TEXT[] DEFAULT ARRAY[]::TEXT[], + "budgetMin" INTEGER, + "budgetMax" INTEGER, + "note" TEXT, + "sourcePage" TEXT, + "sourceTheme" TEXT, + "sourceProductId" TEXT, + "adminNote" TEXT, + "processed" BOOLEAN NOT NULL DEFAULT false, + "status" TEXT NOT NULL DEFAULT 'new', + "assignedUserId" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Lead_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "LeadFollowup" ( + "id" TEXT NOT NULL, + "leadId" TEXT NOT NULL, + "content" TEXT NOT NULL, + "nextAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "LeadFollowup_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "MiniProgramUser" ( + "id" TEXT NOT NULL, + "appId" TEXT NOT NULL, + "openId" TEXT NOT NULL, + "unionId" TEXT, + "nickname" TEXT, + "avatarUrl" TEXT, + "phone" TEXT, + "phoneAuthorizedAt" TIMESTAMP(3), + "note" TEXT, + "source" TEXT NOT NULL DEFAULT 'mini_program', + "status" TEXT NOT NULL DEFAULT 'active', + "customerId" TEXT, + "firstSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "lastLoginAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "MiniProgramUser_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "MiniProgramFavorite" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "productId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "MiniProgramFavorite_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "MiniProgramHistory" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "productId" TEXT NOT NULL, + "viewCount" INTEGER NOT NULL DEFAULT 1, + "lastViewedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "MiniProgramHistory_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Customer" ( + "id" TEXT NOT NULL, + "phone" TEXT, + "name" TEXT, + "wechat" TEXT, + "note" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Customer_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "WecomContactWay" ( + "id" TEXT NOT NULL, + "configId" TEXT NOT NULL, + "type" INTEGER NOT NULL DEFAULT 1, + "scene" INTEGER NOT NULL DEFAULT 1, + "style" INTEGER NOT NULL DEFAULT 1, + "remark" TEXT, + "state" TEXT, + "wecomUserId" TEXT, + "enabled" BOOLEAN NOT NULL DEFAULT true, + "lastSyncedAt" TIMESTAMP(3), + "lastSyncError" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "WecomContactWay_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "WecomExternalContact" ( + "id" TEXT NOT NULL, + "externalUserId" TEXT NOT NULL, + "wecomUserId" TEXT NOT NULL, + "contactWayId" TEXT, + "miniProgramUserId" TEXT, + "customerId" TEXT, + "name" TEXT, + "avatarUrl" TEXT, + "type" INTEGER, + "gender" INTEGER, + "unionId" TEXT, + "corpName" TEXT, + "position" TEXT, + "remark" TEXT, + "description" TEXT, + "profile" JSONB, + "status" TEXT NOT NULL DEFAULT 'active', + "addedAt" TIMESTAMP(3), + "lastEventAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "WecomExternalContact_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Order" ( + "id" TEXT NOT NULL, + "customerId" TEXT, + "productId" TEXT, + "status" TEXT NOT NULL DEFAULT 'draft', + "travelDate" TIMESTAMP(3), + "amount" INTEGER, + "note" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Order_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "SiteVersion" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'draft', + "snapshot" JSONB NOT NULL, + "publishedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "SiteVersion_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AuditLog" ( + "id" TEXT NOT NULL, + "actorId" TEXT, + "action" TEXT NOT NULL, + "entity" TEXT NOT NULL, + "entityId" TEXT, + "before" JSONB, + "after" JSONB, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "AdminUser_email_key" ON "AdminUser"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "MediaAsset_url_key" ON "MediaAsset"("url"); + +-- CreateIndex +CREATE UNIQUE INDEX "Destination_name_key" ON "Destination"("name"); + +-- CreateIndex +CREATE UNIQUE INDEX "Destination_slug_key" ON "Destination"("slug"); + +-- CreateIndex +CREATE UNIQUE INDEX "DestinationAlias_alias_destinationId_key" ON "DestinationAlias"("alias", "destinationId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Product_sourceId_key" ON "Product"("sourceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Campaign_slug_key" ON "Campaign"("slug"); + +-- CreateIndex +CREATE INDEX "Lead_userId_createdAt_idx" ON "Lead"("userId", "createdAt"); + +-- CreateIndex +CREATE INDEX "Lead_phone_idx" ON "Lead"("phone"); + +-- CreateIndex +CREATE INDEX "Lead_requestType_status_createdAt_idx" ON "Lead"("requestType", "status", "createdAt"); + +-- CreateIndex +CREATE INDEX "Lead_wecomContactId_idx" ON "Lead"("wecomContactId"); + +-- CreateIndex +CREATE UNIQUE INDEX "MiniProgramUser_customerId_key" ON "MiniProgramUser"("customerId"); + +-- CreateIndex +CREATE INDEX "MiniProgramUser_phone_idx" ON "MiniProgramUser"("phone"); + +-- CreateIndex +CREATE INDEX "MiniProgramUser_status_lastLoginAt_idx" ON "MiniProgramUser"("status", "lastLoginAt"); + +-- CreateIndex +CREATE UNIQUE INDEX "MiniProgramUser_appId_openId_key" ON "MiniProgramUser"("appId", "openId"); + +-- CreateIndex +CREATE INDEX "MiniProgramFavorite_productId_idx" ON "MiniProgramFavorite"("productId"); + +-- CreateIndex +CREATE UNIQUE INDEX "MiniProgramFavorite_userId_productId_key" ON "MiniProgramFavorite"("userId", "productId"); + +-- CreateIndex +CREATE INDEX "MiniProgramHistory_userId_lastViewedAt_idx" ON "MiniProgramHistory"("userId", "lastViewedAt"); + +-- CreateIndex +CREATE UNIQUE INDEX "MiniProgramHistory_userId_productId_key" ON "MiniProgramHistory"("userId", "productId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Customer_phone_key" ON "Customer"("phone"); + +-- CreateIndex +CREATE UNIQUE INDEX "WecomContactWay_configId_key" ON "WecomContactWay"("configId"); + +-- CreateIndex +CREATE INDEX "WecomExternalContact_status_lastEventAt_idx" ON "WecomExternalContact"("status", "lastEventAt"); + +-- CreateIndex +CREATE INDEX "WecomExternalContact_miniProgramUserId_idx" ON "WecomExternalContact"("miniProgramUserId"); + +-- CreateIndex +CREATE INDEX "WecomExternalContact_customerId_idx" ON "WecomExternalContact"("customerId"); + +-- CreateIndex +CREATE INDEX "WecomExternalContact_contactWayId_idx" ON "WecomExternalContact"("contactWayId"); + +-- CreateIndex +CREATE UNIQUE INDEX "WecomExternalContact_externalUserId_wecomUserId_key" ON "WecomExternalContact"("externalUserId", "wecomUserId"); + +-- AddForeignKey +ALTER TABLE "DestinationAlias" ADD CONSTRAINT "DestinationAlias_destinationId_fkey" FOREIGN KEY ("destinationId") REFERENCES "Destination"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Product" ADD CONSTRAINT "Product_destinationId_fkey" FOREIGN KEY ("destinationId") REFERENCES "Destination"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ProductImage" ADD CONSTRAINT "ProductImage_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "CampaignProduct" ADD CONSTRAINT "CampaignProduct_campaignId_fkey" FOREIGN KEY ("campaignId") REFERENCES "Campaign"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "CampaignProduct" ADD CONSTRAINT "CampaignProduct_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Lead" ADD CONSTRAINT "Lead_userId_fkey" FOREIGN KEY ("userId") REFERENCES "MiniProgramUser"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Lead" ADD CONSTRAINT "Lead_wecomContactId_fkey" FOREIGN KEY ("wecomContactId") REFERENCES "WecomExternalContact"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Lead" ADD CONSTRAINT "Lead_sourceProductId_fkey" FOREIGN KEY ("sourceProductId") REFERENCES "Product"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Lead" ADD CONSTRAINT "Lead_assignedUserId_fkey" FOREIGN KEY ("assignedUserId") REFERENCES "AdminUser"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "LeadFollowup" ADD CONSTRAINT "LeadFollowup_leadId_fkey" FOREIGN KEY ("leadId") REFERENCES "Lead"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MiniProgramUser" ADD CONSTRAINT "MiniProgramUser_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MiniProgramFavorite" ADD CONSTRAINT "MiniProgramFavorite_userId_fkey" FOREIGN KEY ("userId") REFERENCES "MiniProgramUser"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MiniProgramFavorite" ADD CONSTRAINT "MiniProgramFavorite_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MiniProgramHistory" ADD CONSTRAINT "MiniProgramHistory_userId_fkey" FOREIGN KEY ("userId") REFERENCES "MiniProgramUser"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MiniProgramHistory" ADD CONSTRAINT "MiniProgramHistory_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "WecomExternalContact" ADD CONSTRAINT "WecomExternalContact_contactWayId_fkey" FOREIGN KEY ("contactWayId") REFERENCES "WecomContactWay"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "WecomExternalContact" ADD CONSTRAINT "WecomExternalContact_miniProgramUserId_fkey" FOREIGN KEY ("miniProgramUserId") REFERENCES "MiniProgramUser"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "WecomExternalContact" ADD CONSTRAINT "WecomExternalContact_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Order" ADD CONSTRAINT "Order_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Order" ADD CONSTRAINT "Order_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_actorId_fkey" FOREIGN KEY ("actorId") REFERENCES "AdminUser"("id") ON DELETE SET NULL ON UPDATE CASCADE;