Files
sfera-new/2025-09-19/GLOBAL_ROUTES_ELIMINATION_PLAN.md
Veronika Smirnova fe24b73634 fix: исправить критические ошибки системы партнерских заявок
КРИТИЧЕСКИЕ ИСПРАВЛЕНИЯ:
- Исправлено отображение входящих заявок (неправильное извлечение данных)
- Устранен ApolloError при принятии заявок (неправильная структура мутаций)
- Исправлено отображение контрагентов после принятия заявки
- Обновлены типы возврата GraphQL мутаций для соответствия резолверам

UI/UX УЛУЧШЕНИЯ:
- Обновлены все компоненты на темную glass-morphism тему
- Компактные карточки контрагентов (удалена избыточная информация)
- Удален дублирующий блок поиска новых партнеров

ЗАТРОНУТЫЕ ФАЙЛЫ:
- useCounterpartyData.ts: исправлено извлечение данных
- useCounterpartyActions.ts: исправлены структуры мутаций
- IncomingRequestsBlock.tsx: темная тема + исправления UI
- OutgoingRequestsBlock.tsx: темная тема
- CounterpartiesListBlock.tsx: компактные карточки + темная тема
- typedefs.ts: исправлены типы возврата мутаций

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-19 23:23:03 +03:00

15 KiB
Raw Blame History

🚨 ПЛАН УСТРАНЕНИЯ ГЛОБАЛЬНЫХ МАРШРУТОВ И СОЗДАНИЯ РОЛЬ-СПЕЦИФИЧНЫХ КОМПОНЕНТОВ

Дата: 2025-09-19
Приоритет: 🔴 КРИТИЧЕСКИЙ
Статус: В реализации
Цель: Устранить критические уязвимости безопасности через удаление глобальных маршрутов


🔍 РЕЗУЛЬТАТЫ МАКСИМАЛЬНОЙ ДИАГНОСТИКИ

ОБНАРУЖЕННЫЕ ГЛОБАЛЬНЫЕ МАРШРУТЫ

10 критических глобальных page.tsx файлов:

src/app/economics/page.tsx       ❌ УЯЗВИМОСТЬ
src/app/partners/page.tsx        ❌ УЯЗВИМОСТЬ
src/app/market/page.tsx          ❌ УЯЗВИМОСТЬ
src/app/messenger/page.tsx       ❌ УЯЗВИМОСТЬ
src/app/services/page.tsx        ❌ УЯЗВИМОСТЬ
src/app/settings/page.tsx        ❌ УЯЗВИМОСТЬ
src/app/warehouse/page.tsx       ❌ УЯЗВИМОСТЬ
src/app/exchange/page.tsx        ❌ УЯЗВИМОСТЬ
src/app/supplies/page.tsx        ❌ УЯЗВИМОСТЬ
src/app/employees/page.tsx       ❌ УЯЗВИМОСТЬ

ОБНАРУЖЕННЫЕ ССЫЛКИ НА ГЛОБАЛЬНЫЕ МАРШРУТЫ

Опасная ссылка в messenger-empty-state.tsx:

// src/components/messenger/messenger-empty-state.tsx:12
router.push('/market') // ❌ Ведет на глобальный маршрут!

АНАЛИЗ УЯЗВИМОСТИ

Сценарий атаки:

1. Пользователь LOGIST авторизован ✅
2. Заходит на /partners/ ❌ (обходит useRoleGuard)
3. Видит PartnersDashboard со всеми табами ❌
4. Получает доступ к интерфейсу других ролей ❌

Критичность: 🔴 Высокая - возможность обхода роль-специфичной защиты


🎯 ДЕТАЛЬНЫЙ ПЛАН УСТРАНЕНИЯ

ЭТАП 1: БЕЗОПАСНОЕ УДАЛЕНИЕ ГЛОБАЛЬНЫХ МАРШРУТОВ

1.1 ПОДГОТОВКА К УДАЛЕНИЮ

Создать бэкап:

