# ПЛАН РЕАЛИЗАЦИИ БЕЗОПАСНОСТИ ДАННЫХ В ПОСТАВКАХ

## 🎯 ОБЗОР ПЛАНА

План поэтапной реализации системы безопасности данных в поставках с минимальными рисками для существующей функциональности.

### КЛЮЧЕВЫЕ ПРИНЦИПЫ РЕАЛИЗАЦИИ:

1. **Постепенное внедрение** - каждая фаза независима и тестируема
2. **Обратная совместимость** - не ломаем существующий функционал
3. **Мониторинг на каждом этапе** - отслеживаем влияние изменений
4. **Откат при проблемах** - возможность быстро вернуться к предыдущей версии

## 📅 TIMELINE И ПРИОРИТЕТЫ

| Фаза      | Название                    | Длительность  | Приоритет      | Риски   |
| --------- | --------------------------- | ------------- | -------------- | ------- |
| **1**     | Подготовка инфраструктуры   | 2-3 дня       | 🔴 Критический | Низкие  |
| **2**     | Базовые классы безопасности | 3-4 дня       | 🔴 Критический | Низкие  |
| **3**     | Обновление резолверов       | 5-7 дней      | 🔴 Критический | Средние |
| **4**     | Система аудита              | 2-3 дня       | 🟡 Высокий     | Низкие  |
| **5**     | Тестирование                | 3-4 дня       | 🟡 Высокий     | Низкие  |
| **6**     | Оптимизация                 | 2-3 дня       | 🟢 Средний     | Низкие  |
| **ИТОГО** |                             | **17-24 дня** |                |         |

## 🛠️ ФАЗА 1: ПОДГОТОВКА ИНФРАСТРУКТУРЫ (2-3 дня)

### Цель:

Подготовить кодовую базу для внедрения безопасности без нарушения работы системы.

### Задачи:

#### 1.1 Создание структуры директорий

```bash
src/
├── graphql/
│   ├── security/               # Новая папка для безопасности
│   │   ├── index.ts           # Экспорт всех модулей
│   │   ├── supply-data-filter.ts
│   │   ├── participant-isolation.ts
│   │   ├── recipe-access-control.ts
│   │   ├── commercial-data-audit.ts
│   │   └── types.ts           # Типы для безопасности
│   └── resolvers/
│       └── supply-orders/      # Рефакторинг резолверов
│           ├── queries.ts
│           ├── mutations.ts
│           └── helpers.ts
```

#### 1.2 Создание feature flag для постепенного внедрения

```typescript
// src/config/features.ts
export const FEATURE_FLAGS = {
  SUPPLY_DATA_SECURITY: {
    enabled: process.env.ENABLE_SUPPLY_SECURITY === 'true',
    auditEnabled: process.env.ENABLE_SECURITY_AUDIT === 'true',
    strictMode: process.env.SECURITY_STRICT_MODE === 'true',
  },
}

// Использование в коде
if (FEATURE_FLAGS.SUPPLY_DATA_SECURITY.enabled) {
  // Новая логика безопасности
  return SupplyDataFilter.filterByRole(data, userRole)
} else {
  // Старая логика
  return data
}
```

#### 1.3 Настройка логирования для отладки

```typescript
// src/lib/security-logger.ts
export class SecurityLogger {
  private static readonly DEBUG = process.env.SECURITY_DEBUG === 'true'

  static logDataAccess(params: { userId: string; action: string; resource: string; filtered: boolean }) {
    if (this.DEBUG) {
      console.log('[SECURITY]', {
        ...params,
        timestamp: new Date().toISOString(),
      })
    }
  }
}
```

#### 1.4 Создание миграции БД для аудита (без применения)

```sql
-- prisma/migrations/add_audit_log_table.sql
CREATE TABLE "AuditLog" (
    "id" TEXT NOT NULL,
    "userId" TEXT NOT NULL,
    "organizationType" TEXT NOT NULL,
    "action" TEXT NOT NULL,
    "resourceType" TEXT NOT NULL,
    "resourceId" TEXT,
    "metadata" JSONB DEFAULT '{}',
    "ipAddress" TEXT,
    "userAgent" TEXT,
    "timestamp" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id")
);

CREATE INDEX "AuditLog_userId_idx" ON "AuditLog"("userId");
CREATE INDEX "AuditLog_timestamp_idx" ON "AuditLog"("timestamp");
CREATE INDEX "AuditLog_action_idx" ON "AuditLog"("action");
```

