w-funnel/AB_TESTING_IMPLEMENTATION.md
dev.daminik00 6c50d05123 ab
2025-10-21 01:27:08 +02:00

15 KiB
Raw Blame History

AB Testing Integration - Полная реализация

🎯 Задача

Интегрировать Unleash feature flags в систему воронок для проведения AB тестирования:

  • Возможность тестировать варианты экранов
  • Возможность тестировать разные пути навигации
  • UI в админке для настройки AB тестов
  • Полная типизация TypeScript

Что реализовано

1. 📦 Backend Infrastructure

Типы и интерфейсы (src/lib/funnel/types.ts)

// Расширен NavigationConditionDefinition
interface NavigationConditionDefinition {
  conditionType?: "options" | "values" | "unleash";  // ← Новый тип
  
  // Новые поля для Unleash
  unleashFlag?: string;        // Название флага
  unleashVariants?: string[];  // Ожидаемые варианты
}

Поддерживаемые операторы:

  • includesAny - хотя бы один вариант совпадает
  • includesAll - все варианты совпадают
  • includesExactly - только указанные варианты
  • equals - точное совпадение

Логика проверки условий

src/lib/funnel/navigation.ts:

export type UnleashChecker = (
  flag: string,
  expectedVariants: string[],
  operator?: "includesAny" | "includesAll" | "includesExactly" | "equals"
) => boolean;

function satisfiesCondition(
  condition: NavigationConditionDefinition,
  answers: FunnelAnswers,
  allScreens?: ScreenDefinition[],
  unleashChecker?: UnleashChecker  // ← Новый параметр
): boolean {
  if (conditionType === "unleash") {
    return unleashChecker(
      condition.unleashFlag,
      condition.unleashVariants,
      operator
    );
  }
  // ... остальная логика
}

src/lib/funnel/variants.ts:

export function resolveScreenVariant<T>(
  screen: T,
  answers: FunnelAnswers,
  allScreens?: ScreenDefinition[],
  unleashChecker?: UnleashChecker  // ← Новый параметр
): T {
  // Проверяет варианты с учетом Unleash условий
}

2. 🔌 Unleash SDK Integration

Provider (src/lib/funnel/unleash/UnleashProvider.tsx)

export function UnleashProvider({ children, userId, sessionId }) {
  // Инициализирует Unleash клиент
  // Если env переменные не заданы - graceful fallback
  
  const config = {
    url: process.env.NEXT_PUBLIC_UNLEASH_URL,
    clientKey: process.env.NEXT_PUBLIC_UNLEASH_CLIENT_KEY,
    context: {
      userId,
      sessionId: sessionId || userId || "anonymous",
    }
  };
  
  return <FlagProvider config={config}>{children}</FlagProvider>;
}

Context (src/lib/funnel/unleash/UnleashContext.tsx)

export function UnleashContextProvider({ 
  children, 
  activeVariants  // { "flag-name": "v1", ... }
}) {
  const checkVariant = (flag, expectedVariants, operator) => {
    // Проверяет соответствие текущего варианта ожидаемым
  };
  
  return (
    <UnleashContext.Provider value={{ activeVariants, checkVariant }}>
      {children}
    </UnleashContext.Provider>
  );
}

Wrapper (src/components/funnel/FunnelUnleashWrapper.tsx)

export function FunnelUnleashWrapper({ funnel, children }) {
  // 1. Сканирует все экраны воронки
  // 2. Находит все unleashFlag в conditions (variants + navigation)
  // 3. Получает варианты для всех флагов через useVariant
  // 4. Передает activeVariants в UnleashContextProvider
  
  const allFlags = useMemo(() => {
    // Собирает unique флаги из всех условий
  }, [funnel.screens]);
  
  const activeVariants = useMemo(() => {
    // Получает текущие варианты для всех флагов
  }, [flagsReady, flagVariants]);
}

Runtime Integration (src/components/funnel/FunnelRuntime.tsx)

export function FunnelRuntime({ funnel, initialScreenId }) {
  const { checkVariant } = useUnleashContext();
  
  // Создаем unleashChecker для передачи в navigation/variants
  const unleashChecker: UnleashChecker = useCallback(
    (flag, expectedVariants, operator) => {
      return checkVariant(flag, expectedVariants, operator);
    },
    [checkVariant]
  );
  
  // Передаем во все функции проверки
  resolveScreenVariant(baseScreen, answers, funnel.screens, unleashChecker);
  resolveNextScreenId(currentScreen, answers, funnel.screens, unleashChecker);
  estimatePathLength(funnel, answers, unleashChecker);
}

