# 📋 ПЛАН УЛУЧШЕНИЯ АРХИТЕКТУРЫ АВТОРИЗАЦИИ И БЕЗОПАСНОСТИ SFERA

**Дата создания:** 2025-09-18  
**Автор:** Claude AI + Вероника Смирнова  
**Статус:** В разработке

## 📊 Анализ текущего состояния

### ✅ Что уже реализовано и работает:

1. **Безопасные ID (CUID)**
   - Все модели используют `@default(cuid())`
   - Невозможно угадать ID других организаций
   - Пример: `cmfpe46iv0001y51d87f4vy2n`

2. **Защита типов кабинетов**
   - `useRoleGuard` на 49 страницах
   - Автоматический редирект при попытке доступа к чужому типу кабинета
   - Селлер не может зайти в кабинет Поставщика

3. **Изоляция данных на уровне API**
   - Все резолверы фильтруют по `organizationId`
   - Каждая организация видит только свои данные
   - Проверки в каждом GraphQL резолвере

4. **Структура роутинга**
   - Четкое разделение: `/seller/*`, `/fulfillment/*`, `/logistics/*`, `/wholesale/*`
   - DashboardHome автоматически направляет в нужный кабинет

### 🚨 Выявленные проблемы:

1. **Отсутствие глобального состояния (AuthContext)**
   - Каждый компонент создает свой экземпляр useAuth
   - Состояние не синхронизируется между компонентами
   - Sidebar не видит данные пользователя после авторизации

2. **Дублирование кода безопасности**
   - Одинаковые проверки в 50+ резолверах
   - Риск забыть добавить проверку в новый резолвер
   - Сложность поддержки

3. **Отсутствие персистентности**
   - При обновлении страницы состояние теряется
   - Повторные запросы GET_ME
   - Плохой UX при F5

4. **Нет серверной проверки роутов**
   - Проверки только на уровне компонентов
   - Страница начинает загружаться до проверки прав

## 🎯 План улучшений

### ФАЗА 1: Критические исправления

#### 1. Реализация AuthContext [🔴 КРИТИЧНО]

**Срок:** 2-3 часа  
**Приоритет:** Максимальный  
**Влияние:** Решает проблему с sidebar и синхронизацией состояния

**План реализации:**

1. Создать `/src/contexts/AuthContext.tsx`:
```typescript
import { createContext, useContext, useState, useEffect } from 'react'
import { useApolloClient } from '@apollo/client'

interface AuthContextType {
  user: User | null
  isAuthenticated: boolean
  isLoading: boolean
  checkAuth: () => Promise<void>
  login: (phone: string, code: string) => Promise<void>
  logout: () => void
}

const AuthContext = createContext<AuthContextType | null>(null)

export function AuthProvider({ children }) {
  // Перенести всю логику из текущего useAuth
  const [user, setUser] = useState<User | null>(null)
  const [isLoading, setIsLoading] = useState(true)
  
  // ... вся логика авторизации
  
  return (
    <AuthContext.Provider value={{ user, ... }}>
      {children}
    </AuthContext.Provider>
  )
}

export function useAuth() {
  const context = useContext(AuthContext)
  if (!context) {
    throw new Error('useAuth must be used within AuthProvider')
  }
  return context
}
```

2. Обновить `/src/app/providers.tsx`:
```typescript
export function Providers({ children }) {
  return (
    <ApolloProvider client={apolloClient}>
      <AuthProvider>
        <SidebarProvider>
          {children}
        </SidebarProvider>
      </AuthProvider>
    </ApolloProvider>
  )
}
```

3. Убрать временные решения:
   - Удалить `useQuery(GET_ME)` из AppShell
   - Убрать передачу user через props
   - Вернуть оригинальную логику компонентов

#### 2. GraphQL Middleware для безопасности [🟡 ВАЖНО]

**Срок:** 1 день  
**Приоритет:** Высокий  
**Влияние:** Централизованная безопасность, чистый код

**План реализации:**

1. Создать `/src/graphql/middleware/organizationAccess.ts`:
```typescript
export const organizationAccessMiddleware = async (
  resolve, 
  parent, 
  args, 
  context, 
  info
) => {
  // Пропускаем публичные операции
  const PUBLIC_OPERATIONS = ['login', 'sendSmsCode', 'verifySmsCode']
  if (PUBLIC_OPERATIONS.includes(info.fieldName)) {
    return resolve(parent, args, context, info)
  }
  
  // Проверяем авторизацию
  if (!context.user?.organizationId) {
    throw new GraphQLError('Unauthorized', {
      extensions: { code: 'UNAUTHENTICATED' }
    })
  }
  
  // Автоматически добавляем organizationId к запросам
  if (args.where && typeof args.where === 'object') {
    args.where.organizationId = context.user.organizationId
  }
  
  // Логирование для безопасности
  console.log(`[${context.user.organizationId}] ${info.fieldName}`, {
    userId: context.user.id,
    operation: info.fieldName,
    timestamp: new Date().toISOString()
  })
  
  return resolve(parent, args, context, info)
}
```