### Результаты фазы 1:

- ✅ Структура готова для новых классов
- ✅ Feature flags позволяют безопасное тестирование
- ✅ Логирование настроено для отладки
- ✅ Миграция БД подготовлена

## 🔐 ФАЗА 2: БАЗОВЫЕ КЛАССЫ БЕЗОПАСНОСТИ (3-4 дня)

### Цель:

Реализовать основные классы фильтрации данных с полным покрытием тестами.

### Задачи:

#### 2.1 Создание типов безопасности

```typescript
// src/graphql/security/types.ts
export interface SecurityContext {
  user: {
    id: string
    organizationId: string
    organizationType: OrganizationType
  }
  ipAddress?: string
  userAgent?: string
}

export interface FilteredData<T> {
  data: T
  filtered: boolean
  removedFields: string[]
}

export type DataAccessLevel = 'FULL' | 'PARTIAL' | 'NONE'
```

#### 2.2 Реализация SupplyDataFilter

```typescript
// src/graphql/security/supply-data-filter.ts
export class SupplyDataFilter {
  // Статические методы для фильтрации
  static filterSupplyOrder(order: SupplyOrder, context: SecurityContext): FilteredData<Partial<SupplyOrder>> {
    const { organizationType, organizationId } = context.user

    // Логика фильтрации по ролям
    switch (organizationType) {
      case 'SELLER':
        return this.filterForSeller(order, organizationId)
      case 'WHOLESALE':
        return this.filterForWholesale(order, organizationId)
      case 'FULFILLMENT':
        return this.filterForFulfillment(order, organizationId)
      case 'LOGIST':
        return this.filterForLogist(order, organizationId)
      default:
        throw new GraphQLError('Unauthorized organization type')
    }
  }

  // Приватные методы для каждой роли
  private static filterForSeller(/*...*/) {
    /*...*/
  }
  private static filterForWholesale(/*...*/) {
    /*...*/
  }
  private static filterForFulfillment(/*...*/) {
    /*...*/
  }
  private static filterForLogist(/*...*/) {
    /*...*/
  }
}
```

#### 2.3 Реализация ParticipantIsolation

```typescript
// src/graphql/security/participant-isolation.ts
export class ParticipantIsolation {
  static async checkAccess(
    prisma: PrismaClient,
    context: SecurityContext,
    resourceId: string,
    resourceType: 'SUPPLY_ORDER' | 'PRODUCT' | 'SERVICE',
  ): Promise<boolean> {
    // Проверка доступа к ресурсу
    const hasAccess = await this.validateResourceAccess(prisma, context, resourceId, resourceType)

    if (!hasAccess) {
      // Логируем попытку несанкционированного доступа
      await CommercialDataAudit.logUnauthorizedAccess({
        ...context,
        resourceId,
        resourceType,
      })
    }

    return hasAccess
  }
}
```

#### 2.4 Создание тестов для классов

```typescript
// src/graphql/security/__tests__/supply-data-filter.test.ts
describe('SupplyDataFilter', () => {
  describe('filterForFulfillment', () => {
    it('should hide product prices from fulfillment', () => {
      const order = createMockSupplyOrder()
      const context = createMockContext('FULFILLMENT')

      const filtered = SupplyDataFilter.filterSupplyOrder(order, context)

      expect(filtered.data.items[0].price).toBeNull()
      expect(filtered.data.productPrice).toBeNull()
      expect(filtered.removedFields).toContain('productPrice')
    })

    it('should show recipe to fulfillment', () => {
      const order = createMockSupplyOrder()
      const context = createMockContext('FULFILLMENT')

      const filtered = SupplyDataFilter.filterSupplyOrder(order, context)

      expect(filtered.data.items[0].recipe).toBeDefined()
      expect(filtered.data.items[0].recipe.services).toHaveLength(2)
    })
  })
})
```

### Результаты фазы 2:

