# СХЕМА БАЗЫ ДАННЫХ SFERA ## 🎯 ОБЗОР АРХИТЕКТУРЫ БД База данных SFERA построена на PostgreSQL с использованием Prisma ORM для type-safe доступа к данным. Схема спроектирована для поддержки сложных B2B взаимодействий между четырьмя типами организаций: фулфилмент-центрами, селлерами, логистами и оптовыми поставщиками. ### Ключевые особенности: - **29 основных таблиц** для полного покрытия бизнес-логики - **CUID идентификаторы** для глобальной уникальности - **Составные индексы** для оптимизации частых запросов - **JSON поля** для гибкого хранения структурированных данных - **Каскадное удаление** для целостности данных - **Временные метки** на всех основных сущностях ## 📊 СТРУКТУРА ТАБЛИЦ ### 1. АУТЕНТИФИКАЦИЯ И ПОЛЬЗОВАТЕЛИ #### `users` (User) Основная таблица пользователей системы. ```prisma model User { id String @id @default(cuid()) phone String @unique // Телефон для входа avatar String? // URL аватара managerName String? // Имя менеджера createdAt DateTime @default(now()) updatedAt DateTime @updatedAt organizationId String? // Связь с организацией // Relations sentMessages Message[] @relation("SentMessages") smsCodes SmsCode[] organization Organization? @relation(fields: [organizationId], references: [id]) } ``` **Индексы:** - Уникальный индекс по `phone` - Foreign key индекс по `organizationId` #### `admins` (Admin) Администраторы системы с отдельной авторизацией. ```prisma model Admin { id String @id @default(cuid()) username String @unique // Логин администратора password String // Хэшированный пароль email String? @unique // Email администратора isActive Boolean @default(true) // Статус активности lastLogin DateTime? // Последний вход createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } ``` #### `sms_codes` (SmsCode) Временные SMS коды для двухфакторной аутентификации. ```prisma model SmsCode { id String @id @default(cuid()) code String // 4-значный код phone String // Телефон получателя expiresAt DateTime // Срок действия кода isUsed Boolean @default(false) // Использован ли код attempts Int @default(0) // Попытки ввода maxAttempts Int @default(3) // Максимум попыток createdAt DateTime @default(now()) userId String? // Связь с пользователем // Relations user User? @relation(fields: [userId], references: [id]) } ``` ### 2. ОРГАНИЗАЦИИ И ПАРТНЕРСТВО #### `organizations` (Organization) Центральная таблица организаций с полной информацией из DaData. ```prisma model Organization { id String @id @default(cuid()) inn String @unique // ИНН (уникальный) kpp String? // КПП name String? // Краткое название fullName String? // Полное юридическое название ogrn String? // ОГРН ogrnDate DateTime? // Дата ОГРН type OrganizationType // FULFILLMENT|SELLER|LOGIST|WHOLESALE market String? // Рынок/площадка // Адрес и местоположение address String? // Краткий адрес addressFull String? // Полный адрес okato String? // ОКАТО код oktmo String? // ОКТМО код // Юридическая информация status String? // Статус организации actualityDate DateTime? // Дата актуальности данных registrationDate DateTime? // Дата регистрации liquidationDate DateTime? // Дата ликвидации managementName String? // ФИО руководителя managementPost String? // Должность руководителя // Организационно-правовая форма opfCode String? // Код ОПФ opfFull String? // Полное название ОПФ opfShort String? // Краткое название ОПФ // Коды деятельности okpo String? // ОКПО okved String? // ОКВЭД основной // Контакты (JSON массивы) phones Json? // [{value: "+7...", label: "Основной"}] emails Json? // [{value: "...", label: "Общий"}] // Финансовая информация employeeCount Int? // Количество сотрудников revenue BigInt? // Годовая выручка taxSystem String? // Система налогообложения // DaData сырые данные dadataData Json? // Полный ответ от DaData // Реферальная система referralCode String? @unique // Уникальный реф. код referredById String? // Кто привел referralPoints Int @default(0) // Накопленные баллы // Временные метки createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations (29 связей) apiKeys ApiKey[] carts Cart? counterpartyOf Counterparty[] @relation("CounterpartyOf") organizationCounterparties Counterparty[] @relation("OrganizationCounterparties") receivedRequests CounterpartyRequest[] @relation("ReceivedRequests") sentRequests CounterpartyRequest[] @relation("SentRequests") employees Employee[] externalAds ExternalAd[] @relation("ExternalAds") favorites Favorites[] logistics Logistics[] receivedMessages Message[] @relation("ReceivedMessages") sentMessages Message[] @relation("SentMessages") referredBy Organization? @relation("ReferralRelation", fields: [referredById], references: [id]) referrals Organization[] @relation("ReferralRelation") products Product[] referralTransactions ReferralTransaction[] @relation("ReferralTransactions") referrerTransactions ReferralTransaction[] @relation("ReferrerTransactions") sellerStatsCaches SellerStatsCache[] @relation("SellerStatsCaches") services Service[] supplies Supply[] sellerSupplies Supply[] @relation("SellerSupplies") fulfillmentSupplyOrders SupplyOrder[] @relation("SupplyOrderFulfillmentCenter") logisticsSupplyOrders SupplyOrder[] @relation("SupplyOrderLogistics") supplyOrders SupplyOrder[] partnerSupplyOrders SupplyOrder[] @relation("SupplyOrderPartner") supplySuppliers SupplySupplier[] @relation("SupplySuppliers") users User[] wbWarehouseCaches WBWarehouseCache[] @relation("WBWarehouseCaches") wildberriesSupplies WildberriesSupply[] // Индексы @@index([referralCode]) @@index([referredById]) } ``` #### `counterparties` (Counterparty) Связи между организациями-партнерами. ```prisma model Counterparty { id String @id @default(cuid()) createdAt DateTime @default(now()) organizationId String // Организация counterpartyId String // Ее контрагент type CounterpartyType @default(MANUAL) // MANUAL|REFERRAL|AUTO_BUSINESS|AUTO triggeredBy String? // Кем инициировано triggerEntityId String? // ID сущности-триггера // Relations counterparty Organization @relation("CounterpartyOf", fields: [counterpartyId], references: [id]) organization Organization @relation("OrganizationCounterparties", fields: [organizationId], references: [id]) // Уникальность и индексы @@unique([organizationId, counterpartyId]) @@index([type]) } ``` #### `counterparty_requests` (CounterpartyRequest) Заявки на установление партнерских отношений. ```prisma model CounterpartyRequest { id String @id @default(cuid()) status CounterpartyRequestStatus @default(PENDING) // PENDING|ACCEPTED|REJECTED|CANCELLED createdAt DateTime @default(now()) updatedAt DateTime @updatedAt senderId String // Отправитель заявки receiverId String // Получатель заявки message String? // Сопроводительное сообщение // Relations receiver Organization @relation("ReceivedRequests", fields: [receiverId], references: [id]) sender Organization @relation("SentRequests", fields: [senderId], references: [id]) // Уникальность @@unique([senderId, receiverId]) } ``` ### 3. СООБЩЕНИЯ И КОММУНИКАЦИИ #### `messages` (Message) Система B2B сообщений между организациями. ```prisma model Message { id String @id @default(cuid()) content String? // Текст сообщения type MessageType @default(TEXT) // TEXT|VOICE|IMAGE|FILE // Голосовые сообщения voiceUrl String? // URL аудиофайла voiceDuration Int? // Длительность в секундах // Файловые вложения fileUrl String? // URL файла fileName String? // Название файла fileSize Int? // Размер в байтах fileType String? // MIME тип isRead Boolean @default(false) // Статус прочтения createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Участники переписки senderId String // ID пользователя-отправителя senderOrganizationId String // ID организации-отправителя receiverOrganizationId String // ID организации-получателя // Relations receiverOrganization Organization @relation("ReceivedMessages", fields: [receiverOrganizationId], references: [id]) sender User @relation("SentMessages", fields: [senderId], references: [id]) senderOrganization Organization @relation("SentMessages", fields: [senderOrganizationId], references: [id]) // Индексы для производительности @@index([senderOrganizationId, receiverOrganizationId, createdAt]) @@index([receiverOrganizationId, isRead]) } ``` ### 4. ТОВАРЫ И УСЛУГИ #### `products` (Product) Товары оптовых поставщиков. ```prisma model Product { id String @id @default(cuid()) name String // Название товара article String // Артикул description String? // Описание price Decimal @db.Decimal(12, 2) // Цена за единицу pricePerSet Decimal? @db.Decimal(12, 2) // Цена за комплект quantity Int @default(0) // Остаток доступный setQuantity Int? // Штук в комплекте ordered Int? // Зарезервировано inTransit Int? // В пути stock Int? // Физический остаток sold Int? // Продано всего type ProductType @default(PRODUCT) // PRODUCT|CONSUMABLE // Характеристики categoryId String? // Категория товара brand String? // Бренд color String? // Цвет size String? // Размер weight Decimal? @db.Decimal(8, 3) // Вес в кг dimensions String? // Габариты material String? // Материал // Медиафайлы images Json @default("[]") // Массив URL изображений mainImage String? // Основное изображение isActive Boolean @default(true) // Активность товара createdAt DateTime @default(now()) updatedAt DateTime @updatedAt organizationId String // Организация-владелец // Relations cartItems CartItem[] favorites Favorites[] category Category? @relation(fields: [categoryId], references: [id]) organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) supplyOrderItems SupplyOrderItem[] // Уникальность артикула в рамках организации @@unique([organizationId, article]) } ``` #### `categories` (Category) Категории товаров. ```prisma model Category { id String @id @default(cuid()) name String @unique // Название категории createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations products Product[] } ``` #### `services` (Service) Услуги фулфилмент-центров. ```prisma model Service { id String @id @default(cuid()) name String // Название услуги description String? // Описание price Decimal @db.Decimal(10, 2) // Цена услуги imageUrl String? // Изображение услуги createdAt DateTime @default(now()) updatedAt DateTime @updatedAt organizationId String // Фулфилмент-центр // Relations organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) } ``` ### 5. РАСХОДНЫЕ МАТЕРИАЛЫ #### `supplies` (Supply) Расходные материалы фулфилмента и селлеров. ```prisma model Supply { id String @id @default(cuid()) name String // Название расходника article String // Артикул СФ description String? // Описание price Decimal @db.Decimal(10, 2) // Общая цена pricePerUnit Decimal? @db.Decimal(10, 2) // Цена за единицу quantity Int @default(0) // Общее количество unit String @default("шт") // Единица измерения category String @default("Расходники") // Категория status String @default("planned") // Статус поставки date DateTime @default(now()) // Дата поставки supplier String @default("Не указан") // Поставщик minStock Int @default(0) // Минимальный остаток currentStock Int @default(0) // Текущий остаток usedStock Int @default(0) // Использовано imageUrl String? // Изображение type SupplyType @default(FULFILLMENT_CONSUMABLES) // Тип расходника // Для селлерских расходников sellerOwnerId String? // ID селлера-владельца shopLocation String? // Расположение магазина // Количество после приемки actualQuantity Int? // Фактическое количество createdAt DateTime @default(now()) updatedAt DateTime @updatedAt organizationId String // Организация-владелец // Relations organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) sellerOwner Organization? @relation("SellerSupplies", fields: [sellerOwnerId], references: [id]) } ``` ### 6. КОРЗИНА И ИЗБРАННОЕ #### `carts` (Cart) Корзина организации (одна на организацию). ```prisma model Cart { id String @id @default(cuid()) organizationId String @unique // Одна корзина на организацию createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations items CartItem[] organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) } ``` #### `cart_items` (CartItem) Товары в корзине. ```prisma model CartItem { id String @id @default(cuid()) cartId String // Корзина productId String // Товар quantity Int @default(1) // Количество createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations cart Cart @relation(fields: [cartId], references: [id], onDelete: Cascade) product Product @relation(fields: [productId], references: [id], onDelete: Cascade) // Уникальность товара в корзине @@unique([cartId, productId]) } ``` #### `favorites` (Favorites) Избранные товары организаций. ```prisma model Favorites { id String @id @default(cuid()) organizationId String // Организация productId String // Избранный товар createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) product Product @relation(fields: [productId], references: [id], onDelete: Cascade) // Уникальность @@unique([organizationId, productId]) } ``` ### 7. ЗАКАЗЫ И ПОСТАВКИ #### `supply_orders` (SupplyOrder) Заказы поставок между организациями. ```prisma model SupplyOrder { id String @id @default(cuid()) partnerId String // Поставщик deliveryDate DateTime // Дата доставки status SupplyOrderStatus @default(PENDING) // Статус заказа totalAmount Decimal @db.Decimal(12, 2) // Общая сумма totalItems Int // Общее количество // Многоуровневая система поставок fulfillmentCenterId String? // ID фулфилмент-центра logisticsPartnerId String? // ID логиста consumableType String? // Тип расходников packagesCount Int? // Количество грузовых мест volume Float? // Объём в м³ responsibleEmployee String? // Ответственный сотрудник notes String? // Примечания createdAt DateTime @default(now()) updatedAt DateTime @updatedAt organizationId String // Организация-заказчик // Relations items SupplyOrderItem[] routes SupplyRoute[] fulfillmentCenter Organization? @relation("SupplyOrderFulfillmentCenter", fields: [fulfillmentCenterId], references: [id]) logisticsPartner Organization? @relation("SupplyOrderLogistics", fields: [logisticsPartnerId], references: [id]) organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) partner Organization @relation("SupplyOrderPartner", fields: [partnerId], references: [id]) employee Employee? @relation("SupplyOrderResponsible", fields: [responsibleEmployee], references: [id]) } ``` #### `supply_order_items` (SupplyOrderItem) Позиции в заказе поставки. ```prisma model SupplyOrderItem { id String @id @default(cuid()) supplyOrderId String // Заказ поставки productId String // Товар quantity Int // Количество price Decimal @db.Decimal(12, 2) // Цена за единицу totalPrice Decimal @db.Decimal(12, 2) // Общая цена // Рецептура для фулфилмента services String[] @default([]) // ID услуг fulfillmentConsumables String[] @default([]) // ID расходников фулфилмента sellerConsumables String[] @default([]) // ID расходников селлера marketplaceCardId String? // ID карточки маркетплейса createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations product Product @relation(fields: [productId], references: [id]) supplyOrder SupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade) // Уникальность товара в заказе @@unique([supplyOrderId, productId]) } ``` #### `supply_routes` (SupplyRoute) Маршруты доставки для заказов. ```prisma model SupplyRoute { id String @id @default(cuid()) supplyOrderId String // Заказ поставки logisticsId String? // Предустановленный маршрут fromLocation String // Точка забора toLocation String // Точка доставки fromAddress String? // Адрес забора toAddress String? // Адрес доставки distance Float? // Расстояние в км estimatedTime Int? // Время в часах price Decimal? @db.Decimal(10, 2) // Стоимость доставки status String? @default("pending") // Статус маршрута createdAt DateTime @default(now()) updatedAt DateTime @updatedAt createdDate DateTime @default(now()) // Дата создания маршрута // Relations supplyOrder SupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade) logistics Logistics? @relation("SupplyRouteLogistics", fields: [logisticsId], references: [id]) } ``` ### 8. СОТРУДНИКИ #### `employees` (Employee) Сотрудники организаций (в основном фулфилмент). ```prisma model Employee { id String @id @default(cuid()) firstName String // Имя lastName String // Фамилия middleName String? // Отчество birthDate DateTime? // Дата рождения avatar String? // Фото сотрудника // Паспортные данные passportPhoto String? // Фото паспорта passportSeries String? // Серия паспорта passportNumber String? // Номер паспорта passportIssued String? // Кем выдан passportDate DateTime? // Дата выдачи address String? // Адрес регистрации // Рабочая информация position String // Должность department String? // Отдел hireDate DateTime // Дата приема salary Float? // Зарплата status EmployeeStatus @default(ACTIVE) // Статус сотрудника // Контакты phone String // Телефон email String? // Email telegram String? // Telegram whatsapp String? // WhatsApp emergencyContact String? // Экстренный контакт emergencyPhone String? // Телефон экстренного контакта organizationId String // Организация-работодатель createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations scheduleRecords EmployeeSchedule[] organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) supplyOrders SupplyOrder[] @relation("SupplyOrderResponsible") } ``` #### `employee_schedules` (EmployeeSchedule) Табель учета рабочего времени. ```prisma model EmployeeSchedule { id String @id @default(cuid()) date DateTime // Дата status ScheduleStatus // WORK|WEEKEND|VACATION|SICK|ABSENT hoursWorked Float? // Отработано часов overtimeHours Float? // Сверхурочные часы notes String? // Примечания employeeId String // Сотрудник createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations employee Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade) // Уникальность записи на дату @@unique([employeeId, date]) } ``` ### 9. ЛОГИСТИКА #### `logistics` (Logistics) Логистические маршруты организаций. ```prisma model Logistics { id String @id @default(cuid()) fromLocation String // Откуда toLocation String // Куда priceUnder1m3 Float // Цена до 1м³ priceOver1m3 Float // Цена свыше 1м³ description String? // Описание маршрута createdAt DateTime @default(now()) updatedAt DateTime @updatedAt organizationId String // Организация-логист // Relations organization Organization @relation(fields: [organizationId], references: [id]) routes SupplyRoute[] @relation("SupplyRouteLogistics") } ``` #### `supply_suppliers` (SupplySupplier) Поставщики для поставок (контакты на рынках). ```prisma model SupplySupplier { id String @id @default(cuid()) name String // Название поставщика contactName String // Контактное лицо phone String // Телефон market String? // Рынок address String? // Адрес place String? // Место/павильон telegram String? // Telegram organizationId String // Организация createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations organization Organization @relation("SupplySuppliers", fields: [organizationId], references: [id], onDelete: Cascade) } ``` ### 10. ИНТЕГРАЦИИ С МАРКЕТПЛЕЙСАМИ #### `api_keys` (ApiKey) API ключи для интеграции с маркетплейсами. ```prisma model ApiKey { id String @id @default(cuid()) marketplace MarketplaceType // WILDBERRIES|OZON apiKey String // Зашифрованный ключ isActive Boolean @default(true) // Активность ключа createdAt DateTime @default(now()) updatedAt DateTime @updatedAt validationData Json? // Данные валидации organizationId String // Организация-владелец // Relations organization Organization @relation(fields: [organizationId], references: [id]) // Уникальность ключа для маркетплейса @@unique([organizationId, marketplace]) } ``` #### `wildberries_supplies` (WildberriesSupply) Поставки на Wildberries. ```prisma model WildberriesSupply { id String @id @default(cuid()) organizationId String // Организация-селлер deliveryDate DateTime? // Дата доставки status WildberriesSupplyStatus @default(DRAFT) // Статус поставки totalAmount Decimal @db.Decimal(12, 2) // Общая сумма totalItems Int // Общее количество createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) cards WildberriesSupplyCard[] } ``` #### `wildberries_supply_cards` (WildberriesSupplyCard) Карточки товаров в поставке WB. ```prisma model WildberriesSupplyCard { id String @id @default(cuid()) supplyId String // Поставка nmId String // Номенклатура WB vendorCode String // Артикул поставщика title String // Название товара brand String? // Бренд price Decimal @db.Decimal(12, 2) // Цена discountedPrice Decimal? @db.Decimal(12, 2) // Цена со скидкой quantity Int // Общее количество selectedQuantity Int // Выбранное количество selectedMarket String? // Выбранный склад selectedPlace String? // Место на складе sellerName String? // Имя продавца sellerPhone String? // Телефон продавца deliveryDate DateTime? // Дата доставки mediaFiles Json @default("[]") // Медиафайлы selectedServices Json @default("[]") // Выбранные услуги createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations supply WildberriesSupply @relation(fields: [supplyId], references: [id], onDelete: Cascade) } ``` ### 11. АНАЛИТИКА И КЭШИРОВАНИЕ #### `external_ads` (ExternalAd) Внешняя реклама и продвижение. ```prisma model ExternalAd { id String @id @default(cuid()) name String // Название кампании url String // URL рекламы cost Decimal @db.Decimal(12, 2) // Стоимость date DateTime // Дата размещения nmId String // ID товара clicks Int @default(0) // Количество кликов organizationId String // Организация createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations organization Organization @relation("ExternalAds", fields: [organizationId], references: [id], onDelete: Cascade) // Индекс для аналитики @@index([organizationId, date]) } ``` #### `wb_warehouse_caches` (WBWarehouseCache) Кэш данных склада Wildberries. ```prisma model WBWarehouseCache { id String @id @default(cuid()) organizationId String // Организация cacheDate DateTime // Дата кэша data Json // Данные склада totalProducts Int @default(0) // Всего товаров totalStocks Int @default(0) // Всего остатков totalReserved Int @default(0) // Зарезервировано createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations organization Organization @relation("WBWarehouseCaches", fields: [organizationId], references: [id], onDelete: Cascade) // Уникальность и индексы @@unique([organizationId, cacheDate]) @@index([organizationId, cacheDate]) } ``` #### `seller_stats_caches` (SellerStatsCache) Кэш статистики продаж селлеров. ```prisma model SellerStatsCache { id String @id @default(cuid()) organizationId String // Организация cacheDate DateTime // Дата кэша period String // Период (day|week|month) dateFrom DateTime? // Начало периода dateTo DateTime? // Конец периода // Данные о продуктах productsData Json? // Детальные данные productsTotalSales Decimal? @db.Decimal(15, 2) // Общие продажи productsTotalOrders Int? // Количество заказов productsCount Int? // Количество товаров // Данные о рекламе advertisingData Json? // Детальные данные advertisingTotalCost Decimal? @db.Decimal(15, 2) // Затраты на рекламу advertisingTotalViews Int? // Просмотры advertisingTotalClicks Int? // Клики expiresAt DateTime // Срок истечения кэша createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations organization Organization @relation("SellerStatsCaches", fields: [organizationId], references: [id], onDelete: Cascade) // Уникальность и индексы @@unique([organizationId, cacheDate, period, dateFrom, dateTo]) @@index([organizationId, cacheDate]) @@index([expiresAt]) } ``` ### 12. РЕФЕРАЛЬНАЯ СИСТЕМА #### `referral_transactions` (ReferralTransaction) Транзакции реферальной системы. ```prisma model ReferralTransaction { id String @id @default(cuid()) referrerId String // Кто привел (получает баллы) referralId String // Кого привели points Int // Количество баллов type ReferralTransactionType // Тип транзакции description String? // Описание createdAt DateTime @default(now()) // Relations referral Organization @relation("ReferralTransactions", fields: [referralId], references: [id]) referrer Organization @relation("ReferrerTransactions", fields: [referrerId], references: [id]) // Индексы @@index([referrerId, createdAt]) @@index([referralId]) } ``` ## 🔗 ТИПЫ ПЕРЕЧИСЛЕНИЙ (ENUMS) ### OrganizationType ```prisma enum OrganizationType { FULFILLMENT // Фулфилмент-центр SELLER // Продавец/Селлер LOGIST // Логистическая компания WHOLESALE // Оптовый поставщик } ``` ### MarketplaceType ```prisma enum MarketplaceType { WILDBERRIES // Wildberries OZON // Ozon } ``` ### CounterpartyRequestStatus ```prisma enum CounterpartyRequestStatus { PENDING // Ожидает ответа ACCEPTED // Принята REJECTED // Отклонена CANCELLED // Отменена отправителем } ``` ### MessageType ```prisma enum MessageType { TEXT // Текстовое сообщение VOICE // Голосовое сообщение IMAGE // Изображение FILE // Файл } ``` ### EmployeeStatus ```prisma enum EmployeeStatus { ACTIVE // Активный сотрудник VACATION // В отпуске SICK // На больничном FIRED // Уволен } ``` ### ScheduleStatus ```prisma enum ScheduleStatus { WORK // Рабочий день WEEKEND // Выходной VACATION // Отпуск SICK // Больничный ABSENT // Отсутствие } ``` ### SupplyOrderStatus ```prisma enum SupplyOrderStatus { PENDING // Ожидает одобрения поставщика CONFIRMED // Подтверждено (устаревший) IN_TRANSIT // В пути (устаревший) SUPPLIER_APPROVED // Поставщик одобрил LOGISTICS_CONFIRMED // Логистика подтверждена SHIPPED // Отправлено DELIVERED // Доставлено CANCELLED // Отменено } ``` ### WildberriesSupplyStatus ```prisma enum WildberriesSupplyStatus { DRAFT // Черновик CREATED // Создана IN_PROGRESS // В процессе DELIVERED // Доставлена CANCELLED // Отменена } ``` ### ProductType ```prisma enum ProductType { PRODUCT // Товар CONSUMABLE // Расходный материал } ``` ### SupplyType ```prisma enum SupplyType { FULFILLMENT_CONSUMABLES // Расходники фулфилмента SELLER_CONSUMABLES // Расходники селлеров } ``` ### CounterpartyType ```prisma enum CounterpartyType { MANUAL // Ручное добавление REFERRAL // По реферальной ссылке AUTO_BUSINESS // Автоматическое B2B AUTO // Автоматическое общее } ``` ### ReferralTransactionType ```prisma enum ReferralTransactionType { REGISTRATION // Регистрация по реф. ссылке AUTO_PARTNERSHIP // Автоматическое партнерство FIRST_ORDER // Первый заказ реферала MONTHLY_BONUS // Ежемесячный бонус } ``` ## 📊 ИНДЕКСЫ И ОПТИМИЗАЦИЯ ### Составные индексы для производительности: 1. **messages** - Оптимизация чатов: - `[senderOrganizationId, receiverOrganizationId, createdAt]` - Быстрая выборка истории - `[receiverOrganizationId, isRead]` - Подсчет непрочитанных 2. **organizations** - Реферальная система: - `[referralCode]` - Быстрый поиск по реф. коду - `[referredById]` - Список рефералов 3. **external_ads** - Аналитика рекламы: - `[organizationId, date]` - Выборка по периодам 4. **wb_warehouse_caches** - Кэш склада: - `[organizationId, cacheDate]` - Актуальные данные 5. **seller_stats_caches** - Статистика продаж: - `[organizationId, cacheDate]` - Быстрый доступ - `[expiresAt]` - Очистка устаревших 6. **referral_transactions** - История транзакций: - `[referrerId, createdAt]` - Транзакции реферера - `[referralId]` - Транзакции реферала ### Уникальные ограничения: 1. **Бизнес-логика**: - `organizations.inn` - Уникальный ИНН - `organizations.referralCode` - Уникальный реф. код - `api_keys.[organizationId, marketplace]` - Один ключ на маркетплейс - `products.[organizationId, article]` - Уникальный артикул в организации 2. **Связи M:M**: - `counterparties.[organizationId, counterpartyId]` - Уникальная связь - `cart_items.[cartId, productId]` - Один товар в корзине - `favorites.[organizationId, productId]` - Одно избранное - `employee_schedules.[employeeId, date]` - Одна запись на дату ## 🔄 МИГРАЦИИ И ЭВОЛЮЦИЯ ### Стратегия миграций: ```bash # Создание миграции npx prisma migrate dev --name add_feature_name # Применение в production npx prisma migrate deploy # Сброс базы (только dev!) npx prisma migrate reset ``` ### Seed данные: ```javascript // prisma/seed.js const seedDatabase = async () => { // 1. Создание тестовых организаций const fulfillment = await prisma.organization.create({ data: { inn: '1234567890', type: 'FULFILLMENT', name: 'Тестовый фулфилмент', referralCode: 'TEST-FUL-001', }, }) // 2. Создание тестовых пользователей const user = await prisma.user.create({ data: { phone: '+79001234567', managerName: 'Тестовый менеджер', organizationId: fulfillment.id, }, }) // 3. Создание базовых категорий const categories = ['Электроника', 'Одежда', 'Продукты'] for (const name of categories) { await prisma.category.create({ data: { name } }) } } ``` ## 🚀 ПРОИЗВОДИТЕЛЬНОСТЬ ### Рекомендации по оптимизации: 1. **Пагинация для больших выборок**: ```typescript const products = await prisma.product.findMany({ take: 20, skip: (page - 1) * 20, orderBy: { createdAt: 'desc' }, }) ``` 2. **Выборочная загрузка полей**: ```typescript const organizations = await prisma.organization.findMany({ select: { id: true, inn: true, name: true, type: true, }, }) ``` 3. **Использование транзакций**: ```typescript const result = await prisma.$transaction(async (tx) => { const order = await tx.supplyOrder.create({ data: orderData }) await tx.supplyOrderItem.createMany({ data: itemsData }) return order }) ``` 4. **Connection pooling**: ```typescript const prisma = new PrismaClient({ datasources: { db: { url: DATABASE_URL, connectionLimit: 10, }, }, }) ``` --- _Схема базы данных документирована на основе анализа prisma/schema.prisma_ _PostgreSQL + Prisma ORM 6.12.0_ _Последнее обновление: 2025-08-21_