2. Применить middleware ко всем резолверам
3. Удалить дублированные проверки из резолверов

### ФАЗА 2: Важные улучшения

#### 3. Персистентность состояния [🟡 ВАЖНО]

**Срок:** 0.5 дня  
**Приоритет:** Средний  
**Влияние:** Улучшение UX при обновлении страницы

**План реализации:**

1. Добавить в AuthContext сохранение состояния:
```typescript
// При успешной авторизации
const encryptedUser = encrypt(JSON.stringify(user))
localStorage.setItem('auth:user', encryptedUser)

// При инициализации
const savedUser = localStorage.getItem('auth:user')
if (savedUser) {
  const user = JSON.parse(decrypt(savedUser))
  // Проверить валидность токена
}
```

2. Реализовать refresh token механизм
3. Очистка при logout

#### 4. Next.js Middleware [🟢 ЖЕЛАТЕЛЬНО]

**Срок:** 1 день  
**Приоритет:** Средний  
**Влияние:** Производительность, серверная защита

**План реализации:**

1. Создать `/src/middleware.ts`:
```typescript
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { jwtVerify } from 'jose'

export async function middleware(request: NextRequest) {
  const token = request.cookies.get('auth-token')?.value
  const pathname = request.nextUrl.pathname
  
  // Публичные маршруты
  const publicPaths = ['/', '/login', '/register']
  if (publicPaths.includes(pathname)) return
  
  // Проверка токена
  if (!token) {
    return NextResponse.redirect(new URL('/login', request.url))
  }
  
  try {
    const { payload } = await jwtVerify(token, new TextEncoder().encode(process.env.JWT_SECRET!))
    const orgType = payload.organization?.type
    
    // Проверка доступа к кабинету
    if (pathname.startsWith('/seller') && orgType !== 'SELLER') {
      return NextResponse.redirect(new URL('/dashboard', request.url))
    }
    // ... остальные проверки
    
  } catch (error) {
    return NextResponse.redirect(new URL('/login', request.url))
  }
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)']
}
```

### ФАЗА 3: Оптимизации

#### 5. Улучшение загрузки [🔵 ОПЦИОНАЛЬНО]

**Срок:** 1 неделя  
**Приоритет:** Низкий  
**Влияние:** Улучшение UX

- Skeleton screens для всех страниц
- Prefetch критических данных
- Оптимистичные обновления UI
- PWA функциональность

#### 6. Расширенная система прав [🔵 ОПЦИОНАЛЬНО]

**Срок:** 2 недели  
**Приоритет:** Низкий  
**Влияние:** Enterprise функциональность

- Роли: Admin, Manager, Viewer
- Permissions: canEdit, canDelete, canApprove
- Аудит всех действий
- Делегирование доступа

## 📈 Ожидаемые результаты

### После ФАЗЫ 1:
- ✅ Sidebar работает стабильно
- ✅ Состояние синхронизировано между компонентами
- ✅ Единая точка контроля безопасности
- ✅ Чистый, поддерживаемый код

### После ФАЗЫ 2:
- ✅ Мгновенная загрузка после F5
- ✅ Защита на уровне сервера
- ✅ Автоматическое управление сессией

### После ФАЗЫ 3:
- ✅ Премиум UX
- ✅ Enterprise-ready система
- ✅ Готовность к масштабированию

## 🚀 Рекомендуемый порядок выполнения

1. **Неделя 1:** AuthContext (решает критическую проблему)
2. **Неделя 2:** GraphQL Middleware + Персистентность
3. **Месяц 2:** Next.js Middleware + Оптимизации по необходимости

## 📝 Критерии успеха

- [ ] Sidebar отображается сразу после авторизации
- [ ] Нет дублирования состояния между компонентами
- [ ] Единая проверка безопасности для всех API запросов
- [ ] Состояние сохраняется при обновлении страницы
- [ ] Производительность не ухудшилась
- [ ] Код стал чище и проще в поддержке

---

*Документ будет обновляться по мере реализации плана*