- ✅ Базовые классы реализованы
- ✅ 100% покрытие тестами
- ✅ Готовы к интеграции в резолверы

## 🔄 ФАЗА 3: ОБНОВЛЕНИЕ РЕЗОЛВЕРОВ (5-7 дней)

### Цель:

Интегрировать классы безопасности в существующие GraphQL резолверы с минимальным риском.

### Задачи:

#### 3.1 Создание обертки для безопасных резолверов

```typescript
// src/graphql/security/secure-resolver.ts
export function createSecureResolver<TArgs, TResult>(
  resolver: (parent: any, args: TArgs, context: Context) => Promise<TResult>,
  options: {
    resourceType: string
    requiredRole?: OrganizationType[]
    auditAction: string
  },
) {
  return async (parent: any, args: TArgs, context: Context): Promise<TResult> => {
    // Проверка аутентификации
    if (!context.user) {
      throw new GraphQLError('Authentication required')
    }

    // Проверка роли если требуется
    if (options.requiredRole && !options.requiredRole.includes(context.user.organizationType)) {
      throw new GraphQLError('Insufficient permissions')
    }

    // Логирование доступа
    if (FEATURE_FLAGS.SUPPLY_DATA_SECURITY.auditEnabled) {
      await CommercialDataAudit.logAccess({
        userId: context.user.id,
        organizationType: context.user.organizationType,
        action: options.auditAction,
        resourceType: options.resourceType,
        metadata: { args },
      })
    }

    // Выполнение оригинального резолвера
    const result = await resolver(parent, args, context)

    // Фильтрация результата если включена безопасность
    if (FEATURE_FLAGS.SUPPLY_DATA_SECURITY.enabled) {
      return filterResultByRole(result, context)
    }

    return result
  }
}
```

#### 3.2 Постепенное обновление резолверов

```typescript
// src/graphql/resolvers/supply-orders/queries.ts
export const supplyOrderQueries = {
  // Старый резолвер
  mySupplyOrders_OLD: async (parent, args, context) => {
    // Существующая логика
  },

  // Новый безопасный резолвер
  mySupplyOrders: createSecureResolver(
    async (parent, args, context) => {
      // Получаем данные
      const orders = await prisma.supplyOrder.findMany({
        where: buildWhereClause(context.user, args),
        include: fullInclude,
      })

      // Фильтруем если безопасность включена
      if (FEATURE_FLAGS.SUPPLY_DATA_SECURITY.enabled) {
        return orders.map((order) => SupplyDataFilter.filterSupplyOrder(order, context).data)
      }

      return orders
    },
    {
      resourceType: 'SUPPLY_ORDER',
      auditAction: 'VIEW_SUPPLY_ORDERS',
    },
  ),
}
```

#### 3.3 A/B тестирование с метриками

```typescript
// src/graphql/security/metrics.ts
export class SecurityMetrics {
  static async compareResults(oldResult: any, newResult: any, context: SecurityContext) {
    const differences = this.findDifferences(oldResult, newResult)

    if (differences.length > 0) {
      await this.logDifferences({
        userId: context.user.id,
        organizationType: context.user.organizationType,
        differences,
        timestamp: new Date(),
      })
    }

    // Отправка метрик в мониторинг
    metrics.increment('security.filter.applied', {
      organizationType: context.user.organizationType,
      hasDifferences: differences.length > 0,
    })
  }
}
```

#### 3.4 Поэтапная миграция резолверов

```typescript
// План миграции резолверов
const MIGRATION_PLAN = [
  // Неделя 1: Читающие запросы
  { resolver: 'mySupplyOrders', risk: 'LOW', rollout: '10%' },
  { resolver: 'supplyOrder', risk: 'LOW', rollout: '25%' },
  { resolver: 'searchSupplies', risk: 'MEDIUM', rollout: '10%' },

  // Неделя 2: Мутации
  { resolver: 'createSupplyOrder', risk: 'HIGH', rollout: '5%' },
  { resolver: 'updateSupplyOrderStatus', risk: 'HIGH', rollout: '5%' },

  // Неделя 3: Полный rollout
  { resolver: '*', risk: 'MEDIUM', rollout: '100%' },
]
```

### Результаты фазы 3:

