# СХЕМА БАЗЫ ДАННЫХ 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_
