
АРХИТЕКТУРНЫЕ ИЗМЕНЕНИЯ: - Полная миграция на URL структуру /{role}/{domain}/{section}/{view} - Удаление всех старых директорий (/fulfillment-supplies/, /fulfillment-warehouse/, etc.) - Модульная архитектура seller warehouse с URL-based routing - Система rollback через комментарии для безопасных изменений НОВЫЕ КОМПОНЕНТЫ И СТРАНИЦЫ: - Создание всех недостающих страниц для FULFILLMENT, SELLER ролей - Модульный layout для seller warehouse с 3 табами - Извлечение переиспользуемого хука useWBWarehouseData ИСПРАВЛЕНИЯ БЕЗОПАСНОСТИ: - Добавление 'use client' директив во все WHOLESALE и LOGISTICS страницы - Исправление отсутствующих security guards (useRoleGuard + AuthGuard) - Обновление navigation конфигураций для всех ролей ДОКУМЕНТАЦИЯ: - Создание MIGRATION_GUIDE_V1_TO_V2.md: 8-этапное руководство по миграции - Создание NEXTJS_BEST_PRACTICES.md: паттерны для Next.js 13+ в SFERA - Обновление URL_ROUTING_RULES.md с seller warehouse и rollback системой - Обновление SIDEBAR_ARCHITECTURE_IMPLEMENTATION.md с новыми метриками - Обновление INDEX.md с новыми документами Development раздела ИСПРАВЛЕНИЯ ESLINT: - Удаление неиспользуемых импортов и переменных - Исправление import/order ошибок в модульных компонентах - Исправление react/no-unescaped-entities - Перенос длинных строк для соответствия max-len 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
10 KiB
10 KiB
⚛️ 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 СТРАНИЦ:
'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 (
<AuthGuard>
<ComponentDashboard />
</AuthGuard>
)
}
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
ЗАЩИТА СТРАНИЦ:
Базовый паттерн:
'use client'
import { AuthGuard } from '@/components/auth-guard'
import { useRoleGuard } from '@/hooks/useRoleGuard'
export default function SecurePage() {
useRoleGuard('REQUIRED_ROLE') // Проверка роли
return (
<AuthGuard> {/* Проверка авторизации */}
<PageContent />
</AuthGuard>
)
}
Доступные роли:
'SELLER'
- селлеры'FULFILLMENT'
- фулфилмент'WHOLESALE'
- поставщики'LOGIST'
- логистика
MIDDLEWARE ЗАЩИТА:
// 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:
'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 (
<div className="space-y-6">
{/* Tabs Header */}
<div className="flex space-x-1 bg-gray-900 p-1 rounded-lg">
<Link
href="/seller/warehouse/fulfillment"
className={`flex-1 py-2 px-4 text-center rounded-md transition-all whitespace-nowrap ${
activeTab === 'fulfillment'
? 'bg-blue-600 text-white shadow-lg'
: 'text-white/60 hover:bg-white/10'
}`}
>
Склад фулфилмент
</Link>
{/* другие табы */}
</div>
{/* Tab Content */}
{children}
</div>
)
}
ПЕРЕИСПОЛЬЗУЕМЫЕ ХУКИ:
Паттерн извлечения данных:
// 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
ПРОГРАММНАЯ НАВИГАЦИЯ:
import { useRouter } from 'next/navigation'
function NavigationComponent() {
const router = useRouter()
// ✅ Правильно: используем новые пути
const handleNavigate = () => {
router.push('/seller/warehouse/fulfillment')
}
// ❌ Неправильно: старые пути
// router.push('/wb-warehouse')
}
ОПРЕДЕЛЕНИЕ АКТИВНЫХ СОСТОЯНИЙ:
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
Основной компонент:
'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 (
<ComponentNameProvider>
<div className="space-y-6">
<Header />
<Content />
</div>
</ComponentNameProvider>
)
}
🚨 ОШИБКИ И РЕШЕНИЯ
ПРОБЛЕМА 1: "useRoleGuard from server"
Ошибка:
Error: Attempted to call useRoleGuard() from the server but useRoleGuard is on the client
Причина: Отсутствует 'use client' в page.tsx
Решение:
'use client' // Добавить в начало файла
import { useRoleGuard } from '@/hooks/useRoleGuard'
ПРОБЛЕМА 2: Redirect loops
Ошибка: Бесконечные редиректы между путями
Причина: Одновременно существуют старые и новые пути
Решение: Удалить старые директории:
rm -rf src/app/fulfillment-supplies/
rm -rf src/app/fulfillment-warehouse/
ПРОБЛЕМА 3: Потеря активных состояний
Ошибка: Табы не показывают активное состояние
Причина: Проверка pathname на старые пути
Решение: Обновить логику проверки:
// ✅ До:
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