Files
sfera/partners-rules.md
Veronika Smirnova 6b425d075f Унификация UI раздела Партнеры и создание системы документирования
🎨 Унификация UI:
- Полная унификация визуала вкладок Рефералы и Мои контрагенты
- Исправлены React Hooks ошибки в sidebar.tsx
- Убрана лишняя обертка glass-card в partners-dashboard.tsx
- Исправлена цветовая схема (purple → yellow)
- Табличный формат вместо карточного grid-layout
- Компактные блоки статистики (4 метрики в ряд)
- Правильная прозрачность glass-morphism эффектов

📚 Документация:
- Переименован referral-system-rules.md → partners-rules.md
- Детальные UI/UX правила в partners-rules.md
- Правила унификации в visual-design-rules.md
- Обновлен current-session.md
- Создан development-diary.md

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-11 15:38:23 +03:00

30 KiB
Raw Blame History

🎯 ПРАВИЛА РЕФЕРАЛЬНОЙ СИСТЕМЫ SFERA

⚠️ КРИТИЧЕСКИ ВАЖНОЕ ПРАВИЛО: НЕ ПУТАТЬ "ПАРТНЁРСКИЕ ССЫЛКИ" И "РЕФЕРАЛЬНЫЕ ССЫЛКИ"

📅 Дата создания: 2025-01-10
🔧 Статус: Спецификация для разработки
📌 Версия: 1.1

📋 ОГЛАВЛЕНИЕ

  1. Общие принципы
  2. Структура данных
  3. Генерация реферальных ссылок
  4. UI/UX компоненты
  5. Система начисления баллов
  6. GraphQL API
  7. Процесс регистрации по реферальной ссылке
  8. Автоматическое партнерство через бизнес-сделки
  9. Безопасность и ограничения

1. ОБЩИЕ ПРИНЦИПЫ

1.1 Основные положения

  • УНИВЕРСАЛЬНОСТЬ: Реферальная система доступна для всех типов кабинетов (SELLER, WHOLESALE, FULFILLMENT, LOGIST)
  • АВТОМАТИЗАЦИЯ: Реферальная ссылка генерируется автоматически при создании организации
  • ПРОЗРАЧНОСТЬ: Все начисления сфер видны в режиме реального времени
  • БЕЗОПАСНОСТЬ: Невозможно изменить реферальную ссылку после генерации
  • ИНТЕГРАЦИЯ С БИЗНЕСОМ: Партнерство создается не только через рефералы, но и через коммерческие сделки

1.2 Терминология

  • РЕФЕРЕР - организация, которая приглашает новых участников
  • РЕФЕРАЛ - организация, зарегистрированная по реферальной ссылке
  • РЕФЕРАЛЬНЫЙ КОД - уникальный идентификатор в ссылке (10 символов)
  • СФЕРЫ - единица вознаграждения за привлечение рефералов и коммерческие сделки
  • АВТОПАРТНЕРСТВО - автоматическое создание партнерских связей при коммерческих сделках
  • РЕФЕРАЛЬНАЯ ССЫЛКА - маркетинговый инструмент (?ref=), только начисление сфер
  • ПАРТНЕРСКАЯ ССЫЛКА - бизнес-инструмент (?partner=), сферы + автоматическое партнерство

1.3 Разделение ссылок

Реферальная система (маркетинг):

  • URL формат: https://app.sfera.ru/register?ref=SF2X9K4M7P
  • Местоположение: Вкладка "Рефералы"
  • Цель: Привлечение новых пользователей на платформу
  • Результат: +100 сфер , автоматического партнерства НЕТ
  • Ссылка: Уже готова при создании организации, быстрое копирование

Партнерская система (бизнес):

  • URL формат: https://app.sfera.ru/register?partner=SF2X9K4M7P
  • Местоположение: Вкладка "Мои партнеры"
  • Цель: Прямое деловое сотрудничество
  • Результат: +100 сфер + автоматическое добавление в партнеры
  • Ссылка: Уже готова при создании организации, быстрое копирование

2. СТРУКТУРА ДАННЫХ

2.1 Расширение модели Organization (Prisma)

