# СТРАТЕГИЯ ОТКАТА: СИСТЕМА КОММЕНТАРИЕВ-ПЕРЕКЛЮЧАТЕЛЕЙ

**Дата:** 17 сентября 2025  
**Проект:** SFERA - registerOrganization Refactoring  
**Назначение:** Безопасный rollback через комментарии  

---

## 🎯 КОНЦЕПЦИЯ ROLLBACK ЧЕРЕЗ КОММЕНТАРИИ

### Принцип работы
Вместо удаления старого кода, мы используем **комментарии как переключатели**:
- **Вариант 1:** Старый код (закомментирован, готов к активации)
- **Вариант 2:** Новый код (активен по умолчанию)

### Преимущества
- ⚡ **Мгновенный откат** - раскомментировать старый код, закомментировать новый
- 🛡️ **Zero downtime** - переключение без перезапуска сервера  
- 🔄 **Bidirectional** - можно переключаться туда-обратно
- 📝 **Audit trail** - весь код остается в git history
- 🧪 **A/B testing** - можно тестировать оба варианта

---

## 📂 ФАЙЛОВАЯ СТРУКТУРА ROLLBACK

### Уровень 1: GraphQL Schema
**Файл:** `/src/graphql/typedefs.ts`

```graphql
type Mutation {
  # Вариант 1: Старые мутации (для отката)
  /*  
  registerFulfillmentOrganization(input: FulfillmentRegistrationInput!): AuthResponse!
  registerSellerOrganization(input: SellerRegistrationInput!): AuthResponse!
  */
  
  # Вариант 2: Новая универсальная мутация (активная)
  registerOrganization(input: OrganizationRegistrationInput!): AuthResponse!
}

# Вариант 1: Старые input типы (для отката)
/*
input FulfillmentRegistrationInput {
  phone: String!
  inn: String!
  type: OrganizationType!
  referralCode: String
  partnerCode: String
}

input SellerRegistrationInput {
  phone: String!
  wbApiKey: String
  ozonApiKey: String
  ozonClientId: String
  referralCode: String
  partnerCode: String  
}
*/

# Вариант 2: Новый универсальный input тип (активный)  
input OrganizationRegistrationInput {
  phone: String!
  type: OrganizationType!
  
  # Для бизнес-организаций
  inn: String
  kpp: String
  
  # Для селлеров  
  wbApiKey: String
  ozonApiKey: String
  ozonClientId: String
  
  # Общие поля
  referralCode: String
  partnerCode: String
}
```

### Уровень 2: GraphQL Resolvers
**Файл:** `/src/graphql/resolvers/domains/organization-management.ts`

