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>
This commit is contained in:
Veronika Smirnova
2025-08-27 12:29:00 +03:00
parent 2790fa9b98
commit 121a4dece1
4 changed files with 1763 additions and 0 deletions

View File

@ -0,0 +1,390 @@
# 🔄 ПРАВИЛА КЕШИРОВАНИЯ 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 данных!** 🚀