model Organization {
  // Существующие поля...
  
  // Реферальная система
  referralCode      String?   @unique @default(cuid()) // Уникальный код для реферальной ссылки
  referredById      String?   // ID организации-реферера
  referredBy        Organization? @relation("ReferralRelation", fields: [referredById], references: [id])
  referrals         Organization[] @relation("ReferralRelation")
  referralPoints    Int       @default(0) // Общее количество баллов
  
  @@index([referralCode])
  @@index([referredById])
}

2.2 Новая модель ReferralTransaction

model ReferralTransaction {
  id              String       @id @default(cuid())
  referrerId      String       // Кто получил баллы
  referralId      String       // За кого получил баллы
  points          Int          // Количество баллов
  type            ReferralTransactionType // Тип транзакции
  description     String?      // Описание транзакции
  createdAt       DateTime     @default(now())
  
  referrer        Organization @relation("ReferrerTransactions", fields: [referrerId], references: [id])
  referral        Organization @relation("ReferralTransactions", fields: [referralId], references: [id])
  
  @@index([referrerId, createdAt])
  @@index([referralId])
}

enum ReferralTransactionType {
  REGISTRATION     // За регистрацию по реферальной ссылке
  AUTO_PARTNERSHIP // За автоматическое партнерство через бизнес-сделку
  FIRST_ORDER      // За первый заказ (будущее расширение)
  MONTHLY_BONUS    // Ежемесячный бонус (будущее расширение)
}

3. ГЕНЕРАЦИЯ РЕФЕРАЛЬНЫХ ССЫЛОК

3.1 Формат реферальной ссылки

https://app.sfera.ru/register?ref={referralCode}

3.2 Алгоритм генерации кода

  • Длина: 10 символов
  • Символы: A-Z, 0-9 (исключая похожие: O/0, I/1)
  • Пример: SF2X9K4M7P

3.3 Правила генерации

  • Генерируется автоматически при создании организации
  • Проверка уникальности перед сохранением
  • Невозможно изменить после создания
  • Хранится в поле referralCode модели Organization

4. UI/UX КОМПОНЕНТЫ

4.1 Вкладка "Рефералы" в разделе Партнеры

Расположение

  • Раздел: /partners
  • Новая вкладка: 6-я позиция после "Поставщик"
  • Название: "Рефералы"
  • Иконка: Gift или Users2 из lucide-react

Структура страницы

<div className="referrals-page">
  {/* Блок с реферальной ссылкой */}
  <div className="referral-link-section glass-card p-6 mb-6">
    <h3>Ваша реферальная ссылка</h3>
    <div className="flex items-center gap-4">
      <div className="hidden-link">••••••••••</div>
      <Button onClick={copyLink}>
        <Copy className="h-4 w-4 mr-2" />
        Копировать ссылку
      </Button>
    </div>
    <p className="text-sm text-white/60 mt-2">
      Поделитесь ссылкой с партнерами и получайте баллы за каждую регистрацию
    </p>
  </div>

  {/* Статистика */}
  <div className="stats-grid grid grid-cols-4 gap-4 mb-6">
    <StatsCard title="Всего партнеров" value={totalReferrals} icon="Users" />
    <StatsCard title="Сфер заработано" value={totalPoints} icon="Zap" suffix="⚡" />
    <StatsCard title="Партнеров за месяц" value={monthlyReferrals} icon="TrendingUp" />
    <StatsCard title="Сфер за месяц" value={monthlyPoints} icon="Zap" suffix="⚡" />
  </div>

  {/* Фильтры */}
  <div className="filters glass-card p-4 mb-6">
    <DateRangePicker />
    <TypeFilter types={['SELLER', 'WHOLESALE', 'FULFILLMENT', 'LOGIST']} />
    <SearchInput placeholder="Поиск по названию или ИНН" />
  </div>

  {/* Таблица рефералов */}
  <div className="referrals-table glass-card">
    <Table>
      <TableHeader>
        <TableRow>
          <TableHead>Дата регистрации</TableHead>
          <TableHead>Название организации</TableHead>
          <TableHead>ИНН</TableHead>
          <TableHead>Тип кабинета</TableHead>
          <TableHead>Источник</TableHead>
          <TableHead>Начислено сфер </TableHead>
          <TableHead>Статус</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        {referrals.map(referral => (
          <TableRow key={referral.id}>
            <TableCell>{formatDate(referral.createdAt)}</TableCell>
            <TableCell>{referral.name || referral.fullName}</TableCell>
            <TableCell>{referral.inn}</TableCell>
            <TableCell>
              <Badge className={getTypeBadgeStyles(referral.type)}>
                {getTypeLabel(referral.type)}
              </Badge>
            </TableCell>
            <TableCell>
              <div className="flex items-center gap-2">
                {referral.source === 'REFERRAL' ? (
                  <>
                    <UserPlus className="h-4 w-4 text-blue-400" />
                    <span className="text-blue-300">Реферальная ссылка</span>
                  </>
                ) : (
                  <>
                    <ShoppingCart className="h-4 w-4 text-orange-400" />
                    <span className="text-orange-300">Бизнес-сделка</span>
                  </>
                )}
              </div>
            </TableCell>
            <TableCell>
              <div className="flex items-center gap-1">
                <span className="text-green-400">+{referral.points}</span>
                <Zap className="h-4 w-4 text-yellow-400" />
              </div>
            </TableCell>
            <TableCell>
              <Badge variant="success">Активен</Badge>
            </TableCell>
          </TableRow>
        ))}
      </TableBody>
    </Table>
  </div>