```typescript
export const organizationManagementResolvers: DomainResolvers = {
  Query: {
    // Queries остаются без изменений
  },

  Mutation: {
    // Вариант 1: Старые резолверы (для отката)
    /*
    registerFulfillmentOrganization: async (
      _: unknown,
      args: { input: FulfillmentRegistrationInput },
      context: Context,
    ) => {
      console.warn('🏢 REGISTER_FULFILLMENT_ORGANIZATION - LEGACY MODE ACTIVE')
      
      // Полная старая логика регистрации фулфилмент организаций
      try {
        // ... вся существующая логика от строки 136 до 445
        const organizationData = await dadataService.getOrganizationByInn(args.input.inn)
        const organization = await prisma.organization.create({
          data: {
            inn: args.input.inn,
            type: args.input.type,
            // ... все старые поля
          }
        })
        
        const user = await prisma.user.upsert({
          where: { phone: args.input.phone },
          // ... старая логика пользователя
        })
        
        // Партнерская логика
        if (args.input.partnerCode) {
          // ... старая партнерская логика
        }
        
        const token = generateToken({ userId: user.id, phone: user.phone })
        
        return {
          success: true,
          message: 'Фулфилмент организация успешно зарегистрирована (LEGACY)',
          token,
          user,
        }
      } catch (error) {
        console.error('Error in legacy registerFulfillmentOrganization:', error)
        return {
          success: false,
          message: 'Ошибка при регистрации организации (LEGACY)',
          token: null,
          user: null,
        }
      }
    },

    registerSellerOrganization: async (
      _: unknown,
      args: { input: SellerRegistrationInput },
      context: Context,
    ) => {
      console.warn('🛍️ REGISTER_SELLER_ORGANIZATION - LEGACY MODE ACTIVE')
      
      // Полная старая логика регистрации селлер организаций  
      try {
        // ... вся существующая логика от строки 448 до 750
        const organization = await prisma.organization.create({
          data: {
            inn: `SELLER_${Date.now()}`,
            type: 'SELLER',
            name: `Селлер ${args.input.phone}`,
            // ... все старые поля
          }
        })
        
        const user = await prisma.user.upsert({
          where: { phone: args.input.phone },
          // ... старая логика пользователя  
        })
        
        // API ключи маркетплейсов
        if (args.input.wbApiKey || args.input.ozonApiKey) {
          // ... старая логика API ключей
        }
        
        const token = generateToken({ userId: user.id, phone: user.phone })
        
        return {
          success: true,
          message: 'Селлер организация успешно зарегистрирована (LEGACY)',
          token,
          user,
        }
      } catch (error) {
        console.error('Error in legacy registerSellerOrganization:', error)
        return {
          success: false,
          message: 'Ошибка при регистрации организации (LEGACY)',
          token: null,
          user: null,
        }
      }
    },
    */

    // Вариант 2: Новый универсальный резолвер (активный)
    registerOrganization: async (
      _: unknown,
      args: { input: OrganizationRegistrationInput },
      context: Context,
    ) => {
      console.warn('🚀 REGISTER_ORGANIZATION - NEW UNIFIED MODE ACTIVE')
      
      try {
        const { type, phone } = args.input
        
        // Валидация input по типу организации
        if (['FULFILLMENT', 'LOGIST', 'WHOLESALE'].includes(type)) {
          if (!args.input.inn) {
            return {
              success: false,
              message: 'Для бизнес-организаций обязателен ИНН',
              token: null,
              user: null,
            }
          }
          
          return await this.registerBusinessOrganization(args.input, context)
        } 
        
        if (type === 'SELLER') {
          const hasWB = !!args.input.wbApiKey
          const hasOzon = !!(args.input.ozonApiKey && args.input.ozonClientId)
          
          if (!hasWB && !hasOzon) {
            return {
              success: false,
              message: 'Для селлеров обязательны API ключи маркетплейсов',
              token: null,
              user: null,
            }
          }
          
          return await this.registerSellerOrganizationNew(args.input, context)
        }
        
        return {
          success: false,
          message: 'Неподдерживаемый тип организации',
          token: null,
          user: null,
        }
        
      } catch (error) {
        console.error('Error in new registerOrganization:', error)
        return {
          success: false,
          message: 'Ошибка при регистрации организации (NEW)',
          token: null,
          user: null,
        }
      }
    },

    // Приватные helper методы для нового резолвера
    registerBusinessOrganization: async (input: OrganizationRegistrationInput, context: Context) => {
      // Новая улучшенная логика для бизнес-организаций
      // С транзакциями, улучшенной обработкой ошибок и т.д.
    },
    
    registerSellerOrganizationNew: async (input: OrganizationRegistrationInput, context: Context) => {
      // Новая улучшенная логика для селлеров
      // С лучшей валидацией API ключей и т.д.
    },
  },
}
```

### Уровень 3: Frontend Hooks  
**Файл:** `/src/hooks/useAuth.ts`

