
- DATA_SYNCHRONIZATION_RULES.md - правила синхронизации между компонентами - GRAPHQL_CACHE_RULES.md - настройки кеширования и fetchPolicy - CSS_LAYOUT_SCROLL_RULES.md - решение проблем с overflow и scroll - STATISTICAL_COMPONENTS_RULES.md - правила Master-Detail архитектуры Документация основана на исправлениях в кабинете фулфилмента 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
10 KiB
10 KiB
🔄 ПРАВИЛА СИНХРОНИЗАЦИИ ДАННЫХ МЕЖДУ КОМПОНЕНТАМИ
Цель: Обеспечить консистентность данных между различными компонентами системы SFERA
📋 ОСНОВНЫЕ ПРИНЦИПЫ
1. ЕДИНЫЙ ИСТОЧНИК ИСТИНЫ (Single Source of Truth)
- ✅ Один резолвер = одна таблица БД для одного типа данных
- ✅ V2 система - приоритет над legacy кодом
- ❌ Никогда не дублируйте одни данные в разных резолверах
2. КОНСИСТЕНТНАЯ CACHE POLICY
// ✅ ПРАВИЛЬНО - одинаковая policy для связанных данных
const query1 = useQuery(QUERY_A, { fetchPolicy: 'cache-and-network' })
const query2 = useQuery(QUERY_B, { fetchPolicy: 'cache-and-network' })
// ❌ НЕПРАВИЛЬНО - разные policies создают рассинхронизацию
const query1 = useQuery(QUERY_A, { fetchPolicy: 'cache-and-network' })
const query2 = useQuery(QUERY_B, {}) // default cache-first policy
3. ОБЯЗАТЕЛЬНЫЕ FETCH POLICIES
Для связанных компонентов:
fetchPolicy: 'cache-and-network', // Всегда актуальные данные
pollInterval: 30000, // Автообновление каждые 30 сек
Для dashboard/статистики:
fetchPolicy: 'cache-and-network', // Синхронизация с основными данными
pollInterval: 30000, // Регулярное обновление
errorPolicy: 'all', // Показывать частичные данные при ошибках
🏢 ПРАВИЛА ДЛЯ ФУЛФИЛМЕНТА
ТАБЛИЦЫ V2 СИСТЕМЫ
fulfillmentConsumableInventory
- складские остатки расходниковfulfillmentConsumableSupplyOrder
- поставки расходниковfulfillmentInventoryV2
- общий инвентарь фулфилмента
СВЯЗАННЫЕ КОМПОНЕНТЫ
// Все эти компоненты должны использовать одинаковые данные:
1. Главный dashboard склада (/fulfillment-warehouse)
- Карточка "РАСХОДНИКИ ФУЛФИЛМЕНТА"
2. Подраздел расходников (/fulfillment-warehouse/supplies)
- Карточка "ОСТАТОК"
- Главная таблица поставок
3. Раздел услуг (/services)
- Вкладка "Расходники"
4. История поставок
- Раскрывающиеся детали каждого товара
СИНХРОНИЗИРОВАННЫЕ ПОЛЯ
interface SynchronizedData {
currentStock: number // Текущий остаток (одинаковый везде)
totalReceived: number // Общее количество поступлений
productId: string // ID для группировки истории поставок
fulfillmentCenterId: string // ID фулфилмент-центра
}
📊 ПРАВИЛА ДЛЯ СТАТИСТИЧЕСКИХ КОМПОНЕНТОВ
1. АРХИТЕКТУРА MASTER-DETAIL
// MASTER компонент (главный раздел)
const masterStats = useQuery(GET_WAREHOUSE_STATS, {
fetchPolicy: 'cache-and-network',
pollInterval: 30000,
})
// DETAIL компонент (подраздел)
const detailStats = useQuery(GET_DETAILED_SUPPLIES, {
fetchPolicy: 'cache-and-network', // ← ОБЯЗАТЕЛЬНО то же самое!
pollInterval: 30000, // ← ОБЯЗАТЕЛЬНО то же самое!
})
// Вычисление должно давать одинаковые результаты
const masterValue = masterStats.data?.fulfillmentSupplies?.current
const detailValue = detailStats.data?.supplies?.reduce((sum, s) => sum + s.currentStock, 0)
// masterValue === detailValue ← ОБЯЗАТЕЛЬНО!
2. ПРАВИЛА АГРЕГАЦИИ
// ✅ ПРАВИЛЬНО - агрегация из одного источника данных
const totalStock = inventoryItems.reduce((sum, item) => sum + item.currentStock, 0)
// ❌ НЕПРАВИЛЬНО - агрегация из разных источников
const totalStock1 = supplies.reduce((sum, s) => sum + s.currentStock, 0) // источник A
const totalStock2 = inventory.reduce((sum, i) => sum + i.remainingStock, 0) // источник B
🔗 ПРАВИЛА СВЯЗЫВАНИЯ ДАННЫХ
ОБЯЗАТЕЛЬНЫЕ ПОЛЯ ДЛЯ СВЯЗИ
// В GraphQL схемах ОБЯЗАТЕЛЬНО указывать связующие поля:
type Supply {
id: ID!
productId: ID! // ← Для фильтрации истории поставок
fulfillmentCenterId: ID // ← Для привязки к фулфилменту
}
type SupplyOrder {
id: ID!
fulfillmentCenterId: ID! // ← Для фильтрации по фулфилменту
items: [SupplyOrderItem!]!
}
type SupplyOrderItem {
productId: ID! // ← Для связи с inventory
requestedQuantity: Int!
receivedQuantity: Int! // ← Для подсчёта остатков
}
ФИЛЬТРАЦИЯ ПО СВЯЗАННЫМ ДАННЫМ
// ✅ ПРАВИЛЬНО - фильтрация по ID
const getSupplyHistory = (supply: Supply) => {
return allDeliveries.filter((delivery) => delivery.items?.some((item) => item.productId === supply.productId))
}
// ❌ НЕПРАВИЛЬНО - фильтрация по названию (может быть дубли)
const getSupplyHistory = (supply: Supply) => {
return allDeliveries.filter((delivery) => delivery.name === supply.name && delivery.category === supply.category)
}
⚡ ПРАВИЛА REAL-TIME ОБНОВЛЕНИЙ
АВТОМАТИЧЕСКАЯ СИНХРОНИЗАЦИЯ
// Компоненты должны обновляться автоматически при изменениях
// 1. При приёме поставки на склад
prisma.fulfillmentConsumableInventory.update({
where: { id: itemId },
data: { currentStock: newStock },
})
// → Автоматически обновятся: статистика, таблица, услуги
// 2. При отгрузке товаров
prisma.fulfillmentConsumableInventory.update({
where: { id: itemId },
data: { currentStock: { decrement: shippedQuantity } },
})
// → Автоматически обновятся все связанные компоненты
POLLING ИНТЕРВАЛЫ
pollInterval: 30000 // 30 сек - для статистики и dashboard
pollInterval: 60000 // 1 мин - для списков и таблиц
pollInterval: 120000 // 2 мин - для отчётов и архивных данных
🚨 АНТИ-ПАТТЕРНЫ И ТИПИЧНЫЕ ОШИБКИ
❌ НИКОГДА НЕ ДЕЛАЙТЕ:
1. Разные источники для одних данных
// ❌ ПЛОХО
const stats = useQuery(GET_OLD_SUPPLIES) // legacy таблица
const details = useQuery(GET_NEW_SUPPLIES) // V2 таблица
2. Разные cache policies для связанных данных
// ❌ ПЛОХО
const master = useQuery(QUERY_A, { fetchPolicy: 'cache-and-network' })
const detail = useQuery(QUERY_B, {}) // default cache-first
3. Ручная синхронизация через состояние
// ❌ ПЛОХО
const [manualSync, setManualSync] = useState(0)
useEffect(() => {
// Попытка ручной синхронизации через state
}, [manualSync])
4. Группировка по нестабильным полям
// ❌ ПЛОХО - названия могут изменяться
supplies.filter((s) => s.name === targetName)
// ✅ ХОРОШО - ID стабильны
supplies.filter((s) => s.productId === targetProductId)
🎯 ЧЕКЛИСТ СИНХРОНИЗАЦИИ
При создании связанных компонентов:
- Используют одну таблицу БД как источник данных
- Одинаковые
fetchPolicy
настройки - Одинаковые
pollInterval
значения - Связь через стабильные ID поля
- Одинаковая логика агрегации/фильтрации
- Обработка ошибок и loading состояний
При тестировании синхронизации:
- Изменение данных обновляет все связанные компоненты
- Значения в master и detail компонентах совпадают
- Нет задержек между обновлениями (< 30 сек)
- Ошибки в одном компоненте не ломают другие
📈 МОНИТОРИНГ СИНХРОНИЗАЦИИ
DEBUG ЛОГИ
// Добавляйте логи для контроля синхронизации
console.warn('SYNC CHECK:', {
masterValue: masterData?.totalStock,
detailValue: detailData?.reduce(sum, 0),
timestamp: new Date().toISOString(),
source: 'fulfillmentInventorySync',
})
УВЕДОМЛЕНИЯ О РАССИНХРОНИЗАЦИИ
// Проверка консистентности данных
if (Math.abs(masterValue - detailValue) > 0) {
console.error('🚨 DATA SYNCHRONIZATION ERROR', {
master: masterValue,
detail: detailValue,
component: 'FulfillmentStats',
})
// Отправка уведомления разработчикам
toast.error('Обнаружена рассинхронизация данных')
}
Следование этим правилам обеспечит надёжную синхронизацию данных между всеми компонентами системы! 🚀