diff --git a/docs/api-layer/GRAPHQL_CACHE_RULES.md b/docs/api-layer/GRAPHQL_CACHE_RULES.md
new file mode 100644
index 0000000..cbc82f3
--- /dev/null
+++ b/docs/api-layer/GRAPHQL_CACHE_RULES.md
@@ -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 данных!** 🚀
diff --git a/docs/presentation-layer/CSS_LAYOUT_SCROLL_RULES.md b/docs/presentation-layer/CSS_LAYOUT_SCROLL_RULES.md
new file mode 100644
index 0000000..3ad6112
--- /dev/null
+++ b/docs/presentation-layer/CSS_LAYOUT_SCROLL_RULES.md
@@ -0,0 +1,489 @@
+# 🎨 ПРАВИЛА CSS LAYOUT И СКРОЛЛА
+
+> **Цель:** Предотвратить проблемы с overflow, scroll и позиционированием в Next.js 15 + React 19 приложении
+
+## 📋 **ОСНОВНЫЕ ПРИНЦИПЫ LAYOUT**
+
+### 1. **БАЗОВАЯ АРХИТЕКТУРА LAYOUT**
+
+```typescript
+// ✅ ПРАВИЛЬНАЯ структура для всех страниц приложения
+
{/* Контейнер полной высоты */}
+
{/* Фиксированная боковая панель */}
+
+ {/* ЕДИНСТВЕННАЯ зона скролла */}
+ {/* Весь контент здесь */}
+
+
+
+```
+
+### 2. **КРИТИЧЕСКИЕ ПРАВИЛА OVERFLOW**
+
+#### **✅ ПРАВИЛЬНО: Один уровень overflow**
+
+```css
+/* Родительский контейнер */
+.container {
+ height: 100vh;
+ overflow: hidden; /* Запрещаем скролл на уровне экрана */
+}
+
+/* Дочерний скроллируемый контейнер */
+.scrollable-content {
+ flex: 1;
+ overflow-y: auto; /* ЕДИНСТВЕННАЯ зона скролла */
+}
+```
+
+#### **❌ НЕПРАВИЛЬНО: Множественные overflow зоны**
+
+```css
+/* Создаёт конфликты скролла */
+.parent {
+ overflow-y: auto; /* Первый скролл */
+}
+.child {
+ overflow-y: auto; /* Второй скролл - ПРОБЛЕМА! */
+}
+```
+
+---
+
+## 🚨 **ТИПИЧНЫЕ ПРОБЛЕМЫ И РЕШЕНИЯ**
+
+### **ПРОБЛЕМА 1: Контент смещается вправо**
+
+**❌ Причина:**
+
+```jsx
+
+ {' '}
+ {/* Принудительная высота */}
+
+ {' '}
+ {/* Скрывает контент */}
+ {/* Контент не помещается и смещается */}
+
+
+```
+
+**✅ Решение:**
+
+```jsx
+
+ {' '}
+ {/* Простая вертикальная компоновка */}
+ {/* Контент автоматически размещается правильно */}
+
+```
+
+### **ПРОБЛЕМА 2: Скролл не работает**
+
+**❌ Причина:**
+
+```jsx
+
+ {' '}
+ {/* Блокирует скролл */}
+
+ {' '}
+ {/* Дублирует блокировку */}
+
+ {' '}
+ {/* Создаёт контент больше экрана */}
+ {/* Контент не скроллится */}
+
+
+
+```
+
+**✅ Решение:**
+
+```jsx
+
+
+ {' '}
+ {/* ЕДИНСТВЕННАЯ зона скролла */}
+ {/* Контент свободно скроллится */}
+
+
+```
+
+### **ПРОБЛЕМА 3: Двойной sidebar в layout**
+
+**❌ Причина:**
+
+```jsx
+// В page.tsx
+
+
{/* Первый sidebar */}
+
+
+ {/* Второй sidebar - ДУБЛИРОВАНИЕ! */}
+
+
+
+
+```
+
+**✅ Решение:**
+
+```jsx
+// В page.tsx - УБРАТЬ дублирование
+
+
{/* ЕДИНСТВЕННЫЙ sidebar */}
+
+ {/* Весь контент */}
+
+
+```
+
+---
+
+## 🏗️ **АРХИТЕКТУРНЫЕ ПАТТЕРНЫ**
+
+### **ПАТТЕРН 1: Dashboard с статистикой**
+
+```jsx
+export function DashboardPage() {
+ return (
+
+
+
+
+ {/* Заголовок */}
+
+
+ {/* Статистические карточки */}
+
+
+ {/* Основное содержимое */}
+
+
+
+
+ )
+}
+```
+
+### **ПАТТЕРН 2: Таблица с фильтрами**
+
+```jsx
+export function TablePage() {
+ return (
+
+
+
+
+ {/* Фильтры (фиксированные) */}
+
+
+ {/* Таблица (скроллируемая) */}
+
+
+
+
+
+
+ )
+}
+```
+
+### **ПАТТЕРН 3: Модальные окна**
+
+```jsx
+// ✅ Модалки не должны влиять на основной скролл
+
+```
+
+---
+
+## 📱 **RESPONSIVE DESIGN ПРАВИЛА**
+
+### **АДАПТИВНЫЕ КОНТЕЙНЕРЫ**
+
+```jsx
+
+ {/* Карточки адаптивно размещаются */}
+
+```
+
+### **АДАПТИВНЫЕ ОТСТУПЫ**
+
+```jsx
+
+```
+
+---
+
+## 🎯 **СПЕЦИФИЧЕСКИЕ ПРАВИЛА ДЛЯ SFERA**
+
+### **ПРАВИЛА ДЛЯ ФУЛФИЛМЕНТ КОМПОНЕНТОВ**
+
+#### **1. Главная страница склада**
+
+```jsx
+// src/app/fulfillment-warehouse/page.tsx
+
+
+
+
+
+ {/* Статистика - НЕ скроллится */}
+ {/* Контент - скроллится */}
+
+
+
+```
+
+#### **2. Таблицы поставок**
+
+```jsx
+// src/components/fulfillment-warehouse/fulfillment-supplies-page.tsx
+
+
+
+
+ {' '}
+ {/* ← КЛЮЧЕВОЙ ЭЛЕМЕНТ */}
+ {/* Фильтры */}
+ {/* Статистика */}
+ {/* Основная таблица - скроллируется естественно */}
+
+
+
+```
+
+#### **3. Раскрывающиеся детали (Master-Detail)**
+
+```jsx
+// Детали поставок в раскрывающихся строках
+
+
+
+ {' '}
+ {/* Локальный скролл */}
+
+
+ |
+
+```
+
+---
+
+## ⚡ **ПРОИЗВОДИТЕЛЬНОСТЬ И ОПТИМИЗАЦИЯ**
+
+### **ВИРТУАЛИЗАЦИЯ ДЛЯ БОЛЬШИХ СПИСКОВ**
+
+```jsx
+// Для таблиц с >100 строк
+import { FixedSizeList as List } from 'react-window'
+
+;
+ {' '}
+ {/* Контейнер фиксированной высоты */}
+
+ {({ index, style }) => (
+
+ )}
+
+
+```
+
+### **LAZY LOADING ДЛЯ КОНТЕНТА**
+
+```jsx
+const LazyTableSection = lazy(() => import('./TableSection'))
+
+// В компоненте
+
+ {/* Загружается сразу */}
+ Загрузка...
}>
+ {/* Загружается по требованию */}
+
+
+```
+
+---
+
+## 🚨 **АНТИ-ПАТТЕРНЫ И ЗАПРЕТЫ**
+
+### **❌ НИКОГДА НЕ ДЕЛАЙТЕ:**
+
+#### **1. Принудительные размеры**
+
+```jsx
+// ❌ Создаёт проблемы с layout
+
+
+```
+
+#### **2. Множественные overflow зоны**
+
+```jsx
+// ❌ Конфликты скролла
+
+
+
+```
+
+#### **3. Смешивание fixed и sticky позиционирования**
+
+```jsx
+// ❌ Непредсказуемое поведение
+
+
+```
+
+#### **4. Игнорирование responsive дизайна**
+
+```jsx
+// ❌ Не адаптируется к мобильным устройствам
+
{/* Сломается на мобильных */}
+```
+
+---
+
+## 🔧 **ИНСТРУМЕНТЫ ОТЛАДКИ**
+
+### **CSS DEBUG КЛАССЫ**
+
+```css
+/* Добавьте для визуализации проблем */
+.debug-borders * {
+ border: 1px solid red !important;
+}
+
+.debug-overflow {
+ overflow: visible !important;
+ background: rgba(255, 0, 0, 0.1) !important;
+}
+
+.debug-scroll {
+ scrollbar-color: red transparent !important;
+ scrollbar-width: thick !important;
+}
+```
+
+### **REACT DevTools**
+
+```jsx
+// Добавьте data-атрибуты для отладки
+
+```
+
+### **КОНСОЛЬНЫЕ ЛОГИ ДЛЯ РАЗМЕРОВ**
+
+```jsx
+useEffect(() => {
+ const element = ref.current
+ if (element) {
+ console.log('LAYOUT DEBUG:', {
+ scrollHeight: element.scrollHeight,
+ clientHeight: element.clientHeight,
+ offsetHeight: element.offsetHeight,
+ hasOverflow: element.scrollHeight > element.clientHeight,
+ })
+ }
+}, [])
+```
+
+---
+
+## 📊 **ЧЕКЛИСТ ПРОВЕРКИ LAYOUT**
+
+### **Перед релизом:**
+
+- [ ] Единственная зона скролла на странице
+- [ ] Нет принудительных высот (`minHeight: '200vh'`)
+- [ ] Правильная структура с `h-screen` и `overflow-hidden`
+- [ ] Responsive дизайн для мобильных устройств
+- [ ] Sidebar не дублируется в компонентах
+- [ ] Модальные окна не влияют на основной скролл
+
+### **При проблемах со скроллом:**
+
+- [ ] Проверить количество `overflow-y-auto` в иерархии
+- [ ] Убедиться в отсутствии `overflow-hidden` на скроллируемом контейнере
+- [ ] Проверить наличие `flex-1` у родительского контейнера
+- [ ] Убрать принудительные размеры (`min-height`, `height: 200vh`)
+
+---
+
+## 🎨 **КАСТОМНЫЕ СКРОЛЛБАРЫ**
+
+### **TAILWIND CLASSES**
+
+```jsx
+
+```
+
+### **CUSTOM CSS**
+
+```css
+/* Кастомные скроллбары для SFERA */
+.custom-scrollbar::-webkit-scrollbar {
+ width: 8px;
+}
+
+.custom-scrollbar::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+.custom-scrollbar::-webkit-scrollbar-thumb {
+ background: rgba(255, 255, 255, 0.2);
+ border-radius: 4px;
+}
+
+.custom-scrollbar::-webkit-scrollbar-thumb:hover {
+ background: rgba(255, 255, 255, 0.3);
+}
+```
+
+**Следование этим правилам обеспечит корректную работу layout и скролла во всех компонентах!** 🚀
diff --git a/docs/presentation-layer/DATA_SYNCHRONIZATION_RULES.md b/docs/presentation-layer/DATA_SYNCHRONIZATION_RULES.md
new file mode 100644
index 0000000..015ee46
--- /dev/null
+++ b/docs/presentation-layer/DATA_SYNCHRONIZATION_RULES.md
@@ -0,0 +1,286 @@
+# 🔄 ПРАВИЛА СИНХРОНИЗАЦИИ ДАННЫХ МЕЖДУ КОМПОНЕНТАМИ
+
+> **Цель:** Обеспечить консистентность данных между различными компонентами системы SFERA
+
+## 📋 **ОСНОВНЫЕ ПРИНЦИПЫ**
+
+### 1. **ЕДИНЫЙ ИСТОЧНИК ИСТИНЫ (Single Source of Truth)**
+
+- ✅ **Один резолвер = одна таблица БД** для одного типа данных
+- ✅ **V2 система** - приоритет над legacy кодом
+- ❌ **Никогда не дублируйте** одни данные в разных резолверах
+
+### 2. **КОНСИСТЕНТНАЯ CACHE POLICY**
+
+```typescript
+// ✅ ПРАВИЛЬНО - одинаковая 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**
+
+#### **Для связанных компонентов:**
+
+```typescript
+fetchPolicy: 'cache-and-network', // Всегда актуальные данные
+pollInterval: 30000, // Автообновление каждые 30 сек
+```
+
+#### **Для dashboard/статистики:**
+
+```typescript
+fetchPolicy: 'cache-and-network', // Синхронизация с основными данными
+pollInterval: 30000, // Регулярное обновление
+errorPolicy: 'all', // Показывать частичные данные при ошибках
+```
+
+---
+
+## 🏢 **ПРАВИЛА ДЛЯ ФУЛФИЛМЕНТА**
+
+### **ТАБЛИЦЫ V2 СИСТЕМЫ**
+
+- **`fulfillmentConsumableInventory`** - складские остатки расходников
+- **`fulfillmentConsumableSupplyOrder`** - поставки расходников
+- **`fulfillmentInventoryV2`** - общий инвентарь фулфилмента
+
+### **СВЯЗАННЫЕ КОМПОНЕНТЫ**
+
+```typescript
+// Все эти компоненты должны использовать одинаковые данные:
+
+1. Главный dashboard склада (/fulfillment-warehouse)
+ - Карточка "РАСХОДНИКИ ФУЛФИЛМЕНТА"
+
+2. Подраздел расходников (/fulfillment-warehouse/supplies)
+ - Карточка "ОСТАТОК"
+ - Главная таблица поставок
+
+3. Раздел услуг (/services)
+ - Вкладка "Расходники"
+
+4. История поставок
+ - Раскрывающиеся детали каждого товара
+```
+
+### **СИНХРОНИЗИРОВАННЫЕ ПОЛЯ**
+
+```typescript
+interface SynchronizedData {
+ currentStock: number // Текущий остаток (одинаковый везде)
+ totalReceived: number // Общее количество поступлений
+ productId: string // ID для группировки истории поставок
+ fulfillmentCenterId: string // ID фулфилмент-центра
+}
+```
+
+---
+
+## 📊 **ПРАВИЛА ДЛЯ СТАТИСТИЧЕСКИХ КОМПОНЕНТОВ**
+
+### **1. АРХИТЕКТУРА MASTER-DETAIL**
+
+```typescript
+// 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. ПРАВИЛА АГРЕГАЦИИ**
+
+```typescript
+// ✅ ПРАВИЛЬНО - агрегация из одного источника данных
+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
+```
+
+---
+
+## 🔗 **ПРАВИЛА СВЯЗЫВАНИЯ ДАННЫХ**
+
+### **ОБЯЗАТЕЛЬНЫЕ ПОЛЯ ДЛЯ СВЯЗИ**
+
+```typescript
+// В 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! // ← Для подсчёта остатков
+}
+```
+
+### **ФИЛЬТРАЦИЯ ПО СВЯЗАННЫМ ДАННЫМ**
+
+```typescript
+// ✅ ПРАВИЛЬНО - фильтрация по 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 ОБНОВЛЕНИЙ**
+
+### **АВТОМАТИЧЕСКАЯ СИНХРОНИЗАЦИЯ**
+
+```typescript
+// Компоненты должны обновляться автоматически при изменениях
+
+// 1. При приёме поставки на склад
+prisma.fulfillmentConsumableInventory.update({
+ where: { id: itemId },
+ data: { currentStock: newStock },
+})
+// → Автоматически обновятся: статистика, таблица, услуги
+
+// 2. При отгрузке товаров
+prisma.fulfillmentConsumableInventory.update({
+ where: { id: itemId },
+ data: { currentStock: { decrement: shippedQuantity } },
+})
+// → Автоматически обновятся все связанные компоненты
+```
+
+### **POLLING ИНТЕРВАЛЫ**
+
+```typescript
+pollInterval: 30000 // 30 сек - для статистики и dashboard
+pollInterval: 60000 // 1 мин - для списков и таблиц
+pollInterval: 120000 // 2 мин - для отчётов и архивных данных
+```
+
+---
+
+## 🚨 **АНТИ-ПАТТЕРНЫ И ТИПИЧНЫЕ ОШИБКИ**
+
+### **❌ НИКОГДА НЕ ДЕЛАЙТЕ:**
+
+#### **1. Разные источники для одних данных**
+
+```typescript
+// ❌ ПЛОХО
+const stats = useQuery(GET_OLD_SUPPLIES) // legacy таблица
+const details = useQuery(GET_NEW_SUPPLIES) // V2 таблица
+```
+
+#### **2. Разные cache policies для связанных данных**
+
+```typescript
+// ❌ ПЛОХО
+const master = useQuery(QUERY_A, { fetchPolicy: 'cache-and-network' })
+const detail = useQuery(QUERY_B, {}) // default cache-first
+```
+
+#### **3. Ручная синхронизация через состояние**
+
+```typescript
+// ❌ ПЛОХО
+const [manualSync, setManualSync] = useState(0)
+useEffect(() => {
+ // Попытка ручной синхронизации через state
+}, [manualSync])
+```
+
+#### **4. Группировка по нестабильным полям**
+
+```typescript
+// ❌ ПЛОХО - названия могут изменяться
+supplies.filter((s) => s.name === targetName)
+
+// ✅ ХОРОШО - ID стабильны
+supplies.filter((s) => s.productId === targetProductId)
+```
+
+---
+
+## 🎯 **ЧЕКЛИСТ СИНХРОНИЗАЦИИ**
+
+### **При создании связанных компонентов:**
+
+- [ ] Используют одну таблицу БД как источник данных
+- [ ] Одинаковые `fetchPolicy` настройки
+- [ ] Одинаковые `pollInterval` значения
+- [ ] Связь через стабильные ID поля
+- [ ] Одинаковая логика агрегации/фильтрации
+- [ ] Обработка ошибок и loading состояний
+
+### **При тестировании синхронизации:**
+
+- [ ] Изменение данных обновляет все связанные компоненты
+- [ ] Значения в master и detail компонентах совпадают
+- [ ] Нет задержек между обновлениями (< 30 сек)
+- [ ] Ошибки в одном компоненте не ломают другие
+
+---
+
+## 📈 **МОНИТОРИНГ СИНХРОНИЗАЦИИ**
+
+### **DEBUG ЛОГИ**
+
+```typescript
+// Добавляйте логи для контроля синхронизации
+console.warn('SYNC CHECK:', {
+ masterValue: masterData?.totalStock,
+ detailValue: detailData?.reduce(sum, 0),
+ timestamp: new Date().toISOString(),
+ source: 'fulfillmentInventorySync',
+})
+```
+
+### **УВЕДОМЛЕНИЯ О РАССИНХРОНИЗАЦИИ**
+
+```typescript
+// Проверка консистентности данных
+if (Math.abs(masterValue - detailValue) > 0) {
+ console.error('🚨 DATA SYNCHRONIZATION ERROR', {
+ master: masterValue,
+ detail: detailValue,
+ component: 'FulfillmentStats',
+ })
+
+ // Отправка уведомления разработчикам
+ toast.error('Обнаружена рассинхронизация данных')
+}
+```
+
+**Следование этим правилам обеспечит надёжную синхронизацию данных между всеми компонентами системы!** 🚀
diff --git a/docs/presentation-layer/STATISTICAL_COMPONENTS_RULES.md b/docs/presentation-layer/STATISTICAL_COMPONENTS_RULES.md
new file mode 100644
index 0000000..d30a220
--- /dev/null
+++ b/docs/presentation-layer/STATISTICAL_COMPONENTS_RULES.md
@@ -0,0 +1,598 @@
+# 📊 ПРАВИЛА СТАТИСТИЧЕСКИХ КОМПОНЕНТОВ
+
+> **Цель:** Обеспечить корректную работу, синхронизацию и консистентность статистических компонентов в системе SFERA
+
+## 📋 **ОСНОВНЫЕ ПРИНЦИПЫ СТАТИСТИЧЕСКИХ КОМПОНЕНТОВ**
+
+### 1. **АРХИТЕКТУРА MASTER-DETAIL**
+
+```typescript
+// ✅ ПРАВИЛЬНАЯ архитектура связанных статистических компонентов
+interface StatisticsHierarchy {
+ masterComponent: {
+ location: '/fulfillment-warehouse'
+ cards: ['РАСХОДНИКИ ФУЛФИЛМЕНТА', 'ТОВАРЫ СЕЛЛЕРОВ', ...]
+ role: 'Обзор всего склада'
+ }
+
+ detailComponent: {
+ location: '/fulfillment-warehouse/supplies'
+ cards: ['ВСЕГО ПОЗИЦИЙ', 'ДОСТУПНО', 'ОСТАТОК', 'НЕТ В НАЛИЧИИ', ...]
+ role: 'Детализация расходников'
+ }
+
+ // ОБЯЗАТЕЛЬНО: masterComponent.cards[X] === sum(detailComponent.items)
+ consistency: 'Значения master должны равняться агрегации detail'
+}
+```
+
+### 2. **ЕДИНЫЕ ИСТОЧНИКИ ДАННЫХ**
+
+```typescript
+// ✅ ПРАВИЛЬНО - один источник данных для связанных статистик
+const warehouseQuery = useQuery(GET_WAREHOUSE_STATS, {
+ fetchPolicy: 'cache-and-network',
+ pollInterval: 30000,
+})
+
+const suppliesQuery = useQuery(GET_SUPPLIES_STATS, {
+ fetchPolicy: 'cache-and-network', // ← ОБЯЗАТЕЛЬНО то же самое!
+ pollInterval: 30000, // ← ОБЯЗАТЕЛЬНО то же самое!
+})
+
+// ОБЯЗАТЕЛЬНАЯ проверка консистентности
+useEffect(() => {
+ const masterValue = warehouseQuery.data?.fulfillmentSupplies?.current
+ const detailValue = suppliesQuery.data?.supplies?.reduce((sum, s) => sum + s.currentStock, 0)
+
+ if (masterValue !== detailValue) {
+ console.error('🚨 STATISTICS SYNC ERROR:', { masterValue, detailValue })
+ }
+}, [warehouseQuery.data, suppliesQuery.data])
+```
+
+---
+
+## 🎯 **ТИПЫ СТАТИСТИЧЕСКИХ КАРТОЧЕК**
+
+### **ТИП 1: Счётчики (Counters)**
+
+```jsx
+// Подсчёт количества элементов
+;
+
+// Логика расчёта
+const totalItems = supplies.length
+const availableItems = supplies.filter((s) => s.currentStock > 0).length
+const outOfStockItems = supplies.filter((s) => s.currentStock === 0).length
+```
+
+### **ТИП 2: Агрегаторы (Aggregators)**
+
+```jsx
+// Суммирование значений
+;
sum + s.currentStock, 0)}
+ unit="шт"
+ icon={Package}
+ color="blue"
+ format="number"
+/>
+
+// Логика расчёта
+const totalStock = supplies.reduce((sum, supply) => sum + supply.currentStock, 0)
+const totalValue = supplies.reduce((sum, supply) => sum + supply.price * supply.currentStock, 0)
+```
+
+### **ТИП 3: Индикаторы состояния (Status Indicators)**
+
+```jsx
+// Показатели состояния системы
+
+```
+
+### **ТИП 4: Финансовые показатели (Financial)**
+
+```jsx
+// Денежные значения
+
+```
+
+---
+
+## 🏢 **СПЕЦИФИЧЕСКИЕ ПРАВИЛА ДЛЯ ФУЛФИЛМЕНТА**
+
+### **КАРТОЧКИ ГЛАВНОГО DASHBOARD (/fulfillment-warehouse)**
+
+```typescript
+interface WarehouseMasterStats {
+ 'РАСХОДНИКИ ФУЛФИЛМЕНТА': {
+ source: 'fulfillmentConsumableInventory'
+ calculation: 'SUM(currentStock)'
+ syncWith: '/fulfillment-warehouse/supplies - карточка ОСТАТОК'
+ }
+
+ 'ТОВАРЫ СЕЛЛЕРОВ': {
+ source: 'sellerInventoryOnWarehouse'
+ calculation: 'SUM(currentStock)'
+ syncWith: 'Таблица товаров селлеров'
+ }
+
+ 'АКТИВНЫЕ ЗАКАЗЫ': {
+ source: 'supplyOrders'
+ calculation: 'COUNT where status IN [PENDING, SHIPPED]'
+ syncWith: 'Раздел входящих заказов'
+ }
+}
+```
+
+### **КАРТОЧКИ ПОДРАЗДЕЛА РАСХОДНИКОВ (/fulfillment-warehouse/supplies)**
+
+```typescript
+interface SuppliesDetailStats {
+ 'ВСЕГО ПОЗИЦИЙ': {
+ calculation: 'COUNT(DISTINCT productId)'
+ description: 'Количество уникальных товаров'
+ }
+
+ ДОСТУПНО: {
+ calculation: 'COUNT WHERE currentStock > 0'
+ description: 'Товары в наличии'
+ }
+
+ ОСТАТОК: {
+ calculation: 'SUM(currentStock)'
+ description: 'Общее количество единиц товара'
+ syncWith: 'Master: РАСХОДНИКИ ФУЛФИЛМЕНТА' // ← КРИТИЧЕСКАЯ СИНХРОНИЗАЦИЯ
+ }
+
+ 'НЕТ В НАЛИЧИИ': {
+ calculation: 'COUNT WHERE currentStock = 0'
+ description: 'Товары с нулевыми остатками'
+ }
+
+ 'ОБЩАЯ СТОИМОСТЬ': {
+ calculation: 'SUM(price * currentStock)'
+ format: 'currency'
+ }
+
+ 'В ПУТИ': {
+ calculation: 'COUNT WHERE status = "shipped"'
+ description: 'Товары в транспортировке'
+ }
+}
+```
+
+---
+
+## 🔄 **ПРАВИЛА СИНХРОНИЗАЦИИ СТАТИСТИК**
+
+### **1. ОБЯЗАТЕЛЬНАЯ КОНСИСТЕНТНОСТЬ MASTER-DETAIL**
+
+```typescript
+// ✅ ПРАВИЛЬНАЯ реализация проверки синхронизации
+const validateStatisticsConsistency = (masterData: any, detailData: any[]) => {
+ const masterValue = masterData?.fulfillmentSupplies?.current || 0
+ const detailValue = detailData.reduce((sum, item) => sum + item.currentStock, 0)
+
+ const tolerance = 0 // Для inventory данных - точное соответствие!
+ const isConsistent = Math.abs(masterValue - detailValue) <= tolerance
+
+ if (!isConsistent) {
+ console.error('🚨 CRITICAL STATISTICS INCONSISTENCY:', {
+ component: 'FulfillmentStatistics',
+ masterValue,
+ detailValue,
+ difference: masterValue - detailValue,
+ timestamp: new Date().toISOString(),
+ requiresAttention: true,
+ })
+
+ // Уведомление пользователя о проблеме
+ toast.error('Обнаружена несогласованность данных статистики')
+
+ // Попытка принудительного обновления
+ refetchMasterData()
+ refetchDetailData()
+ }
+
+ return isConsistent
+}
+
+// Использование в компонентах
+useEffect(() => {
+ validateStatisticsConsistency(warehouseMasterData, suppliesDetailData)
+}, [warehouseMasterData, suppliesDetailData])
+```
+
+### **2. АВТОМАТИЧЕСКОЕ ОБНОВЛЕНИЕ СВЯЗАННЫХ СТАТИСТИК**
+
+```typescript
+// При изменении данных - все связанные статистики обновляются
+const handleInventoryUpdate = async (inventoryChange: InventoryChange) => {
+ // 1. Обновляем основные данные
+ await updateInventoryRecord(inventoryChange)
+
+ // 2. Принудительное обновление всех связанных статистик
+ await Promise.all([
+ refetchWarehouseStats(), // Master dashboard
+ refetchSuppliesStats(), // Detail dashboard
+ refetchServiceStats(), // Services section
+ ])
+
+ // 3. Проверяем консистентность после обновления
+ setTimeout(() => validateStatisticsConsistency(), 1000)
+}
+```
+
+---
+
+## 🎨 **ДИЗАЙН И UI ПРАВИЛА**
+
+### **СТАНДАРТНАЯ СТРУКТУРА КАРТОЧКИ**
+
+```jsx
+
+
+
+ {/* Основная информация */}
+
{title}
+
+ {formattedValue} {unit && {unit}}
+
+
+ {/* Дополнительная информация */}
+ {subtitle &&
{subtitle}
}
+
+
+ {/* Иконка */}
+
+
+
+
+
+```
+
+### **ЦВЕТОВЫЕ СХЕМЫ ПО ТИПАМ**
+
+```typescript
+const StatCardColors = {
+ // Позитивные показатели (наличие, доступность)
+ positive: {
+ background: 'bg-green-500/20',
+ text: 'text-green-300',
+ icon: 'text-green-300',
+ },
+
+ // Нейтральные показатели (общие счётчики)
+ neutral: {
+ background: 'bg-blue-500/20',
+ text: 'text-blue-300',
+ icon: 'text-blue-300',
+ },
+
+ // Внимание требующие (мало на складе)
+ warning: {
+ background: 'bg-yellow-500/20',
+ text: 'text-yellow-300',
+ icon: 'text-yellow-300',
+ },
+
+ // Негативные показатели (отсутствие, проблемы)
+ negative: {
+ background: 'bg-red-500/20',
+ text: 'text-red-300',
+ icon: 'text-red-300',
+ },
+
+ // Финансовые показатели
+ financial: {
+ background: 'bg-purple-500/20',
+ text: 'text-purple-300',
+ icon: 'text-purple-300',
+ },
+
+ // Процессы и активность
+ process: {
+ background: 'bg-orange-500/20',
+ text: 'text-orange-300',
+ icon: 'text-orange-300',
+ },
+}
+```
+
+---
+
+## 📈 **ФОРМАТИРОВАНИЕ ДАННЫХ**
+
+### **ЧИСЛОВЫЕ ФОРМАТЫ**
+
+```typescript
+const formatStatValue = (value: number, type: StatType) => {
+ switch (type) {
+ case 'currency':
+ return new Intl.NumberFormat('ru-RU', {
+ style: 'currency',
+ currency: 'RUB',
+ minimumFractionDigits: 0,
+ }).format(value)
+
+ case 'number':
+ return new Intl.NumberFormat('ru-RU').format(value)
+
+ case 'percentage':
+ return new Intl.NumberFormat('ru-RU', {
+ style: 'percent',
+ minimumFractionDigits: 1,
+ }).format(value / 100)
+
+ case 'compact':
+ return new Intl.NumberFormat('ru-RU', {
+ notation: 'compact',
+ compactDisplay: 'short',
+ }).format(value)
+
+ default:
+ return String(value)
+ }
+}
+
+// Примеры использования
+formatStatValue(1500, 'number') // "1 500"
+formatStatValue(25000, 'currency') // "25 000 ₽"
+formatStatValue(1500000, 'compact') // "1,5 млн"
+```
+
+### **ЕДИНИЦЫ ИЗМЕРЕНИЯ**
+
+```typescript
+const StatUnits = {
+ quantity: 'шт',
+ weight: 'кг',
+ volume: 'л',
+ currency: '₽',
+ percentage: '%',
+ count: '', // без единицы для простых счётчиков
+ days: 'дн.',
+ hours: 'ч',
+}
+```
+
+---
+
+## 🚨 **АНТИ-ПАТТЕРНЫ И ТИПИЧНЫЕ ОШИБКИ**
+
+### **❌ НИКОГДА НЕ ДЕЛАЙТЕ:**
+
+#### **1. Разные источники данных для связанных статистик**
+
+```typescript
+// ❌ ПЛОХО - создаёт несогласованность
+const masterStats = useQuery(GET_OLD_WAREHOUSE_DATA) // legacy таблица
+const detailStats = useQuery(GET_NEW_SUPPLIES_DATA) // V2 таблица
+
+// Результат: разные значения в связанных карточках
+```
+
+#### **2. Игнорирование ошибок в статистике**
+
+```typescript
+// ❌ ПЛОХО - скрывает проблемы с данными
+const { data, error } = useQuery(STATS_QUERY, {
+ errorPolicy: 'ignore', // Ошибки не видны!
+})
+
+// ✅ ПРАВИЛЬНО
+const { data, error } = useQuery(STATS_QUERY, {
+ errorPolicy: 'all', // Показываем ошибки
+ onError: (error) => {
+ console.error('Stats error:', error)
+ toast.error('Ошибка загрузки статистики')
+ },
+})
+```
+
+#### **3. Вычисления на фронтенде вместо БД**
+
+```typescript
+// ❌ ПЛОХО - медленно и неточно
+const totalValue = supplies.map(s => s.price * s.quantity).reduce((a, b) => a + b, 0)
+
+// ✅ ПРАВИЛЬНО - вычисления в GraphQL resolver
+query GetSuppliesStats {
+ suppliesStats {
+ totalValue # Рассчитано на сервере
+ totalStock # Рассчитано на сервере
+ }
+}
+```
+
+#### **4. Отсутствие проверки синхронизации**
+
+```typescript
+// ❌ ПЛОХО - не контролируем консистентность
+const Stats = () => {
+ const master = useQuery(MASTER_QUERY)
+ const detail = useQuery(DETAIL_QUERY)
+
+ return {master.value} vs {detail.sum}
// Может не совпадать!
+}
+
+// ✅ ПРАВИЛЬНО - с проверкой синхронизации
+const Stats = () => {
+ const master = useQuery(MASTER_QUERY)
+ const detail = useQuery(DETAIL_QUERY)
+
+ useEffect(() => {
+ validateConsistency(master.data, detail.data)
+ }, [master.data, detail.data])
+
+ return
+}
+```
+
+---
+
+## 🔧 **ИНСТРУМЕНТЫ ОТЛАДКИ И МОНИТОРИНГА**
+
+### **DEBUG КОМПОНЕНТ ДЛЯ СТАТИСТИКИ**
+
+```jsx
+const StatisticsDebugPanel = ({ masterData, detailData }) => {
+ if (process.env.NODE_ENV !== 'development') return null
+
+ return (
+
+
Statistics Debug
+
Master: {masterData?.value}
+
Detail Sum: {detailData?.reduce((sum, item) => sum + item.value, 0)}
+
Sync: {masterData?.value === detailSum ? '✅' : '❌'}
+
Last Update: {new Date().toLocaleTimeString()}
+
+ )
+}
+```
+
+### **АВТОМАТИЧЕСКИЕ ТЕСТЫ СИНХРОНИЗАЦИИ**
+
+```typescript
+// Тест для проверки синхронизации статистик
+describe('Statistics Synchronization', () => {
+ it('должен синхронизировать master и detail значения', async () => {
+ const { masterValue } = await fetchMasterStats()
+ const detailItems = await fetchDetailItems()
+ const detailSum = detailItems.reduce((sum, item) => sum + item.value, 0)
+
+ expect(masterValue).toBe(detailSum)
+ })
+
+ it('должен обновлять связанные статистики при изменении данных', async () => {
+ const initialStats = await fetchStats()
+ await updateInventory({ productId: '1', change: +10 })
+
+ // Ждём обновления
+ await new Promise((resolve) => setTimeout(resolve, 1000))
+
+ const updatedStats = await fetchStats()
+ expect(updatedStats.totalStock).toBe(initialStats.totalStock + 10)
+ })
+})
+```
+
+---
+
+## 📊 **ШАБЛОНЫ КОМПОНЕНТОВ**
+
+### **БАЗОВЫЙ СТАТИСТИЧЕСКИЙ КОМПОНЕНТ**
+
+```tsx
+interface StatCardProps {
+ title: string
+ value: number | string
+ icon: React.ComponentType
+ color: 'blue' | 'green' | 'red' | 'yellow' | 'purple' | 'orange'
+ unit?: string
+ subtitle?: string
+ trend?: { value: number; period: string }
+ format?: 'number' | 'currency' | 'percentage' | 'compact'
+ loading?: boolean
+ error?: string
+}
+
+export const StatCard: React.FC = ({
+ title,
+ value,
+ icon: Icon,
+ color,
+ unit,
+ subtitle,
+ trend,
+ format = 'number',
+ loading,
+ error,
+}) => {
+ const formattedValue = useMemo(() => {
+ if (loading) return '...'
+ if (error) return 'Ошибка'
+ return formatStatValue(Number(value), format)
+ }, [value, format, loading, error])
+
+ return (
+
+
+
+
{title}
+
+ {formattedValue}
+ {unit && {unit}}
+
+ {subtitle &&
{subtitle}
}
+ {trend && (
+
+ {trend.value > 0 ? '+' : ''}
+ {trend.value} {trend.period}
+
+ )}
+
+
+
+
+
+
+ )
+}
+```
+
+### **КОМПОНЕНТ ГРУППЫ СТАТИСТИК**
+
+```tsx
+interface StatsGridProps {
+ stats: Array
+ columns?: 1 | 2 | 3 | 4 | 6
+ loading?: boolean
+ error?: string
+}
+
+export const StatsGrid: React.FC = ({ stats, columns = 6, loading, error }) => {
+ if (error) {
+ return (
+
+ Ошибка загрузки статистики: {error}
+
+ )
+ }
+
+ return (
+
+ {stats.map((stat) => (
+
+ ))}
+
+ )
+}
+```
+
+**Следование этим правилам обеспечит надёжную работу статистических компонентов!** 🚀