3. 🎨 Admin UI Components

Селектор типа условия (ConditionTypeSelector.tsx)

export function ConditionTypeSelector({ condition, onChange }) {
  return (
    <select value={conditionType} onChange={...}>
      <option value="options">Выбранные опции (list экраны)</option>
      <option value="values">Значения (зодиак, возраст, email)</option>
      <option value="unleash">AB тест (Unleash)</option>
    </select>
  );
}

Редактор Unleash условий (UnleashConditionEditor.tsx)

export function UnleashConditionEditor({ condition, onChange }) {
  return (
    <>
      {/* Название флага */}
      <Input 
        value={unleashFlag} 
        placeholder="trial-button-test"
        onChange={handleFlagChange}
      />
      
      {/* Оператор проверки */}
      <select value={operator} onChange={handleOperatorChange}>
        <option value="includesAny">Любой из вариантов (OR)</option>
        <option value="equals">Равен (один вариант)</option>
      </select>
      
      {/* Ожидаемые варианты */}
      <Input 
        value={unleashVariants.join(", ")}
        placeholder="v1, v2, v3"
        onChange={handleVariantsChange}
      />
    </>
  );
}

Интеграция в VariantConditionEditor

export function VariantConditionEditor({ condition, allScreens, onChange }) {
  const conditionType = condition.conditionType ?? "options";
  const isUnleashCondition = conditionType === "unleash";
  
  return (
    <>
      <ConditionTypeSelector 
        condition={condition} 
        onChange={handleConditionTypeChange} 
      />
      
      {isUnleashCondition ? (
        <UnleashConditionEditor condition={condition} onChange={onChange} />
      ) : (
        // Существующая логика для options/values
      )}
    </>
  );
}

4. 📚 Документация

  • AB_TESTING_GUIDE.md - Полное руководство (200+ строк)

    • Настройка environment
    • Примеры использования
    • API Reference
    • Best Practices
    • Troubleshooting
  • UNLEASH_SETUP.md - Quick Start

    • Быстрый старт за 4 шага
    • Структура файлов
    • Примеры
    • Требования
  • ab-test-example.json - Тестовая воронка

    • 6 экранов с разными типами AB тестов
    • Button text testing
    • Content variant testing
    • Navigation testing
    • Combined conditions (gender + AB test)

🚀 Использование

В админке

  1. Откройте экран для редактирования
  2. Перейдите в "Вариативность" → Добавить вариант
  3. В условиях выберите "AB тест (Unleash)"
  4. Укажите флаг и варианты
  5. Настройте overrides
  6. Сохраните

В JSON

{
  "variants": [
    {
      "conditions": [
        {
          "screenId": "payment",
          "conditionType": "unleash",
          "unleashFlag": "button-test",
          "unleashVariants": ["v1"],
          "operator": "equals"
        }
      ],
      "overrides": {
        "bottomActionButton": {
          "text": "New Button Text"
        }
      }
    }
  ]
}

Environment Setup

# .env.local
NEXT_PUBLIC_UNLEASH_URL=https://unleash.example.com/api/frontend
NEXT_PUBLIC_UNLEASH_CLIENT_KEY=your-key

📊 Возможности

Что можно тестировать

Варианты экранов:

  • Тексты (заголовки, подзаголовки, кнопки)
  • Контент (описания, иконки, блоки)
  • Любые поля через variants overrides

Навигация:

  • Разные пути через воронку
  • Длинный vs короткий onboarding
  • A/B тест целых flow

Комбинированные условия:

  • AB тест + пол пользователя
  • AB тест + возраст
  • AB тест + ответы на вопросы

Архитектура

┌─────────────────────────────────────┐
│   Unleash Dashboard                 │
│   (Feature Flags Config)            │
└─────────────────┬───────────────────┘
                  │
                  ▼
┌─────────────────────────────────────┐
│   UnleashProvider                   │
│   (@unleash/proxy-client-react)     │
└─────────────────┬───────────────────┘
                  │
                  ▼
┌─────────────────────────────────────┐
│   FunnelUnleashWrapper              │
│   - Сканирует воронку               │
│   - Собирает все флаги              │
│   - Получает варианты               │
└─────────────────┬───────────────────┘
                  │
                  ▼
