# Система регистрации и верификации выигрышей ## Архитектура ### Модели данных #### 1. User (Расширенная) - `club_card_number` - номер клубной карты (уникальный идентификатор клиента) - `phone` - телефон для связи - `is_registered` - прошел ли полную регистрацию - `verification_code` - секретный код для подтверждения выигрыша (генерируется автоматически) #### 2. Account (Новая) - `account_number` - номер счета в формате XX-XX-XX-XX-XX-XX-XX - `owner_id` - владелец счета (связь с User через club_card_number) - `is_active` - активен ли счет #### 3. WinnerVerification (Новая) - `winner_id` - связь с Winner - `verification_token` - токен для подтверждения выигрыша - `is_verified` - подтвержден ли выигрыш - `expires_at` - срок действия токена (24 часа) ## Процессы ### 1. Регистрация пользователя **Инициатор:** Обычный пользователь через бота **Шаги:** 1. Пользователь отправляет `/start` 2. Бот проверяет `is_registered` 3. Если `False` - запрашивает: - Номер клубной карты - Телефон (опционально) 4. Генерируется `verification_code` (8-символьный уникальный код) 5. Код показывается пользователю: "Ваш код верификации: **AB12CD34**. Сохраните его!" 6. `is_registered = True` ### 2. Создание счета администратором **Инициатор:** Администратор **Формат команды:** ``` /add_account 2223 11-22-33-44-55-66-77 ``` **Процесс:** 1. Админ отправляет команду с номером КК и счетом 2. Бот находит пользователя по `club_card_number = 2223` 3. Создается запись в таблице `accounts`: ```python Account( account_number="11-22-33-44-55-66-77", owner_id=user.id, is_active=True ) ``` 4. Пользователю отправляется уведомление: ``` ✅ К вашему профилю добавлен счет: 11-22-33-44-55-66-77 ``` ### 3. Проведение розыгрыша с уведомлением победителей **Процесс:** 1. Администратор проводит розыгрыш 2. Выбирается случайный счет (например, `11-22-33-44-55-66-77`) 3. Система ищет владельца счета: ```python account = Account.query.filter_by(account_number="11-22-33-44-55-66-77").first() user = account.owner if account else None ``` 4. Создается запись `Winner` и `WinnerVerification`: ```python winner = Winner( lottery_id=lottery.id, user_id=user.id if user else None, account_number="11-22-33-44-55-66-77", place=1, prize="iPhone 15" ) verification = WinnerVerification( winner_id=winner.id, verification_token=generate_token(), expires_at=now + 24hours ) ``` 5. Если `user` найден - отправляется личное сообщение: ``` 🎉 ПОЗДРАВЛЯЕМ! Вы выиграли 1 место в розыгрыше "Новогодний розыгрыш"! 🏆 Приз: iPhone 15 📋 Ваш выигрышный счет: 11-22-33-44-55-66-77 ✅ Для подтверждения выигрыша: 1. Свяжитесь с администратором @admin_username 2. Сообщите ваш код верификации: AB12CD34 3. Администратор подтвердит ваш выигрыш в системе ⏰ Срок подтверждения: 24 часа ``` ### 4. Верификация выигрыша администратором **Сценарий:** 1. Победитель связывается с админом в личных сообщениях 2. Сообщает код верификации: `AB12CD34` 3. Админ проверяет код в боте: ``` /verify_winner AB12CD34 1 ``` где `1` - ID розыгрыша 4. Система: - Находит пользователя по `verification_code = "AB12CD34"` - Проверяет, что у него есть выигрыш в розыгрыше #1 - Помечает `winner.is_claimed = True` - Обновляет `verification.is_verified = True` 5. Победителю отправляется: ``` ✅ Ваш выигрыш подтвержден! Администратор свяжется с вами для получения приза. ``` ## Дополнительные механизмы безопасности ### 1. Двухфакторная верификация (опционально) Можно добавить отправку одноразового кода на телефон победителя. ### 2. Ограничение по времени Токены верификации действуют 24 часа. После истечения срока требуется повторная генерация. ### 3. Логирование Все действия с выигрышами логируются: - Создание выигрыша - Отправка уведомления - Подтверждение администратором - Получение приза ## API для админа ### Команды бота #### `/add_account ` Добавить счет к профилю клиента ``` /add_account 2223 11-22-33-44-55-66-77 ``` #### `/remove_account ` Деактивировать счет ``` /remove_account 11-22-33-44-55-66-77 ``` #### `/verify_winner ` Подтвердить выигрыш победителя ``` /verify_winner AB12CD34 1 ``` #### `/winner_status ` Показать статус всех победителей розыгрыша ``` /winner_status 1 Результаты: 1 место - @username (КК: 2223) ✅ Подтвержден 2 место - Счет: 33-44-55-66-77-88-99 ⏳ Ожидает подтверждения 3 место - @user2 (КК: 4445) ❌ Не подтвержден (истек срок) ``` ## Аналитика и отчеты ### Запросы для аналитики ```sql -- Победители по клубным картам SELECT u.club_card_number, u.first_name, COUNT(w.id) as total_wins, SUM(CASE WHEN w.is_claimed THEN 1 ELSE 0 END) as claimed_wins FROM users u JOIN winners w ON w.user_id = u.id GROUP BY u.id; -- Счета с наибольшим количеством участий SELECT a.account_number, u.club_card_number, COUNT(p.id) as participation_count FROM accounts a JOIN users u ON u.id = a.owner_id JOIN participations p ON p.account_id = a.id GROUP BY a.id, u.id ORDER BY participation_count DESC; -- Невостребованные выигрыши SELECT l.title, w.place, w.prize, w.account_number, u.club_card_number FROM winners w JOIN lotteries l ON l.id = w.lottery_id LEFT JOIN users u ON u.id = w.user_id WHERE w.is_claimed = false AND w.created_at < NOW() - INTERVAL '24 hours'; ``` ## Миграция существующих данных Если у вас уже есть данные в старой схеме: ```python # Миграция старых account_number из users в таблицу accounts async def migrate_accounts(): users = await session.execute(select(User).where(User.account_number != None)) for user in users.scalars(): account = Account( account_number=user.account_number, owner_id=user.id, is_active=True ) session.add(account) user.account_number = None # Очищаем старое поле await session.commit() ``` ## Тестирование ### Сценарий 1: Полный цикл выигрыша 1. Регистрация пользователя (КК: 2223) 2. Админ добавляет счет: `/add_account 2223 11-22-33-44-55-66-77` 3. Счет участвует в розыгрыше 4. Счет выигрывает 1 место 5. Пользователю приходит уведомление с кодом 6. Пользователь связывается с админом, сообщает код 7. Админ подтверждает: `/verify_winner AB12CD34 1` 8. Выигрыш получен ✅ ### Сценарий 2: Выигрыш незарегистрированного счета 1. Админ добавляет счет без владельца 2. Счет участвует и выигрывает 3. Бот показывает в публичном объявлении: "Счет 11-22-33-44-55-66-77 выиграл!" 4. Владелец счета регистрируется в боте 5. Админ привязывает счет к владельцу 6. Дальше стандартная процедура верификации