Apps, web, i18n, UI, partners, payouts, backoffice, bariki, prod infra

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
zabudko-ruandClaude Opus 5.5 committed 2026-10-25 22:55:29 +04:00
1 parent 45d7512d2b
commit 3489e0b816
319 files changed
+45483 -121

No files matched your search

@@ -0,0 +1,22 @@
-- AlterTable
ALTER TABLE "Order" ADD COLUMN "priceBreakdown" JSONB;
-- AlterTable
ALTER TABLE "Provider" ADD COLUMN "payoutPresetId" TEXT;
-- CreateTable
CREATE TABLE "PayoutPreset" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"role" "ProviderRole" NOT NULL,
"rules" JSONB NOT NULL,
"sortOrder" INTEGER NOT NULL DEFAULT 0,
"active" BOOLEAN NOT NULL DEFAULT true,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "PayoutPreset_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "Provider" ADD CONSTRAINT "Provider_payoutPresetId_fkey" FOREIGN KEY ("payoutPresetId") REFERENCES "PayoutPreset"("id") ON DELETE SET NULL ON UPDATE CASCADE;
@@ -0,0 +1,54 @@
-- CreateEnum
CREATE TYPE "WebRequestStatus" AS ENUM ('NEW', 'LINKED', 'ORDERED', 'CANCELLED');
-- CreateTable
CREATE TABLE "WebRequest" (
"id" TEXT NOT NULL,
"number" SERIAL NOT NULL,
"token" TEXT NOT NULL,
"serviceId" TEXT NOT NULL,
"params" JSONB NOT NULL,
"preferredAt" TIMESTAMP(3) NOT NULL,
"durationMinutes" INTEGER NOT NULL,
"districtId" TEXT NOT NULL,
"addressText" TEXT NOT NULL,
"note" TEXT,
"phone" TEXT NOT NULL,
"name" TEXT,
"locale" "Locale" NOT NULL,
"totalPrice" INTEGER NOT NULL,
"consentAt" TIMESTAMP(3) NOT NULL,
"consentVersion" TEXT NOT NULL,
"status" "WebRequestStatus" NOT NULL DEFAULT 'NEW',
"clientId" TEXT,
"orderId" TEXT,
"adminNote" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "WebRequest_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "WebRequest_number_key" ON "WebRequest"("number");
-- CreateIndex
CREATE UNIQUE INDEX "WebRequest_token_key" ON "WebRequest"("token");
-- CreateIndex
CREATE UNIQUE INDEX "WebRequest_orderId_key" ON "WebRequest"("orderId");
-- CreateIndex
CREATE INDEX "WebRequest_status_createdAt_idx" ON "WebRequest"("status", "createdAt");
-- AddForeignKey
ALTER TABLE "WebRequest" ADD CONSTRAINT "WebRequest_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "WebRequest" ADD CONSTRAINT "WebRequest_districtId_fkey" FOREIGN KEY ("districtId") REFERENCES "District"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "WebRequest" ADD CONSTRAINT "WebRequest_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "WebRequest" ADD CONSTRAINT "WebRequest_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "Order"("id") ON DELETE SET NULL ON UPDATE CASCADE;
@@ -0,0 +1,38 @@
-- CreateEnum
CREATE TYPE "LeadStatus" AS ENUM ('NEW', 'IN_WORK', 'DONE', 'CANCELLED');
-- CreateEnum
CREATE TYPE "LeadContactType" AS ENUM ('PHONE', 'TELEGRAM');
-- CreateTable
CREATE TABLE "Lead" (
"id" TEXT NOT NULL,
"number" SERIAL NOT NULL,
"key" TEXT NOT NULL,
"name" TEXT NOT NULL,
"contact" TEXT NOT NULL,
"contactType" "LeadContactType" NOT NULL,
"locale" "Locale" NOT NULL,
"agency" TEXT,
"utm" JSONB,
"moved" BOOLEAN,
"moveWhen" TEXT,
"moveDate" TIMESTAMP(3),
"package" TEXT,
"options" JSONB,
"submittedAt" TIMESTAMP(3),
"consentAt" TIMESTAMP(3) NOT NULL,
"consentVersion" TEXT NOT NULL,
"status" "LeadStatus" NOT NULL DEFAULT 'NEW',
"adminNote" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Lead_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "Lead_number_key" ON "Lead"("number");
-- CreateIndex
CREATE INDEX "Lead_status_createdAt_idx" ON "Lead"("status", "createdAt");
@@ -0,0 +1,106 @@
-- CreateEnum
CREATE TYPE "ClientSegment" AS ENUM ('MOVING', 'LIVING');
-- CreateEnum
CREATE TYPE "LeadStepStatus" AS ENUM ('TODO', 'IN_PROGRESS', 'DONE', 'SKIPPED');
-- CreateEnum
CREATE TYPE "ClientRequestKind" AS ENUM ('SUBSCRIPTION', 'SERVICE');
-- CreateEnum
CREATE TYPE "ClientRequestStatus" AS ENUM ('NEW', 'DONE', 'CANCELLED');
-- CreateEnum
CREATE TYPE "ConciergeAuthor" AS ENUM ('CLIENT', 'OPERATOR');
-- AlterEnum
ALTER TYPE "SubscriptionPlan" ADD VALUE 'ELITE';
-- AlterTable
ALTER TABLE "Category" ADD COLUMN "eliteDiscountPct" INTEGER NOT NULL DEFAULT 0;
-- AlterTable
ALTER TABLE "Client" ADD COLUMN "segment" "ClientSegment";
-- AlterTable
ALTER TABLE "Lead" ADD COLUMN "checklist" TEXT[] DEFAULT ARRAY[]::TEXT[],
ADD COLUMN "clientId" TEXT;
-- CreateTable
CREATE TABLE "LeadStep" (
"id" TEXT NOT NULL,
"leadId" TEXT NOT NULL,
"code" TEXT NOT NULL,
"sortOrder" INTEGER NOT NULL,
"status" "LeadStepStatus" NOT NULL DEFAULT 'TODO',
"note" TEXT,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "LeadStep_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "ClientRequest" (
"id" TEXT NOT NULL,
"number" SERIAL NOT NULL,
"clientId" TEXT NOT NULL,
"kind" "ClientRequestKind" NOT NULL,
"plan" "SubscriptionPlan",
"serviceCode" TEXT,
"comment" TEXT,
"status" "ClientRequestStatus" NOT NULL DEFAULT 'NEW',
"adminNote" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "ClientRequest_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "ConciergeMessage" (
"id" TEXT NOT NULL,
"clientId" TEXT NOT NULL,
"author" "ConciergeAuthor" NOT NULL,
"adminUserId" TEXT,
"text" TEXT NOT NULL,
"readAt" TIMESTAMP(3),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "ConciergeMessage_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "LeadStep_leadId_code_key" ON "LeadStep"("leadId", "code");
-- CreateIndex
CREATE UNIQUE INDEX "ClientRequest_number_key" ON "ClientRequest"("number");
-- CreateIndex
CREATE INDEX "ClientRequest_status_createdAt_idx" ON "ClientRequest"("status", "createdAt");
-- CreateIndex
CREATE INDEX "ClientRequest_clientId_idx" ON "ClientRequest"("clientId");
-- CreateIndex
CREATE INDEX "ConciergeMessage_clientId_createdAt_idx" ON "ConciergeMessage"("clientId", "createdAt");
-- CreateIndex
CREATE INDEX "ConciergeMessage_author_readAt_idx" ON "ConciergeMessage"("author", "readAt");
-- CreateIndex
CREATE INDEX "Lead_clientId_idx" ON "Lead"("clientId");
-- AddForeignKey
ALTER TABLE "Lead" ADD CONSTRAINT "Lead_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LeadStep" ADD CONSTRAINT "LeadStep_leadId_fkey" FOREIGN KEY ("leadId") REFERENCES "Lead"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ClientRequest" ADD CONSTRAINT "ClientRequest_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ConciergeMessage" ADD CONSTRAINT "ConciergeMessage_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- Elite: скидки по направлениям как на главной («до −35%»)
UPDATE "Category" SET "eliteDiscountPct" = 35 WHERE "code" IN ('HOME', 'DOCS', 'LEARNING');
@@ -0,0 +1,94 @@
-- CreateEnum
CREATE TYPE "RelocationItemKind" AS ENUM ('STEP', 'DOC');
-- AlterEnum
ALTER TYPE "ConciergeAuthor" ADD VALUE 'PROVIDER';
-- DropForeignKey
ALTER TABLE "ConciergeMessage" DROP CONSTRAINT "ConciergeMessage_clientId_fkey";
-- AlterTable
ALTER TABLE "AdminUser" ADD COLUMN "telegramId" BIGINT,
ADD COLUMN "tgLinkToken" TEXT,
ADD COLUMN "tgNotify" BOOLEAN NOT NULL DEFAULT true;
-- AlterTable
ALTER TABLE "ConciergeMessage" ADD COLUMN "providerId" TEXT,
ALTER COLUMN "clientId" DROP NOT NULL;
-- AlterTable
ALTER TABLE "Lead" DROP COLUMN "checklist";
-- AlterTable
ALTER TABLE "LeadStep" ADD COLUMN "title" TEXT;
-- CreateTable
CREATE TABLE "RelocationItem" (
"id" TEXT NOT NULL,
"kind" "RelocationItemKind" NOT NULL,
"code" TEXT NOT NULL,
"name" JSONB NOT NULL,
"hint" JSONB,
"sortOrder" INTEGER NOT NULL DEFAULT 0,
"active" BOOLEAN NOT NULL DEFAULT true,
"inTurnkey" BOOLEAN NOT NULL DEFAULT true,
CONSTRAINT "RelocationItem_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "LeadDoc" (
"id" TEXT NOT NULL,
"leadId" TEXT NOT NULL,
"code" TEXT NOT NULL,
"title" TEXT,
"checked" BOOLEAN NOT NULL DEFAULT false,
"sortOrder" INTEGER NOT NULL,
CONSTRAINT "LeadDoc_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "RelocationItem_kind_code_key" ON "RelocationItem"("kind", "code");
-- CreateIndex
CREATE UNIQUE INDEX "LeadDoc_leadId_code_key" ON "LeadDoc"("leadId", "code");
-- CreateIndex
CREATE UNIQUE INDEX "AdminUser_telegramId_key" ON "AdminUser"("telegramId");
-- CreateIndex
CREATE UNIQUE INDEX "AdminUser_tgLinkToken_key" ON "AdminUser"("tgLinkToken");
-- CreateIndex
CREATE INDEX "ConciergeMessage_providerId_createdAt_idx" ON "ConciergeMessage"("providerId", "createdAt");
-- AddForeignKey
ALTER TABLE "LeadDoc" ADD CONSTRAINT "LeadDoc_leadId_fkey" FOREIGN KEY ("leadId") REFERENCES "Lead"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ConciergeMessage" ADD CONSTRAINT "ConciergeMessage_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ConciergeMessage" ADD CONSTRAINT "ConciergeMessage_providerId_fkey" FOREIGN KEY ("providerId") REFERENCES "Provider"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- стартовые шаблоны: шаги переезда и чек-лист документов (дальше правятся в админке)
INSERT INTO "RelocationItem" ("id", "kind", "code", "name", "hint", "sortOrder", "active", "inTurnkey") VALUES
(gen_random_uuid()::text, 'STEP', 'consult', '{"ru": "Консультация по переезду", "en": "Relocation consultation", "zh": "搬家咨询", "hy": "Տեղափոխության խորհրդատվություն", "es": "Consulta de mudanza"}'::jsonb, NULL, 0, true, false),
(gen_random_uuid()::text, 'STEP', 'airport', '{"ru": "Встреча в аэропорту", "en": "Airport pickup", "zh": "机场接机", "hy": "Դիմավորում օդանավակայանում", "es": "Recogida en el aeropuerto"}'::jsonb, NULL, 1, true, true),
(gen_random_uuid()::text, 'STEP', 'stay', '{"ru": "Жильё на первое время", "en": "A place for the first days", "zh": "初期住宿", "hy": "Բնակություն առաջին օրերի համար", "es": "Alojamiento para empezar"}'::jsonb, NULL, 2, true, true),
(gen_random_uuid()::text, 'STEP', 'flat', '{"ru": "Поиск квартиры", "en": "Flat search", "zh": "找房", "hy": "Բնակարանի որոնում", "es": "Búsqueda de piso"}'::jsonb, NULL, 3, true, true),
(gen_random_uuid()::text, 'STEP', 'registration', '{"ru": "Регистрация", "en": "Registration", "zh": "登记", "hy": "Գրանցում", "es": "Empadronamiento"}'::jsonb, NULL, 4, true, true),
(gen_random_uuid()::text, 'STEP', 'socialCard', '{"ru": "Соцкарта", "en": "Social card", "zh": "社保卡", "hy": "Սոցքարտ", "es": "Tarjeta social"}'::jsonb, NULL, 5, true, true),
(gen_random_uuid()::text, 'STEP', 'bankCard', '{"ru": "Банковская карта", "en": "Bank card", "zh": "银行卡", "hy": "Բանկային քարտ", "es": "Tarjeta bancaria"}'::jsonb, NULL, 6, true, true),
(gen_random_uuid()::text, 'STEP', 'residence', '{"ru": "ВНЖ", "en": "Residence permit", "zh": "居留许可", "hy": "Կացության քարտ", "es": "Permiso de residencia"}'::jsonb, NULL, 7, true, true),
(gen_random_uuid()::text, 'DOC', 'passport', '{"ru": "Загранпаспорт", "en": "International passport", "zh": "护照", "hy": "Արտասահմանյան անձնագիր", "es": "Pasaporte"}'::jsonb, '{"ru": "Действует ещё минимум 6 месяцев после переезда", "en": "Valid for at least 6 months after the move", "zh": "搬家后至少还有 6 个月有效期", "hy": "Վավեր տեղափոխվելուց հետո առնվազն 6 ամիս", "es": "Vigente al menos 6 meses después de la mudanza"}'::jsonb, 0, true, false),
(gen_random_uuid()::text, 'DOC', 'passportCopies', '{"ru": "Копии паспорта", "en": "Passport copies", "zh": "护照复印件", "hy": "Անձնագրի պատճեններ", "es": "Copias del pasaporte"}'::jsonb, '{"ru": "2–3 копии страницы с фото", "en": "2–3 copies of the photo page", "zh": "照片页复印 2–3 份", "hy": "Լուսանկարով էջի 2–3 պատճեն", "es": "2–3 copias de la página con foto"}'::jsonb, 1, true, false),
(gen_random_uuid()::text, 'DOC', 'photos', '{"ru": "Фото 3×4", "en": "3×4 photos", "zh": "3×4 照片", "hy": "3×4 լուսանկարներ", "es": "Fotos 3×4"}'::jsonb, '{"ru": "4–6 штук для ВНЖ и соцкарты", "en": "4–6 for the residence permit and social card", "zh": "4–6 张,用于居留许可和社保卡", "hy": "4–6 հատ՝ կացության քարտի և սոցքարտի համար", "es": "4–6 para la residencia y la tarjeta social"}'::jsonb, 2, true, false),
(gen_random_uuid()::text, 'DOC', 'birthCertificate', '{"ru": "Свидетельство о рождении", "en": "Birth certificate", "zh": "出生证明", "hy": "Ծննդյան վկայական", "es": "Partida de nacimiento"}'::jsonb, '{"ru": "С апостилем — нужно для ВНЖ", "en": "Apostilled — needed for the residence permit", "zh": "需海牙认证,办理居留许可时使用", "hy": "Ապոստիլով՝ պետք է կացության քարտի համար", "es": "Apostillada: se necesita para la residencia"}'::jsonb, 3, true, false),
(gen_random_uuid()::text, 'DOC', 'marriageCertificate', '{"ru": "Свидетельство о браке", "en": "Marriage certificate", "zh": "结婚证", "hy": "Ամուսնության վկայական", "es": "Certificado de matrimonio"}'::jsonb, '{"ru": "С апостилем, если переезжаете семьёй", "en": "Apostilled, if moving as a family", "zh": "需海牙认证,全家搬迁时需要", "hy": "Ապոստիլով, եթե տեղափոխվում եք ընտանիքով", "es": "Apostillado, si os mudáis en familia"}'::jsonb, 4, true, false),
(gen_random_uuid()::text, 'DOC', 'diploma', '{"ru": "Диплом", "en": "Diploma", "zh": "学历证书", "hy": "Դիպլոմ", "es": "Título universitario"}'::jsonb, '{"ru": "С апостилем — пригодится для работы и ВНЖ", "en": "Apostilled — useful for work and the residence permit", "zh": "需海牙认证,工作和居留许可时有用", "hy": "Ապոստիլով՝ պետք կգա աշխատանքի և կացության քարտի համար", "es": "Apostillado: útil para trabajar y para la residencia"}'::jsonb, 5, true, false),
(gen_random_uuid()::text, 'DOC', 'criminalRecord', '{"ru": "Справка о несудимости", "en": "Criminal record certificate", "zh": "无犯罪记录证明", "hy": "Դատվածության բացակայության տեղեկանք", "es": "Certificado de antecedentes penales"}'::jsonb, '{"ru": "С апостилем, действует 3 месяца", "en": "Apostilled, valid for 3 months", "zh": "需海牙认证,有效期 3 个月", "hy": "Ապոստիլով, վավեր է 3 ամիս", "es": "Apostillado, válido 3 meses"}'::jsonb, 6, true, false),
(gen_random_uuid()::text, 'DOC', 'insurance', '{"ru": "Медицинская страховка", "en": "Health insurance", "zh": "医疗保险", "hy": "Բժշկական ապահովագրություն", "es": "Seguro médico"}'::jsonb, '{"ru": "На первые месяцы, пока нет ВНЖ", "en": "For the first months before the residence permit", "zh": "覆盖办下居留许可前的头几个月", "hy": "Առաջին ամիսների համար, մինչև կացության քարտը", "es": "Para los primeros meses, hasta tener la residencia"}'::jsonb, 7, true, false)
ON CONFLICT ("kind", "code") DO NOTHING;
@@ -0,0 +1,81 @@
-- CreateEnum
CREATE TYPE "OfferLimit" AS ENUM ('NONE', 'ONCE', 'WEEK', 'MONTH');
-- CreateEnum
CREATE TYPE "PartnerRole" AS ENUM ('OWNER', 'STAFF');
-- AlterTable
ALTER TABLE "CardUsage" ADD COLUMN "level" TEXT,
ADD COLUMN "memberUserId" TEXT,
ADD COLUMN "offerId" TEXT;
-- AlterTable
ALTER TABLE "Partner" ADD COLUMN "ownerInviteCode" TEXT;
-- CreateTable
CREATE TABLE "PartnerOffer" (
"id" TEXT NOT NULL,
"partnerId" TEXT NOT NULL,
"title" JSONB NOT NULL,
"minLevel" "SubscriptionPlan",
"limit" "OfferLimit" NOT NULL DEFAULT 'NONE',
"limitCount" INTEGER NOT NULL DEFAULT 1,
"active" BOOLEAN NOT NULL DEFAULT true,
"sortOrder" INTEGER NOT NULL DEFAULT 0,
CONSTRAINT "PartnerOffer_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "PartnerMember" (
"id" TEXT NOT NULL,
"partnerId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"role" "PartnerRole" NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "PartnerMember_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "PartnerInvite" (
"id" TEXT NOT NULL,
"code" TEXT NOT NULL,
"partnerId" TEXT NOT NULL,
"expiresAt" TIMESTAMP(3) NOT NULL,
"usedAt" TIMESTAMP(3),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "PartnerInvite_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "PartnerMember_partnerId_userId_key" ON "PartnerMember"("partnerId", "userId");
-- CreateIndex
CREATE UNIQUE INDEX "PartnerInvite_code_key" ON "PartnerInvite"("code");
-- CreateIndex
CREATE INDEX "CardUsage_clientId_offerId_createdAt_idx" ON "CardUsage"("clientId", "offerId", "createdAt");
-- CreateIndex
CREATE INDEX "CardUsage_partnerId_createdAt_idx" ON "CardUsage"("partnerId", "createdAt");
-- CreateIndex
CREATE UNIQUE INDEX "Partner_ownerInviteCode_key" ON "Partner"("ownerInviteCode");
-- AddForeignKey
ALTER TABLE "PartnerOffer" ADD CONSTRAINT "PartnerOffer_partnerId_fkey" FOREIGN KEY ("partnerId") REFERENCES "Partner"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "PartnerMember" ADD CONSTRAINT "PartnerMember_partnerId_fkey" FOREIGN KEY ("partnerId") REFERENCES "Partner"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "PartnerMember" ADD CONSTRAINT "PartnerMember_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "PartnerInvite" ADD CONSTRAINT "PartnerInvite_partnerId_fkey" FOREIGN KEY ("partnerId") REFERENCES "Partner"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "CardUsage" ADD CONSTRAINT "CardUsage_offerId_fkey" FOREIGN KEY ("offerId") REFERENCES "PartnerOffer"("id") ON DELETE SET NULL ON UPDATE CASCADE;
@@ -0,0 +1,64 @@
-- CreateEnum
CREATE TYPE "StaffRole" AS ENUM ('SUPERADMIN', 'SUPPORT', 'CONCIERGE', 'SALES');
-- AlterTable
ALTER TABLE "AdminUser" ADD COLUMN "roles" "StaffRole"[] DEFAULT ARRAY[]::"StaffRole"[],
ALTER COLUMN "email" DROP NOT NULL,
ALTER COLUMN "passwordHash" DROP NOT NULL;
-- AlterTable
ALTER TABLE "Client" ADD COLUMN "adminNote" TEXT,
ADD COLUMN "tags" TEXT[] DEFAULT ARRAY[]::TEXT[];
-- AlterTable
ALTER TABLE "Subscription" ADD COLUMN "agencyId" TEXT,
ADD COLUMN "amount" INTEGER,
ADD COLUMN "cancelledAt" TIMESTAMP(3),
ADD COLUMN "grantedByAdminId" TEXT,
ADD COLUMN "note" TEXT,
ADD COLUMN "payMethod" TEXT,
ADD COLUMN "refundAmount" INTEGER,
ADD COLUMN "refundedAt" TIMESTAMP(3);
-- CreateTable
CREATE TABLE "AdminLoginRequest" (
"id" TEXT NOT NULL,
"code" TEXT NOT NULL,
"pollKey" TEXT NOT NULL,
"adminUserId" TEXT,
"approvedAt" TIMESTAMP(3),
"consumedAt" TIMESTAMP(3),
"expiresAt" TIMESTAMP(3) NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "AdminLoginRequest_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "SavedSegment" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"filters" JSONB NOT NULL,
"adminUserId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "SavedSegment_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "AdminLoginRequest_code_key" ON "AdminLoginRequest"("code");
-- CreateIndex
CREATE INDEX "Subscription_createdAt_idx" ON "Subscription"("createdAt");
-- AddForeignKey
ALTER TABLE "AdminLoginRequest" ADD CONSTRAINT "AdminLoginRequest_adminUserId_fkey" FOREIGN KEY ("adminUserId") REFERENCES "AdminUser"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "SavedSegment" ADD CONSTRAINT "SavedSegment_adminUserId_fkey" FOREIGN KEY ("adminUserId") REFERENCES "AdminUser"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- существующие админы получают роли новой админки
UPDATE "AdminUser" SET "roles" = ARRAY['SUPERADMIN']::"StaffRole"[] WHERE "role" = 'OWNER';
UPDATE "AdminUser" SET "roles" = ARRAY['SUPPORT','CONCIERGE']::"StaffRole"[] WHERE "role" = 'OPERATOR';
-- подарки агентств: запоминаем агентство
UPDATE "Subscription" s SET "agencyId" = c."agencyId" FROM "Client" c WHERE s."clientId" = c.id AND s.source = 'AGENCY_GIFT';