Files
new_lottery_bot/docs/ACCOUNT_BASED_CONFIRMATION.md
Andrew K. Choi 388c4e8aad
All checks were successful
continuous-integration/drone/push Build is passing
Пересборка клавиатур, рефакторинг чата
2026-02-13 20:03:44 +09:00

11 KiB
Raw Blame History

Подтверждение выигрышей по счетам

🎯 Концепция

Система подтверждения выигрышей работает на уровне счетов, а не пользователей.

Основные принципы:

  1. Один пользователь = Много счетов

    • У клиента может быть несколько счетов (11-22-33..., 44-55-66..., и т.д.)
    • Каждый счет участвует в розыгрыше независимо
  2. Один счет = Один выигрыш = Одно подтверждение

    • Если счет 11-22-33-44-55-66-77 выиграл 1 место - требуется подтверждение
    • Если счет 44-55-66-77-88-99-00 выиграл 3 место - требуется отдельное подтверждение
    • Даже если оба счета принадлежат одному клиенту
  3. Независимое подтверждение

    • Каждый выигрышный счет подтверждается отдельной кнопкой
    • Подтверждение одного счета не влияет на другие
    • У каждого счета свой 24-часовой лимит

📱 Как это работает для пользователя

Сценарий: У клиента 3 счета, выиграли 2

Счета клиента:

  • 11-22-33-44-55-66-77 Выиграл 1 место (iPhone 15)
  • 22-33-44-55-66-77-88 Не выиграл
  • 33-44-55-66-77-88-99 Выиграл 3 место (AirPods Pro)

Клиент получает 2 сообщения:

Сообщение 1:

🎉 Поздравляем! Ваш счет выиграл!

🎯 Розыгрыш: Новогодний розыгрыш
🏆 Место: 1
🎁 Приз: iPhone 15
💳 Выигрышный счет: 11-22-33-44-55-66-77

⏰ У вас есть 24 часа для подтверждения!

Нажмите кнопку ниже, чтобы подтвердить получение приза по этому счету.
Если вы не подтвердите в течение 24 часов, приз будет разыгран заново.

 Если у вас несколько выигрышных счетов, подтвердите каждый из них отдельно.

[✅ Подтвердить счет 11-22-33-44-55-66-77]
[📞 Связаться с администратором]

Сообщение 2:

🎉 Поздравляем! Ваш счет выиграл!

🎯 Розыгрыш: Новогодний розыгрыш
🏆 Место: 3
🎁 Приз: AirPods Pro
💳 Выигрышный счет: 33-44-55-66-77-88-99

⏰ У вас есть 24 часа для подтверждения!

[✅ Подтвердить счет 33-44-55-66-77-88-99]
[📞 Связаться с администратором]

Действия клиента:

  1. Нажимает первую кнопку → Счет 11-22-33-44-55-66-77 подтвержден
  2. Нажимает вторую кнопку → Счет 33-44-55-66-77-88-99 подтвержден

🔒 Безопасность

Проверка владения счетом

При нажатии кнопки подтверждения система проверяет:

# Получаем владельца КОНКРЕТНОГО счета
owner = await AccountService.get_account_owner(session, winner.account_number)

# Проверяем что текущий пользователь - владелец ЭТОГО счета
if not owner or owner.telegram_id != callback.from_user.id:
    await callback.answer(
        f"❌ Счет {winner.account_number} вам не принадлежит", 
        show_alert=True
    )
    return

Что НЕ может сделать пользователь:

Подтвердить чужой счет Подтвердить один счет дважды

Что может сделать пользователь:

Подтвердить каждый свой выигрышный счет отдельно Видеть номер счета на каждой кнопке

🎊 После подтверждения

Сообщение пользователю:

✅ Выигрыш успешно подтвержден!

🎯 Розыгрыш: Новогодний розыгрыш
🏆 Место: 1
🎁 Приз: iPhone 15
💳 Счет: 11-22-33-44-55-66-77

🎊 Поздравляем! Администратор свяжется с вами 
для передачи приза в ближайшее время.

Спасибо за участие!

Уведомление администратору:

✅ Победитель подтвердил получение приза!

🎯 Розыгрыш: Новогодний розыгрыш
🏆 Место: 1
🎁 Приз: iPhone 15
💳 Подтвержденный счет: 11-22-33-44-55-66-77

👤 Владелец: Иван Петров (@ivan)
🎫 Клубная карта: 2223
📱 Телефон: +7 900 123-45-67

📊 База данных

Таблица winners