┌─────────────────────────────────────┐
│   UnleashContextProvider            │
│   activeVariants: {                 │
│     "flag-1": "v1",                 │
│     "flag-2": "v2"                  │
│   }                                 │
└─────────────────┬───────────────────┘
                  │
                  ▼
┌─────────────────────────────────────┐
│   FunnelRuntime                     │
│   - unleashChecker: UnleashChecker  │
│   - resolveScreenVariant(...)       │
│   - resolveNextScreenId(...)        │
└─────────────────┬───────────────────┘
                  │
         ┌────────┴────────┐
         ▼                 ▼
    ┌─────────┐      ┌─────────┐
    │variants │      │navigation│
    │.ts      │      │.ts       │
    └─────────┘      └─────────┘

📁 Файлы

Новые файлы (14)

src/lib/funnel/unleash/
├── UnleashProvider.tsx          ✨ Unleash SDK wrapper
├── UnleashContext.tsx           ✨ React Context для вариантов
├── useUnleash.ts                ✨ Hooks для работы с флагами
└── index.ts                     ✨ Экспорты

src/components/funnel/
└── FunnelUnleashWrapper.tsx     ✨ Сборщик флагов из воронки

src/components/admin/builder/forms/
├── UnleashConditionEditor.tsx   ✨ UI редактор AB тестов
└── ConditionTypeSelector.tsx    ✨ Селектор типа условия

docs/
├── AB_TESTING_GUIDE.md          ✨ Полное руководство
├── UNLEASH_SETUP.md             ✨ Quick start
└── AB_TESTING_IMPLEMENTATION.md ✨ Этот файл

public/funnels/
└── ab-test-example.json         ✨ Тестовая воронка

package.json                     ✏️ +@unleash/proxy-client-react

Модифицированные файлы (6)

src/lib/funnel/
├── types.ts                     ✏️ +unleash поля в NavigationConditionDefinition
├── navigation.ts                ✏️ +UnleashChecker support
└── variants.ts                  ✏️ +UnleashChecker support

src/components/
├── funnel/FunnelRuntime.tsx     ✏️ +unleashChecker integration
└── admin/builder/forms/variants/
    └── VariantConditionEditor.tsx ✏️ +Unleash UI

src/app/[funnelId]/[screenId]/
└── page.tsx                     ✏️ +UnleashProvider wrapper

Проверка

Сборка

✓ npm run build
✓ No TypeScript errors
✓ No ESLint errors
✓ All pages compiled successfully

Тестирование

# 1. Запустите dev сервер
npm run dev

# 2. Откройте тестовую воронку
http://localhost:3000/ab-test-example/welcome

# 3. Проверьте разные варианты
# Откройте в нескольких вкладках - увидите разные версии

🎓 Примеры

Пример 1: Button Text AB Test

{
  "id": "payment",
  "bottomActionButton": { "text": "Continue" },
  "variants": [
    {
      "conditions": [{
        "conditionType": "unleash",
        "unleashFlag": "payment-button-test",
        "unleashVariants": ["variant-a"]
      }],
      "overrides": {
        "bottomActionButton": { "text": "Start Trial" }
      }
    }
  ]
}

Пример 2: Navigation AB Test

{
  "navigation": {
    "defaultNextScreenId": "long-flow",
    "rules": [{
      "conditions": [{
        "conditionType": "unleash",
        "unleashFlag": "onboarding-length",
        "unleashVariants": ["short"]
      }],
      "nextScreenId": "payment"
    }]
  }
}

Пример 3: Combined Conditions

{
  "variants": [{
    "conditions": [
      {
        "screenId": "gender",
        "conditionType": "options",
        "optionIds": ["female"]
      },
      {
        "conditionType": "unleash",
        "unleashFlag": "female-test",
        "unleashVariants": ["v1"]
      }
    ],
    "overrides": {
      "title": { "text": "Special for Women!" }
    }
  }]
}

🎯 Следующие шаги

  1. Настройте Unleash instance
  2. Создайте первые feature flags
  3. Добавьте AB тесты в существующие воронки
  4. Соберите метрики и выберите победителей
  5. Масштабируйте на все воронки

📞 Поддержка

  • Документация: AB_TESTING_GUIDE.md
  • Quick Start: UNLEASH_SETUP.md
  • Примеры: /public/funnels/ab-test-example.json
  • Unleash Docs: https://docs.getunleash.io/

Статус: Готово к production

Версия: 1.0.0

Дата: 2025-01-20