mkdir backup-global-routes-$(date +%Y%m%d)
cp src/app/economics/page.tsx backup-global-routes-$(date +%Y%m%d)/
cp src/app/partners/page.tsx backup-global-routes-$(date +%Y%m%d)/
cp src/app/market/page.tsx backup-global-routes-$(date +%Y%m%d)/
cp src/app/messenger/page.tsx backup-global-routes-$(date +%Y%m%d)/
cp src/app/services/page.tsx backup-global-routes-$(date +%Y%m%d)/
cp src/app/settings/page.tsx backup-global-routes-$(date +%Y%m%d)/
cp src/app/warehouse/page.tsx backup-global-routes-$(date +%Y%m%d)/
cp src/app/exchange/page.tsx backup-global-routes-$(date +%Y%m%d)/
cp src/app/supplies/page.tsx backup-global-routes-$(date +%Y%m%d)/
cp src/app/employees/page.tsx backup-global-routes-$(date +%Y%m%d)/

1.2 БЕЗОПАСНОЕ УДАЛЕНИЕ

Последовательность удаления (от менее к более критичным):

  1. Второстепенные разделы:

    rm src/app/services/page.tsx
    rm src/app/settings/page.tsx
    rm src/app/warehouse/page.tsx
    rm src/app/exchange/page.tsx
    rm src/app/employees/page.tsx
    
  2. Основные разделы:

    rm src/app/supplies/page.tsx
    rm src/app/economics/page.tsx
    
  3. Критичные разделы (после создания замены):

    rm src/app/partners/page.tsx
    rm src/app/market/page.tsx
    rm src/app/messenger/page.tsx
    

ЭТАП 2: СОЗДАНИЕ РОЛЬ-СПЕЦИФИЧНЫХ КОМПОНЕНТОВ

2.1 PARTNERS - ПЕРВЫЙ ПРИОРИТЕТ

Анализ текущего PartnersDashboard:

// Текущие табы (одинаковые для всех ролей):
- Мои контрагенты
- Фулфилмент
- Селлеры
- Логистика
- Поставщик
- Рефералы

Создание роль-специфичных компонентов:

A. SellerPartners:

// src/components/partners/seller-partners.tsx
export function SellerPartners() {
  const { user } = useAuthContext()

  // Дополнительная защита
  if (user?.organization?.type !== 'SELLER') {
    console.error('Security violation: wrong role in SellerPartners')
    redirect('/login')
  }

  return (
    <Tabs defaultValue="my-counterparties">
      <TabsList>
        <TabsTrigger value="my-counterparties">Мои партнеры</TabsTrigger>
        <TabsTrigger value="find-fulfillment">Найти фулфилмент</TabsTrigger>
        <TabsTrigger value="find-suppliers">Найти поставщиков</TabsTrigger>
        <TabsTrigger value="referrals">Рефералы</TabsTrigger>
      </TabsList>

      <TabsContent value="my-counterparties">
        <MarketCounterparties /> {/* Показывает только партнеров селлера */}
      </TabsContent>

      <TabsContent value="find-fulfillment">
        <MarketFulfillment /> {/* Поиск фулфилмент-центров */}
      </TabsContent>

      <TabsContent value="find-suppliers">
        <MarketSuppliers /> {/* Поиск поставщиков */}
      </TabsContent>

      <TabsContent value="referrals">
        <ReferralsTab /> {/* Реферальная система */}
      </TabsContent>
    </Tabs>
  )
}

B. FulfillmentPartners:

// src/components/partners/fulfillment-partners.tsx
export function FulfillmentPartners() {
  const { user } = useAuthContext()

  if (user?.organization?.type !== 'FULFILLMENT') {
    console.error('Security violation: wrong role in FulfillmentPartners')
    redirect('/login')
  }

  return (
    <Tabs defaultValue="sellers">
      <TabsList>
        <TabsTrigger value="sellers">Селлеры</TabsTrigger>
        <TabsTrigger value="suppliers">Поставщики</TabsTrigger>
        <TabsTrigger value="logistics">Логистика</TabsTrigger>
        <TabsTrigger value="incoming-requests">Заявки</TabsTrigger>
      </TabsList>

      <TabsContent value="sellers">
        <MarketSellers /> {/* Управление селлерами */}
      </TabsContent>

      <TabsContent value="suppliers">
        <MarketSuppliers /> {/* Поставщики расходников */}
      </TabsContent>

      <TabsContent value="logistics">
        <MarketLogistics /> {/* Логистические партнеры */}
      </TabsContent>
    </Tabs>
  )
}