</div>

4.2 Визуальные элементы

Скрытие реферальной ссылки

  • Ссылка НЕ отображается в явном виде
  • Показываются точки или звездочки: ••••••••••
  • Только кнопка "Копировать ссылку"

Уведомления

  • При копировании: "Реферальная ссылка скопирована"
  • При новом реферале: push-уведомление
  • При начислении баллов: анимация изменения баланса

5. СИСТЕМА НАЧИСЛЕНИЯ БАЛЛОВ

5.1 Базовые ставки

Тип регистрации Количество баллов
SELLER 100 сфер
WHOLESALE 100 сфер
FULFILLMENT 100 сфер
LOGIST 100 сфер

💡 ИКОНКА СФЕРЫ: (молния) - символизирует энергию, скорость и силу партнерства

5.2 Правила начисления

  • МОМЕНТ НАЧИСЛЕНИЯ: Сразу после успешной регистрации реферала
  • УСЛОВИЕ: Реферал должен пройти полную регистрацию (подтвердить ИНН)
  • ОГРАНИЧЕНИЯ: Один ИНН = одно начисление (защита от дублей)
  • ВИДИМОСТЬ: Баллы сразу отображаются в таблице и общем счетчике

5.3 Будущие расширения

  • Бонусы за первый заказ реферала
  • Ежемесячные начисления за активных рефералов
  • Многоуровневая система (рефералы рефералов)

6. GRAPHQL API

6.1 Новые Queries

type Query {
  # Получить мою реферальную ссылку
  myReferralLink: String!
  
  # Список моих рефералов
  myReferrals(
    dateFrom: DateTime
    dateTo: DateTime
    type: OrganizationType
    search: String
    limit: Int
    offset: Int
  ): ReferralsResponse!
  
  # Статистика по рефералам
  myReferralStats: ReferralStats!
  
  # История транзакций баллов
  myReferralTransactions(
    limit: Int
    offset: Int
  ): ReferralTransactionsResponse!
}

6.2 Новые Types

type ReferralsResponse {
  referrals: [Referral!]!
  totalCount: Int!
  totalPages: Int!
}

type Referral {
  id: ID!
  organization: Organization!
  registeredAt: DateTime!
  pointsEarned: Int!
  status: ReferralStatus!
  transactions: [ReferralTransaction!]!
}

type ReferralStats {
  totalReferrals: Int!
  totalPoints: Int!
  monthlyReferrals: Int!
  monthlyPoints: Int!
  referralsByType: [ReferralTypeStats!]!
}

type ReferralTypeStats {
  type: OrganizationType!
  count: Int!
  points: Int!
}

type ReferralTransaction {
  id: ID!
  points: Int!
  type: ReferralTransactionType!
  description: String
  createdAt: DateTime!
  referral: Organization!
}

enum ReferralStatus {
  ACTIVE
  INACTIVE
  BLOCKED
}

