feat(fulfillment-supplies): миграция формы создания поставок расходников на v2 систему
- Обновлена форма создания поставок расходников фулфилмента для использования v2 GraphQL API - Заменена мутация CREATE_SUPPLY_ORDER на CREATE_FULFILLMENT_CONSUMABLE_SUPPLY - Обновлена структура input данных под новый формат v2 - Сделано поле логистики опциональным - Добавлено поле notes для комментариев к поставке - Обновлены refetchQueries на новые v2 запросы - Исправлены TypeScript ошибки в интерфейсах - Удалена дублирующая страница consumables-v2 - Сохранен оригинальный богатый UI интерфейс формы (819 строк) - Подтверждена работа с новой таблицей FulfillmentConsumableSupplyOrder Технические изменения: - src/components/fulfillment-supplies/create-fulfillment-consumables-supply-v2.tsx - основная форма - src/components/fulfillment-supplies/fulfillment-supplies-layout.tsx - обновлена навигация - Добавлены недостающие поля quantity и ordered в интерфейсы продуктов - Исправлены импорты и зависимости Результат: форма полностью интегрирована с v2 системой поставок, которая использует отдельные таблицы для каждого типа поставок согласно новой архитектуре. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
348
docs/business-processes/SUPPLY_CHAIN_WORKFLOW_V2.md
Normal file
348
docs/business-processes/SUPPLY_CHAIN_WORKFLOW_V2.md
Normal file
@ -0,0 +1,348 @@
|
||||
# 🚚 WORKFLOW ЦЕПОЧКИ ПОСТАВОК SFERA v2.0
|
||||
|
||||
> **⚠️ ВАЖНО:** Этот документ описывает НОВУЮ архитектуру системы поставок с разделением на отдельные типы. Для старой системы см. SUPPLY_CHAIN_WORKFLOW.md
|
||||
|
||||
## 🎯 ОБЗОР НОВОЙ СИСТЕМЫ
|
||||
|
||||
Система поставок SFERA v2.0 включает **5 типов поставок**, разделенных на две категории:
|
||||
|
||||
### 📦 **ПОСТАВКИ НА ФУЛФИЛМЕНТ**
|
||||
- `GoodsSupplyOrder` - товары селлера → склад ФФ
|
||||
- `FulfillmentConsumableSupplyOrder` - расходники ФФ → склад ФФ
|
||||
- `SellerConsumableSupplyOrder` - расходники селлера → склад ФФ
|
||||
|
||||
### 🛒 **ПОСТАВКИ НА МАРКЕТПЛЕЙСЫ**
|
||||
- `OzonSupplyOrder` - готовые продукты → Ozon
|
||||
- `WildberriesSupplyOrder` - готовые продукты → Wildberries
|
||||
|
||||
---
|
||||
|
||||
## 🔄 WORKFLOW ПО ТИПАМ ПОСТАВОК
|
||||
|
||||
### 1️⃣ **WORKFLOW: Поставки расходников ФФ**
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[ФФ создает заказ расходников] --> B[PENDING]
|
||||
B --> C{Поставщик одобряет?}
|
||||
C -->|Да| D[SUPPLIER_APPROVED]
|
||||
C -->|Нет| X[CANCELLED]
|
||||
D --> E{Логистика назначена?}
|
||||
E -->|Да| F[LOGISTICS_CONFIRMED]
|
||||
E -->|Нет| D
|
||||
F --> G[Поставщик отгружает]
|
||||
G --> H[SHIPPED]
|
||||
H --> I[IN_TRANSIT]
|
||||
I --> J[ФФ принимает на склад]
|
||||
J --> K[DELIVERED]
|
||||
|
||||
style A fill:#e1f5fe
|
||||
style K fill:#c8e6c9
|
||||
style X fill:#ffcdd2
|
||||
```
|
||||
|
||||
**Участники:**
|
||||
- 🏭 **Фулфилмент** - создатель, получатель
|
||||
- 🏪 **Поставщик (WHOLESALE)** - одобрение, отгрузка
|
||||
- 🚛 **Логистика (LOGIST)** - доставка
|
||||
|
||||
**Особенности:**
|
||||
- ✅ ФФ видит все детали + устанавливает цены продажи селлерам
|
||||
- ✅ Поставщик видит товары/количества, НЕ видит цены продажи ФФ
|
||||
- ✅ Показывается сразу после создания
|
||||
|
||||
### 2️⃣ **WORKFLOW: Поставки товаров селлера**
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Селлер создает заказ товаров] --> B[PENDING]
|
||||
B --> C{Поставщик одобряет?}
|
||||
C -->|Да| D[SUPPLIER_APPROVED]
|
||||
C -->|Нет| X[CANCELLED]
|
||||
D --> E{Логистика назначена?}
|
||||
E -->|Да| F[LOGISTICS_CONFIRMED]
|
||||
E -->|Нет| D
|
||||
F --> G[Поставщик отгружает]
|
||||
G --> H[SHIPPED]
|
||||
H --> I[IN_TRANSIT]
|
||||
I --> J[ФФ принимает + обрабатывает]
|
||||
J --> K[DELIVERED]
|
||||
|
||||
style A fill:#fff3e0
|
||||
style K fill:#c8e6c9
|
||||
style X fill:#ffcdd2
|
||||
```
|
||||
|
||||
**Участники:**
|
||||
- 🛒 **Селлер** - создатель, владелец товара
|
||||
- 🏪 **Поставщик (WHOLESALE)** - поставка
|
||||
- 🚛 **Логистика (LOGIST)** - доставка
|
||||
- 🏭 **Фулфилмент** - получатель, обработка
|
||||
|
||||
**Особенности:**
|
||||
- ✅ Селлер видит свои товары + рецептуры + закупочные цены
|
||||
- ✅ ФФ видит товары + рецептуры + услуги, НЕ видит закупочные цены селлера
|
||||
- ✅ Поставщик видит товары + количества, НЕ видит рецептуры
|
||||
- ✅ Расходники селлера идут **в состав продукта**, не отслеживаются отдельно
|
||||
|
||||
### 3️⃣ **WORKFLOW: Поставки расходников селлера**
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Селлер заказывает свои расходники] --> B[PENDING]
|
||||
B --> C{Поставщик одобряет?}
|
||||
C -->|Да| D[SUPPLIER_APPROVED]
|
||||
C -->|Нет| X[CANCELLED]
|
||||
D --> E{Логистика назначена?}
|
||||
E -->|Да| F[LOGISTICS_CONFIRMED]
|
||||
E -->|Нет| D
|
||||
F --> G[Поставщик отгружает]
|
||||
G --> H[SHIPPED]
|
||||
H --> I[IN_TRANSIT]
|
||||
I --> J[ФФ принимает НА ХРАНЕНИЕ]
|
||||
J --> K[DELIVERED]
|
||||
|
||||
style A fill:#f3e5f5
|
||||
style K fill:#c8e6c9
|
||||
style X fill:#ffcdd2
|
||||
```
|
||||
|
||||
**Участники:**
|
||||
- 🛒 **Селлер** - создатель, владелец расходников
|
||||
- 🏪 **Поставщик (WHOLESALE)** - поставка
|
||||
- 🚛 **Логистика (LOGIST)** - доставка
|
||||
- 🏭 **Фулфилмент** - хранитель (НЕ владелец)
|
||||
|
||||
**Особенности:**
|
||||
- ✅ Селлер видит свои расходники + закупочные цены
|
||||
- ✅ ФФ видит факт хранения + количества, НЕ видит закупочные цены селлера
|
||||
- ✅ Срок хранения + права доступа настраиваются
|
||||
- ✅ Используются селлером в рецептурах своих товаров
|
||||
|
||||
---
|
||||
|
||||
## 📊 СТАТУСЫ И ПЕРЕХОДЫ
|
||||
|
||||
### **SupplyOrderStatus (поставки НА фулфилмент)**
|
||||
|
||||
| Статус | Описание | Ответственный | Действия |
|
||||
|--------|----------|---------------|----------|
|
||||
| `PENDING` | Ожидает одобрения поставщика | Поставщик | Одобрить/Отклонить |
|
||||
| `SUPPLIER_APPROVED` | Одобрено поставщиком | Логистика | Назначить маршрут |
|
||||
| `LOGISTICS_CONFIRMED` | Логистика подтверждена | Поставщик | Отгрузить товар |
|
||||
| `SHIPPED` | Отгружено | Система | Автоматический переход |
|
||||
| `IN_TRANSIT` | В пути | Логистика | Отслеживание доставки |
|
||||
| `DELIVERED` | Доставлено | ФФ | Принять на склад |
|
||||
| `CANCELLED` | Отменено | Любой участник | Указать причину |
|
||||
|
||||
### **MarketplaceSupplyStatus (поставки НА маркетплейсы)**
|
||||
|
||||
| Статус | Описание | Ответственный | Действия |
|
||||
|--------|----------|---------------|----------|
|
||||
| `PLANNED` | Запланирована | ФФ | Подготовить товары |
|
||||
| `PREPARED` | Подготовлена | ФФ | Отгрузить |
|
||||
| `SHIPPED_TO_MARKETPLACE` | Отгружена | Маркетплейс | Принять товар |
|
||||
| `ACCEPTED_BY_MARKETPLACE` | Принята | Система | Обновить остатки |
|
||||
| `CANCELLED` | Отменена | ФФ/Маркетплейс | Указать причину |
|
||||
|
||||
---
|
||||
|
||||
## 🎭 РОЛИ И ПРАВА ДОСТУПА
|
||||
|
||||
### 🏭 **ФУЛФИЛМЕНТ**
|
||||
|
||||
**Может создавать:**
|
||||
- ✅ Поставки расходников ФФ
|
||||
- ✅ Поставки на маркетплейсы
|
||||
|
||||
**Может видеть:**
|
||||
- ✅ Свои поставки расходников: все детали + цены продажи
|
||||
- ✅ Товарные поставки селлеров: товары + рецептуры, НЕ закупочные цены
|
||||
- ✅ Расходники селлеров на хранении: количества, НЕ закупочные цены
|
||||
|
||||
### 🛒 **СЕЛЛЕР**
|
||||
|
||||
**Может создавать:**
|
||||
- ✅ Товарные поставки
|
||||
- ✅ Поставки расходников селлера
|
||||
|
||||
**Может видеть:**
|
||||
- ✅ Свои товарные поставки: все детали + рецептуры + закупочные цены
|
||||
- ✅ Свои расходники: все детали + закупочные цены
|
||||
- ❌ Чужие поставки
|
||||
- ❌ Поставки расходников ФФ
|
||||
|
||||
### 🏪 **ПОСТАВЩИК (WHOLESALE)**
|
||||
|
||||
**Может видеть:**
|
||||
- ✅ Заказы к себе: товары + количества
|
||||
- ❌ Рецептуры товаров
|
||||
- ❌ Цены продажи ФФ селлерам
|
||||
- ❌ Услуги ФФ
|
||||
|
||||
### 🚛 **ЛОГИСТИКА (LOGIST)**
|
||||
|
||||
**Может видеть:**
|
||||
- ✅ Маршруты + объемы + вес
|
||||
- ❌ Коммерческие данные (цены, услуги)
|
||||
- ❌ Рецептуры товаров
|
||||
|
||||
---
|
||||
|
||||
## 🌐 ИНТЕРФЕЙСЫ СИСТЕМЫ
|
||||
|
||||
### 📦 **Кабинет фулфилмента**
|
||||
|
||||
**URL:** `/fulfillment-supplies/`
|
||||
|
||||
**Вкладки:**
|
||||
- `ff-consumables` - поставки расходников ФФ (создание + просмотр)
|
||||
- `seller-consumables` - расходники селлеров на хранении
|
||||
- `goods?status=new` - новые товарные поставки
|
||||
- `goods?status=receiving` - товары в приемке
|
||||
- `goods?status=accepted` - принятые товары
|
||||
|
||||
### 🛒 **Кабинет селлера**
|
||||
|
||||
**URL:** `/seller-supplies/`
|
||||
|
||||
**Вкладки:**
|
||||
- `my-goods` - мои товарные поставки
|
||||
- `my-consumables` - мои расходники
|
||||
- `create-goods` - создать поставку товаров
|
||||
- `create-consumables` - заказать расходники
|
||||
|
||||
### 🛍️ **Кабинет маркетплейсов**
|
||||
|
||||
**URL:** `/marketplace-supplies/`
|
||||
|
||||
**Вкладки:**
|
||||
- `ozon` - поставки на Ozon
|
||||
- `wildberries` - поставки на Wildberries
|
||||
- `create-ozon` - создать поставку на Ozon
|
||||
- `create-wildberries` - создать поставку на WB
|
||||
|
||||
---
|
||||
|
||||
## ⚡ ОСОБЕННОСТИ РЕАЛИЗАЦИИ
|
||||
|
||||
### 🔄 **Дополнение данных по этапам**
|
||||
|
||||
Каждая поставка - это **одна запись**, которая дополняется участниками:
|
||||
|
||||
```typescript
|
||||
// Создание (селлер/ФФ)
|
||||
supply = {
|
||||
id: "...",
|
||||
status: "PENDING",
|
||||
sellerId: "...", // кто создал
|
||||
requestedDate: "...", // когда нужно
|
||||
items: [...] // что заказано
|
||||
}
|
||||
|
||||
// Одобрение (поставщик)
|
||||
supply = {
|
||||
...supply,
|
||||
status: "SUPPLIER_APPROVED",
|
||||
supplierId: "...", // кто одобрил
|
||||
approvedAt: "...", // когда одобрил
|
||||
packagesCount: 5, // уточненные параметры
|
||||
estimatedVolume: 2.5
|
||||
}
|
||||
|
||||
// Назначение логистики (ФФ)
|
||||
supply = {
|
||||
...supply,
|
||||
status: "LOGISTICS_CONFIRMED",
|
||||
logisticsPartnerId: "...", // кто повезет
|
||||
routeId: "...", // маршрут
|
||||
logisticsCost: 1500 // стоимость
|
||||
}
|
||||
```
|
||||
|
||||
### 🔐 **Фильтрация по безопасности**
|
||||
|
||||
Каждый resolver применяет фильтрацию по роли:
|
||||
|
||||
```typescript
|
||||
// Пример: поставки расходников ФФ
|
||||
const supplies = await prisma.fulfillmentConsumableSupplyOrder.findMany({
|
||||
where: {
|
||||
// Только свои поставки для ФФ
|
||||
fulfillmentCenterId: user.organizationId
|
||||
}
|
||||
})
|
||||
|
||||
// Фильтрация полей по роли
|
||||
return supplies.map(supply =>
|
||||
SupplyDataFilter.filterByRole(supply, user.organizationType)
|
||||
)
|
||||
```
|
||||
|
||||
### 📈 **Масштабируемость**
|
||||
|
||||
Новые типы поставок добавляются независимо:
|
||||
|
||||
```typescript
|
||||
// Будущее: Поставки на Яндекс.Маркет
|
||||
interface YandexMarketSupplyOrder {
|
||||
// специфичные поля для Яндекс.Маркета
|
||||
}
|
||||
|
||||
// Отдельные операции
|
||||
createYandexMarketSupply()
|
||||
myYandexMarketSupplies()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ ПРЕИМУЩЕСТВА НОВОЙ АРХИТЕКТУРЫ
|
||||
|
||||
### 🎯 **Четкое разделение ответственности**
|
||||
- Каждый тип поставки имеет свою логику
|
||||
- Независимая разработка и тестирование
|
||||
- Простота добавления новых типов
|
||||
|
||||
### 🔒 **Надежная безопасность**
|
||||
- Раздельные правила доступа для каждого типа
|
||||
- Невозможно случайно показать чужие данные
|
||||
- Гранулярные права по ролям
|
||||
|
||||
### 📈 **Масштабируемость**
|
||||
- Легко добавлять новые маркетплейсы
|
||||
- Независимые схемы для разных процессов
|
||||
- Оптимизация каждого типа отдельно
|
||||
|
||||
### 🛡️ **Безопасная миграция**
|
||||
- Поэтапное внедрение без остановки системы
|
||||
- Система откатов на каждом этапе
|
||||
- Сохранение работоспособности старой системы
|
||||
|
||||
---
|
||||
|
||||
## 🚀 ПЛАН ВНЕДРЕНИЯ
|
||||
|
||||
### **Phase 1:** FulfillmentConsumableSupplyOrder ⏳
|
||||
- Новая модель данных
|
||||
- GraphQL операции
|
||||
- Интерфейс создания и просмотра
|
||||
- Тестирование
|
||||
|
||||
### **Phase 2:** SellerConsumableSupplyOrder
|
||||
- Аналогично Phase 1
|
||||
- Интеграция с системой хранения
|
||||
|
||||
### **Phase 3:** GoodsSupplyOrder
|
||||
- Самый сложный тип с рецептурами
|
||||
- Миграция существующих товарных поставок
|
||||
|
||||
### **Phase 4:** Поставки на маркетплейсы
|
||||
- Отдельная система для Ozon/WB
|
||||
- API интеграции с маркетплейсами
|
||||
|
||||
### **Phase 5:** Очистка и оптимизация
|
||||
- Миграция старых данных
|
||||
- Удаление устаревшего кода (с одобрения)
|
||||
- Финальная оптимизация
|
||||
|
||||
**Следующий шаг:** Начало реализации Phase 1 - FulfillmentConsumableSupplyOrder
|
487
docs/business-processes/SUPPLY_SYSTEM_ARCHITECTURE.md
Normal file
487
docs/business-processes/SUPPLY_SYSTEM_ARCHITECTURE.md
Normal file
@ -0,0 +1,487 @@
|
||||
# 🚚 АРХИТЕКТУРА СИСТЕМЫ ПОСТАВОК SFERA
|
||||
|
||||
## 🎯 ОБЗОР СИСТЕМЫ
|
||||
|
||||
Система поставок SFERA включает **5 типов поставок**, разделенных на две категории:
|
||||
|
||||
### 📦 **ПОСТАВКИ НА ФУЛФИЛМЕНТ (3 типа)**
|
||||
1. **Товарные поставки** - товары селлера → склад ФФ
|
||||
2. **Поставки расходников ФФ** - расходники ФФ → склад ФФ
|
||||
3. **Поставки расходников селлеров** - расходники селлера → склад ФФ (на хранение)
|
||||
|
||||
### 🛒 **ПОСТАВКИ НА МАРКЕТПЛЕЙСЫ (2+ типов)**
|
||||
4. **Поставки на Ozon** - готовые продукты со склада ФФ → Ozon
|
||||
5. **Поставки на Wildberries** - готовые продукты со склада ФФ → Wildberries
|
||||
|
||||
---
|
||||
|
||||
## 📊 АРХИТЕКТУРА ДАННЫХ
|
||||
|
||||
### ✅ **ПРИНЦИП: ОТДЕЛЬНАЯ ТАБЛИЦА ДЛЯ КАЖДОГО ТИПА ПОСТАВКИ**
|
||||
|
||||
#### **Преимущества подхода:**
|
||||
- 🎯 Четкое разделение ответственности
|
||||
- 🔒 Упрощение системы безопасности
|
||||
- 📈 Независимые схемы для разных процессов
|
||||
- 🔧 Простота миграций и изменений
|
||||
- 📝 Специфичные поля для каждого типа
|
||||
|
||||
### 🏗️ **СТРУКТУРА ТАБЛИЦ ПОСТАВОК НА ФУЛФИЛМЕНТ**
|
||||
|
||||
#### **1. GoodsSupplyOrder - Товарные поставки**
|
||||
```typescript
|
||||
interface GoodsSupplyOrder {
|
||||
// === БАЗОВЫЕ ПОЛЯ ===
|
||||
id: string
|
||||
status: SupplyOrderStatus
|
||||
createdAt: DateTime
|
||||
updatedAt: DateTime
|
||||
|
||||
// === ДАННЫЕ СЕЛЛЕРА (создатель) ===
|
||||
sellerId: string // кто заказывает
|
||||
fulfillmentCenterId: string // куда доставить
|
||||
requestedDeliveryDate: DateTime // когда нужно
|
||||
|
||||
// === ДАННЫЕ ПОСТАВЩИКА ===
|
||||
supplierId: string // кто поставляет
|
||||
supplierApprovedAt?: DateTime // когда одобрил
|
||||
packagesCount?: number // количество грузомест
|
||||
estimatedVolume?: number // объем груза
|
||||
supplierContractId?: string // номер договора
|
||||
|
||||
// === ДАННЫЕ ЛОГИСТИКИ ===
|
||||
logisticsPartnerId?: string // кто везет
|
||||
estimatedDeliveryDate?: DateTime // план доставки
|
||||
routeId?: string // маршрут
|
||||
logisticsCost?: number // стоимость доставки
|
||||
|
||||
// === ДАННЫЕ ОТГРУЗКИ ===
|
||||
shippedAt?: DateTime // факт отгрузки
|
||||
|
||||
// === ДАННЫЕ ПРИЕМКИ ===
|
||||
receivedAt?: DateTime // факт приемки
|
||||
receivedById?: string // кто принял (сотрудник ФФ)
|
||||
actualQuantity?: number // принято количество
|
||||
defectQuantity?: number // брак
|
||||
|
||||
// === УНИКАЛЬНЫЕ ПОЛЯ ДЛЯ ТОВАРОВ ===
|
||||
hasRecipes: boolean // есть ли рецептуры
|
||||
totalServicesValue?: number // стоимость услуг ФФ
|
||||
|
||||
// === СВЯЗИ ===
|
||||
items: GoodsSupplyItem[]
|
||||
}
|
||||
|
||||
interface GoodsSupplyItem {
|
||||
id: string
|
||||
supplyOrderId: string // связь с поставкой
|
||||
productId: string // какой товар
|
||||
requestedQuantity: number // запросили
|
||||
approvedQuantity?: number // поставщик одобрил
|
||||
shippedQuantity?: number // отгрузили
|
||||
receivedQuantity?: number // приняли
|
||||
defectQuantity?: number // брак
|
||||
unitPrice: number // цена за единицу
|
||||
totalPrice: number // общая стоимость
|
||||
|
||||
// === РЕЦЕПТУРА (JSON) ===
|
||||
recipe?: {
|
||||
services: string[] // ID услуг ФФ
|
||||
fulfillmentConsumables: string[] // ID расходников ФФ
|
||||
sellerConsumables: string[] // ID расходников селлера
|
||||
marketplaceCardId?: string // карточка товара
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **2. FulfillmentConsumableSupplyOrder - Поставки расходников ФФ**
|
||||
```typescript
|
||||
interface FulfillmentConsumableSupplyOrder {
|
||||
// === БАЗОВЫЕ ПОЛЯ ===
|
||||
id: string
|
||||
status: SupplyOrderStatus
|
||||
createdAt: DateTime
|
||||
updatedAt: DateTime
|
||||
|
||||
// === ДАННЫЕ ФФ (создатель) ===
|
||||
fulfillmentCenterId: string // кто заказывает
|
||||
requestedDeliveryDate: DateTime // когда нужно
|
||||
|
||||
// === ДАННЫЕ ПОСТАВЩИКА ===
|
||||
supplierId: string // кто поставляет
|
||||
supplierApprovedAt?: DateTime // когда одобрил
|
||||
packagesCount?: number // количество грузомест
|
||||
estimatedVolume?: number // объем груза
|
||||
supplierContractId?: string // номер договора
|
||||
|
||||
// === ДАННЫЕ ЛОГИСТИКИ ===
|
||||
logisticsPartnerId?: string // кто везет
|
||||
estimatedDeliveryDate?: DateTime // план доставки
|
||||
routeId?: string // маршрут
|
||||
logisticsCost?: number // стоимость доставки
|
||||
|
||||
// === ДАННЫЕ ОТГРУЗКИ ===
|
||||
shippedAt?: DateTime // факт отгрузки
|
||||
|
||||
// === ДАННЫЕ ПРИЕМКИ ===
|
||||
receivedAt?: DateTime // факт приемки
|
||||
receivedById?: string // кто принял (сотрудник ФФ)
|
||||
actualQuantity?: number // принято количество
|
||||
defectQuantity?: number // брак
|
||||
|
||||
// === УНИКАЛЬНЫЕ ПОЛЯ ДЛЯ РАСХОДНИКОВ ФФ ===
|
||||
resalePricePerUnit?: number // цена продажи селлерам
|
||||
minStockLevel?: number // складские лимиты
|
||||
|
||||
// === СВЯЗИ ===
|
||||
items: FulfillmentConsumableSupplyItem[]
|
||||
}
|
||||
|
||||
interface FulfillmentConsumableSupplyItem {
|
||||
id: string
|
||||
supplyOrderId: string // связь с поставкой
|
||||
productId: string // какой расходник
|
||||
requestedQuantity: number // запросили
|
||||
approvedQuantity?: number // поставщик одобрил
|
||||
shippedQuantity?: number // отгрузили
|
||||
receivedQuantity?: number // приняли
|
||||
defectQuantity?: number // брак
|
||||
unitPrice: number // цена за единицу от поставщика
|
||||
totalPrice: number // общая стоимость
|
||||
}
|
||||
```
|
||||
|
||||
#### **3. SellerConsumableSupplyOrder - Поставки расходников селлеров**
|
||||
```typescript
|
||||
interface SellerConsumableSupplyOrder {
|
||||
// === БАЗОВЫЕ ПОЛЯ ===
|
||||
id: string
|
||||
status: SupplyOrderStatus
|
||||
createdAt: DateTime
|
||||
updatedAt: DateTime
|
||||
|
||||
// === ДАННЫЕ СЕЛЛЕРА (создатель) ===
|
||||
sellerId: string // кто заказывает
|
||||
fulfillmentCenterId: string // где будет храниться
|
||||
requestedDeliveryDate: DateTime // когда нужно
|
||||
|
||||
// === ДАННЫЕ ПОСТАВЩИКА ===
|
||||
supplierId: string // кто поставляет
|
||||
supplierApprovedAt?: DateTime // когда одобрил
|
||||
packagesCount?: number // количество грузомест
|
||||
estimatedVolume?: number // объем груза
|
||||
supplierContractId?: string // номер договора
|
||||
|
||||
// === ДАННЫЕ ЛОГИСТИКИ ===
|
||||
logisticsPartnerId?: string // кто везет
|
||||
estimatedDeliveryDate?: DateTime // план доставки
|
||||
routeId?: string // маршрут
|
||||
logisticsCost?: number // стоимость доставки
|
||||
|
||||
// === ДАННЫЕ ОТГРУЗКИ ===
|
||||
shippedAt?: DateTime // факт отгрузки
|
||||
|
||||
// === ДАННЫЕ ПРИЕМКИ ===
|
||||
receivedAt?: DateTime // факт приемки ФФ
|
||||
receivedById?: string // кто принял (сотрудник ФФ)
|
||||
actualQuantity?: number // принято количество
|
||||
defectQuantity?: number // брак
|
||||
|
||||
// === УНИКАЛЬНЫЕ ПОЛЯ ДЛЯ РАСХОДНИКОВ СЕЛЛЕРОВ ===
|
||||
storageTermMonths?: number // срок хранения
|
||||
accessRights: 'SELLER_ONLY' | 'SHARED_WITH_FF' // кто может использовать
|
||||
storageCostPerMonth?: number // стоимость хранения
|
||||
|
||||
// === СВЯЗИ ===
|
||||
items: SellerConsumableSupplyItem[]
|
||||
}
|
||||
|
||||
interface SellerConsumableSupplyItem {
|
||||
id: string
|
||||
supplyOrderId: string // связь с поставкой
|
||||
productId: string // какой расходник селлера
|
||||
requestedQuantity: number // запросили
|
||||
approvedQuantity?: number // поставщик одобрил
|
||||
shippedQuantity?: number // отгрузили
|
||||
receivedQuantity?: number // приняли
|
||||
defectQuantity?: number // брак
|
||||
unitPrice: number // цена за единицу
|
||||
totalPrice: number // общая стоимость
|
||||
}
|
||||
```
|
||||
|
||||
### 🛒 **СТРУКТУРА ТАБЛИЦ ПОСТАВОК НА МАРКЕТПЛЕЙСЫ**
|
||||
|
||||
#### **4. OzonSupplyOrder - Поставки на Ozon**
|
||||
```typescript
|
||||
interface OzonSupplyOrder {
|
||||
// === БАЗОВЫЕ ПОЛЯ ===
|
||||
id: string
|
||||
status: MarketplaceSupplyStatus
|
||||
createdAt: DateTime
|
||||
updatedAt: DateTime
|
||||
|
||||
// === СПЕЦИФИЧНЫЕ ПОЛЯ OZON ===
|
||||
ozonWarehouseId: string // склад Ozon
|
||||
ozonSupplyId?: string // ID поставки в системе Ozon
|
||||
// ... дополнительные поля для Ozon API
|
||||
|
||||
// === СВЯЗИ ===
|
||||
items: OzonSupplyItem[]
|
||||
}
|
||||
```
|
||||
|
||||
#### **5. WildberriesSupplyOrder - Поставки на Wildberries**
|
||||
```typescript
|
||||
interface WildberriesSupplyOrder {
|
||||
// === БАЗОВЫЕ ПОЛЯ ===
|
||||
id: string
|
||||
status: MarketplaceSupplyStatus
|
||||
createdAt: DateTime
|
||||
updatedAt: DateTime
|
||||
|
||||
// === СПЕЦИФИЧНЫЕ ПОЛЯ WB ===
|
||||
wbWarehouseId: string // склад WB
|
||||
wbSupplyId?: string // ID поставки в системе WB
|
||||
// ... дополнительные поля для WB API
|
||||
|
||||
// === СВЯЗИ ===
|
||||
items: WildberriesSupplyItem[]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 СИСТЕМА БЕЗОПАСНОСТИ
|
||||
|
||||
### 📋 **ПРАВИЛА ДОСТУПА К ПОСТАВКАМ РАСХОДНИКОВ ФФ**
|
||||
|
||||
**Кто видит и что:**
|
||||
- ✅ **ФФ (создатель):** все детали + цены + остатки
|
||||
- ✅ **Поставщик:** товары, количества, НЕ цены продажи ФФ
|
||||
- ✅ **Логистика:** маршруты, объемы, НЕ коммерческие данные
|
||||
- ❌ **Селлеры:** вообще не видят
|
||||
|
||||
### 📋 **ПРАВИЛА ДОСТУПА К ПОСТАВКАМ РАСХОДНИКОВ СЕЛЛЕРОВ**
|
||||
|
||||
**Кто видит и что:**
|
||||
- ✅ **Селлер (создатель):** все свои детали + свои цены
|
||||
- ✅ **ФФ (хранитель):** факт хранения + количества, НЕ закупочные цены селлера
|
||||
- ✅ **Поставщик:** товары, количества для селлера
|
||||
- ✅ **Логистика:** маршруты, объемы
|
||||
- ❌ **Другие селлеры:** не видят чужие расходники
|
||||
|
||||
### 📋 **ПРАВИЛА ДОСТУПА К ТОВАРНЫМ ПОСТАВКАМ**
|
||||
|
||||
**Кто видит и что:**
|
||||
- ✅ **Селлер (создатель):** все детали своих товаров + рецептуры
|
||||
- ✅ **ФФ (получатель):** товары + рецептуры + услуги, НЕ закупочные цены селлера
|
||||
- ✅ **Поставщик:** товары + количества, НЕ рецептуры и НЕ цены ФФ
|
||||
- ✅ **Логистика:** маршруты + объемы, НЕ коммерческие данные
|
||||
- ❌ **Другие селлеры:** не видят чужие поставки
|
||||
|
||||
---
|
||||
|
||||
## 🌐 URL-СТРУКТУРА ИНТЕРФЕЙСОВ
|
||||
|
||||
### 📦 **ПОСТАВКИ НА ФУЛФИЛМЕНТ**
|
||||
```
|
||||
/fulfillment-supplies/goods?status=new # Товар → Новые
|
||||
/fulfillment-supplies/goods?status=receiving # Товар → Приёмка
|
||||
/fulfillment-supplies/goods?status=accepted # Товар → Принято
|
||||
/fulfillment-supplies/ff-consumables # Расходники фулфилмента
|
||||
/fulfillment-supplies/seller-consumables # Расходники селлеров
|
||||
/fulfillment-supplies/create-consumables # Создание поставки расходников ФФ
|
||||
```
|
||||
|
||||
### 🛒 **ПОСТАВКИ НА МАРКЕТПЛЕЙСЫ**
|
||||
```
|
||||
/marketplace-supplies/ozon # Поставки на Ozon
|
||||
/marketplace-supplies/wildberries # Поставки на Wildberries
|
||||
/marketplace-supplies/create-ozon # Создание поставки на Ozon
|
||||
/marketplace-supplies/create-wildberries # Создание поставки на WB
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚡ GRAPHQL API АРХИТЕКТУРА
|
||||
|
||||
### 🎯 **ПРИНЦИП: ОТДЕЛЬНЫЕ ОПЕРАЦИИ ДЛЯ КАЖДОГО ТИПА**
|
||||
|
||||
#### **Поставки расходников ФФ:**
|
||||
```graphql
|
||||
# Queries
|
||||
myFulfillmentConsumableSupplies: [FulfillmentConsumableSupplyOrder!]!
|
||||
fulfillmentConsumableSupply(id: ID!): FulfillmentConsumableSupplyOrder
|
||||
|
||||
# Mutations
|
||||
createFulfillmentConsumableSupply(input: CreateFulfillmentConsumableSupplyInput!): CreateSupplyResult!
|
||||
updateFulfillmentConsumableSupply(id: ID!, input: UpdateFulfillmentConsumableSupplyInput!): UpdateSupplyResult!
|
||||
```
|
||||
|
||||
#### **Поставки расходников селлеров:**
|
||||
```graphql
|
||||
# Queries
|
||||
mySellerConsumableSupplies: [SellerConsumableSupplyOrder!]!
|
||||
sellerConsumableSupply(id: ID!): SellerConsumableSupplyOrder
|
||||
|
||||
# Mutations
|
||||
createSellerConsumableSupply(input: CreateSellerConsumableSupplyInput!): CreateSupplyResult!
|
||||
updateSellerConsumableSupply(id: ID!, input: UpdateSellerConsumableSupplyInput!): UpdateSupplyResult!
|
||||
```
|
||||
|
||||
#### **Товарные поставки:**
|
||||
```graphql
|
||||
# Queries
|
||||
myGoodsSupplies: [GoodsSupplyOrder!]!
|
||||
goodsSupply(id: ID!): GoodsSupplyOrder
|
||||
|
||||
# Mutations
|
||||
createGoodsSupply(input: CreateGoodsSupplyInput!): CreateSupplyResult!
|
||||
updateGoodsSupply(id: ID!, input: UpdateGoodsSupplyInput!): UpdateSupplyResult!
|
||||
```
|
||||
|
||||
#### **Поставки на маркетплейсы (отдельная система):**
|
||||
```graphql
|
||||
# Queries
|
||||
myOzonSupplies: [OzonSupplyOrder!]!
|
||||
myWildberriesSupplies: [WildberriesSupplyOrder!]!
|
||||
|
||||
# Mutations
|
||||
createOzonSupply(input: CreateOzonSupplyInput!): CreateMarketplaceSupplyResult!
|
||||
createWildberriesSupply(input: CreateWildberriesSupplyInput!): CreateMarketplaceSupplyResult!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 ПЛАН ПОЭТАПНОЙ МИГРАЦИИ
|
||||
|
||||
### ✅ **ПРИНЦИПЫ БЕЗОПАСНОЙ МИГРАЦИИ**
|
||||
- 🛡️ Сохранение работоспособности существующей системы
|
||||
- 🔄 Система откатов на каждом этапе
|
||||
- 🧪 Тестирование каждого типа поставки отдельно
|
||||
- 📝 Модульная архитектура
|
||||
- ❌ **Удаление старого кода ТОЛЬКО после одобрения пользователя**
|
||||
|
||||
### **ЭТАП 1: FulfillmentConsumableSupplyOrder**
|
||||
|
||||
#### **1.1 Создание новой модели данных**
|
||||
```typescript
|
||||
// Новая таблица параллельно со старой
|
||||
model FulfillmentConsumableSupplyOrder {
|
||||
// ... вся структура
|
||||
}
|
||||
|
||||
// Старая таблица остается для совместимости
|
||||
model SupplyOrder {
|
||||
// ... существующая структура
|
||||
}
|
||||
```
|
||||
|
||||
#### **1.2 GraphQL API**
|
||||
```graphql
|
||||
# Новые операции
|
||||
createFulfillmentConsumableSupply()
|
||||
myFulfillmentConsumableSupplies()
|
||||
|
||||
# Старые операции остаются работать
|
||||
createSupplyOrder() # для других типов
|
||||
mySupplyOrders() # для других типов
|
||||
```
|
||||
|
||||
#### **1.3 Интерфейс**
|
||||
- Форма `/fulfillment-supplies/create-consumables` → новая мутация
|
||||
- Вкладка `/fulfillment-supplies/ff-consumables` → новый запрос
|
||||
|
||||
#### **1.4 Тестирование**
|
||||
- ✅ Создание поставки расходников ФФ
|
||||
- ✅ Отображение в интерфейсе
|
||||
- ✅ Безопасность доступа
|
||||
- ✅ Работа старой системы
|
||||
|
||||
### **ЭТАП 2: SellerConsumableSupplyOrder**
|
||||
- Аналогично этапу 1
|
||||
- Тестирование + интеграция
|
||||
|
||||
### **ЭТАП 3: GoodsSupplyOrder**
|
||||
- Аналогично этапу 1
|
||||
- Тестирование + интеграция
|
||||
|
||||
### **ЭТАП 4: Очистка (ТОЛЬКО после одобрения)**
|
||||
- Миграция данных из старых таблиц
|
||||
- Удаление старого кода
|
||||
- Обновление документации
|
||||
|
||||
---
|
||||
|
||||
## 🎯 СТАТУСЫ ПОСТАВОК
|
||||
|
||||
### **SupplyOrderStatus (для поставок НА фулфилмент)**
|
||||
```typescript
|
||||
enum SupplyOrderStatus {
|
||||
PENDING // Создана, ждет одобрения поставщика
|
||||
SUPPLIER_APPROVED // Одобрена поставщиком
|
||||
LOGISTICS_CONFIRMED // Логистика подтверждена
|
||||
SHIPPED // Отгружена поставщиком
|
||||
IN_TRANSIT // В пути
|
||||
DELIVERED // Доставлена на склад ФФ
|
||||
CANCELLED // Отменена
|
||||
}
|
||||
```
|
||||
|
||||
### **MarketplaceSupplyStatus (для поставок НА маркетплейсы)**
|
||||
```typescript
|
||||
enum MarketplaceSupplyStatus {
|
||||
PLANNED // Запланирована
|
||||
PREPARED // Подготовлена к отгрузке
|
||||
SHIPPED_TO_MARKETPLACE // Отгружена на маркетплейс
|
||||
ACCEPTED_BY_MARKETPLACE // Принята маркетплейсом
|
||||
CANCELLED // Отменена
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 ИНТЕГРАЦИИ
|
||||
|
||||
### **Поставки НА фулфилмент:**
|
||||
- 🏪 **DaData API** - валидация ИНН поставщиков
|
||||
- 📱 **SMS Aero** - уведомления участникам
|
||||
- ☁️ **AWS S3** - документы поставок
|
||||
- 🚚 **Логистические партнеры** - трекинг доставки
|
||||
|
||||
### **Поставки НА маркетплейсы:**
|
||||
- 🛒 **Ozon API** - создание поставок
|
||||
- 🛍️ **Wildberries API** - создание поставок
|
||||
- 📦 **Трекинг системы** - статусы доставки
|
||||
- 💰 **Биллинг системы** - расчет комиссий
|
||||
|
||||
---
|
||||
|
||||
## 🔍 МОНИТОРИНГ И АУДИТ
|
||||
|
||||
### **Коммерческие данные:**
|
||||
- 📊 Логирование доступа к ценам
|
||||
- 🔐 Аудит прав доступа по ролям
|
||||
- 📈 Метрики безопасности
|
||||
- ⚠️ Алерты на подозрительную активность
|
||||
|
||||
### **Операционные метрики:**
|
||||
- ⏱️ Время выполнения поставок
|
||||
- 📦 Процент успешных доставок
|
||||
- 🔄 SLA по статусам
|
||||
- 📊 Аналитика по типам поставок
|
||||
|
||||
---
|
||||
|
||||
## ✅ ЗАКЛЮЧЕНИЕ
|
||||
|
||||
Новая архитектура системы поставок обеспечивает:
|
||||
|
||||
- 🎯 **Четкое разделение** типов поставок
|
||||
- 🔒 **Надежную безопасность** коммерческих данных
|
||||
- 📈 **Масштабируемость** для новых маркетплейсов
|
||||
- 🔧 **Простоту развития** каждого типа независимо
|
||||
- 🛡️ **Безопасную миграцию** без потери данных
|
||||
|
||||
**Следующий шаг:** Поэтапная реализация начиная с `FulfillmentConsumableSupplyOrder`
|
600
docs/development/DATABASE_SCHEMA_V2.md
Normal file
600
docs/development/DATABASE_SCHEMA_V2.md
Normal file
@ -0,0 +1,600 @@
|
||||
# 🗄️ СХЕМА БАЗЫ ДАННЫХ SFERA v2.0 - СИСТЕМА ПОСТАВОК
|
||||
|
||||
> **⚠️ ВАЖНО:** Этот документ описывает НОВЫЕ таблицы для системы поставок v2.0. Существующие таблицы остаются без изменений для обратной совместимости.
|
||||
|
||||
## 📦 НОВЫЕ ТАБЛИЦЫ ПОСТАВОК НА ФУЛФИЛМЕНТ
|
||||
|
||||
### 1️⃣ **FulfillmentConsumableSupplyOrder - Поставки расходников ФФ**
|
||||
|
||||
```prisma
|
||||
model FulfillmentConsumableSupplyOrder {
|
||||
// === БАЗОВЫЕ ПОЛЯ ===
|
||||
id String @id @default(cuid())
|
||||
status SupplyOrderStatusV2 @default(PENDING)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// === ДАННЫЕ ФФ (создатель) ===
|
||||
fulfillmentCenterId String // кто заказывает (FK: Organization)
|
||||
requestedDeliveryDate DateTime // когда нужно
|
||||
resalePricePerUnit Decimal? @db.Decimal(10, 2) // цена продажи селлерам
|
||||
minStockLevel Int? // минимальный остаток
|
||||
notes String? // заметки ФФ
|
||||
|
||||
// === ДАННЫЕ ПОСТАВЩИКА ===
|
||||
supplierId String? // кто поставляет (FK: Organization)
|
||||
supplierApprovedAt DateTime? // когда одобрил
|
||||
packagesCount Int? // количество грузомест
|
||||
estimatedVolume Decimal? @db.Decimal(8, 3) // объем груза в м³
|
||||
supplierContractId String? // номер договора
|
||||
supplierNotes String? // заметки поставщика
|
||||
|
||||
// === ДАННЫЕ ЛОГИСТИКИ ===
|
||||
logisticsPartnerId String? // кто везет (FK: Organization)
|
||||
estimatedDeliveryDate DateTime? // план доставки
|
||||
routeId String? // маршрут (FK: LogisticsRoute)
|
||||
logisticsCost Decimal? @db.Decimal(10, 2) // стоимость доставки
|
||||
logisticsNotes String? // заметки логистики
|
||||
|
||||
// === ДАННЫЕ ОТГРУЗКИ ===
|
||||
shippedAt DateTime? // факт отгрузки
|
||||
trackingNumber String? // номер отслеживания
|
||||
|
||||
// === ДАННЫЕ ПРИЕМКИ ===
|
||||
receivedAt DateTime? // факт приемки
|
||||
receivedById String? // кто принял (FK: User)
|
||||
actualQuantity Int? // принято количество
|
||||
defectQuantity Int? // брак
|
||||
receiptNotes String? // заметки приемки
|
||||
|
||||
// === СВЯЗИ ===
|
||||
fulfillmentCenter Organization @relation("FFSupplyOrdersFulfillment", fields: [fulfillmentCenterId], references: [id])
|
||||
supplier Organization? @relation("FFSupplyOrdersSupplier", fields: [supplierId], references: [id])
|
||||
logisticsPartner Organization? @relation("FFSupplyOrdersLogistics", fields: [logisticsPartnerId], references: [id])
|
||||
receivedBy User? @relation("FFSupplyOrdersReceiver", fields: [receivedById], references: [id])
|
||||
items FulfillmentConsumableSupplyItem[]
|
||||
|
||||
@@map("fulfillment_consumable_supply_orders")
|
||||
}
|
||||
|
||||
model FulfillmentConsumableSupplyItem {
|
||||
id String @id @default(cuid())
|
||||
supplyOrderId String // связь с поставкой
|
||||
productId String // какой расходник (FK: Product)
|
||||
|
||||
// === КОЛИЧЕСТВА ===
|
||||
requestedQuantity Int // запросили
|
||||
approvedQuantity Int? // поставщик одобрил
|
||||
shippedQuantity Int? // отгрузили
|
||||
receivedQuantity Int? // приняли
|
||||
defectQuantity Int? @default(0) // брак
|
||||
|
||||
// === ЦЕНЫ ===
|
||||
unitPrice Decimal @db.Decimal(10, 2) // цена за единицу от поставщика
|
||||
totalPrice Decimal @db.Decimal(12, 2) // общая стоимость
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// === СВЯЗИ ===
|
||||
supplyOrder FulfillmentConsumableSupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade)
|
||||
product Product @relation("FFSupplyItems", fields: [productId], references: [id])
|
||||
|
||||
@@unique([supplyOrderId, productId])
|
||||
@@map("fulfillment_consumable_supply_items")
|
||||
}
|
||||
```
|
||||
|
||||
### 2️⃣ **SellerConsumableSupplyOrder - Поставки расходников селлеров**
|
||||
|
||||
```prisma
|
||||
model SellerConsumableSupplyOrder {
|
||||
// === БАЗОВЫЕ ПОЛЯ ===
|
||||
id String @id @default(cuid())
|
||||
status SupplyOrderStatusV2 @default(PENDING)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// === ДАННЫЕ СЕЛЛЕРА (создатель) ===
|
||||
sellerId String // кто заказывает (FK: Organization)
|
||||
fulfillmentCenterId String // где будет храниться (FK: Organization)
|
||||
requestedDeliveryDate DateTime // когда нужно
|
||||
notes String? // заметки селлера
|
||||
|
||||
// === ДАННЫЕ ПОСТАВЩИКА ===
|
||||
supplierId String? // кто поставляет (FK: Organization)
|
||||
supplierApprovedAt DateTime? // когда одобрил
|
||||
packagesCount Int? // количество грузомест
|
||||
estimatedVolume Decimal? @db.Decimal(8, 3) // объем груза в м³
|
||||
supplierContractId String? // номер договора
|
||||
supplierNotes String? // заметки поставщика
|
||||
|
||||
// === ДАННЫЕ ЛОГИСТИКИ ===
|
||||
logisticsPartnerId String? // кто везет (FK: Organization)
|
||||
estimatedDeliveryDate DateTime? // план доставки
|
||||
routeId String? // маршрут (FK: LogisticsRoute)
|
||||
logisticsCost Decimal? @db.Decimal(10, 2) // стоимость доставки
|
||||
logisticsNotes String? // заметки логистики
|
||||
|
||||
// === ДАННЫЕ ОТГРУЗКИ ===
|
||||
shippedAt DateTime? // факт отгрузки
|
||||
trackingNumber String? // номер отслеживания
|
||||
|
||||
// === ДАННЫЕ ПРИЕМКИ ===
|
||||
receivedAt DateTime? // факт приемки ФФ
|
||||
receivedById String? // кто принял (FK: User)
|
||||
actualQuantity Int? // принято количество
|
||||
defectQuantity Int? // брак
|
||||
receiptNotes String? // заметки приемки
|
||||
|
||||
// === УНИКАЛЬНЫЕ ПОЛЯ ДЛЯ РАСХОДНИКОВ СЕЛЛЕРОВ ===
|
||||
storageTermMonths Int? // срок хранения в месяцах
|
||||
accessRights SellerConsumableAccessRights @default(SELLER_ONLY)
|
||||
storageCostPerMonth Decimal? @db.Decimal(8, 2) // стоимость хранения за месяц
|
||||
|
||||
// === СВЯЗИ ===
|
||||
seller Organization @relation("SellerSupplyOrdersSeller", fields: [sellerId], references: [id])
|
||||
fulfillmentCenter Organization @relation("SellerSupplyOrdersFulfillment", fields: [fulfillmentCenterId], references: [id])
|
||||
supplier Organization? @relation("SellerSupplyOrdersSupplier", fields: [supplierId], references: [id])
|
||||
logisticsPartner Organization? @relation("SellerSupplyOrdersLogistics", fields: [logisticsPartnerId], references: [id])
|
||||
receivedBy User? @relation("SellerSupplyOrdersReceiver", fields: [receivedById], references: [id])
|
||||
items SellerConsumableSupplyItem[]
|
||||
|
||||
@@map("seller_consumable_supply_orders")
|
||||
}
|
||||
|
||||
model SellerConsumableSupplyItem {
|
||||
id String @id @default(cuid())
|
||||
supplyOrderId String // связь с поставкой
|
||||
productId String // какой расходник селлера (FK: Product)
|
||||
|
||||
// === КОЛИЧЕСТВА ===
|
||||
requestedQuantity Int // запросили
|
||||
approvedQuantity Int? // поставщик одобрил
|
||||
shippedQuantity Int? // отгрузили
|
||||
receivedQuantity Int? // приняли
|
||||
defectQuantity Int? @default(0) // брак
|
||||
|
||||
// === ЦЕНЫ (видит только селлер) ===
|
||||
unitPrice Decimal @db.Decimal(10, 2) // цена за единицу от поставщика
|
||||
totalPrice Decimal @db.Decimal(12, 2) // общая стоимость
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// === СВЯЗИ ===
|
||||
supplyOrder SellerConsumableSupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade)
|
||||
product Product @relation("SellerSupplyItems", fields: [productId], references: [id])
|
||||
|
||||
@@unique([supplyOrderId, productId])
|
||||
@@map("seller_consumable_supply_items")
|
||||
}
|
||||
```
|
||||
|
||||
### 3️⃣ **GoodsSupplyOrder - Товарные поставки**
|
||||
|
||||
```prisma
|
||||
model GoodsSupplyOrder {
|
||||
// === БАЗОВЫЕ ПОЛЯ ===
|
||||
id String @id @default(cuid())
|
||||
status SupplyOrderStatusV2 @default(PENDING)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// === ДАННЫЕ СЕЛЛЕРА (создатель) ===
|
||||
sellerId String // кто заказывает (FK: Organization)
|
||||
fulfillmentCenterId String // куда доставить (FK: Organization)
|
||||
requestedDeliveryDate DateTime // когда нужно
|
||||
notes String? // заметки селлера
|
||||
|
||||
// === ДАННЫЕ ПОСТАВЩИКА ===
|
||||
supplierId String? // кто поставляет (FK: Organization)
|
||||
supplierApprovedAt DateTime? // когда одобрил
|
||||
packagesCount Int? // количество грузомест
|
||||
estimatedVolume Decimal? @db.Decimal(8, 3) // объем груза в м³
|
||||
supplierContractId String? // номер договора
|
||||
supplierNotes String? // заметки поставщика
|
||||
|
||||
// === ДАННЫЕ ЛОГИСТИКИ ===
|
||||
logisticsPartnerId String? // кто везет (FK: Organization)
|
||||
estimatedDeliveryDate DateTime? // план доставки
|
||||
routeId String? // маршрут (FK: LogisticsRoute)
|
||||
logisticsCost Decimal? @db.Decimal(10, 2) // стоимость доставки
|
||||
logisticsNotes String? // заметки логистики
|
||||
|
||||
// === ДАННЫЕ ОТГРУЗКИ ===
|
||||
shippedAt DateTime? // факт отгрузки
|
||||
trackingNumber String? // номер отслеживания
|
||||
|
||||
// === ДАННЫЕ ПРИЕМКИ ===
|
||||
receivedAt DateTime? // факт приемки
|
||||
receivedById String? // кто принял (FK: User)
|
||||
actualQuantity Int? // принято количество
|
||||
defectQuantity Int? // брак
|
||||
receiptNotes String? // заметки приемки
|
||||
|
||||
// === УНИКАЛЬНЫЕ ПОЛЯ ДЛЯ ТОВАРОВ ===
|
||||
hasRecipes Boolean @default(false) // есть ли рецептуры
|
||||
totalServicesValue Decimal? @db.Decimal(12, 2) // общая стоимость услуг ФФ
|
||||
|
||||
// === СВЯЗИ ===
|
||||
seller Organization @relation("GoodsSupplyOrdersSeller", fields: [sellerId], references: [id])
|
||||
fulfillmentCenter Organization @relation("GoodsSupplyOrdersFulfillment", fields: [fulfillmentCenterId], references: [id])
|
||||
supplier Organization? @relation("GoodsSupplyOrdersSupplier", fields: [supplierId], references: [id])
|
||||
logisticsPartner Organization? @relation("GoodsSupplyOrdersLogistics", fields: [logisticsPartnerId], references: [id])
|
||||
receivedBy User? @relation("GoodsSupplyOrdersReceiver", fields: [receivedById], references: [id])
|
||||
items GoodsSupplyItem[]
|
||||
|
||||
@@map("goods_supply_orders")
|
||||
}
|
||||
|
||||
model GoodsSupplyItem {
|
||||
id String @id @default(cuid())
|
||||
supplyOrderId String // связь с поставкой
|
||||
productId String // какой товар (FK: Product)
|
||||
|
||||
// === КОЛИЧЕСТВА ===
|
||||
requestedQuantity Int // запросили
|
||||
approvedQuantity Int? // поставщик одобрил
|
||||
shippedQuantity Int? // отгрузили
|
||||
receivedQuantity Int? // приняли
|
||||
defectQuantity Int? @default(0) // брак
|
||||
|
||||
// === ЦЕНЫ (видит только селлер) ===
|
||||
unitPrice Decimal @db.Decimal(10, 2) // цена за единицу от поставщика
|
||||
totalPrice Decimal @db.Decimal(12, 2) // общая стоимость
|
||||
|
||||
// === РЕЦЕПТУРА (JSON) ===
|
||||
recipe Json? // полная рецептура в JSON
|
||||
/*
|
||||
recipe structure:
|
||||
{
|
||||
services: string[] // ID услуг ФФ
|
||||
fulfillmentConsumables: string[] // ID расходников ФФ
|
||||
sellerConsumables: string[] // ID расходников селлера
|
||||
marketplaceCardId?: string // карточка товара
|
||||
}
|
||||
*/
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// === СВЯЗИ ===
|
||||
supplyOrder GoodsSupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade)
|
||||
product Product @relation("GoodsSupplyItems", fields: [productId], references: [id])
|
||||
|
||||
@@unique([supplyOrderId, productId])
|
||||
@@map("goods_supply_items")
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛒 ТАБЛИЦЫ ПОСТАВОК НА МАРКЕТПЛЕЙСЫ
|
||||
|
||||
### 4️⃣ **OzonSupplyOrder - Поставки на Ozon**
|
||||
|
||||
```prisma
|
||||
model OzonSupplyOrder {
|
||||
// === БАЗОВЫЕ ПОЛЯ ===
|
||||
id String @id @default(cuid())
|
||||
status MarketplaceSupplyStatus @default(PLANNED)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// === ДАННЫЕ ФФ (создатель) ===
|
||||
fulfillmentCenterId String // кто отгружает (FK: Organization)
|
||||
plannedShipmentDate DateTime // план отгрузки
|
||||
notes String? // заметки ФФ
|
||||
|
||||
// === СПЕЦИФИЧНЫЕ ПОЛЯ OZON ===
|
||||
ozonWarehouseId String // склад Ozon
|
||||
ozonSupplyId String? // ID поставки в системе Ozon
|
||||
ozonPostingNumber String? // номер отправления Ozon
|
||||
|
||||
// === ДАННЫЕ ОТГРУЗКИ ===
|
||||
preparedAt DateTime? // готово к отгрузке
|
||||
shippedAt DateTime? // отгружено
|
||||
trackingNumber String? // номер отслеживания
|
||||
|
||||
// === ДАННЫЕ ПРИЕМКИ МАРКЕТПЛЕЙСОМ ===
|
||||
acceptedAt DateTime? // принято Ozon
|
||||
acceptedQuantity Int? // принято количество
|
||||
rejectedQuantity Int? // отклонено
|
||||
rejectionReason String? // причина отклонения
|
||||
|
||||
// === СВЯЗИ ===
|
||||
fulfillmentCenter Organization @relation("OzonSupplyOrders", fields: [fulfillmentCenterId], references: [id])
|
||||
items OzonSupplyItem[]
|
||||
|
||||
@@map("ozon_supply_orders")
|
||||
}
|
||||
|
||||
model OzonSupplyItem {
|
||||
id String @id @default(cuid())
|
||||
supplyOrderId String // связь с поставкой
|
||||
productId String // какой готовый продукт (FK: Product)
|
||||
|
||||
// === КОЛИЧЕСТВА ===
|
||||
plannedQuantity Int // планируется отгрузить
|
||||
preparedQuantity Int? // подготовлено
|
||||
shippedQuantity Int? // отгружено
|
||||
acceptedQuantity Int? // принято Ozon
|
||||
rejectedQuantity Int? @default(0) // отклонено
|
||||
|
||||
// === OZON СПЕЦИФИЧНЫЕ ПОЛЯ ===
|
||||
ozonProductId String? // ID товара в Ozon
|
||||
ozonSku String? // SKU в Ozon
|
||||
ozonBarcode String? // штрихкод
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// === СВЯЗИ ===
|
||||
supplyOrder OzonSupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade)
|
||||
product Product @relation("OzonSupplyItems", fields: [productId], references: [id])
|
||||
|
||||
@@unique([supplyOrderId, productId])
|
||||
@@map("ozon_supply_items")
|
||||
}
|
||||
```
|
||||
|
||||
### 5️⃣ **WildberriesSupplyOrder - Поставки на Wildberries**
|
||||
|
||||
```prisma
|
||||
model WildberriesSupplyOrder {
|
||||
// === БАЗОВЫЕ ПОЛЯ ===
|
||||
id String @id @default(cuid())
|
||||
status MarketplaceSupplyStatus @default(PLANNED)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// === ДАННЫЕ ФФ (создатель) ===
|
||||
fulfillmentCenterId String // кто отгружает (FK: Organization)
|
||||
plannedShipmentDate DateTime // план отгрузки
|
||||
notes String? // заметки ФФ
|
||||
|
||||
// === СПЕЦИФИЧНЫЕ ПОЛЯ WILDBERRIES ===
|
||||
wbWarehouseId String // склад WB
|
||||
wbSupplyId String? // ID поставки в системе WB
|
||||
wbStickerId String? // ID стикера WB
|
||||
|
||||
// === ДАННЫЕ ОТГРУЗКИ ===
|
||||
preparedAt DateTime? // готово к отгрузке
|
||||
shippedAt DateTime? // отгружено
|
||||
trackingNumber String? // номер отслеживания
|
||||
|
||||
// === ДАННЫЕ ПРИЕМКИ МАРКЕТПЛЕЙСОМ ===
|
||||
acceptedAt DateTime? // принято WB
|
||||
acceptedQuantity Int? // принято количество
|
||||
rejectedQuantity Int? // отклонено
|
||||
rejectionReason String? // причина отклонения
|
||||
|
||||
// === СВЯЗИ ===
|
||||
fulfillmentCenter Organization @relation("WildberriesSupplyOrders", fields: [fulfillmentCenterId], references: [id])
|
||||
items WildberriesSupplyItem[]
|
||||
|
||||
@@map("wildberries_supply_orders")
|
||||
}
|
||||
|
||||
model WildberriesSupplyItem {
|
||||
id String @id @default(cuid())
|
||||
supplyOrderId String // связь с поставкой
|
||||
productId String // какой готовый продукт (FK: Product)
|
||||
|
||||
// === КОЛИЧЕСТВА ===
|
||||
plannedQuantity Int // планируется отгрузить
|
||||
preparedQuantity Int? // подготовлено
|
||||
shippedQuantity Int? // отгружено
|
||||
acceptedQuantity Int? // принято WB
|
||||
rejectedQuantity Int? @default(0) // отклонено
|
||||
|
||||
// === WB СПЕЦИФИЧНЫЕ ПОЛЯ ===
|
||||
wbNmId String? // Номенклатура WB
|
||||
wbSku String? // SKU в WB
|
||||
wbBarcode String? // штрихкод
|
||||
wbSize String? // размер для WB
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// === СВЯЗИ ===
|
||||
supplyOrder WildberriesSupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade)
|
||||
product Product @relation("WBSupplyItems", fields: [productId], references: [id])
|
||||
|
||||
@@unique([supplyOrderId, productId])
|
||||
@@map("wildberries_supply_items")
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 НОВЫЕ ENUMS
|
||||
|
||||
### **SupplyOrderStatusV2 - Статусы поставок НА фулфилмент**
|
||||
|
||||
```prisma
|
||||
enum SupplyOrderStatusV2 {
|
||||
PENDING // Ожидает одобрения поставщика
|
||||
SUPPLIER_APPROVED // Одобрено поставщиком
|
||||
LOGISTICS_CONFIRMED // Логистика подтверждена
|
||||
SHIPPED // Отгружено поставщиком
|
||||
IN_TRANSIT // В пути
|
||||
DELIVERED // Доставлено и принято
|
||||
CANCELLED // Отменено
|
||||
}
|
||||
```
|
||||
|
||||
### **MarketplaceSupplyStatus - Статусы поставок НА маркетплейсы**
|
||||
|
||||
```prisma
|
||||
enum MarketplaceSupplyStatus {
|
||||
PLANNED // Запланирована
|
||||
PREPARED // Подготовлена к отгрузке
|
||||
SHIPPED_TO_MARKETPLACE // Отгружена на маркетплейс
|
||||
ACCEPTED_BY_MARKETPLACE // Принята маркетплейсом
|
||||
CANCELLED // Отменена
|
||||
}
|
||||
```
|
||||
|
||||
### **SellerConsumableAccessRights - Права доступа к расходникам селлеров**
|
||||
|
||||
```prisma
|
||||
enum SellerConsumableAccessRights {
|
||||
SELLER_ONLY // Только селлер может использовать
|
||||
SHARED_WITH_FF // ФФ тоже может использовать (с разрешения)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 ОБНОВЛЕНИЯ СУЩЕСТВУЮЩИХ ТАБЛИЦ
|
||||
|
||||
### **Product - Добавление новых связей**
|
||||
|
||||
```prisma
|
||||
model Product {
|
||||
// ... существующие поля остаются без изменений
|
||||
|
||||
// === НОВЫЕ СВЯЗИ С ПОСТАВКАМИ V2 ===
|
||||
fulfillmentSupplyItems FulfillmentConsumableSupplyItem[] @relation("FFSupplyItems")
|
||||
sellerSupplyItems SellerConsumableSupplyItem[] @relation("SellerSupplyItems")
|
||||
goodsSupplyItems GoodsSupplyItem[] @relation("GoodsSupplyItems")
|
||||
ozonSupplyItems OzonSupplyItem[] @relation("OzonSupplyItems")
|
||||
wildberriesSupplyItems WildberriesSupplyItem[] @relation("WBSupplyItems")
|
||||
|
||||
// ... остальные поля остаются без изменений
|
||||
}
|
||||
```
|
||||
|
||||
### **Organization - Добавление новых связей**
|
||||
|
||||
```prisma
|
||||
model Organization {
|
||||
// ... существующие поля остаются без изменений
|
||||
|
||||
// === НОВЫЕ СВЯЗИ С ПОСТАВКАМИ V2 ===
|
||||
// Поставки расходников ФФ
|
||||
fulfillmentSupplyOrdersAsFulfillment FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersFulfillment")
|
||||
fulfillmentSupplyOrdersAsSupplier FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersSupplier")
|
||||
fulfillmentSupplyOrdersAsLogistics FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersLogistics")
|
||||
|
||||
// Поставки расходников селлеров
|
||||
sellerSupplyOrdersAsSeller SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersSeller")
|
||||
sellerSupplyOrdersAsFulfillment SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersFulfillment")
|
||||
sellerSupplyOrdersAsSupplier SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersSupplier")
|
||||
sellerSupplyOrdersAsLogistics SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersLogistics")
|
||||
|
||||
// Товарные поставки
|
||||
goodsSupplyOrdersAsSeller GoodsSupplyOrder[] @relation("GoodsSupplyOrdersSeller")
|
||||
goodsSupplyOrdersAsFulfillment GoodsSupplyOrder[] @relation("GoodsSupplyOrdersFulfillment")
|
||||
goodsSupplyOrdersAsSupplier GoodsSupplyOrder[] @relation("GoodsSupplyOrdersSupplier")
|
||||
goodsSupplyOrdersAsLogistics GoodsSupplyOrder[] @relation("GoodsSupplyOrdersLogistics")
|
||||
|
||||
// Поставки на маркетплейсы
|
||||
ozonSupplyOrders OzonSupplyOrder[] @relation("OzonSupplyOrders")
|
||||
wildberriesSupplyOrders WildberriesSupplyOrder[] @relation("WildberriesSupplyOrders")
|
||||
|
||||
// ... остальные поля остаются без изменений
|
||||
}
|
||||
```
|
||||
|
||||
### **User - Добавление новых связей**
|
||||
|
||||
```prisma
|
||||
model User {
|
||||
// ... существующие поля остаются без изменений
|
||||
|
||||
// === НОВЫЕ СВЯЗИ С ПРИЕМКОЙ ПОСТАВОК V2 ===
|
||||
fulfillmentSupplyOrdersReceived FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersReceiver")
|
||||
sellerSupplyOrdersReceived SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersReceiver")
|
||||
goodsSupplyOrdersReceived GoodsSupplyOrder[] @relation("GoodsSupplyOrdersReceiver")
|
||||
|
||||
// ... остальные поля остаются без изменений
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 ИНДЕКСЫ ДЛЯ ПРОИЗВОДИТЕЛЬНОСТИ
|
||||
|
||||
```prisma
|
||||
// Индексы для быстрого поиска поставок по статусу и организации
|
||||
@@index([fulfillmentCenterId, status])
|
||||
@@index([sellerId, status])
|
||||
@@index([supplierId, status])
|
||||
@@index([logisticsPartnerId, status])
|
||||
|
||||
// Индексы для поиска по датам
|
||||
@@index([createdAt])
|
||||
@@index([requestedDeliveryDate])
|
||||
@@index([estimatedDeliveryDate])
|
||||
|
||||
// Индексы для отслеживания
|
||||
@@index([trackingNumber])
|
||||
@@index([supplierContractId])
|
||||
|
||||
// Маркетплейс-специфичные индексы
|
||||
@@index([ozonSupplyId])
|
||||
@@index([ozonProductId])
|
||||
@@index([wbSupplyId])
|
||||
@@index([wbNmId])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 ПЛАН МИГРАЦИИ
|
||||
|
||||
### **Phase 1: Создание новых таблиц**
|
||||
```sql
|
||||
-- Создание таблиц параллельно с существующими
|
||||
CREATE TABLE fulfillment_consumable_supply_orders (...);
|
||||
CREATE TABLE fulfillment_consumable_supply_items (...);
|
||||
-- и т.д.
|
||||
```
|
||||
|
||||
### **Phase 2: Новые enum значения**
|
||||
```sql
|
||||
-- Добавление новых enum без затрагивания старых
|
||||
CREATE TYPE "SupplyOrderStatusV2" AS ENUM (...);
|
||||
CREATE TYPE "MarketplaceSupplyStatus" AS ENUM (...);
|
||||
```
|
||||
|
||||
### **Phase 3: Обновление связей (без удаления старых)**
|
||||
```sql
|
||||
-- Добавление новых foreign key связей
|
||||
ALTER TABLE "Product" ADD COLUMN ...;
|
||||
ALTER TABLE "Organization" ADD COLUMN ...;
|
||||
```
|
||||
|
||||
### **Phase 4: Данные миграции (только с одобрения)**
|
||||
```sql
|
||||
-- Миграция данных из старых таблиц в новые
|
||||
-- ТОЛЬКО после полного тестирования новой системы
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ ВАЖНЫЕ ПРИНЦИПЫ
|
||||
|
||||
### ✅ **ОБРАТНАЯ СОВМЕСТИМОСТЬ**
|
||||
- Все существующие таблицы остаются без изменений
|
||||
- Новые таблицы создаются параллельно
|
||||
- Старая система продолжает работать
|
||||
|
||||
### 🔒 **БЕЗОПАСНОСТЬ ДАННЫХ**
|
||||
- Каждый тип поставки изолирован в отдельной таблице
|
||||
- Связи защищены foreign key constraints
|
||||
- Каскадное удаление только для зависимых записей
|
||||
|
||||
### 📈 **МАСШТАБИРУЕМОСТЬ**
|
||||
- Легко добавлять новые типы поставок
|
||||
- Оптимизированные индексы для каждого use case
|
||||
- Независимые схемы для разных процессов
|
||||
|
||||
### 🛡️ **ЦЕЛОСТНОСТЬ ДАННЫХ**
|
||||
- Строгие ограничения на связи между таблицами
|
||||
- Валидация через enum значения
|
||||
- Уникальные индексы предотвращают дублирование
|
||||
|
||||
**Следующий шаг:** Создание Prisma миграций для FulfillmentConsumableSupplyOrder
|
817
docs/development/SUPPLY_SYSTEM_IMPLEMENTATION_PLAN.md
Normal file
817
docs/development/SUPPLY_SYSTEM_IMPLEMENTATION_PLAN.md
Normal file
@ -0,0 +1,817 @@
|
||||
# 🛡️ ДЕТАЛЬНЫЙ БЕЗОПАСНЫЙ ПЛАН РЕАЛИЗАЦИИ СИСТЕМЫ ПОСТАВОК v2.0
|
||||
|
||||
> **🎯 ЦЕЛЬ:** Поэтапная миграция на новую архитектуру системы поставок без нарушения работы существующей системы
|
||||
|
||||
## 🔒 ПРИНЦИПЫ БЕЗОПАСНОЙ РЕАЛИЗАЦИИ
|
||||
|
||||
### ✅ **ЗОЛОТЫЕ ПРАВИЛА:**
|
||||
1. **НИКОГДА НЕ ЛОМАТЬ СУЩЕСТВУЮЩИЙ ФУНКЦИОНАЛ** - старая система работает на 100%
|
||||
2. **КАЖДЫЙ ЭТАП ИМЕЕТ ТОЧКУ ОТКАТА** - можно вернуться к предыдущему состоянию
|
||||
3. **ТЕСТИРОВАНИЕ ПЕРЕД ПРОДАКШЕНОМ** - каждое изменение проверяется отдельно
|
||||
4. **МОДУЛЬНОСТЬ** - изменения изолированы друг от друга
|
||||
5. **ОДОБРЕНИЕ ПОЛЬЗОВАТЕЛЯ** - удаление старого кода ТОЛЬКО с разрешения
|
||||
6. **МОНИТОРИНГ** - отслеживание работы на каждом этапе
|
||||
|
||||
### 🛠️ **ИНСТРУМЕНТЫ БЕЗОПАСНОСТИ:**
|
||||
- **Feature Flags** - включение/отключение новой функциональности
|
||||
- **Database Migrations** - обратимые изменения схемы БД
|
||||
- **Parallel Testing** - новая система тестируется параллельно со старой
|
||||
- **Gradual Rollout** - постепенное включение для пользователей
|
||||
- **Automated Rollback** - автоматический откат при критических ошибках
|
||||
|
||||
---
|
||||
|
||||
## 📋 PHASE 1: FULFILLMENT CONSUMABLE SUPPLY ORDERS
|
||||
|
||||
> **Сроки:** 2-3 недели
|
||||
> **Риск:** НИЗКИЙ (новая функциональность параллельно со старой)
|
||||
|
||||
### 🎯 **ЦЕЛЬ PHASE 1:**
|
||||
Создать полностью рабочую систему для поставок расходников фулфилмента, которая работает параллельно со старой системой.
|
||||
|
||||
---
|
||||
|
||||
## 📊 STEP 1.1: ПОДГОТОВКА ИНФРАСТРУКТУРЫ
|
||||
|
||||
### **Задачи:**
|
||||
1. ✅ Создание feature flag системы
|
||||
2. ✅ Настройка параллельного тестирования
|
||||
3. ✅ Подготовка инструментов мониторинга
|
||||
|
||||
### **1.1.1 Feature Flags**
|
||||
```typescript
|
||||
// /src/lib/featureFlags.ts
|
||||
export const FEATURE_FLAGS = {
|
||||
FULFILLMENT_CONSUMABLE_SUPPLY_V2: process.env.FULFILLMENT_CONSUMABLE_V2 === 'true',
|
||||
ENABLE_PARALLEL_TESTING: process.env.PARALLEL_TESTING === 'true',
|
||||
} as const
|
||||
|
||||
export function isFeatureEnabled(flag: keyof typeof FEATURE_FLAGS): boolean {
|
||||
return FEATURE_FLAGS[flag] || false
|
||||
}
|
||||
```
|
||||
|
||||
### **1.1.2 Мониторинг**
|
||||
```typescript
|
||||
// /src/lib/monitoring/supplySystemMonitor.ts
|
||||
export class SupplySystemMonitor {
|
||||
static logMigrationEvent(event: string, data: any) {
|
||||
console.log(`[SUPPLY_V2_MIGRATION] ${event}:`, data)
|
||||
// Отправка в систему мониторинга
|
||||
}
|
||||
|
||||
static logError(error: Error, context: string) {
|
||||
console.error(`[SUPPLY_V2_ERROR] ${context}:`, error)
|
||||
// Алерты в систему мониторинга
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **1.1.3 Тестовая база данных**
|
||||
```bash
|
||||
# Создание отдельной БД для тестирования миграций
|
||||
npm run db:create:test-migration
|
||||
npm run db:migrate:test
|
||||
```
|
||||
|
||||
### **⚠️ ТОЧКА ПРОВЕРКИ 1.1:**
|
||||
- [ ] Feature flags работают
|
||||
- [ ] Мониторинг настроен
|
||||
- [ ] Тестовая БД создана
|
||||
- [ ] **ОТКАТ:** Отключить feature flags
|
||||
|
||||
**🔒 ROLLBACK PLAN 1.1:**
|
||||
```bash
|
||||
# Отключение feature flags
|
||||
export FULFILLMENT_CONSUMABLE_V2=false
|
||||
# Остановка мониторинга новых метрик
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ STEP 1.2: СОЗДАНИЕ СХЕМЫ БАЗЫ ДАННЫХ
|
||||
|
||||
### **Задачи:**
|
||||
1. ✅ Создание новых Prisma моделей
|
||||
2. ✅ Генерация и проверка миграций
|
||||
3. ✅ Применение миграций в test окружении
|
||||
|
||||
### **1.2.1 Prisma Schema Update**
|
||||
```prisma
|
||||
// Добавление в /prisma/schema.prisma
|
||||
model FulfillmentConsumableSupplyOrder {
|
||||
// ... полная схема из DATABASE_SCHEMA_V2.md
|
||||
}
|
||||
|
||||
model FulfillmentConsumableSupplyItem {
|
||||
// ... полная схема из DATABASE_SCHEMA_V2.md
|
||||
}
|
||||
|
||||
enum SupplyOrderStatusV2 {
|
||||
PENDING
|
||||
SUPPLIER_APPROVED
|
||||
LOGISTICS_CONFIRMED
|
||||
SHIPPED
|
||||
IN_TRANSIT
|
||||
DELIVERED
|
||||
CANCELLED
|
||||
}
|
||||
```
|
||||
|
||||
### **1.2.2 Создание миграции**
|
||||
```bash
|
||||
# Генерация миграции
|
||||
npx prisma migrate dev --name "add_fulfillment_consumable_supply_v2"
|
||||
|
||||
# Проверка SQL миграции ПЕРЕД применением
|
||||
cat prisma/migrations/xxx_add_fulfillment_consumable_supply_v2/migration.sql
|
||||
```
|
||||
|
||||
### **1.2.3 Тестирование миграции**
|
||||
```bash
|
||||
# Применение в тестовой БД
|
||||
npx prisma migrate deploy --schema=./prisma/schema.test.prisma
|
||||
|
||||
# Проверка создания таблиц
|
||||
npx prisma studio --schema=./prisma/schema.test.prisma
|
||||
```
|
||||
|
||||
### **⚠️ ТОЧКА ПРОВЕРКИ 1.2:**
|
||||
- [ ] Миграция создана успешно
|
||||
- [ ] SQL миграции проверен вручную
|
||||
- [ ] Таблицы созданы в тестовой БД
|
||||
- [ ] Все связи (FK) работают корректно
|
||||
- [ ] **ОТКАТ:** Revert migration
|
||||
|
||||
**🔒 ROLLBACK PLAN 1.2:**
|
||||
```bash
|
||||
# Откат миграции
|
||||
npx prisma migrate reset --force --skip-seed
|
||||
# ИЛИ ручной DROP TABLE если нужно
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚡ STEP 1.3: GRAPHQL API
|
||||
|
||||
### **Задачи:**
|
||||
1. ✅ Создание GraphQL типов
|
||||
2. ✅ Создание resolvers с feature flag
|
||||
3. ✅ Тестирование API отдельно
|
||||
|
||||
### **1.3.1 GraphQL Types**
|
||||
```typescript
|
||||
// /src/graphql/typedefs.ts - ДОБАВИТЬ К СУЩЕСТВУЮЩИМ
|
||||
const fulfillmentConsumableTypes = `
|
||||
type FulfillmentConsumableSupplyOrder {
|
||||
id: ID!
|
||||
status: SupplyOrderStatusV2!
|
||||
fulfillmentCenterId: ID!
|
||||
supplierId: ID
|
||||
requestedDeliveryDate: DateTime!
|
||||
resalePricePerUnit: Float
|
||||
# ... все остальные поля
|
||||
items: [FulfillmentConsumableSupplyItem!]!
|
||||
}
|
||||
|
||||
type FulfillmentConsumableSupplyItem {
|
||||
id: ID!
|
||||
productId: ID!
|
||||
requestedQuantity: Int!
|
||||
unitPrice: Float!
|
||||
totalPrice: Float!
|
||||
product: Product!
|
||||
}
|
||||
|
||||
enum SupplyOrderStatusV2 {
|
||||
PENDING
|
||||
SUPPLIER_APPROVED
|
||||
LOGISTICS_CONFIRMED
|
||||
SHIPPED
|
||||
IN_TRANSIT
|
||||
DELIVERED
|
||||
CANCELLED
|
||||
}
|
||||
|
||||
input CreateFulfillmentConsumableSupplyInput {
|
||||
supplierId: ID!
|
||||
requestedDeliveryDate: DateTime!
|
||||
items: [FulfillmentConsumableSupplyItemInput!]!
|
||||
notes: String
|
||||
}
|
||||
|
||||
input FulfillmentConsumableSupplyItemInput {
|
||||
productId: ID!
|
||||
requestedQuantity: Int!
|
||||
}
|
||||
|
||||
type CreateFulfillmentConsumableSupplyResult {
|
||||
success: Boolean!
|
||||
message: String!
|
||||
supplyOrder: FulfillmentConsumableSupplyOrder
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
# Новые запросы с feature flag
|
||||
myFulfillmentConsumableSupplies: [FulfillmentConsumableSupplyOrder!]!
|
||||
fulfillmentConsumableSupply(id: ID!): FulfillmentConsumableSupplyOrder
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
# Новые мутации с feature flag
|
||||
createFulfillmentConsumableSupply(
|
||||
input: CreateFulfillmentConsumableSupplyInput!
|
||||
): CreateFulfillmentConsumableSupplyResult!
|
||||
}
|
||||
`
|
||||
```
|
||||
|
||||
### **1.3.2 Resolvers с Feature Flags**
|
||||
```typescript
|
||||
// /src/graphql/resolvers.ts - ДОБАВИТЬ К СУЩЕСТВУЮЩИМ
|
||||
const fulfillmentConsumableResolvers = {
|
||||
Query: {
|
||||
myFulfillmentConsumableSupplies: async (_: unknown, __: unknown, context: Context) => {
|
||||
// 🚨 FEATURE FLAG ПРОВЕРКА
|
||||
if (!isFeatureEnabled('FULFILLMENT_CONSUMABLE_SUPPLY_V2')) {
|
||||
throw new GraphQLError('Feature not enabled')
|
||||
}
|
||||
|
||||
SupplySystemMonitor.logMigrationEvent('API_CALL', {
|
||||
operation: 'myFulfillmentConsumableSupplies',
|
||||
userId: context.user?.id
|
||||
})
|
||||
|
||||
try {
|
||||
// Полная реализация с системой безопасности
|
||||
// ... код реализации
|
||||
} catch (error) {
|
||||
SupplySystemMonitor.logError(error, 'myFulfillmentConsumableSupplies')
|
||||
throw error
|
||||
}
|
||||
},
|
||||
|
||||
fulfillmentConsumableSupply: async (_: unknown, args: { id: string }, context: Context) => {
|
||||
if (!isFeatureEnabled('FULFILLMENT_CONSUMABLE_SUPPLY_V2')) {
|
||||
throw new GraphQLError('Feature not enabled')
|
||||
}
|
||||
// ... реализация
|
||||
}
|
||||
},
|
||||
|
||||
Mutation: {
|
||||
createFulfillmentConsumableSupply: async (_: unknown, args: any, context: Context) => {
|
||||
if (!isFeatureEnabled('FULFILLMENT_CONSUMABLE_SUPPLY_V2')) {
|
||||
return { success: false, message: 'Feature not enabled' }
|
||||
}
|
||||
|
||||
SupplySystemMonitor.logMigrationEvent('CREATE_SUPPLY', {
|
||||
supplierId: args.input.supplierId,
|
||||
itemsCount: args.input.items.length,
|
||||
userId: context.user?.id
|
||||
})
|
||||
|
||||
try {
|
||||
// Полная реализация создания поставки
|
||||
// ... код реализации
|
||||
|
||||
return { success: true, message: 'Supply created', supplyOrder: result }
|
||||
} catch (error) {
|
||||
SupplySystemMonitor.logError(error, 'createFulfillmentConsumableSupply')
|
||||
return { success: false, message: error.message }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **1.3.3 API Testing**
|
||||
```typescript
|
||||
// /tests/api/fulfillmentConsumableSupply.test.ts
|
||||
describe('FulfillmentConsumableSupply API', () => {
|
||||
beforeAll(() => {
|
||||
// Включаем feature flag для тестов
|
||||
process.env.FULFILLMENT_CONSUMABLE_V2 = 'true'
|
||||
})
|
||||
|
||||
test('should create supply order', async () => {
|
||||
const mutation = `
|
||||
mutation CreateFulfillmentConsumableSupply($input: CreateFulfillmentConsumableSupplyInput!) {
|
||||
createFulfillmentConsumableSupply(input: $input) {
|
||||
success
|
||||
message
|
||||
supplyOrder {
|
||||
id
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
// ... тестирование
|
||||
})
|
||||
|
||||
test('should not work when feature disabled', async () => {
|
||||
process.env.FULFILLMENT_CONSUMABLE_V2 = 'false'
|
||||
// Проверка что API недоступно
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### **⚠️ ТОЧКА ПРОВЕРКИ 1.3:**
|
||||
- [ ] GraphQL типы корректны
|
||||
- [ ] Resolvers работают с feature flag
|
||||
- [ ] API тесты проходят
|
||||
- [ ] Feature flag блокирует доступ когда выключен
|
||||
- [ ] **ОТКАТ:** Отключить feature flag
|
||||
|
||||
**🔒 ROLLBACK PLAN 1.3:**
|
||||
```bash
|
||||
# Отключение API через feature flag
|
||||
export FULFILLMENT_CONSUMABLE_V2=false
|
||||
# API станет недоступно мгновенно
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 STEP 1.4: FRONTEND ИНТЕРФЕЙС
|
||||
|
||||
### **Задачи:**
|
||||
1. ✅ Создание формы создания поставки
|
||||
2. ✅ Создание страницы просмотра поставок
|
||||
3. ✅ Интеграция с существующим интерфейсом
|
||||
|
||||
### **1.4.1 Feature Flag в Frontend**
|
||||
```typescript
|
||||
// /src/lib/featureFlags.client.ts
|
||||
export function useFeatureFlag(flag: string) {
|
||||
return process.env.NEXT_PUBLIC_FULFILLMENT_CONSUMABLE_V2 === 'true'
|
||||
}
|
||||
```
|
||||
|
||||
### **1.4.2 Форма создания (с feature flag)**
|
||||
```typescript
|
||||
// /src/components/fulfillment-supplies/create-consumables-v2.tsx
|
||||
export function CreateConsumablesV2Page() {
|
||||
const featureEnabled = useFeatureFlag('FULFILLMENT_CONSUMABLE_V2')
|
||||
|
||||
if (!featureEnabled) {
|
||||
// Показываем старую версию или заглушку
|
||||
return <CreateConsumablesV1 />
|
||||
}
|
||||
|
||||
// Новая реализация
|
||||
return (
|
||||
<div>
|
||||
<h1>Создать поставку расходников ФФ (v2.0)</h1>
|
||||
{/* Полная форма */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### **1.4.3 Список поставок (с feature flag)**
|
||||
```typescript
|
||||
// /src/components/fulfillment-supplies/ff-consumables-v2.tsx
|
||||
export function FFConsumablesV2Tab() {
|
||||
const featureEnabled = useFeatureFlag('FULFILLMENT_CONSUMABLE_V2')
|
||||
|
||||
if (!featureEnabled) {
|
||||
return <FFConsumablesV1Tab />
|
||||
}
|
||||
|
||||
const { data, loading, error } = useQuery(GET_MY_FULFILLMENT_CONSUMABLE_SUPPLIES)
|
||||
|
||||
// Новая реализация отображения
|
||||
}
|
||||
```
|
||||
|
||||
### **1.4.4 Интеграция в роутинг**
|
||||
```typescript
|
||||
// /src/app/fulfillment-supplies/ff-consumables/page.tsx
|
||||
export default function FFConsumablesPage() {
|
||||
const featureEnabled = useFeatureFlag('FULFILLMENT_CONSUMABLE_V2')
|
||||
|
||||
return featureEnabled ? <FFConsumablesV2Tab /> : <FFConsumablesV1Tab />
|
||||
}
|
||||
```
|
||||
|
||||
### **⚠️ ТОЧКА ПРОВЕРКИ 1.4:**
|
||||
- [ ] Форма создания работает
|
||||
- [ ] Список поставок отображается
|
||||
- [ ] Feature flag переключает версии
|
||||
- [ ] Нет поломок в старом интерфейсе
|
||||
- [ ] **ОТКАТ:** Отключить frontend feature flag
|
||||
|
||||
**🔒 ROLLBACK PLAN 1.4:**
|
||||
```bash
|
||||
# Отключение новых компонентов
|
||||
export NEXT_PUBLIC_FULFILLMENT_CONSUMABLE_V2=false
|
||||
# Пользователи увидят старый интерфейс
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔗 STEP 1.5: ИНТЕГРАЦИЯ И END-TO-END ТЕСТИРОВАНИЕ
|
||||
|
||||
### **Задачи:**
|
||||
1. ✅ Полное тестирование workflow поставки
|
||||
2. ✅ Тестирование безопасности доступа
|
||||
3. ✅ Нагрузочное тестирование
|
||||
4. ✅ Проверка совместимости со старой системой
|
||||
|
||||
### **1.5.1 End-to-End тесты**
|
||||
```typescript
|
||||
// /tests/e2e/fulfillmentConsumableSupply.e2e.ts
|
||||
describe('Fulfillment Consumable Supply E2E', () => {
|
||||
test('Complete supply workflow', async () => {
|
||||
// 1. ФФ создает поставку
|
||||
// 2. Поставщик одобряет
|
||||
// 3. Логистика назначается
|
||||
// 4. Отгрузка
|
||||
// 5. Приемка
|
||||
// Проверяем каждый этап
|
||||
})
|
||||
|
||||
test('Security access control', async () => {
|
||||
// Проверяем что селлеры не видят поставки ФФ
|
||||
// Проверяем фильтрацию данных по ролям
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### **1.5.2 Параллельное тестирование**
|
||||
```typescript
|
||||
// /tests/parallel/oldVsNewSystem.test.ts
|
||||
describe('Old vs New System Compatibility', () => {
|
||||
test('Both systems work independently', async () => {
|
||||
// Создаем поставку в старой системе
|
||||
// Создаем поставку в новой системе
|
||||
// Проверяем что они не мешают друг другу
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### **1.5.3 Performance Testing**
|
||||
```bash
|
||||
# Нагрузочное тестирование API
|
||||
npm run test:load -- --scenario=fulfillment-consumable-v2
|
||||
```
|
||||
|
||||
### **⚠️ ТОЧКА ПРОВЕРКИ 1.5:**
|
||||
- [ ] E2E тесты проходят
|
||||
- [ ] Система безопасности работает
|
||||
- [ ] Производительность приемлемая
|
||||
- [ ] Старая система не затронута
|
||||
- [ ] **ОТКАТ:** Полное отключение feature flags
|
||||
|
||||
**🔒 ROLLBACK PLAN 1.5:**
|
||||
```bash
|
||||
# Полное отключение новой системы
|
||||
export FULFILLMENT_CONSUMABLE_V2=false
|
||||
export NEXT_PUBLIC_FULFILLMENT_CONSUMABLE_V2=false
|
||||
npm run restart
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 STEP 1.6: PRODUCTION DEPLOYMENT
|
||||
|
||||
### **Задачи:**
|
||||
1. ✅ Постепенное включение для пользователей
|
||||
2. ✅ Мониторинг в реальном времени
|
||||
3. ✅ Готовность к быстрому откату
|
||||
|
||||
### **1.6.1 Gradual Rollout**
|
||||
```typescript
|
||||
// Включение для 10% пользователей
|
||||
export function shouldUseV2ForUser(userId: string): boolean {
|
||||
if (!isFeatureEnabled('FULFILLMENT_CONSUMABLE_V2')) return false
|
||||
|
||||
// Хэш от userId, включаем для 10%
|
||||
const hash = hashCode(userId)
|
||||
return (hash % 10) === 0
|
||||
}
|
||||
```
|
||||
|
||||
### **1.6.2 Real-time мониторинг**
|
||||
```typescript
|
||||
// Метрики в реальном времени
|
||||
export const supplyV2Metrics = {
|
||||
createSuccess: 0,
|
||||
createError: 0,
|
||||
querySuccess: 0,
|
||||
queryError: 0,
|
||||
rollbackTriggered: false
|
||||
}
|
||||
|
||||
// Автоматический откат при критических ошибках
|
||||
if (supplyV2Metrics.createError > 10) {
|
||||
// Экстренное отключение
|
||||
process.env.FULFILLMENT_CONSUMABLE_V2 = 'false'
|
||||
supplyV2Metrics.rollbackTriggered = true
|
||||
}
|
||||
```
|
||||
|
||||
### **1.6.3 Production Checklist**
|
||||
```markdown
|
||||
## PRODUCTION DEPLOYMENT CHECKLIST
|
||||
- [ ] Database migration applied successfully
|
||||
- [ ] Feature flags configured
|
||||
- [ ] Monitoring dashboards active
|
||||
- [ ] Rollback procedures tested
|
||||
- [ ] Support team notified
|
||||
- [ ] Documentation updated
|
||||
- [ ] Gradual rollout configured (10% users)
|
||||
```
|
||||
|
||||
### **⚠️ ТОЧКА ПРОВЕРКИ 1.6:**
|
||||
- [ ] Deployment прошел успешно
|
||||
- [ ] 10% пользователей используют новую систему
|
||||
- [ ] Метрики показывают стабильность
|
||||
- [ ] Нет критических ошибок
|
||||
- [ ] **ОТКАТ:** Экстренное отключение
|
||||
|
||||
**🔒 ROLLBACK PLAN 1.6:**
|
||||
```bash
|
||||
# ЭКСТРЕННЫЙ ОТКАТ
|
||||
kubectl set env deployment/app FULFILLMENT_CONSUMABLE_V2=false
|
||||
# ИЛИ через admin panel
|
||||
curl -X POST /admin/feature-flags/disable/FULFILLMENT_CONSUMABLE_V2
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 STEP 1.7: МОНИТОРИНГ И СТАБИЛИЗАЦИЯ
|
||||
|
||||
### **Задачи:**
|
||||
1. ✅ Анализ метрик производительности
|
||||
2. ✅ Сбор фидбека пользователей
|
||||
3. ✅ Исправление найденных проблем
|
||||
4. ✅ Подготовка к Phase 2
|
||||
|
||||
### **1.7.1 Мониторинг (1-2 недели)**
|
||||
```typescript
|
||||
// Ключевые метрики для отслеживания
|
||||
const metricsToWatch = {
|
||||
// Функциональные
|
||||
supplyCreationRate: 'число создаваемых поставок/день',
|
||||
successRate: 'процент успешных операций',
|
||||
averageProcessingTime: 'среднее время обработки',
|
||||
|
||||
// Технические
|
||||
databasePerformance: 'время ответа БД',
|
||||
apiLatency: 'задержка API',
|
||||
errorRate: 'процент ошибок',
|
||||
|
||||
// Бизнесовые
|
||||
userAdoption: 'процент пользователей использующих v2',
|
||||
userSatisfaction: 'оценка пользователей',
|
||||
supportTickets: 'количество тикетов поддержки'
|
||||
}
|
||||
```
|
||||
|
||||
### **1.7.2 Feedback Collection**
|
||||
```typescript
|
||||
// Встроенная система сбора фидбека
|
||||
export function FeedbackWidget() {
|
||||
return (
|
||||
<div className="feedback-widget">
|
||||
<p>Как вам новая система поставок?</p>
|
||||
<button onClick={() => sendFeedback('positive')}>👍</button>
|
||||
<button onClick={() => sendFeedback('negative')}>👎</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### **1.7.3 Анализ и улучшения**
|
||||
```markdown
|
||||
## КРИТЕРИИ УСПЕХА PHASE 1:
|
||||
✅ Успешность операций > 98%
|
||||
✅ Время отклика < 2 сек
|
||||
✅ Пользовательская оценка > 4/5
|
||||
✅ Количество багов < 5 критических
|
||||
✅ Готовность инфраструктуры к Phase 2
|
||||
```
|
||||
|
||||
### **⚠️ ТОЧКА ПРОВЕРКИ 1.7:**
|
||||
- [ ] Метрики в пределах нормы
|
||||
- [ ] Пользователи довольны
|
||||
- [ ] Критические баги исправлены
|
||||
- [ ] Система готова к расширению
|
||||
- [ ] **РЕШЕНИЕ:** Переход к Phase 2 или доработка
|
||||
|
||||
---
|
||||
|
||||
## 🎯 КРИТЕРИИ ГОТОВНОСТИ К PHASE 2
|
||||
|
||||
### ✅ **ОБЯЗАТЕЛЬНЫЕ УСЛОВИЯ:**
|
||||
1. **Функциональность:** Все features Phase 1 работают стабильно
|
||||
2. **Производительность:** Нет деградации по сравнению со старой системой
|
||||
3. **Безопасность:** Нет утечек данных, доступ контролируется корректно
|
||||
4. **Пользователи:** Положительные отзывы от 80%+ пользователей
|
||||
5. **Мониторинг:** Налаженная система отслеживания метрик
|
||||
|
||||
### 📈 **ЧИСЛЕННЫЕ ПОКАЗАТЕЛИ:**
|
||||
- Успешность создания поставок: **> 98%**
|
||||
- Время загрузки списка поставок: **< 2 сек**
|
||||
- Время создания поставки: **< 5 сек**
|
||||
- Uptime системы: **> 99.5%**
|
||||
- Количество критических багов: **= 0**
|
||||
|
||||
---
|
||||
|
||||
## 📋 PHASE 2: SELLER CONSUMABLE SUPPLY ORDERS
|
||||
|
||||
> **Сроки:** 2-3 недели после стабилизации Phase 1
|
||||
> **Риск:** СРЕДНИЙ (более сложная логика с хранением)
|
||||
|
||||
### **Ключевые особенности Phase 2:**
|
||||
1. **Мульти-организационность:** Селлер создает, ФФ хранит
|
||||
2. **Права доступа:** Сложная система доступа к данным
|
||||
3. **Сроки хранения:** Временные ограничения на хранение
|
||||
4. **Интеграция с Phase 1:** Должна работать вместе с поставками ФФ
|
||||
|
||||
### **Plan Phase 2:**
|
||||
- Step 2.1: Database Schema для селлерских расходников
|
||||
- Step 2.2: GraphQL API с правами доступа
|
||||
- Step 2.3: Frontend для селлеров и ФФ
|
||||
- Step 2.4: Интеграция с системой хранения
|
||||
- Step 2.5: Тестирование совместимости с Phase 1
|
||||
|
||||
---
|
||||
|
||||
## 📋 PHASE 3: GOODS SUPPLY ORDERS
|
||||
|
||||
> **Сроки:** 3-4 недели после стабилизации Phase 2
|
||||
> **Риск:** ВЫСОКИЙ (самая сложная система с рецептурами)
|
||||
|
||||
### **Ключевые особенности Phase 3:**
|
||||
1. **Рецептуры:** Сложная JSON структура с услугами
|
||||
2. **Мульти-компонентность:** Товары + услуги + расходники
|
||||
3. **Marketplace интеграция:** Связь с карточками товаров
|
||||
4. **Миграция данных:** Перенос существующих товарных поставок
|
||||
|
||||
---
|
||||
|
||||
## 📋 PHASE 4: ОЧИСТКА И ОПТИМИЗАЦИЯ
|
||||
|
||||
> **Сроки:** 1-2 недели
|
||||
> **Риск:** НИЗКИЙ (только после полного одобрения)
|
||||
|
||||
### **Задачи Phase 4:**
|
||||
1. **Миграция старых данных** (ТОЛЬКО с одобрения)
|
||||
2. **Удаление устаревшего кода** (ТОЛЬКО с одобрения)
|
||||
3. **Оптимизация производительности**
|
||||
4. **Финальное тестирование**
|
||||
|
||||
---
|
||||
|
||||
## 🚨 EMERGENCY PROCEDURES
|
||||
|
||||
### **🔴 CRITICAL ROLLBACK (при критических ошибках)**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# emergency-rollback.sh
|
||||
|
||||
echo "🚨 EMERGENCY ROLLBACK INITIATED"
|
||||
|
||||
# Отключение всех feature flags
|
||||
export FULFILLMENT_CONSUMABLE_V2=false
|
||||
export SELLER_CONSUMABLE_V2=false
|
||||
export GOODS_SUPPLY_V2=false
|
||||
export NEXT_PUBLIC_FULFILLMENT_CONSUMABLE_V2=false
|
||||
|
||||
# Перезапуск сервисов
|
||||
kubectl rollout restart deployment/app
|
||||
kubectl rollout restart deployment/api
|
||||
|
||||
# Уведомления
|
||||
curl -X POST "$SLACK_WEBHOOK" -d '{"text": "🚨 Supply System V2 Emergency Rollback Executed"}'
|
||||
|
||||
echo "✅ Rollback completed. System reverted to V1."
|
||||
```
|
||||
|
||||
### **🟡 PARTIAL ROLLBACK (при локальных проблемах)**
|
||||
```bash
|
||||
# Откат конкретной фазы
|
||||
rollback_phase_1() {
|
||||
export FULFILLMENT_CONSUMABLE_V2=false
|
||||
kubectl set env deployment/app FULFILLMENT_CONSUMABLE_V2=false
|
||||
}
|
||||
|
||||
rollback_phase_2() {
|
||||
export SELLER_CONSUMABLE_V2=false
|
||||
kubectl set env deployment/app SELLER_CONSUMABLE_V2=false
|
||||
}
|
||||
```
|
||||
|
||||
### **📊 MONITORING ALERTS**
|
||||
```typescript
|
||||
// Автоматические алерты
|
||||
const ALERT_THRESHOLDS = {
|
||||
ERROR_RATE: 5, // > 5% ошибок = алерт
|
||||
RESPONSE_TIME: 5000, // > 5 сек = алерт
|
||||
FAILED_CREATES: 10, // > 10 неудачных создания = алерт
|
||||
DATABASE_ERRORS: 3 // > 3 ошибки БД = критический алерт
|
||||
}
|
||||
|
||||
// Автоматическое отключение при превышении порогов
|
||||
if (currentMetrics.errorRate > ALERT_THRESHOLDS.ERROR_RATE) {
|
||||
triggerEmergencyRollback('HIGH_ERROR_RATE')
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 SUCCESS METRICS
|
||||
|
||||
### **📊 KPI для каждой фазы:**
|
||||
|
||||
#### **Phase 1 Success Criteria:**
|
||||
- ✅ 100% функций поставок расходников ФФ работают
|
||||
- ✅ 0 критических багов в production
|
||||
- ✅ < 2 сек время отклика API
|
||||
- ✅ > 90% положительных отзывов пользователей
|
||||
- ✅ 0 инцидентов безопасности
|
||||
|
||||
#### **Phase 2 Success Criteria:**
|
||||
- ✅ Поставки расходников селлеров работают корректно
|
||||
- ✅ Права доступа работают (селлер видит свое, ФФ видит ограниченно)
|
||||
- ✅ Интеграция с Phase 1 без конфликтов
|
||||
|
||||
#### **Phase 3 Success Criteria:**
|
||||
- ✅ Товарные поставки с рецептурами работают
|
||||
- ✅ Миграция существующих данных (если одобрена)
|
||||
- ✅ Интеграция с маркетплейсами
|
||||
|
||||
#### **Overall Success Criteria:**
|
||||
- ✅ **Производительность:** Не хуже старой системы
|
||||
- ✅ **Стабильность:** 99.9% uptime
|
||||
- ✅ **Безопасность:** 0 утечек данных
|
||||
- ✅ **Пользователи:** > 85% satisfaction rate
|
||||
- ✅ **Бизнес:** Увеличение эффективности процессов поставок
|
||||
|
||||
---
|
||||
|
||||
## ⏰ TIMELINE
|
||||
|
||||
```mermaid
|
||||
gantt
|
||||
title Supply System V2 Implementation Timeline
|
||||
dateFormat YYYY-MM-DD
|
||||
section Phase 1
|
||||
Infrastructure Setup :2024-08-25, 3d
|
||||
Database Schema :2024-08-28, 2d
|
||||
GraphQL API :2024-08-30, 4d
|
||||
Frontend Interface :2024-09-03, 4d
|
||||
Integration Testing :2024-09-07, 3d
|
||||
Production Deployment :2024-09-10, 2d
|
||||
Monitoring & Stabilization :2024-09-12, 7d
|
||||
|
||||
section Phase 2
|
||||
Seller Consumables Schema :2024-09-19, 3d
|
||||
Complex Access Control :2024-09-22, 5d
|
||||
Multi-org Frontend :2024-09-27, 4d
|
||||
Integration Testing :2024-10-01, 4d
|
||||
|
||||
section Phase 3
|
||||
Goods Supply Schema :2024-10-05, 4d
|
||||
Recipe System :2024-10-09, 6d
|
||||
Data Migration Prep :2024-10-15, 3d
|
||||
Testing & Validation :2024-10-18, 5d
|
||||
|
||||
section Phase 4
|
||||
Data Migration :2024-10-23, 3d
|
||||
Code Cleanup :2024-10-26, 2d
|
||||
Final Testing :2024-10-28, 2d
|
||||
```
|
||||
|
||||
### **🎯 MILESTONE DATES:**
|
||||
- **Phase 1 Complete:** September 19, 2024
|
||||
- **Phase 2 Complete:** October 4, 2024
|
||||
- **Phase 3 Complete:** October 23, 2024
|
||||
- **Full Migration Complete:** October 30, 2024
|
||||
|
||||
---
|
||||
|
||||
## ✅ ЗАКЛЮЧЕНИЕ
|
||||
|
||||
Данный план обеспечивает:
|
||||
|
||||
### 🛡️ **МАКСИМАЛЬНУЮ БЕЗОПАСНОСТЬ:**
|
||||
- Поэтапное внедрение без риска для работающей системы
|
||||
- Множественные точки отката на каждом этапе
|
||||
- Тщательное тестирование перед каждым шагом
|
||||
|
||||
### 📈 **КОНТРОЛИРУЕМЫЙ РОСТ:**
|
||||
- Постепенное увеличение сложности (ФФ → Селлер → Товары)
|
||||
- Feature flags для контроля доступа
|
||||
- Мониторинг метрик на каждом этапе
|
||||
|
||||
### 🔧 **ГИБКОСТЬ РЕАЛИЗАЦИИ:**
|
||||
- Возможность приостановить на любом этапе
|
||||
- Адаптация планов по результатам предыдущих фаз
|
||||
- Учет пожеланий пользователей
|
||||
|
||||
**Система готова к безопасной поэтапной реализации!**
|
Reference in New Issue
Block a user