- ✅ Резолверы обновлены с feature flags
- ✅ A/B тестирование настроено
- ✅ Метрики собираются для анализа

## 📊 ФАЗА 4: СИСТЕМА АУДИТА (2-3 дня)

### Цель:

Реализовать полноценную систему аудита доступа к коммерческим данным.

### Задачи:

#### 4.1 Применение миграции БД

```bash
# Применяем подготовленную миграцию
npx prisma migrate deploy

# Обновляем Prisma Client
npx prisma generate
```

#### 4.2 Реализация CommercialDataAudit

```typescript
// src/graphql/security/commercial-data-audit.ts
export class CommercialDataAudit {
  private static readonly ALERT_THRESHOLDS = {
    VIEW_PRICE: { perHour: 100, perDay: 500 },
    VIEW_RECIPE: { perHour: 50, perDay: 200 },
    BULK_EXPORT: { perHour: 5, perDay: 20 },
  }

  static async logAccess(params: AuditParams): Promise<void> {
    // Сохраняем в БД
    await prisma.auditLog.create({
      data: {
        userId: params.userId,
        organizationType: params.organizationType,
        action: params.action,
        resourceType: params.resourceType,
        resourceId: params.resourceId,
        metadata: params.metadata || {},
        ipAddress: params.ipAddress,
        userAgent: params.userAgent,
        timestamp: new Date(),
      },
    })

    // Проверяем на подозрительную активность
    await this.checkSuspiciousActivity(params)
  }

  private static async checkSuspiciousActivity(params: AuditParams) {
    const threshold = this.ALERT_THRESHOLDS[params.action]
    if (!threshold) return

    // Считаем активность за последний час
    const hourlyCount = await this.getActivityCount(
      params.userId,
      params.action,
      60 * 60 * 1000, // 1 час
    )

    if (hourlyCount > threshold.perHour) {
      await this.sendAlert({
        type: 'EXCESSIVE_ACCESS',
        severity: 'HIGH',
        userId: params.userId,
        action: params.action,
        count: hourlyCount,
        threshold: threshold.perHour,
      })
    }
  }
}
```

#### 4.3 Dashboard для мониторинга

```typescript
// src/pages/admin/security-audit.tsx
export function SecurityAuditDashboard() {
  const [alerts, setAlerts] = useState<SecurityAlert[]>([])
  const [metrics, setMetrics] = useState<SecurityMetrics>()

  // Real-time подписка на алерты
  useEffect(() => {
    const subscription = subscribeToSecurityAlerts((alert) => {
      setAlerts(prev => [alert, ...prev])

      // Показываем критичные алерты
      if (alert.severity === 'HIGH') {
        toast.error(`Security Alert: ${alert.message}`)
      }
    })

    return () => subscription.unsubscribe()
  }, [])

  return (
    <div className="security-dashboard">
      <AlertsList alerts={alerts} />
      <AccessMetrics metrics={metrics} />
      <SuspiciousActivityLog />
    </div>
  )
}
```

### Результаты фазы 4:

- ✅ Аудит логирует все обращения
- ✅ Алерты работают в real-time
- ✅ Dashboard для мониторинга

## ✅ ФАЗА 5: ТЕСТИРОВАНИЕ (3-4 дня)

### Цель:

Обеспечить полное покрытие тестами и проверить все сценарии безопасности.

### Задачи:

#### 5.1 Unit тесты для каждой роли

```typescript
// src/graphql/security/__tests__/role-based-filtering.test.ts
describe('Role-based filtering', () => {
  const testCases = [
    {
      role: 'SELLER',
      canSee: ['productPrice', 'recipe', 'totalAmount'],
      cannotSee: [],
    },
    {
      role: 'WHOLESALE',
      canSee: ['productPrice', 'packagesCount'],
      cannotSee: ['recipe', 'fulfillmentServicePrice'],
    },
    {
      role: 'FULFILLMENT',
      canSee: ['recipe', 'fulfillmentServicePrice'],
      cannotSee: ['productPrice'],
    },
    {
      role: 'LOGIST',
      canSee: ['logisticsPrice', 'routes'],
      cannotSee: ['productPrice', 'recipe', 'items'],
    },
  ]

  testCases.forEach(({ role, canSee, cannotSee }) => {
    describe(`${role} role`, () => {
      canSee.forEach((field) => {
        it(`should see ${field}`, async () => {
          const result = await testQuery(role, SUPPLY_ORDER_QUERY)
          expect(result.data.supplyOrder[field]).toBeDefined()
        })
      })

      cannotSee.forEach((field) => {
        it(`should NOT see ${field}`, async () => {
          const result = await testQuery(role, SUPPLY_ORDER_QUERY)
          expect(result.data.supplyOrder[field]).toBeNull()
        })
      })
    })
  })
})
```