6.3 Расширение существующих типов

extend type Organization {
  referralCode: String
  referredBy: Organization
  referrals: [Organization!]!
  referralPoints: Int!
  isMyReferral: Boolean! # Computed field
}

7. ПРОЦЕСС РЕГИСТРАЦИИ ПО ССЫЛКАМ

7.1 Реферальная ссылка (маркетинг)

Пошаговый процесс:

  1. Переход по ссылке

    • Пользователь переходит по ссылке: https://app.sfera.ru/register?ref=SF2X9K4M7P
    • Система сохраняет реферальный код в sessionStorage
  2. Регистрация

    • Стандартный процесс регистрации
    • Реферальный код передается в mutation registerOrganization
  3. Валидация

    • Проверка существования реферального кода
    • Проверка, что организация не регистрировалась ранее
  4. Создание связи

    • Установка referredById для новой организации
    • Создание записи в ReferralTransaction
    • ВАЖНО: Автоматическое партнерство НЕ создается
  5. Начисление баллов

    • Автоматическое начисление 100 сфер рефереру
    • Отправка уведомления рефереру

7.2 Партнерская ссылка (бизнес)

Пошаговый процесс:

  1. Переход по ссылке

    • Пользователь переходит по ссылке: https://app.sfera.ru/register?partner=SF2X9K4M7P
    • Система сохраняет партнерский код в sessionStorage
  2. Регистрация

    • Стандартный процесс регистрации
    • Партнерский код передается в mutation registerOrganization
  3. Валидация

    • Проверка существования партнерского кода
    • Проверка, что организация не регистрировалась ранее
  4. Создание связи

    • Установка referredById для новой организации
    • Создание записи в ReferralTransaction
    • ВАЖНО: Автоматическое создание партнерства (Counterparty)
  5. Начисление баллов

    • Автоматическое начисление 100 сфер партнеру
    • Отправка уведомления партнеру
    • Добавление в список "Мои партнеры"

7.3 Логика различения

// В процессе регистрации
if (query.ref) {
  // Реферальная ссылка - только сферы
  await addReferralTransaction(referrerId, newUserId, 100, 'REFERRAL_LINK')
} else if (query.partner) {
  // Партнерская ссылка - сферы + автоматическое партнерство  
  await addReferralTransaction(partnerId, newUserId, 100, 'REFERRAL_LINK')
  await createPartnership(partnerId, newUserId, 'REFERRAL')
}

7.4 Обработка ошибок

  • Невалидный код: Регистрация продолжается без реферала/партнерства
  • Самореферал: Блокировка (нельзя регистрироваться по своей ссылке)
  • Повторная регистрация: Игнорирование кода

8. АВТОМАТИЧЕСКОЕ ПАРТНЕРСТВО ЧЕРЕЗ БИЗНЕС-СДЕЛКИ

8.1 Принцип работы

Кроме реферальных ссылок, партнерские отношения создаются автоматически через коммерческие взаимодействия в системе.

8.2 Триггер автопартнерства

МОМЕНТ СОЗДАНИЯ ПАРТНЕРСТВА: Когда поставщик одобряет заявку на поставку (supplierApproveOrder mutation)

УСЛОВИЕ: Если между организациями еще нет партнерских отношений (Counterparty связи)

ДЕЙСТВИЕ: Автоматическое создание взаимного партнерства

8.3 Алгоритм автопартнерства

// В GraphQL резолвере supplierApproveOrder
async supplierApproveOrder(supplyOrderId: string) {
  // 1. Одобрить заявку
  const supplyOrder = await updateSupplyOrderStatus(supplyOrderId, 'SUPPLIER_APPROVED')
  
  // 2. Проверить существование партнерства
  const existingCounterparty = await checkCounterpartyExists(
    supplyOrder.organizationId, // Покупатель
    supplyOrder.partnerId       // Поставщик
  )
  
  // 3. Создать автопартнерство если его нет
  if (!existingCounterparty) {
    await createAutoCounterparty({
      organizationId: supplyOrder.organizationId,
      counterpartyId: supplyOrder.partnerId,
      type: 'AUTO_BUSINESS',
      triggeredBy: 'SUPPLY_ORDER_APPROVAL',
      supplyOrderId: supplyOrderId
    })
  }
  
  return supplyOrder
}

