# 🚚 АРХИТЕКТУРА СИСТЕМЫ ПОСТАВОК 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`