Files
sfera-new/docs/api-layer/GRAPHQL_CACHE_RULES.md
Veronika Smirnova 121a4dece1 docs: создать правила для синхронизации данных, layout и статистических компонентов
- 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>
2025-08-27 12:29:00 +03:00

391 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🔄 ПРАВИЛА КЕШИРОВАНИЯ GRAPHQL И FETCHPOLICY
> **Цель:** Обеспечить корректное кеширование GraphQL данных и предотвратить проблемы синхронизации между компонентами
## 📋 **ОСНОВНЫЕ ПРИНЦИПЫ КЕШИРОВАНИЯ**
### 1. **СИНХРОНИЗАЦИЯ СВЯЗАННЫХ КОМПОНЕНТОВ**
```typescript
// ✅ ПРАВИЛЬНО - одинаковые настройки для связанных данных
const masterComponent = useQuery(GET_WAREHOUSE_STATS, {
fetchPolicy: 'cache-and-network',
pollInterval: 30000,
errorPolicy: 'all',
})
const detailComponent = useQuery(GET_SUPPLIES_DETAILS, {
fetchPolicy: 'cache-and-network', // ← ОБЯЗАТЕЛЬНО то же самое!
pollInterval: 30000, // ← ОБЯЗАТЕЛЬНО то же самое!
errorPolicy: 'all', // ← ОБЯЗАТЕЛЬНО то же самое!
})
```
```typescript
// ❌ НЕПРАВИЛЬНО - разные настройки создают рассинхронизацию
const masterComponent = useQuery(GET_WAREHOUSE_STATS, {
fetchPolicy: 'cache-and-network',
})
const detailComponent = useQuery(GET_SUPPLIES_DETAILS, {
// default fetchPolicy: 'cache-first' - СОЗДАЁТ ПРОБЛЕМУ!
})
```
### 2. **ОБЯЗАТЕЛЬНЫЕ FETCH POLICIES ПО ТИПАМ КОМПОНЕНТОВ**
#### **Dashboard и Статистика**
```typescript
useQuery(DASHBOARD_QUERY, {
fetchPolicy: 'cache-and-network', // Всегда актуальные данные
pollInterval: 30000, // Обновление каждые 30 сек
errorPolicy: 'all', // Показывать частичные данные при ошибках
})
```
#### **Связанные компоненты (Master-Detail)**
```typescript
// Все компоненты одной функциональности ДОЛЖНЫ иметь идентичные настройки
const sharedQueryOptions = {
fetchPolicy: 'cache-and-network' as const,
pollInterval: 30000,
errorPolicy: 'all' as const,
}
// Применение во всех связанных компонентах
useQuery(MASTER_QUERY, sharedQueryOptions)
useQuery(DETAIL_QUERY, sharedQueryOptions)
useQuery(STATS_QUERY, sharedQueryOptions)
```
#### **Списки и таблицы**
```typescript
useQuery(LIST_QUERY, {
fetchPolicy: 'cache-and-network', // Актуальные данные
pollInterval: 60000, // 1 минута для списков
notifyOnNetworkStatusChange: true, // Показывать статус загрузки
})
```
#### **Редко изменяющиеся данные**
```typescript
useQuery(STATIC_DATA_QUERY, {
fetchPolicy: 'cache-first', // Кеш приоритетен
pollInterval: 300000, // 5 минут
errorPolicy: 'ignore', // Не показывать ошибки для статичных данных
})
```
---
## 🏢 **СПЕЦИФИЧЕСКИЕ ПРАВИЛА ДЛЯ ФУЛФИЛМЕНТА**
### **ГРУППЫ СИНХРОНИЗИРОВАННЫХ КОМПОНЕНТОВ**
#### **Группа 1: Складская статистика**
```typescript
// Все эти компоненты ДОЛЖНЫ использовать одинаковые настройки:
const warehouseStatsOptions = {
fetchPolicy: 'cache-and-network' as const,
pollInterval: 30000,
errorPolicy: 'all' as const,
}
// 1. Главный dashboard (/fulfillment-warehouse)
useQuery(GET_WAREHOUSE_STATS, warehouseStatsOptions)
// 2. Подраздел расходников (/fulfillment-warehouse/supplies)
useQuery(GET_SUPPLIES_STATS, warehouseStatsOptions)
// 3. Раздел услуг (/services) - вкладка "Расходники"
useQuery(GET_SERVICE_SUPPLIES, warehouseStatsOptions)
```
#### **Группа 2: История поставок**
```typescript
const suppliesHistoryOptions = {
fetchPolicy: 'cache-and-network' as const,
pollInterval: 30000,
errorPolicy: 'all' as const,
}
// 1. Основные поставки (главная таблица)
useQuery(GET_MY_FULFILLMENT_SUPPLIES, suppliesHistoryOptions)
// 2. Детали поставок (раскрывающиеся строки)
useQuery(GET_MY_FULFILLMENT_CONSUMABLE_SUPPLIES, suppliesHistoryOptions)
```
---
## 🚨 **КРИТИЧЕСКИЕ АНТИ-ПАТТЕРНЫ**
### **❌ НИКОГДА НЕ ДЕЛАЙТЕ:**
#### **1. Разные fetchPolicy для связанных данных**
```typescript
// ❌ СОЗДАЁТ РАССИНХРОНИЗАЦИЮ
const warehouse = useQuery(GET_WAREHOUSE, { fetchPolicy: 'cache-and-network' })
const supplies = useQuery(GET_SUPPLIES, {}) // default cache-first
// Результат: warehouse показывает новые данные, supplies - старые
```
#### **2. Разные pollInterval для одной функциональности**
```typescript
// ❌ СОЗДАЁТ НЕСОГЛАСОВАННОСТЬ
const stats = useQuery(GET_STATS, { pollInterval: 30000 })
const details = useQuery(GET_DETAILS, { pollInterval: 60000 })
// Результат: stats обновляется чаще details - значения не совпадают
```
#### **3. Смешивание cache-first и cache-and-network**
```typescript
// ❌ КЛАССИЧЕСКАЯ ОШИБКА
const mainData = useQuery(MAIN_QUERY, { fetchPolicy: 'cache-and-network' })
const relatedData = useQuery(RELATED_QUERY, { fetchPolicy: 'cache-first' })
// Результат: mainData актуальные, relatedData устаревшие
```
#### **4. Игнорирование ошибок в критических компонентах**
```typescript
// ❌ СКРЫВАЕТ ПРОБЛЕМЫ
useQuery(CRITICAL_DATA_QUERY, {
errorPolicy: 'ignore', // Не показывает ошибки когда нужно!
})
```
---
## 📊 **ПРАВИЛА ПО ТИПАМ ДАННЫХ**
### **СТАТИСТИКА И DASHBOARD**
```typescript
const dashboardOptions = {
fetchPolicy: 'cache-and-network', // Всегда актуальные данные
pollInterval: 30000, // 30 сек - критическая актуальность
errorPolicy: 'all', // Показывать частичные данные
notifyOnNetworkStatusChange: true, // Показывать индикатор обновления
}
```
### **ИНВЕНТАРЬ И ОСТАТКИ**
```typescript
const inventoryOptions = {
fetchPolicy: 'cache-and-network', // Остатки должны быть точными
pollInterval: 30000, // Частое обновление
errorPolicy: 'all', // Критические данные
}
```
### **ИСТОРИЯ И ЛОГИ**
```typescript
const historyOptions = {
fetchPolicy: 'cache-first', // История не меняется часто
pollInterval: 120000, // 2 минуты достаточно
errorPolicy: 'all', // Показывать что есть
}
```
### **СПРАВОЧНИКИ И КАТАЛОГИ**
```typescript
const catalogOptions = {
fetchPolicy: 'cache-first', // Справочники стабильны
pollInterval: 300000, // 5 минут
errorPolicy: 'ignore', // Не критично
}
```
---
## 🔧 **ПРАКТИЧЕСКИЕ ПРИМЕРЫ ИСПРАВЛЕНИЙ**
### **ПРИМЕР 1: Рассинхронизация карточек статистики**
**❌ Проблема:**
```typescript
// Главный dashboard
const warehouseStats = useQuery(GET_WAREHOUSE_STATS, {
fetchPolicy: 'cache-and-network',
})
// Подраздел supplies
const suppliesStats = useQuery(GET_SUPPLIES_STATS, {
// default fetchPolicy: 'cache-first' - ПРОБЛЕМА!
})
// Результат: карточка "РАСХОДНИКИ ФУЛФИЛМЕНТА" = 130, карточка "ОСТАТОК" = 160
```
**✅ Решение:**
```typescript
// Общие настройки для всех статистических компонентов
const statsOptions = {
fetchPolicy: 'cache-and-network' as const,
pollInterval: 30000,
errorPolicy: 'all' as const,
}
// Применяем везде одинаково
const warehouseStats = useQuery(GET_WAREHOUSE_STATS, statsOptions)
const suppliesStats = useQuery(GET_SUPPLIES_STATS, statsOptions)
```
### **ПРИМЕР 2: История поставок не синхронизируется с основной таблицей**
**❌ Проблема:**
```typescript
// Основная таблица
const supplies = useQuery(GET_SUPPLIES, { fetchPolicy: 'cache-and-network' })
// История в раскрывающихся строках
const history = useQuery(GET_SUPPLY_HISTORY, {}) // default cache-first
// Результат: основная таблица обновилась, история показывает старые данные
```
**✅ Решение:**
```typescript
const syncedOptions = {
fetchPolicy: 'cache-and-network',
pollInterval: 30000,
}
const supplies = useQuery(GET_SUPPLIES, syncedOptions)
const history = useQuery(GET_SUPPLY_HISTORY, syncedOptions)
```
---
## 🎯 **ЧЕКЛИСТ НАСТРОЙКИ КЕШИРОВАНИЯ**
### **Перед релизом компонента:**
- [ ] Определили группу связанных компонентов
- [ ] Выбрали единую fetchPolicy для группы
- [ ] Установили одинаковые pollInterval значения
- [ ] Настроили errorPolicy в соответствии с критичностью
- [ ] Протестировали синхронизацию данных
### **При обнаружении рассинхронизации:**
- [ ] Проверили fetchPolicy всех связанных запросов
- [ ] Сравнили pollInterval значения
- [ ] Убедились в использовании одних таблиц БД
- [ ] Проверили последовательность обновления данных
---
## 📈 **МОНИТОРИНГ И ОТЛАДКА**
### **DEBUG ЛОГИ ДЛЯ КЕШИРОВАНИЯ**
```typescript
// Добавляйте в компоненты для контроля кеширования
useQuery(QUERY, {
fetchPolicy: 'cache-and-network',
onCompleted: (data) => {
console.log('CACHE DEBUG:', {
query: 'QUERY_NAME',
timestamp: new Date().toISOString(),
dataLength: data?.items?.length,
source: 'network/cache',
})
},
onError: (error) => {
console.error('CACHE ERROR:', {
query: 'QUERY_NAME',
error: error.message,
networkError: error.networkError?.message,
})
},
})
```
### **ПРОВЕРКА СИНХРОНИЗАЦИИ**
```typescript
// Контрольные точки для проверки консистентности
useEffect(() => {
if (masterData && detailData) {
const masterValue = masterData.total
const detailValue = detailData.reduce((sum, item) => sum + item.value, 0)
if (Math.abs(masterValue - detailValue) > 0) {
console.error('🚨 CACHE SYNC ERROR:', {
component: 'ComponentName',
master: masterValue,
detail: detailValue,
diff: masterValue - detailValue,
})
}
}
}, [masterData, detailData])
```
---
## 🚀 **РЕКОМЕНДАЦИИ ПО ПРОИЗВОДИТЕЛЬНОСТИ**
### **ОПТИМИЗАЦИЯ POLLING**
```typescript
// Адаптивные интервалы в зависимости от активности пользователя
const useAdaptivePolling = () => {
const [isActive, setIsActive] = useState(true)
useEffect(() => {
const handleVisibilityChange = () => {
setIsActive(!document.hidden)
}
document.addEventListener('visibilitychange', handleVisibilityChange)
return () => document.removeEventListener('visibilitychange', handleVisibilityChange)
}, [])
return {
pollInterval: isActive ? 30000 : 120000, // Реже обновляем неактивные вкладки
}
}
```
### **УСЛОВНОЕ КЕШИРОВАНИЕ**
```typescript
// Разные стратегии для разных сценариев
const getCachePolicy = (dataType: string) => {
switch (dataType) {
case 'critical-stats':
return { fetchPolicy: 'cache-and-network', pollInterval: 30000 }
case 'user-lists':
return { fetchPolicy: 'cache-and-network', pollInterval: 60000 }
case 'reference-data':
return { fetchPolicy: 'cache-first', pollInterval: 300000 }
default:
return { fetchPolicy: 'cache-first' }
}
}
```
**Следование этим правилам обеспечит стабильное кеширование и синхронизацию GraphQL данных!** 🚀