#### 5.2 Integration тесты

```typescript
// src/graphql/security/__tests__/integration.test.ts
describe('Supply chain security integration', () => {
  it('should isolate data between competitors', async () => {
    // Создаем двух селлеров-конкурентов
    const seller1 = await createTestSeller()
    const seller2 = await createTestSeller()

    // Seller1 создает поставку
    const supply1 = await createSupplyOrder(seller1, {
      productPrice: 1000,
      recipe: { services: ['Packing'] },
    })

    // Seller2 пытается получить доступ
    const result = await querySupplyOrder(seller2, supply1.id)

    expect(result.errors[0].message).toBe('Access denied')
  })

  it('should allow partners to see limited data', async () => {
    const seller = await createTestSeller()
    const wholesale = await createTestWholesale()
    const fulfillment = await createTestFulfillment()

    // Создаем партнерства
    await createPartnership(seller, wholesale)
    await createPartnership(seller, fulfillment)

    // Создаем поставку
    const supply = await createSupplyOrder(seller, {
      partnerId: wholesale.id,
      fulfillmentCenterId: fulfillment.id,
      productPrice: 1000,
      recipe: { services: ['Packing'] },
    })

    // Поставщик видит свою часть
    const wholesaleView = await querySupplyOrder(wholesale, supply.id)
    expect(wholesaleView.data.productPrice).toBe(1000)
    expect(wholesaleView.data.recipe).toBeNull()

    // Фулфилмент видит свою часть
    const fulfillmentView = await querySupplyOrder(fulfillment, supply.id)
    expect(fulfillmentView.data.productPrice).toBeNull()
    expect(fulfillmentView.data.recipe).toBeDefined()
  })
})
```

#### 5.3 Performance тесты

```typescript
// src/graphql/security/__tests__/performance.test.ts
describe('Security performance', () => {
  it('should not significantly impact query performance', async () => {
    const iterations = 100

    // Тест без фильтрации
    const withoutSecurity = await measurePerformance(async () => {
      await queryWithoutSecurity(COMPLEX_SUPPLY_QUERY)
    }, iterations)

    // Тест с фильтрацией
    const withSecurity = await measurePerformance(async () => {
      await queryWithSecurity(COMPLEX_SUPPLY_QUERY)
    }, iterations)

    const overhead = (withSecurity.avg - withoutSecurity.avg) / withoutSecurity.avg

    // Допустимый overhead - 15%
    expect(overhead).toBeLessThan(0.15)
  })
})
```

### Результаты фазы 5:

- ✅ Полное покрытие unit тестами
- ✅ Integration тесты проверяют изоляцию
- ✅ Performance overhead < 15%

## 🚀 ФАЗА 6: ОПТИМИЗАЦИЯ И ФИНАЛИЗАЦИЯ (2-3 дня)

### Цель:

Оптимизировать производительность и подготовить к production.

### Задачи:

#### 6.1 Кеширование фильтров

```typescript
// src/graphql/security/cache.ts
export class SecurityCache {
  private static cache = new LRUCache<string, FilteredData>({
    max: 1000,
    ttl: 5 * 60 * 1000, // 5 минут
  })

  static getCacheKey(resourceId: string, userId: string, organizationType: string): string {
    return `${resourceId}:${userId}:${organizationType}`
  }

  static get(key: string): FilteredData | undefined {
    return this.cache.get(key)
  }

  static set(key: string, data: FilteredData): void {
    this.cache.set(key, data)
  }
}
```

#### 6.2 Batch фильтрация

