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