Files
sfera/referral-system-rules.md
Veronika Smirnova 8f7ec70fe6 Реализация реферальной системы и улучшение системы авторизации
- Добавлена полная реферальная система с GraphQL резолверами и UI компонентами
- Улучшена система регистрации с поддержкой ВКонтакте и реферальных ссылок
- Обновлена схема Prisma для поддержки реферальной системы
- Добавлены новые файлы документации правил системы
- Улучшена система партнерства и контрагентов
- Обновлены компоненты авторизации для поддержки новых функций
- Удален устаревший server.log

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-11 09:47:00 +03:00

619 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🎯 ПРАВИЛА РЕФЕРАЛЬНОЙ СИСТЕМЫ SFERA
⚠️ **КРИТИЧЕСКИ ВАЖНОЕ ПРАВИЛО: НЕ ПУТАТЬ "ПАРТНЁРСКИЕ ССЫЛКИ" И "РЕФЕРАЛЬНЫЕ ССЫЛКИ"**
> 📅 **Дата создания**: 2025-01-10
> 🔧 **Статус**: Спецификация для разработки
> 📌 **Версия**: 1.1
## 📋 ОГЛАВЛЕНИЕ
1. [Общие принципы](#1-общие-принципы)
2. [Структура данных](#2-структура-данных)
3. [Генерация реферальных ссылок](#3-генерация-реферальных-ссылок)
4. [UI/UX компоненты](#4-uiux-компоненты)
5. [Система начисления баллов](#5-система-начисления-баллов)
6. [GraphQL API](#6-graphql-api)
7. [Процесс регистрации по реферальной ссылке](#7-процесс-регистрации-по-реферальной-ссылке)
8. [Автоматическое партнерство через бизнес-сделки](#8-автоматическое-партнерство-через-бизнес-сделки)
9. [Безопасность и ограничения](#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)
```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
```prisma
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
#### Структура страницы
```tsx
<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
```graphql
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
```graphql
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 Расширение существующих типов
```graphql
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 Логика различения
```javascript
// В процессе регистрации
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 Алгоритм автопартнерства
```typescript
// В 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 Расширение модели данных
```prisma
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 Логирование автопартнерства
```typescript
// Лог события создания автопартнерства
{
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 Логирование
Все действия с реферальной системой логируются:
- Генерация ссылок
- Переходы по ссылкам
- Регистрации
- Начисления баллов
- Попытки злоупотреблений
---
## 🎨 ВИЗУАЛЬНЫЙ ДИЗАЙН
### Цветовая схема для сфер ⚡
- **Положительные начисления**: `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
**Статус**: Готово к реализации