```typescript
// src/graphql/security/batch-filter.ts
export class BatchFilter {
  static async filterSupplyOrders(
    orders: SupplyOrder[],
    context: SecurityContext,
  ): Promise<FilteredData<SupplyOrder>[]> {
    // Группируем по типам доступа
    const grouped = this.groupByAccessLevel(orders, context)

    // Применяем фильтры параллельно
    const filtered = await Promise.all([
      this.filterFullAccess(grouped.full, context),
      this.filterPartialAccess(grouped.partial, context),
      this.filterNoAccess(grouped.none, context),
    ])

    return filtered.flat()
  }
}
```

#### 6.3 Документация для разработчиков

```typescript
/**
 * @example Использование безопасных резолверов
 *
 * // Для queries
 * export const mySecureQuery = createSecureResolver(
 *   async (parent, args, context) => {
 *     // Ваша логика
 *   },
 *   {
 *     resourceType: 'SUPPLY_ORDER',
 *     auditAction: 'VIEW_ORDERS'
 *   }
 * )
 *
 * // Для mutations
 * export const mySecureMutation = createSecureResolver(
 *   async (parent, args, context) => {
 *     // Ваша логика
 *   },
 *   {
 *     resourceType: 'SUPPLY_ORDER',
 *     requiredRole: ['SELLER', 'WHOLESALE'],
 *     auditAction: 'CREATE_ORDER'
 *   }
 * )
 */
```

### Результаты фазы 6:

- ✅ Performance оптимизирован
- ✅ Документация готова
- ✅ Готово к production

## 🔍 МОНИТОРИНГ И МЕТРИКИ

### Ключевые метрики для отслеживания:

```typescript
interface SecurityMetrics {
  // Performance метрики
  filteringOverhead: number // Процент замедления
  cacheHitRate: number // Эффективность кеша

  // Security метрики
  unauthorizedAccessAttempts: number // Попытки несанкц. доступа
  dataLeaksPrevented: number // Предотвращенные утечки

  // Business метрики
  affectedQueries: number // Количество затронутых запросов
  userComplaints: number // Жалобы пользователей
}
```

### Алерты:

```yaml
alerts:
  - name: high_unauthorized_access
    condition: rate(unauthorized_access) > 10/min
    severity: critical

  - name: performance_degradation
    condition: filtering_overhead > 25%
    severity: warning

  - name: audit_log_failure
    condition: audit_write_errors > 0
    severity: critical
```

## ✅ КОНТРОЛЬНЫЙ СПИСОК ГОТОВНОСТИ

### Перед каждой фазой:

- [ ] Feature flag настроен и протестирован
- [ ] Rollback план готов
- [ ] Метрики и логирование настроены
- [ ] Команда проинформирована

### Перед production:

- [ ] Все тесты проходят (unit, integration, e2e)
- [ ] Performance overhead < 15%
- [ ] Security review пройден
- [ ] Документация обновлена
- [ ] Мониторинг настроен
- [ ] Support команда обучена

### После deployment:

- [ ] Мониторинг метрик первые 24 часа
- [ ] Анализ логов на ошибки
- [ ] Feedback от пользователей
- [ ] Performance отчет

## 🚨 ПЛАН ОТКАТА

### Быстрый откат (< 5 минут):

```bash
# Отключение через environment
ENABLE_SUPPLY_SECURITY=false
ENABLE_SECURITY_AUDIT=false

# Перезапуск сервисов
kubectl rollout restart deployment/api-server
```

### Полный откат (< 30 минут):

```bash
# Откат к предыдущей версии
kubectl rollout undo deployment/api-server

# Откат миграции БД если нужно
npx prisma migrate resolve --rolled-back
```

## 📈 КРИТЕРИИ УСПЕХА

1. **Безопасность**: 0 утечек коммерческих данных
2. **Performance**: Overhead < 15%
3. **Стабильность**: 0 критических инцидентов
4. **UX**: 0 жалоб на недоступность данных
5. **Аудит**: 100% логирование критических операций

---

_План разработан с учетом минимизации рисков и постепенного внедрения_  
_Дата: 2025-08-22_  
_Estimated effort: 17-24 дня_  
_Risk level: MEDIUM с правильным подходом_