Каждая запись = один выигрышный счет:

id | lottery_id | account_number        | place | prize      | is_claimed | claimed_at
---|------------|-----------------------|-------|------------|------------|------------------
1  | 5          | 11-22-33-44-55-66-77 | 1     | iPhone 15  | TRUE       | 2025-11-16 14:00
2  | 5          | 33-44-55-66-77-88-99 | 3     | AirPods    | TRUE       | 2025-11-16 14:05
3  | 5          | 55-66-77-88-99-00-11 | 2     | MacBook    | FALSE      | NULL

Ключевые поля:

  • account_number - конкретный выигрышный счет
  • is_claimed - подтвержден ли ЭТОТ счет
  • claimed_at - когда ЭТОТ счет был подтвержден

🔄 Повторный розыгрыш

Если счет не подтвержден в течение 24 часов:

  1. Админ проверяет: /check_unclaimed 5

    ⚠️ Неподтвержденные выигрыши:
    
    🏆 2 место - MacBook
       💳 55-66-77-88-99-00-11
       ⏰ Прошло: 26 часов
    
  2. Админ переигрывает: /redraw 5

    • Удаляется Winner с account_number = 55-66-77-88-99-00-11
    • Выбирается новый случайный счет
    • Новому владельцу счета отправляется уведомление
    • Новый владелец получает свои 24 часа

💡 Преимущества подхода

Для пользователей:

  1. Понятность - видят конкретный номер счета на кнопке
  2. Контроль - могут подтверждать счета независимо
  3. Гибкость - один счет подтвердил, другой нет (если забыл)

Для администраторов:

  1. Точность - знают какой именно счет подтвержден
  2. Прозрачность - видят все действия по каждому счету
  3. Справедливость - переиграть можно конкретный неподтвержденный счет

Для системы:

  1. Масштабируемость - неограниченное количество счетов у одного пользователя
  2. Независимость - каждый счет живет своей жизнью
  3. Целостность - нет конфликтов между разными выигрышами

🔍 Примеры использования

Пример 1: Один пользователь, два выигрыша

Клиент: Иван Петров (КК: 2223)
Счета: 
  - 11-22-33-44-55-66-77 → Выиграл 1 место ✅ Подтвержден
  - 22-33-44-55-66-77-88 → Выиграл 3 место ✅ Подтвержден

Результат: Иван получит 2 приза

Пример 2: Частичное подтверждение

Клиент: Мария Сидорова (КК: 3334)
Счета:
  - 33-44-55-66-77-88-99 → Выиграл 2 место ✅ Подтвержден
  - 44-55-66-77-88-99-00 → Выиграл 4 место ❌ Не подтвержден (> 24ч)

Результат: 
  - Мария получит приз за 2 место
  - 4 место будет переиграно

Пример 3: Полная неявка

Клиент: Петр Иванов (КК: 5556)
Счета:
  - 55-66-77-88-99-00-11 → Выиграл 1 место ❌ Не подтвержден
  - 66-77-88-99-00-11-22 → Выиграл 2 место ❌ Не подтвержден

Результат: Оба места будут переиграны отдельно

📝 Технические детали

Callback данные

# Формат: confirm_win_{winner_id}
callback_data = f"confirm_win_{winner.id}"

# winner.id - уникальный ID записи в таблице winners
# Каждый счет-выигрыш имеет свой winner_id

Проверка при подтверждении

# 1. Получаем winner по ID
winner = await session.get(Winner, winner_id)

# 2. Проверяем что счет принадлежит пользователю
owner = await AccountService.get_account_owner(session, winner.account_number)
if owner.telegram_id != current_user_id:
    return "Не ваш счет"

# 3. Подтверждаем ЭТОТ счет
winner.is_claimed = True
winner.claimed_at = datetime.now(timezone.utc)
await session.commit()

🎓 Выводы

Подход "счет = выигрыш" обеспечивает:

  • 🎯 Точность - подтверждается конкретный счет, а не абстрактный выигрыш
  • 🔒 Безопасность - только владелец счета может подтвердить
  • 📊 Масштабируемость - неограниченное количество счетов и выигрышей
  • 👥 Справедливость - каждый счет обрабатывается независимо
  • 💡 Прозрачность - всегда понятно какой именно счет подтверждается

📞 См. также

  • AUTO_CONFIRM_SYSTEM.md - Полная документация системы подтверждения
  • REGISTRATION_SYSTEM.md - Система регистрации счетов
  • ADMIN_GUIDE.md - Руководство администратора