8.4 Расширение модели данных

model Counterparty {
  // Существующие поля...
  
  // Новые поля для автопартнерства
  type              CounterpartyType   @default(MANUAL)
  triggeredBy       String?            // 'SUPPLY_ORDER_APPROVAL', 'REFERRAL_LINK'
  triggerEntityId   String?            // ID заявки, реферала и т.д.
  
  @@index([type])
}

enum CounterpartyType {
  MANUAL        // Создано вручную через UI
  REFERRAL      // Создано через реферальную ссылку
  AUTO_BUSINESS // Создано автоматически через бизнес-сделку
}

8.5 Начисление сфер за автопартнерство

ДЛЯ ПОСТАВЩИКА (кто одобрил заявку):

  • +100 сфер за каждого нового партнера через бизнес-сделку
  • Равно рефералу, так как это также ценное партнерство

ДЛЯ ПОКУПАТЕЛЯ:

  • Партнерство создается, но сферы не начисляются
  • Выгода в том, что появляется прямая связь с поставщиком

8.6 Отображение в UI

В таблице рефералов добавить колонку "Источник":

Источник Описание Иконка
Реферальная ссылка Зарегистрировались по вашей ссылке UserPlus
Бизнес-сделка Стали партнерами через заказ ShoppingCart

8.7 Логирование автопартнерства

// Лог события создания автопартнерства
{
  event: 'auto_counterparty_created',
  supplierId: '...',
  buyerId: '...',
  supplyOrderId: '...',
  spheresEarned: 50,
  timestamp: '2025-01-10T15:30:00Z'
}

9. БЕЗОПАСНОСТЬ И ОГРАНИЧЕНИЯ

9.1 Защита от злоупотреблений

  • Один ИНН - одна регистрация: Проверка уникальности ИНН
  • Блокировка самореферала: Проверка IP и device fingerprint
  • Лимиты: Максимум 100 регистраций в день с одного реферального кода
  • Валидация ИНН: Обязательная проверка через DaData API

9.2 Права доступа

  • Просмотр своих рефералов: Только владелец реферального кода
  • Изменение кода: Запрещено
  • Просмотр чужих рефералов: Запрещено
  • Администратор: Полный доступ для модерации

9.3 Логирование

Все действия с реферальной системой логируются:

  • Генерация ссылок
  • Переходы по ссылкам
  • Регистрации
  • Начисления баллов
  • Попытки злоупотреблений

🎨 UI/UX ПРАВИЛА РАЗДЕЛА "ПАРТНЕРЫ"

10.1 Принципы унификации интерфейса

КРИТИЧЕСКИ ВАЖНО: Все вкладки раздела "Партнеры" должны иметь единый визуальный дизайн:

Обязательная унификация:

  • Идентичная структура блоков статистики: 4 метрики в ряд
  • Одинаковые цветовые схемы для аналогичных элементов
  • Табличный формат отображения данных вместо карточного grid-layout
  • Компактное использование пространства

Структура DOM для блоков статистики:

{/* ПРАВИЛЬНАЯ структура */}
<div className="grid grid-cols-4 gap-3">
  <Card className="glass-card p-3 hover:bg-white/5 transition-all duration-200">
    <div className="p-1.5 rounded-lg bg-{color}-500/20 border border-{color}-500/30">
      <Icon className="h-4 w-4 text-{color}-400" />
    </div>
  </Card>
</div>

{/* ЗАПРЕЩЕНО - дополнительные обертки */}
<Card className="glass-card"> 
  <div className="grid grid-cols-4 gap-3">
    <div>...</div> // <- НЕ glass-card внутри glass-card!
  </div>
</Card>

10.2 Техническая реализация

A) Вкладка "Рефералы":

  • Файл: src/components/partners/referrals-tab.tsx
  • Структура: Каждый блок статистики = отдельный <Card className="glass-card">
  • Прозрачность: Через glass-morphism эффекты
  • Отступы: Компактные (p-3, p-4)