C. WholesalePartners:

// src/components/partners/wholesale-partners.tsx
export function WholesalePartners() {
  const { user } = useAuthContext()

  if (user?.organization?.type !== 'WHOLESALE') {
    console.error('Security violation: wrong role in WholesalePartners')
    redirect('/login')
  }

  return (
    <Tabs defaultValue="clients">
      <TabsList>
        <TabsTrigger value="clients">Клиенты</TabsTrigger>
        <TabsTrigger value="incoming-orders">Входящие заказы</TabsTrigger>
        <TabsTrigger value="logistics">Логистика</TabsTrigger>
      </TabsList>

      <TabsContent value="clients">
        <MarketCounterparties /> {/* Клиенты поставщика */}
      </TabsContent>

      <TabsContent value="incoming-orders">
        {/* Компонент для обработки входящих заказов */}
        <WholesaleIncomingOrders />
      </TabsContent>
    </Tabs>
  )
}

D. LogistPartners:

// src/components/partners/logist-partners.tsx
export function LogistPartners() {
  const { user } = useAuthContext()

  if (user?.organization?.type !== 'LOGIST') {
    console.error('Security violation: wrong role in LogistPartners')
    redirect('/login')
  }

  return (
    <Tabs defaultValue="routes">
      <TabsList>
        <TabsTrigger value="routes">Маршруты</TabsTrigger>
        <TabsTrigger value="clients">Клиенты</TabsTrigger>
        <TabsTrigger value="pricing">Тарифы</TabsTrigger>
      </TabsList>

      <TabsContent value="routes">
        {/* Агрегированные маршруты без коммерческой информации */}
        <LogisticsRoutes />
      </TabsContent>
    </Tabs>
  )
}

2.2 MESSENGER - ВТОРОЙ ПРИОРИТЕТ

Анализ текущего MessengerDashboard:

  • Общий компонент для всех ролей
  • Показывает myCounterparties для каждой роли
  • Логика мессенджера одинакова, но контрагенты разные

Создание роль-специфичных мессенджеров:

// src/components/messenger/seller-messenger.tsx
export function SellerMessenger() {
  const { user } = useAuthContext()

  if (user?.organization?.type !== 'SELLER') {
    redirect('/login')
  }

  // Специфичная логика для селлера
  return <MessengerDashboard />
}

2.3 MARKET - ТРЕТИЙ ПРИОРИТЕТ

Создание роль-специфичных компонентов маркета:

// src/components/market/seller-market.tsx
export function SellerMarket() {
  return (
    <Tabs defaultValue="products">
      <TabsTrigger value="products">Товары</TabsTrigger>
      <TabsTrigger value="requests">Мои заявки</TabsTrigger>
    </Tabs>
  )
}

// src/components/market/wholesale-market.tsx
export function WholesaleMarket() {
  return (
    <Tabs defaultValue="catalog">
      <TabsTrigger value="catalog">Каталог</TabsTrigger>
      <TabsTrigger value="incoming-requests">Входящие заявки</TabsTrigger>
    </Tabs>
  )
}

ЭТАП 3: ОБНОВЛЕНИЕ КАБИНЕТНЫХ МАРШРУТОВ

Обновление файлов page.tsx в кабинетах:

// src/app/seller/partners/page.tsx
export default function SellerPartnersPage() {
  useRoleGuard('SELLER')

  return (
    <AuthGuard>
      <SellerPartners /> {/* ← Новый роль-специфичный компонент */}
    </AuthGuard>
  )
}

// src/app/fulfillment/partners/page.tsx
export default function FulfillmentPartnersPage() {
  useRoleGuard('FULFILLMENT')

  return (
    <AuthGuard>
      <FulfillmentPartners />
    </AuthGuard>
  )
}

ЭТАП 4: ИСПРАВЛЕНИЕ ССЫЛОК

Найти и исправить все ссылки на глобальные маршруты:

// src/components/messenger/messenger-empty-state.tsx
// БЫЛО:
router.push('/market')