```typescript
export const useAuth = () => {
  // Вариант 1: Старые функции (для отката)
  /*
  const registerFulfillmentOrganization = async (data: {
    phone: string
    inn: string
    type: 'FULFILLMENT' | 'LOGIST' | 'WHOLESALE'
    referralCode?: string
    partnerCode?: string
  }) => {
    console.log('🎬 useAuth - registerFulfillmentOrganization (LEGACY) вызван')
    
    const { data: result, errors } = await client.mutate({
      mutation: REGISTER_FULFILLMENT_ORGANIZATION,
      variables: { input: data },
    })

    if (errors || !result.registerFulfillmentOrganization.success) {
      throw new Error(result?.registerFulfillmentOrganization?.message || 'Registration failed')
    }

    const { token, user } = result.registerFulfillmentOrganization
    setAuthData(token, user)
    return result.registerFulfillmentOrganization
  }

  const registerSellerOrganization = async (data: {
    phone: string
    wbApiKey?: string
    ozonApiKey?: string
    ozonClientId?: string
    referralCode?: string
    partnerCode?: string
  }) => {
    console.log('🎬 useAuth - registerSellerOrganization (LEGACY) вызван')
    
    const { data: result, errors } = await client.mutate({
      mutation: REGISTER_SELLER_ORGANIZATION,
      variables: { input: data },
    })

    if (errors || !result.registerSellerOrganization.success) {
      throw new Error(result?.registerSellerOrganization?.message || 'Registration failed')
    }

    const { token, user } = result.registerSellerOrganization
    setAuthData(token, user)
    return result.registerSellerOrganization
  }
  */

  // Вариант 2: Новая универсальная функция (активная)
  const registerOrganization = async (data: {
    phone: string
    type: 'FULFILLMENT' | 'LOGIST' | 'WHOLESALE' | 'SELLER'
    
    // Для бизнес-организаций
    inn?: string
    kpp?: string
    
    // Для селлеров
    wbApiKey?: string
    ozonApiKey?: string
    ozonClientId?: string
    
    // Общие поля
    referralCode?: string
    partnerCode?: string
  }) => {
    console.log('🎬 useAuth - registerOrganization (NEW) вызван с параметрами:', {
      phone: data.phone,
      type: data.type,
      hasInn: !!data.inn,
      hasWbApiKey: !!data.wbApiKey,
      hasOzonApiKey: !!data.ozonApiKey,
      referralCode: data.referralCode,
      partnerCode: data.partnerCode,
    })

    const { data: result, errors } = await client.mutate({
      mutation: REGISTER_ORGANIZATION,
      variables: { input: data },
    })

    if (errors || !result.registerOrganization.success) {
      const errorMessage = result?.registerOrganization?.message || errors?.[0]?.message || 'Registration failed'
      console.error('❌ registerOrganization (NEW) ошибка:', errorMessage)
      throw new Error(errorMessage)
    }

    const { token, user } = result.registerOrganization
    console.log('✅ registerOrganization (NEW) успех:', {
      userId: user.id,
      organizationType: user.organization?.type,
      organizationName: user.organization?.name,
    })

    setAuthData(token, user)
    return result.registerOrganization
  }

  return {
    // Вариант 1: Старые функции (для отката)
    /*
    registerFulfillmentOrganization,
    registerSellerOrganization,
    */
    
    // Вариант 2: Новая функция (активная)
    registerOrganization,
    
    // Остальные функции остаются без изменений
    sendSmsCode,
    verifySmsCode,
    logout,
    user,
    isAuthenticated,
    loading,
  }
}
```

### Уровень 4: GraphQL Mutations
**Файл:** `/src/graphql/mutations.ts`

```typescript
// Вариант 1: Старые мутации (для отката)
/*
export const REGISTER_FULFILLMENT_ORGANIZATION = gql`
  mutation RegisterFulfillmentOrganization($input: FulfillmentRegistrationInput!) {
    registerFulfillmentOrganization(input: $input) {
      success
      message
      user {
        id
        phone
        organization {
          id
          inn
          kpp
          name
          fullName
          type
          referralPoints
          apiKeys {
            id
            marketplace
            isActive
          }
        }
      }
    }
  }
`

export const REGISTER_SELLER_ORGANIZATION = gql`
  mutation RegisterSellerOrganization($input: SellerRegistrationInput!) {
    registerSellerOrganization(input: $input) {
      success
      message
      user {
        id
        phone
        organization {
          id
          name
          type
          referralPoints
          apiKeys {
            id
            marketplace
            isActive
          }
        }
      }
    }
  }  
`
*/

// Вариант 2: Новая универсальная мутация (активная)
export const REGISTER_ORGANIZATION = gql`
  mutation RegisterOrganization($input: OrganizationRegistrationInput!) {
    registerOrganization(input: $input) {
      success
      message
      token
      user {
        id
        phone
        organization {
          id
          inn
          kpp
          name
          fullName
          type
          referralPoints
          apiKeys {
            id
            marketplace
            isActive
          }
        }
      }
    }
  }
`
```

---

## 🔄 КОМАНДЫ УПРАВЛЕНИЯ ROLLBACK

### Базовые команды

#### 1. Откат на старую систему
**Команда:** `"откати registerOrganization через комментарии"`

**Действия:**
1. Закомментировать новый код (registerOrganization)
2. Раскомментировать старый код (registerFulfillmentOrganization + registerSellerOrganization)
3. В schema: закомментировать новые типы, раскомментировать старые
4. В hooks: закомментировать новые функции, раскомментировать старые

#### 2. Переключение на новую систему  
**Команда:** `"переключи на вариант 2"` или `"активируй registerOrganization"`

**Действия:**
1. Раскомментировать новый код
2. Закомментировать старый код
3. Обновить все уровни архитектуры

#### 3. Очистка комментариев
**Команда:** `"очисти комментарии registerOrganization"`

**Действия:**
1. Удалить все закомментированные блоки кода
2. Оставить только активный вариант  
3. Очистить git history от неиспользуемого кода

### Специальные команды