B) Вкладка "Мои контрагенты":

  • Файл: src/components/market/market-counterparties.tsx
  • Структура: Конвертирована от карточного grid к табличному формату
  • Блоки статистики: Добавлены 4 компактных блока (Партнеров, Заявок, За месяц, Исходящих)
  • Обертки: УБРАНА лишняя обертка glass-card в partners-dashboard.tsx

10.3 Цветовая схема блоков

Реферальные/Партнерские ссылки (верхний блок):

  • Цвет: bg-yellow-500/20 border border-yellow-500/30
  • Иконка: text-yellow-400
  • ЗАПРЕЩЕНО: Использовать фиолетовую схему (bg-purple-500/20)

Блоки статистики:

  • 1-й блок (Партнеров): bg-blue-500/20 + text-blue-400 (синий)
  • 2-й блок (Заработано/Заявок): bg-yellow-500/20 + text-yellow-400 (желтый)
  • 3-й блок (За месяц): bg-green-500/20 + text-green-400 (зеленый)
  • 4-й блок (Сфер за месяц/Исходящих): bg-yellow-500/20 + text-yellow-400 (желтый)

10.4 Компоненты и размеры

Оптимизация пространства:

  • Отступы карточек: p-4 для верхнего блока, p-3 для статистики
  • Размеры иконок: h-4 w-4 (компактно)
  • Шрифты заголовков: text-base вместо text-2xl
  • Отступы между блоками: space-y-4

Hover эффекты:

  • Блоки статистики: hover:bg-white/5 transition-all duration-200
  • Кнопки: glass-button hover:bg-white/20

10.5 Исправления структурных проблем

КРИТИЧЕСКИ ВАЖНЫЕ исправления:

  1. Убрана лишняя обертка в src/components/partners/partners-dashboard.tsx:

    // БЫЛО (неправильно):
    <TabsContent value="counterparties">
      <Card className="glass-card"> // <- ЛИШНЯЯ обертка!
        <MarketCounterparties />
      </Card>
    </TabsContent>
    
    // СТАЛО (правильно):
    <TabsContent value="counterparties">
      <MarketCounterparties />
    </TabsContent>
    
  2. Исправлена цветовая схема верхнего блока в контрагентах:

    // БЫЛО: bg-purple-500/20 text-purple-400
    // СТАЛО: bg-yellow-500/20 text-yellow-400
    

10.6 Результат унификации

После применения правил:

  • Идентичная прозрачность блоков (glass-morphism)
  • Единая цветовая схема между вкладками
  • Компактное использование пространства
  • Табличный формат во всех вкладках
  • Консистентная структура DOM

🎨 ВИЗУАЛЬНЫЙ ДИЗАЙН

Цветовая схема для сфер

  • Положительные начисления: text-green-400
  • Иконка молнии: text-yellow-400 (золотистый)
  • Фон для сфер: bg-yellow-500/20
  • Анимация при изменении: animate-pulse на 2 секунды

Иконки источников партнерства

  • Реферальная ссылка: UserPlus в text-blue-400
  • Бизнес-сделка: ShoppingCart в text-orange-400
  • Сферы: Zap в text-yellow-400

Стили для типов кабинетов (соответствуют существующим)

  • SELLER: bg-green-500/20 text-green-300
  • WHOLESALE: bg-purple-500/20 text-purple-300
  • FULFILLMENT: bg-blue-500/20 text-blue-300
  • LOGIST: bg-orange-500/20 text-orange-300

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

  • Конверсия: % регистраций по реферальным ссылкам
  • Активность: Среднее количество рефералов на одного партнера
  • Retention: % активных рефералов через 30 дней
  • Виральность: Количество рефералов, которые сами привели рефералов

🚀 ПЛАН ВНЕДРЕНИЯ

Фаза 1 (MVP)

  • Базовая генерация ссылок
  • Регистрация по реферальным ссылкам
  • Начисление баллов за регистрацию
  • UI для просмотра рефералов

Фаза 2

  • Бонусы за первый заказ
  • Email уведомления о новых рефералах
  • Экспорт данных о рефералах

Фаза 3

  • Многоуровневая система
  • Использование баллов для оплаты услуг
  • Gamification элементы (достижения, уровни)

Дата создания: 2025-01-10
Автор: Claude AI Assistant
Статус: Готово к реализации