// СТАЛО:
const { user } = useAuthContext()
const userType = user?.organization?.type?.toLowerCase()
router.push(`/${userType}/market`)

ЭТАП 5: ТЕСТИРОВАНИЕ БЕЗОПАСНОСТИ

5.1 АВТОМАТИЧЕСКИЕ ТЕСТЫ

Создать тесты для проверки роль-специфичного доступа:

// tests/security/role-access.test.ts
describe('Role-specific access control', () => {
  test('SELLER cannot access FULFILLMENT components', () => {
    const sellerUser = { organization: { type: 'SELLER' } }

    expect(() => {
      render(<FulfillmentPartners />, { user: sellerUser })
    }).toThrow('Security violation')
  })

  test('Global routes return 404', () => {
    expect(fetch('/partners')).resolves.toHaveStatus(404)
    expect(fetch('/economics')).resolves.toHaveStatus(404)
  })
})

5.2 РУЧНОЕ ТЕСТИРОВАНИЕ

Проверить каждую роль:

  1. SELLER:

    • /seller/partners/ доступен
    • /partners/ возвращает 404
    • Нельзя зайти на /fulfillment/partners/
  2. FULFILLMENT:

    • /fulfillment/partners/ доступен
    • /partners/ возвращает 404
    • Нельзя зайти на /seller/partners/
  3. И т.д. для всех ролей


🚦 ПЛАН БЕЗОПАСНОЙ РЕАЛИЗАЦИИ

ПОРЯДОК РЕАЛИЗАЦИИ (БЕЗ РИСКА СЛОМАТЬ ПРОДАКШН)

ШАГ 1: СОЗДАНИЕ КОМПОНЕНТОВ (0 риска)

  • Создать роль-специфичные компоненты
  • НЕ удалять старые компоненты
  • НЕ удалять глобальные маршруты

ШАГ 2: ОБНОВЛЕНИЕ КАБИНЕТНЫХ МАРШРУТОВ (минимальный риск)

  • Заменить импорты в кабинетных page.tsx
  • Протестировать каждый кабинет
  • Проверить что все работает

ШАГ 3: ИСПРАВЛЕНИЕ ССЫЛОК (средний риск)

  • Найти все ссылки на глобальные маршруты
  • Исправить на роль-специфичные
  • Протестировать навигацию

ШАГ 4: УДАЛЕНИЕ ГЛОБАЛЬНЫХ МАРШРУТОВ (высокий риск)

  • Создать бэкап
  • Удалить глобальные page.tsx файлы
  • Протестировать что возвращается 404

ШАГ 5: ОЧИСТКА СТАРЫХ КОМПОНЕНТОВ (минимальный риск)

  • Удалить неиспользуемые wrapper компоненты
  • Обновить экспорты

ПЛАН ОТКАТА

Если что-то пойдет не так:

# Быстрый откат глобальных маршрутов
git checkout HEAD~1 -- src/app/partners/page.tsx
git checkout HEAD~1 -- src/app/economics/page.tsx
# и т.д.

# Или полный откат коммита
git revert <commit-hash>

📊 МЕТРИКИ УСПЕХА

КРИТЕРИИ ГОТОВНОСТИ

  • Все 10 глобальных маршрутов удалены
  • Все 4 роли имеют специфичные компоненты partners
  • Все ссылки ведут на кабинетные маршруты
  • Автоматические тесты безопасности проходят
  • Ручное тестирование для всех ролей успешно
  • Нет способа обойти роль-специфичную защиту

ОЖИДАЕМЫЙ РЕЗУЛЬТАТ

ДО:

❌ /partners/ → PartnersDashboard (доступно всем ролям)
❌ /economics/ → EconomicsPageWrapper (обход useRoleGuard)
❌ Возможность обхода защиты

ПОСЛЕ:

✅ /seller/partners/ → SellerPartners (только SELLER)
✅ /fulfillment/partners/ → FulfillmentPartners (только FULFILLMENT)
✅ /partners/ → 404 Not Found
✅ Невозможно обойти роль-специфичную защиту

🎯 НАЧАЛО РЕАЛИЗАЦИИ

Готов приступить к реализации по этому плану!

Следующее действие: Создание роль-специфичных компонентов для Partners