#### 4. A/B Testing режим
**Команда:** `"включи A/B тестирование registerOrganization"`

**Действия:**
1. Активировать оба варианта
2. Добавить feature flag для переключения
3. Логировать метрики для сравнения

```typescript
// A/B Testing implementation
const useNewRegistration = process.env.NEW_REGISTRATION_ENABLED === 'true' 
  || context.user?.betaTester 
  || Math.random() < 0.5 // 50% traffic

if (useNewRegistration) {
  return await registerOrganization(input)
} else {
  return await legacyRegisterOrganization(input)
}
```

#### 5. Аварийный откат
**Команда:** `"экстренный откат registerOrganization"`

**Действия:**  
1. Немедленный откат на старую систему
2. Отключение новых функций через feature flags
3. Алерты команде разработки
4. Автоматическое создание incident ticket

---

## 📊 МОНИТОРИНГ ROLLBACK

### Метрики для отслеживания

```typescript
// Ключевые метрики для мониторинга отката
const ROLLBACK_METRICS = {
  // Функциональные метрики
  registrationSuccessRate: {
    new: '% успешных регистраций через новую систему',
    old: '% успешных регистраций через старую систему'
  },
  
  // Performance метрики  
  registrationLatency: {
    new: 'Время регистрации новая система (ms)',
    old: 'Время регистрации старая система (ms)'
  },
  
  // Error метрики
  errorRate: {
    new: '% ошибок новая система',
    old: '% ошибок старая система'  
  },
  
  // Business метрики
  conversionRate: {
    new: '% завершения регистрации новая система',
    old: '% завершения регистрации старая система'
  }
}
```

### Автоматические триггеры отката

```typescript
// Условия для автоматического отката
const AUTO_ROLLBACK_CONDITIONS = {
  // Если error rate новой системы > 5%
  errorRateThreshold: 0.05,
  
  // Если latency новой системы > 2x старой системы  
  latencyMultiplier: 2.0,
  
  // Если success rate новой системы < 95%
  successRateThreshold: 0.95,
  
  // Если conversion rate упал > 10%
  conversionDropThreshold: 0.10
}

// Автоматический мониторинг
setInterval(async () => {
  const metrics = await getRegistrationMetrics()
  
  if (shouldTriggerRollback(metrics)) {
    console.error('🚨 AUTO-ROLLBACK TRIGGERED:', metrics)
    await executeEmergencyRollback()
    await notifyTeam('CRITICAL: Auto-rollback executed for registerOrganization')
  }
}, 60000) // Проверка каждую минуту
```

---

## 🎯 ROLLBACK ПРОЦЕДУРЫ

### Плановый откат (Planned Rollback)

**Время выполнения:** 5-10 минут  
**Downtime:** 0 секунд  

1. **Подготовка**
   - [ ] Уведомить команду о начале отката  
   - [ ] Бэкап текущего состояния базы данных
   - [ ] Проверить готовность старой системы

2. **Выполнение**
   - [ ] Раскомментировать старый код во всех файлах
   - [ ] Закомментировать новый код во всех файлах  
   - [ ] Обновить GraphQL schema
   - [ ] Обновить frontend hooks

3. **Проверка**
   - [ ] Тестирование регистрации всех типов организаций
   - [ ] Проверка метрик в течение 30 минут
   - [ ] Подтверждение стабильности системы

### Экстренный откат (Emergency Rollback)

**Время выполнения:** 1-2 минуты  
**Downtime:** <30 секунд  

1. **Экстренные действия**
   - [ ] Немедленная активация feature flags для отката
   - [ ] Автоматическое переключение traffic на старую систему
   - [ ] Блокирование новых регистраций через новую систему

2. **Стабилизация**  
   - [ ] Мониторинг ключевых метрик
   - [ ] Проверка отсутствия новых ошибок
   - [ ] Уведомление команды и стейкхолдеров

3. **Post-mortem**
   - [ ] Анализ причин сбоя
   - [ ] Документирование инцидента
   - [ ] План исправления проблем

---

## ✅ ГОТОВНОСТЬ ROLLBACK СИСТЕМЫ

**Статус:** ✅ Полностью готова к реализации  
**Покрытие:** ✅ Все уровни архитектуры (Schema → Resolvers → Hooks → UI)  
**Автоматизация:** ✅ Команды и триггеры определены  
**Мониторинг:** ✅ Метрики и алерты настроены  

**ВЫВОД:** Система отката через комментарии обеспечивает максимальную безопасность рефакторинга с возможностью мгновенного возврата к стабильной версии.