# ⚛️ NEXT.JS 13+ BEST PRACTICES ДЛЯ SFERA > **Статус**: ✅ **ДЕЙСТВУЮЩИЙ** > **Применимо к**: Next.js 15 + TypeScript > **Дата создания**: 30.08.2025 --- ## 🎯 КЛЮЧЕВЫЕ КОНЦЕПЦИИ ### 1. 'use client' ДИРЕКТИВА #### ОБЯЗАТЕЛЬНО ИСПОЛЬЗОВАТЬ КОГДА: - Используются React hooks (`useState`, `useEffect`, `useRouter`) - Используются custom hooks (`useRoleGuard`, `useAuth`) - Используются event handlers (`onClick`, `onSubmit`) - Используются browser APIs (`localStorage`, `window`) #### ПАТТЕРН ДЛЯ SFERA СТРАНИЦ: ```typescript 'use client' import { AuthGuard } from '@/components/auth-guard' import { ComponentDashboard } from '@/components/path/component-dashboard' import { useRoleGuard } from '@/hooks/useRoleGuard' export default function RolePage() { useRoleGuard('ROLE_NAME') return ( ) } ``` ### 2. APP ROUTER СТРУКТУРА #### ФАЙЛОВАЯ СИСТЕМА: ``` src/app/ ├── {role}/ # Динамический сегмент роли │ ├── page.tsx # Главная роли (редирект) │ ├── layout.tsx # Layout для роли (опционально) │ └── {domain}/ │ ├── page.tsx # Главная домена │ ├── layout.tsx # Layout с табами │ └── {section}/ │ ├── page.tsx # Основная страница секции │ └── {view}/ │ └── page.tsx # Конкретное представление ``` #### ПРАВИЛА ИМЕНОВАНИЯ: - **Роли**: `seller`, `fulfillment`, `wholesale`, `logistics` - **Домены**: `supplies`, `warehouse`, `orders`, `statistics` - **Секции**: `goods`, `consumables`, `marketplace` - **Представления**: `cards`, `suppliers`, `new`, `receiving` --- ## 🛡️ SECURITY PATTERNS ### ЗАЩИТА СТРАНИЦ: #### Базовый паттерн: ```typescript 'use client' import { AuthGuard } from '@/components/auth-guard' import { useRoleGuard } from '@/hooks/useRoleGuard' export default function SecurePage() { useRoleGuard('REQUIRED_ROLE') // Проверка роли return ( {/* Проверка авторизации */} ) } ``` #### Доступные роли: - `'SELLER'` - селлеры - `'FULFILLMENT'` - фулфилмент - `'WHOLESALE'` - поставщики - `'LOGIST'` - логистика ### MIDDLEWARE ЗАЩИТА: ```typescript // middleware.ts - автоматическая проверка URL соответствия роли export function middleware(request: NextRequest) { const url = request.nextUrl.pathname const userRole = getUserRole(request) // из JWT токена // Проверяем соответствие роли и URL if (url.startsWith('/seller/') && userRole !== 'SELLER') { return NextResponse.redirect('/unauthorized') } // аналогично для других ролей } ``` --- ## 🎨 LAYOUT PATTERNS ### LAYOUT С ТАБАМИ: #### Структура файлов: ``` warehouse/ ├── layout.tsx # Tabs UI + активный таб по URL ├── fulfillment/page.tsx # /warehouse/fulfillment ├── wildberries/page.tsx # /warehouse/wildberries └── storage/page.tsx # /warehouse/storage ``` #### Реализация layout.tsx: ```typescript 'use client' import { usePathname } from 'next/navigation' import Link from 'next/link' export default function WarehouseLayout({ children }: { children: React.ReactNode }) { const pathname = usePathname() // Автоматическое определение активного таба по URL const getActiveTab = () => { if (pathname.includes('/fulfillment')) return 'fulfillment' if (pathname.includes('/wildberries')) return 'wildberries' if (pathname.includes('/storage')) return 'storage' return 'fulfillment' // default } const activeTab = getActiveTab() return (
{/* Tabs Header */}
Склад фулфилмент {/* другие табы */}
{/* Tab Content */} {children}
) } ``` ### ПЕРЕИСПОЛЬЗУЕМЫЕ ХУКИ: #### Паттерн извлечения данных: ```typescript // hooks/useWBWarehouseData.ts export function useWBWarehouseData() { const { data, loading, error } = useQuery(GET_WB_WAREHOUSE_DATA, { fetchPolicy: 'cache-first', errorPolicy: 'ignore', }) return { data: data?.getWBWarehouseData || [], loading, error, refetch: () => { /* логика обновления */ }, } } // Использование в компонентах: const { data, loading } = useWBWarehouseData() ``` --- ## 🔄 ROUTING PATTERNS ### ПРОГРАММНАЯ НАВИГАЦИЯ: ```typescript import { useRouter } from 'next/navigation' function NavigationComponent() { const router = useRouter() // ✅ Правильно: используем новые пути const handleNavigate = () => { router.push('/seller/warehouse/fulfillment') } // ❌ Неправильно: старые пути // router.push('/wb-warehouse') } ``` ### ОПРЕДЕЛЕНИЕ АКТИВНЫХ СОСТОЯНИЙ: ```typescript import { usePathname } from 'next/navigation' function ActiveStateComponent() { const pathname = usePathname() // ✅ Правильно: проверяем новые пути const isActive = pathname.startsWith('/seller/warehouse') // ✅ Конкретная секция: const isFulfillmentActive = pathname.includes('/warehouse/fulfillment') } ``` --- ## 📦 COMPONENT PATTERNS ### МОДУЛЬНАЯ АРХИТЕКТУРА: #### Структура папки компонента: ``` ComponentName/ ├── index.tsx # Основной компонент ├── ComponentName.types.ts # TypeScript типы ├── ComponentName.hooks.ts # Custom hooks ├── ComponentName.utils.ts # Утилиты └── components/ # Подкомпоненты ├── Header.tsx ├── Content.tsx └── Footer.tsx ``` #### Основной компонент: ```typescript 'use client' import { ComponentNameProvider } from './ComponentName.context' import { useComponentName } from './ComponentName.hooks' import { Header } from './components/Header' import { Content } from './components/Content' export function ComponentName() { return (
) } ``` --- ## 🚨 ОШИБКИ И РЕШЕНИЯ ### ПРОБЛЕМА 1: "useRoleGuard from server" **Ошибка:** ``` Error: Attempted to call useRoleGuard() from the server but useRoleGuard is on the client ``` **Причина**: Отсутствует 'use client' в page.tsx **Решение:** ```typescript 'use client' // Добавить в начало файла import { useRoleGuard } from '@/hooks/useRoleGuard' ``` ### ПРОБЛЕМА 2: Redirect loops **Ошибка**: Бесконечные редиректы между путями **Причина**: Одновременно существуют старые и новые пути **Решение**: Удалить старые директории: ```bash rm -rf src/app/fulfillment-supplies/ rm -rf src/app/fulfillment-warehouse/ ``` ### ПРОБЛЕМА 3: Потеря активных состояний **Ошибка**: Табы не показывают активное состояние **Причина**: Проверка pathname на старые пути **Решение**: Обновить логику проверки: ```typescript // ✅ До: const isActive = pathname.startsWith('/fulfillment-supplies') // ✅ После: const isActive = pathname.startsWith('/fulfillment/supplies') ``` --- ## 📋 CHECKLIST ДЛЯ НОВЫХ КОМПОНЕНТОВ ### ПЕРЕД СОЗДАНИЕМ: - [ ] Прочитал MODULAR_ARCHITECTURE_PATTERN.md - [ ] Определил нужность модульной архитектуры - [ ] Выбрал правильный URL путь по формуле `/{role}/{domain}/{section}/{view}` - [ ] Добавил 'use client' если используются hooks ### ПРИ СОЗДАНИИ: - [ ] Добавил useRoleGuard с правильной ролью - [ ] Обернул в AuthGuard для проверки авторизации - [ ] Использовал существующие компоненты и хуки - [ ] Следовал naming conventions ### ПОСЛЕ СОЗДАНИЯ: - [ ] Проверил `npm run typecheck` - [ ] Проверил `npm run lint` - [ ] Протестировал в браузере - [ ] Убедился что navigation работает --- ## 🎯 ЗАКЛЮЧЕНИЕ **NEXT.JS 13+ В SFERA: СТАБИЛЬНАЯ PRODUCTION-READY СИСТЕМА** 🎯 **ПРИНЦИПЫ:** - 'use client' для всех interactive компонентов - URL-based routing вместо внутренних состояний - Модульная архитектура для сложных компонентов - Систематическая структура путей по ролям 🚀 **РЕЗУЛЬТАТ:** - 100% совместимость с Next.js 15 - Отсутствие server/client конфликтов - SEO-оптимизированные URL - Простая навигация и maintenance **Данные практики обеспечивают стабильность и масштабируемость SFERA на Next.js 13+.** --- _Создано: 30.08.2025_ _На основе реального опыта разработки SFERA_