44 KiB
Lottery Application - Complete Overview
Table of Contents
- Application Overview
- Architecture
- Core Features
- Game Mechanics
- Referral System
- Tasks System
- Payment System
- User Management
- Feature Switches
- Lottery Bot System
- Database Schema
- API Endpoints
Application Overview
The Lottery Application is a Telegram Mini App that provides a real-time lottery game experience. Users can participate in lottery rounds across multiple game rooms, complete tasks to earn rewards, refer friends to earn commissions, and manage their balance through Telegram Stars payments.
Technology Stack:
- Backend: Java 17, Spring Boot 3.2.0, MySQL, WebSocket (STOMP)
- Frontend: React, Vite, WebSocket client
- Authentication: Telegram Mini App initData validation, JWT for admin panel
- Payment: Crypto deposits (external API), optional Telegram Stars (legacy); feature switch for deposits
- Payout: Crypto withdrawals (external API), STARS/GIFT (Telegram); feature switch for withdrawals
- Infrastructure: Docker, Nginx, VPS deployment
Domain: win-spin.live
Architecture
Backend Architecture
- Spring Boot REST API with WebSocket support for real-time game updates
- Dual Authentication System:
- Telegram initData validation for app users (via
AuthInterceptor) - JWT-based authentication for admin panel (via Spring Security)
- Telegram initData validation for app users (via
- Session Management: Bearer token-based sessions stored in
sessionstable - Real-time Communication: WebSocket (STOMP) for game state broadcasts
Frontend Architecture
- Main App (lottery-fe): React SPA (Vite) deployed at
win-spin.live. Path/shows a home/landing screen;/auth(or other paths) loads the authenticated app. Screens: Main (game), Game History, FAQ, Support, Support Chat, Referral, Transaction History, Store, Payment Options/Confirmation/Error, Tasks, Payout, Stars Payout Confirmation, Daily Bonus. Balance and user state fromGET /api/users/current; game join and room state via WebSocket. i18n and Telegram WebApp integration. - Admin Panel (lottery-admin): React SPA (Vite, React Router, TanStack Query) at
win-spin.live/{secret-path}/. Routes: Login, Dashboard (stats), Rooms (list + RoomDetail), Feature Switchers, Configurations, Bots, Users (list + UserDetail), Payments, Payouts, Support Tickets (list + TicketDetail, Quick Answers), Masters, Analytics (User, Game, Financial, Referral). Role-based visibility: ROLE_ADMIN (all), ROLE_PAYOUT_SUPPORT (payouts), ROLE_TICKETS_SUPPORT (tickets + quick answers). - WebSocket Client (lottery-fe): Real-time game state via STOMP; subscribe to
/topic/room/{roomNumber}/state, send join via/app/game/join.
Database
- MySQL with Flyway migrations
- Normalized Schema: User data split across multiple tables (A, B, D)
- Performance: Indexed for high concurrency (1000+ concurrent users)
Core Features
1. Real-Time Lottery Game
- 3 Game Rooms with different bet limits:
- Room 1: 1-50 tickets
- Room 2: 10-500 tickets
- Room 3: 100-5000 tickets
- Game Phases:
WAITING: Waiting for at least 2 playersCOUNTDOWN: 5-second countdown after 2nd player joinsSPINNING: 5-second spinning animationRESOLUTION: Winner announcement
- Winner Selection: Random selection based on ticket distribution (weighted lottery)
- House Commission: 20% of total pool (80% distributed to winner)
2. User Balance System
- Balance A: Main balance (used for betting, can be withdrawn)
- Balance B: Secondary balance (bonuses, rewards)
- Currency: Internal "tickets" system (1 ticket = 1,000,000 in bigint format)
- Deposit Conversion: 1 USD = 1,000 tickets (crypto deposits); legacy Telegram Stars conversion no longer used for new deposits
- Withdrawal Limit: Only winnings since last deposit can be withdrawn; tracked in
total_win_after_deposit(reset on deposit, reduced when payout created)
3. Telegram Integration
- Telegram Mini App: Full integration with Telegram WebView
- Telegram Stars Payments: Deposit via Telegram Stars
- Telegram Bot: Handles webhooks, channel membership verification
- Avatar Management: Downloads and stores user avatars from Telegram
4. Multi-Language Support
- i18n: Full internationalization support
- Languages: Multiple language codes stored per user
- Localization Service: Dynamic message translation
5. Support System
- Support Tickets: Users can create tickets
- Support Messages: Threaded conversations per ticket
- Status Tracking: OPENED/CLOSED status
6. Admin Panel
- Secret Path Access: Accessible via
win-spin.live/{secret-path}/ - Role-Based Access:
ROLE_ADMIN(full access),ROLE_PAYOUT_SUPPORT(payouts only),ROLE_TICKETS_SUPPORT(support tickets and quick answers). Admins table storesroleper account. - Dashboard: Stats overview (total/new users, active players 24h/7d/30d, revenue and payouts in Stars and crypto USD, net revenue, rounds count, open support tickets). Served by
GET /api/admin/dashboard/stats. - Rooms: List all game rooms; room detail by room number (participants, phase, totals); repair round for stuck rooms (
POST /api/admin/rooms/{roomNumber}/repair). - Configurations: App configuration view for admins (
GET /api/admin/configurations). - Bots: Lottery bot configs management—create/update/delete bot configs (linked to real users), shuffle bot order. Scheduler (when
lottery_bot_scheduler_enabledis on) auto-joins bots into joinable rounds per time window and persona. - User Management: Paginated users list; user detail (profile, balance, transactions, game rounds, tasks); ban user; manual balance adjustment.
- Feature Switchers: Runtime toggles for remote_bet_enabled, payment_enabled, payout_enabled, lottery_bot_scheduler_enabled.
- Payments: List payments with filters (userId, status); crypto and legacy records.
- Payouts: List payouts with filters (userId, status, type); manual complete/cancel for PROCESSING or WAITING (CRYPTO status synced by cron).
- Support Tickets: List tickets, ticket detail with messages; close ticket. Quick Answers: Per-admin templates for fast replies (CRUD); access for ROLE_ADMIN and ROLE_TICKETS_SUPPORT.
- Masters: Referral masters view.
- Analytics: Revenue time series (crypto USD) and activity metrics (new users, rounds, revenue by period) for charts; range 7d/30d/90d/1y/all.
- JWT Authentication: Separate admin authentication system.
- Admin Table: Separate
adminstable; optionaluser_idlinking todb_users_afor support messages.
Game Mechanics
Game Flow
-
User Joins Room:
- User selects a room (1, 2, or 3)
- User places a bet (within room limits)
- Balance A is deducted immediately
- User becomes a participant
-
Round Start:
- When 2nd player joins, countdown starts (5 seconds)
- During countdown, more players can join
- After countdown, spinning phase begins (5 seconds)
-
Winner Selection:
- Winner selected randomly based on ticket distribution
- Probability = (user_tickets / total_tickets)
- House takes 20% commission
- Winner receives 80% of total pool
-
Round Resolution:
- Winner's balance credited
- Referral commissions processed
- Round marked as completed
- New round starts automatically
Bet Limits Per Room
| Room | Min Bet | Max Bet | Max Bet Per User |
|---|---|---|---|
| 1 | 1 | 50 | 50 |
| 2 | 10 | 500 | 500 |
| 3 | 100 | 5000 | 5000 |
Note: All amounts stored in bigint format (1 ticket = 1,000,000)
Game Phases
- WAITING: Room waiting for players (minimum 2 required)
- COUNTDOWN: 5-second countdown after 2nd player joins
- SPINNING: 5-second spinning animation (no new bets allowed)
- RESOLUTION: Winner announced, payouts processed
Real-Time Updates
- WebSocket Broadcasts: All room state changes broadcast to connected clients
- State Synchronization: Clients receive full room state on connection
- Participant Updates: Real-time participant list and bet totals
Referral System
3-Tier Referral Structure
The referral system tracks up to 5 levels of referrers, but commissions are paid to the first 3 levels:
Referral Chain:
referer_id_1: Direct referrer (Level 1)referer_id_2: Referrer's referrer (Level 2)referer_id_3: Referrer's referrer's referrer (Level 3)referer_id_4: Level 4 (tracked but no commission)referer_id_5: Level 5 (tracked but no commission)
Commission Rates
When Referral Wins:
- All Levels: 1% of referral's net profit
- Net Profit Calculation: (total_pool - house_commission) - referral_bet
When Referral Loses:
- Level 1: 4% of referral's bet
- Level 2: 2% of referral's bet
- Level 3: 1% of referral's bet
Referral Statistics
Each user tracks:
- referals_1 to referals_5: Count of direct referrals at each level
- from_referals_1 to from_referals_5: Total commissions earned from each level
- to_referer_1 to to_referer_5: Total commissions paid to referrers
Third Bet Bonus
- Special bonus given to referrers when their referral makes their 3rd bet
- Uses
rounds_playedcolumn (not transaction count) - Prevents issues with transaction cleanup cron jobs
Tasks System
Task Types
-
Referral Tasks (
referral):- Invite 1, 3, 7, 15, 30, 50, 100 friends
- Rewards: 2, 5, 15, 25, 40, 60, 150 Stars respectively
- One-time rewards (can only claim each tier once)
-
Follow Task (
follow):- Follow the news channel
- Reward: 5 Stars
- Verified via Telegram Bot API
-
Deposit Task (
other):- Top up balance: $5
- Reward: 100 Stars
- Based on
deposit_totalfield
-
Daily Bonus (
daily):- Claim 1 free ticket every 24 hours
- Reward: 1 ticket
- Tracked in
user_daily_bonus_claimstable
Task Completion Logic
- Referral Tasks: Counts
referals_1fromdb_users_d - Follow Task: Verified via Telegram Bot API channel membership check
- Deposit Task: Checks
deposit_total >= requirement - Daily Bonus: Checks if last claim was > 24 hours ago
Task Rewards
- Rewards credited to Balance A (main balance)
- Transaction recorded in
transactionstable with typeTASK_BONUS - Task marked as claimed in
user_task_claimstable
Payment System
Crypto Deposits (Primary)
Deposits are handled via an external crypto API (e.g. spin-passim.tech). The backend syncs deposit methods periodically and provides deposit addresses on demand; balance is credited when the 3rd party sends a completion webhook.
Deposit Flow:
- User enters USD amount on Store screen (min 2, max 10,000 USD; max 2 decimal places).
- User selects a crypto method on Payment Options (methods from
crypto_deposit_methods, synced every 10 min from external API). - Backend calls external API
POST api/v1/deposit-address(pid, amountUsd, userData); no payment record is created yet. - User is shown wallet address and exact amount in coins to send (Payment Confirmation screen).
- When the 3rd party detects the deposit, it calls
POST /api/deposit_webhook/{token}withuser_idandusd_amount. - Backend creates a COMPLETED payment record, credits balance (1 USD = 1,000 tickets in DB units: 1 ticket = 1,000,000), updates deposit_total/deposit_count, resets total_win_after_deposit, and creates a DEPOSIT transaction.
Payment Record (crypto):
usd_amount: decimal (e.g. 1.25 USD)tickets_amount: bigint (1 USD = 1,000 tickets → 1,000,000,000 in DB)stars_amount: 0 for cryptostatus: PENDING (if invoice created but not used), COMPLETED, FAILED, CANCELLED
Feature Switch: When payment_enabled is off, deposit-related endpoints return 503 and the Store shows "deposits temporarily unavailable".
Telegram Stars (Legacy)
- Creating new payments via Stars (invoice link) is no longer supported; the app uses crypto-only for new deposits.
- Telegram payment webhook is still processed for backward compatibility if a legacy payment is completed.
- Legacy conversion: Stars × 0.9 × 1,000,000 for tickets (no longer used for new flows).
Payout System
Payout Types:
- CRYPTO: Primary. User selects withdrawal method (e.g. TON, LTC, TRX), enters wallet and amount in tickets. Backend calls external API
POST api/v1/withdrawal; on success creates payout withpayment_id, deducts balance, and a cron job syncs status fromGET api/v1/withdrawals-info/{payment_id}. - STARS: Convert tickets to Telegram Stars (fixed amounts; admin may process manually).
- GIFT: Convert to Telegram gifts (HEART, BEAR, etc.); admin may process manually.
Crypto Payout Flow:
- User opens Payout screen; backend returns withdrawal methods from
crypto_withdrawal_methods(synced every 30 min from external API). - User selects method, enters wallet and amount (tickets). Frontend may call
GET withdrawal-method-details?pid=for rate_usd and fee to show "You will receive". - User submits; backend acquires per-user lock, calls external API POST withdrawal, then creates payout (type CRYPTO) with payment_id, crypto_name, amount_coins, commission_coins, amount_to_send, wallet, status PROCESSING, and deducts balance.
- Cron job (every minute) fetches PROCESSING/WAITING CRYPTO payouts with payment_id, calls withdrawals-info API, and updates status: -1→PROCESSING, 0→WAITING, 1→COMPLETED (marks completed, updates withdraw_total/count), 2→CANCELLED (refunds balance, creates cancellation transaction).
Payout Statuses:
PROCESSING: Created or being processed by external providerWAITING: Awaiting confirmation (from API status 0)COMPLETED: Resolved; user withdraw_total/count updatedCANCELLED: Refunded to balance_a
Withdrawal Rules:
- At least one deposit required before any withdrawal.
- Withdrawal amount cannot exceed
total_win_after_deposit(winnings since last deposit). - Crypto withdrawal amount must have at most 2 decimal places (in ticket units).
- One withdrawal at a time per user (in-memory lock).
Feature Switch: When payout_enabled is off, withdrawal-related endpoints return 503 and the Payout screen shows "withdrawals temporarily unavailable".
User Management
User Data Structure
User data is split across 3 tables for normalization:
db_users_a (User Authentication & Profile):
- Basic user info (Telegram ID, name, language, country)
- Registration and login timestamps
- Ban status
- Avatar URL
db_users_b (User Balance & Financial):
- Balance A (main balance)
- Balance B (bonus balance)
- Deposit/withdraw totals and counts
- Rounds played counter
- total_win_after_deposit: Total winnings since last deposit (bigint). Reset to 0 on each deposit; incremented when user wins a round; reduced when user creates a payout. Used to enforce withdrawal limit (only this amount can be withdrawn).
db_users_d (User Referral Data):
- Referral chain (5 levels)
- Referral statistics
- Commission tracking
User Sessions
- Session Management: Bearer token-based
- Multi-Device Support: Up to 5 active sessions per user
- Session Expiration: Configurable TTL
- Automatic Cleanup: Cron job removes expired sessions
User Authentication
-
Telegram initData Validation: Validates Telegram Mini App authentication
-
Session Creation: Creates session token on first login
-
Session Validation:
AuthInterceptorvalidates all API requests -
Current User API: Returns
paymentEnabledandpayoutEnabledfrom feature switches (used by frontend to show/hide or disable Store and Payout).
Feature Switches
Runtime toggles stored in feature_switches table. Changes take effect immediately without restart. Configurable from the admin panel.
| Key | Description |
|---|---|
remote_bet_enabled |
When on, 3rd party can register users to rounds via GET /api/remotebet/{token}?user_id=&room=&amount=. When off, endpoint returns 503. |
payment_enabled |
When on, deposits (Store, Payment Options, deposit-address, create invoice) are allowed. When off, related API endpoints return 503 and Store shows "deposits temporarily unavailable". Default: 1. |
payout_enabled |
When on, withdrawals (Payout screen, withdrawal-methods, withdrawal-method-details, crypto-withdrawal) are allowed. When off, related endpoints return 503 and Payout shows "withdrawals temporarily unavailable". Default: 1. |
lottery_bot_scheduler_enabled |
When on, the lottery bot scheduler auto-joins configured bots (from lottery_bot_configs) into joinable rounds within their time windows and persona. When off, scheduler skips registration. Default: 1. |
Lottery Bot System
Bots are real users (from db_users_a/db_users_b) with a config row in lottery_bot_configs. The scheduler runs periodically and, when lottery_bot_scheduler_enabled is on, registers these users into active rounds via the same join flow as real players (balance deducted, etc.).
Bot Config (per user)
- Rooms: Flags
room_1,room_2,room_3(which rooms the bot can play). - Time window (UTC):
time_utc_start,time_utc_end—bot only plays within this window. - Bet range:
bet_min,bet_maxin bigint (1 ticket = 1,000,000). - Persona:
conservative,aggressive, orbalanced—used by the bet decision service to choose bet size and timing. - Active: Toggle to enable/disable this bot without deleting the config.
One config per user; user_id is unique. Admin can create/update/delete configs and shuffle bot order via the Bots page.
Scheduler
- When the feature switch is on, a scheduled job evaluates active configs, checks time windows and room state, and places bets for bots using the bet decision service (persona-based logic).
- Bots participate in the same game flow as human players (rounds, referral logic, etc.).
Database Schema
Core Tables
sessions
User session management for Bearer token authentication.
| Column | Type | Description |
|---|---|---|
id |
BIGINT | Primary key, auto-increment |
session_id_hash |
VARCHAR(255) | Hashed session ID (unique) |
user_id |
INT | Foreign key to db_users_a.id |
created_at |
TIMESTAMP | Session creation time |
expires_at |
TIMESTAMP | Session expiration time |
Indexes:
idx_session_hashonsession_id_hashidx_expires_atonexpires_atidx_user_idonuser_ididx_user_createdon(user_id, created_at)
db_users_a
User authentication and profile information.
| Column | Type | Description |
|---|---|---|
id |
INT | Primary key, auto-increment |
screen_name |
VARCHAR(75) | User's screen name |
telegram_id |
BIGINT | Telegram user ID (unique) |
telegram_name |
VARCHAR(33) | Telegram username |
is_premium |
INT | Telegram Premium status (0/1) |
language_code |
VARCHAR(2) | User's language code |
country_code |
VARCHAR(2) | User's country code |
device_code |
VARCHAR(5) | Device type code |
ip |
VARBINARY(16) | User's IP address (IPv4/IPv6) |
date_reg |
INT | Registration timestamp (Unix) |
date_login |
INT | Last login timestamp (Unix) |
banned |
INT | Ban status (0/1) |
avatar_url |
VARCHAR(500) | Avatar URL with cache busting |
last_telegram_file_id |
VARCHAR(255) | Telegram file ID for avatar |
Indexes:
- Primary key on
id - Unique key on
telegram_id - Index on
telegram_name - Index on
ip
db_users_b
User balance and financial information.
| Column | Type | Description |
|---|---|---|
id |
INT | Primary key (matches db_users_a.id) |
balance_a |
BIGINT UNSIGNED | Main balance (tickets in bigint format) |
balance_b |
BIGINT UNSIGNED | Bonus balance (tickets in bigint format) |
deposit_total |
BIGINT | Total deposits (in bigint format) |
deposit_count |
INT | Number of deposits |
withdraw_total |
BIGINT | Total withdrawals (in bigint format) |
withdraw_count |
INT | Number of withdrawals |
rounds_played |
INT | Number of rounds user participated in |
total_win_after_deposit |
BIGINT | Winnings since last deposit (1 ticket = 1,000,000). Reset on deposit; increased on win; decreased when payout created. Withdrawal limit. |
Indexes:
- Primary key on
id
Note: balance_a and balance_b store values in bigint format where 1 ticket = 1,000,000
db_users_d
User referral data and statistics.
| Column | Type | Description |
|---|---|---|
id |
INT | Primary key (matches db_users_a.id) |
referer_id_1 |
INT | Level 1 referrer ID |
referer_id_2 |
INT | Level 2 referrer ID |
referer_id_3 |
INT | Level 3 referrer ID |
referer_id_4 |
INT | Level 4 referrer ID |
referer_id_5 |
INT | Level 5 referrer ID |
master_id |
INT | Master referrer ID |
referals_1 |
INT | Count of level 1 referrals |
referals_2 |
INT | Count of level 2 referrals |
referals_3 |
INT | Count of level 3 referrals |
referals_4 |
INT | Count of level 4 referrals |
referals_5 |
INT | Count of level 5 referrals |
from_referals_1 |
BIGINT | Commissions earned from level 1 |
from_referals_2 |
BIGINT | Commissions earned from level 2 |
from_referals_3 |
BIGINT | Commissions earned from level 3 |
from_referals_4 |
BIGINT | Commissions earned from level 4 |
from_referals_5 |
BIGINT | Commissions earned from level 5 |
to_referer_1 |
BIGINT | Commissions paid to level 1 referrer |
to_referer_2 |
BIGINT | Commissions paid to level 2 referrer |
to_referer_3 |
BIGINT | Commissions paid to level 3 referrer |
to_referer_4 |
BIGINT | Commissions paid to level 4 referrer |
to_referer_5 |
BIGINT | Commissions paid to level 5 referrer |
Indexes:
- Primary key on
id - Indexes on
referer_id_1throughreferer_id_5 - Index on
master_id
Game Tables
game_rooms
Active game rooms (Room 1, 2, 3).
| Column | Type | Description |
|---|---|---|
id |
INT | Primary key, auto-increment |
room_number |
INT | Room number (1, 2, or 3), unique |
current_phase |
VARCHAR(20) | Current game phase (WAITING, COUNTDOWN, SPINNING, RESOLUTION) |
countdown_end_at |
TIMESTAMP | Countdown end time (NULL if not counting down) |
total_bet |
BIGINT UNSIGNED | Total tickets bet in current round |
registered_players |
INT | Number of players in current round |
created_at |
TIMESTAMP | Room creation time |
updated_at |
TIMESTAMP | Last update time |
Indexes:
- Primary key on
id - Unique key on
room_number - Index on
current_phase - Index on
countdown_end_at
game_rounds
Completed game rounds history.
| Column | Type | Description |
|---|---|---|
id |
BIGINT | Primary key, auto-increment |
room_id |
INT | Foreign key to game_rooms.id |
phase |
VARCHAR(20) | Final phase (usually RESOLUTION) |
total_bet |
BIGINT UNSIGNED | Total tickets/bet in the round |
winner_user_id |
INT | Winner's user ID (NULL if no winner) |
winner_bet |
BIGINT UNSIGNED | Winner's ticket/bet count |
commission |
BIGINT UNSIGNED | House commission (20% of total) |
payout |
BIGINT UNSIGNED | Winner's payout (80% of total) |
started_at |
TIMESTAMP | Round start time |
countdown_started_at |
TIMESTAMP | Countdown start time |
countdown_ended_at |
TIMESTAMP | Countdown end time |
resolved_at |
TIMESTAMP | Resolution time |
created_at |
TIMESTAMP | Record creation time |
Indexes:
- Primary key on
id - Index on
room_id - Index on
winner_user_id - Index on
resolved_at - Foreign key to
game_rooms(id)
game_round_participants
Participants in each game round.
| Column | Type | Description |
|---|---|---|
id |
BIGINT | Primary key, auto-increment |
round_id |
BIGINT | Foreign key to game_rounds.id |
user_id |
INT | Foreign key to db_users_a.id |
tickets |
BIGINT UNSIGNED | User's total tickets in this round |
joined_at |
TIMESTAMP | When user joined the round |
Indexes:
- Primary key on
id - Index on
round_id - Index on
user_id - Composite index on
(round_id, user_id) - Foreign keys to
game_rounds(id)anddb_users_a(id)
Task Tables
tasks
Available tasks for users to complete.
| Column | Type | Description |
|---|---|---|
id |
INT | Primary key, auto-increment |
type |
VARCHAR(20) | Task type: referral, follow, other, daily |
requirement |
INT | Requirement value (e.g., number of referrals, deposit amount) |
reward_amount |
BIGINT | Reward amount in bigint format |
reward_type |
VARCHAR(20) | Reward type: Stars, Tickets, Power |
display_order |
INT | Display order in UI |
title |
VARCHAR(255) | Task title |
description |
TEXT | Task description |
Indexes:
- Primary key on
id - Index on
type - Index on
display_order
Default Tasks:
- Referral: Invite 1, 3, 7, 15, 30, 50, 100 friends (rewards: 2, 5, 15, 25, 40, 60, 150 Stars)
- Follow: Follow news channel (reward: 5 Stars)
- Deposit: Top up $5 (reward: 100 Stars)
- Daily: Daily bonus (reward: 1 ticket, claimable every 24h)
user_task_claims
Tracks which tasks users have claimed.
| Column | Type | Description |
|---|---|---|
id |
BIGINT | Primary key, auto-increment |
user_id |
INT | Foreign key to db_users_a.id |
task_id |
INT | Foreign key to tasks.id |
claimed_at |
TIMESTAMP | When task was claimed |
Indexes:
- Primary key on
id - Unique composite index on
(user_id, task_id) - Index on
user_id - Index on
task_id - Foreign keys to
db_users_a(id)andtasks(id)
user_daily_bonus_claims
Tracks daily bonus claims (optimized table to avoid JOINs).
| Column | Type | Description |
|---|---|---|
id |
BIGINT | Primary key, auto-increment |
user_id |
INT | Foreign key to db_users_a.id |
avatar_url |
VARCHAR(255) | User's avatar URL (denormalized) |
screen_name |
VARCHAR(75) | User's screen name (denormalized) |
claimed_at |
TIMESTAMP | Claim time |
Indexes:
- Primary key on
id - Index on
user_id - Index on
claimed_at(DESC) - Foreign key to
db_users_a(id)
Feature Switches Table
feature_switches
Runtime feature toggles (e.g. remote bet, deposits, withdrawals). Admin can change without restart.
| Column | Type | Description |
|---|---|---|
key |
VARCHAR(64) | Primary key (e.g. remote_bet_enabled, payment_enabled, payout_enabled) |
enabled |
TINYINT(1) | 0 or 1 |
updated_at |
TIMESTAMP | Last update |
Crypto Deposit Tables
crypto_deposit_config
Single row (id=1): minimum_deposit (decimal), methods_hash for sync skip when unchanged.
| Column | Type | Description |
|---|---|---|
id |
INT | Primary key (1) |
methods_hash |
VARCHAR(255) | Hash from external API; skip sync when unchanged |
minimum_deposit |
DECIMAL(10,2) | Minimum USD (e.g. 2.50) |
updated_at |
TIMESTAMP | Last update |
crypto_deposit_methods
One row per active deposit method (synced from external API every 10 min). pid = icon filename without extension (e.g. 235.png).
| Column | Type | Description |
|---|---|---|
id |
BIGINT | Primary key |
pid |
INT | External API PID (unique) |
name |
VARCHAR(100) | e.g. TON, USDT |
network |
VARCHAR(50) | e.g. TON, TRC20 |
example |
VARCHAR(255) | Example address |
min_deposit_sum |
DECIMAL(10,2) | Min USD for this method |
updated_at |
TIMESTAMP | Last update |
Crypto Withdrawal Tables
crypto_withdrawal_methods
One row per active withdrawal method (synced from external API every 30 min). pid = method id; icon_id = icon filename (e.g. 30.png).
| Column | Type | Description |
|---|---|---|
id |
BIGINT | Primary key |
pid |
INT | Method ID (unique) |
name |
VARCHAR(50) | Ticker (e.g. LTC, TON) |
network |
VARCHAR(100) | Network name |
icon_id |
VARCHAR(20) | Icon filename without extension |
min_withdrawal |
DECIMAL(10,2) | Min withdrawal USD |
updated_at |
TIMESTAMP | Last update |
Payment Tables
payments
Payment records (crypto and legacy Telegram Stars).
| Column | Type | Description |
|---|---|---|
id |
BIGINT | Primary key, auto-increment |
user_id |
INT | Foreign key to db_users_a.id |
order_id |
VARCHAR(255) | Unique order ID |
stars_amount |
INT | Telegram Stars (0 for crypto) |
usd_amount |
DECIMAL(20,2) | USD amount (crypto; e.g. 1.25) |
tickets_amount |
BIGINT UNSIGNED | Tickets in bigint (1 USD = 1,000 tickets → 1,000,000,000 per USD) |
status |
VARCHAR(20) | PENDING, COMPLETED, FAILED, CANCELLED |
telegram_payment_charge_id |
VARCHAR(255) | Telegram (legacy) |
telegram_provider_payment_charge_id |
VARCHAR(255) | Telegram (legacy) |
created_at |
TIMESTAMP | Creation time |
completed_at |
TIMESTAMP | Completion time |
Indexes:
- Primary key on
id - Unique key on
order_id - Index on
user_id - Index on
status - Index on
created_at - Composite index on
(user_id, status) - Foreign key to
db_users_a(id)
payouts
Withdrawal/payout requests (CRYPTO, STARS, GIFT).
| Column | Type | Description |
|---|---|---|
id |
BIGINT | Primary key, auto-increment |
user_id |
INT | Foreign key to db_users_a.id |
username |
VARCHAR(255) | User's username (for STARS/GIFT) |
wallet |
VARCHAR(120) | Wallet address (CRYPTO) |
type |
VARCHAR(20) | CRYPTO, STARS, GIFT |
gift_name |
VARCHAR(50) | Gift type for GIFT (HEART, BEAR, etc.) |
crypto_name |
VARCHAR(20) | Ticker for CRYPTO (e.g. TRX, TON) |
total |
BIGINT UNSIGNED | Tickets in bigint format |
stars_amount |
INT | Stars amount (0 for CRYPTO) |
usd_amount |
DECIMAL(20,2) | USD equivalent (CRYPTO) |
amount_coins |
VARCHAR(50) | Withdrawal amount in coins (from API) |
commission_coins |
VARCHAR(50) | Commission in coins (from API) |
amount_to_send |
VARCHAR(50) | Final amount to send (from API) |
payment_id |
INT | Crypto API payment id (for status sync) |
quantity |
INT | Quantity (e.g. gifts); default 1 |
status |
VARCHAR(20) | PROCESSING, WAITING, COMPLETED, CANCELLED |
created_at |
TIMESTAMP | Request time |
updated_at |
TIMESTAMP | Last update (touched by cron sync) |
resolved_at |
TIMESTAMP | Resolution time |
Indexes:
- Primary key on
id - Index on
user_id - Index on
status - Index on
type - Index on
created_at - Index on
updated_at - Composite indexes for CRYPTO status sync
- Foreign key to
db_users_a(id)
transactions
Transaction history (all balance changes).
| Column | Type | Description |
|---|---|---|
id |
BIGINT | Primary key, auto-increment |
user_id |
INT | Foreign key to db_users_a.id |
amount |
BIGINT | Amount in bigint format (positive=credit, negative=debit) |
type |
VARCHAR(50) | Type: DEPOSIT, WITHDRAWAL, WIN, LOSS, TASK_BONUS, CANCELLATION_OF_WITHDRAWAL |
task_id |
INT | Task ID for TASK_BONUS type (nullable) |
round_id |
BIGINT | Round ID for WIN/LOSS type (nullable) |
created_at |
TIMESTAMP | Transaction time |
Indexes:
- Primary key on
id - Composite index on
(user_id, created_at DESC) - Composite index on
(user_id, type) - Foreign key to
db_users_a(id)
Note: Transactions older than 30 days are automatically cleaned up by cron job.
Support Tables
support_tickets
User support tickets.
| Column | Type | Description |
|---|---|---|
id |
BIGINT | Primary key, auto-increment |
user_id |
INT | Foreign key to db_users_a.id |
subject |
VARCHAR(100) | Ticket subject |
status |
ENUM | Status: OPENED, CLOSED |
created_at |
TIMESTAMP | Ticket creation time |
updated_at |
TIMESTAMP | Last update time |
Indexes:
- Primary key on
id - Index on
user_id - Index on
status - Composite index on
(user_id, status) - Index on
created_at - Foreign key to
db_users_a(id)
support_messages
Messages within support tickets.
| Column | Type | Description |
|---|---|---|
id |
BIGINT | Primary key, auto-increment |
ticket_id |
BIGINT | Foreign key to support_tickets.id |
user_id |
INT | Foreign key to db_users_a.id |
message |
VARCHAR(2000) | Message content |
created_at |
TIMESTAMP | Message time |
Indexes:
- Primary key on
id - Index on
ticket_id - Index on
user_id - Composite index on
(ticket_id, created_at) - Foreign keys to
support_tickets(id)anddb_users_a(id)
Admin Tables
admins
Admin user accounts (separate from regular users).
| Column | Type | Description |
|---|---|---|
id |
INT | Primary key, auto-increment |
user_id |
INT | Optional FK to db_users_a.id (for support messages) |
username |
VARCHAR(50) | Admin username (unique) |
password_hash |
VARCHAR(255) | BCrypt hashed password |
role |
VARCHAR(20) | Role: ROLE_ADMIN, ROLE_PAYOUT_SUPPORT, ROLE_TICKETS_SUPPORT |
created_at |
TIMESTAMP | Account creation time |
updated_at |
TIMESTAMP | Last update time |
Indexes:
- Primary key on
id - Unique key on
username - Index on
role - Index on
user_id
lottery_bot_configs
Bot behaviour config: one row per user; user must exist in db_users_a.
| Column | Type | Description |
|---|---|---|
id |
INT | Primary key, auto-increment |
user_id |
INT | FK to db_users_a.id (unique) |
room_1 |
TINYINT(1) | Can play room 1 (0/1) |
room_2 |
TINYINT(1) | Can play room 2 (0/1) |
room_3 |
TINYINT(1) | Can play room 3 (0/1) |
time_utc_start |
TIME | Start of active window (UTC) |
time_utc_end |
TIME | End of active window (UTC) |
bet_min |
BIGINT | Min bet in bigint (1 ticket = 1,000,000) |
bet_max |
BIGINT | Max bet in bigint |
persona |
VARCHAR(20) | conservative, aggressive, balanced |
active |
TINYINT(1) | 1 = enabled, 0 = disabled |
created_at |
TIMESTAMP | Creation time |
updated_at |
TIMESTAMP | Last update time |
Indexes:
- Unique key on
user_id - Index on
(active, room_1, room_2, room_3)
quick_answers
Admin quick-response templates for support (per admin).
| Column | Type | Description |
|---|---|---|
id |
INT | Primary key, auto-increment |
admin_id |
INT | FK to admins.id |
text |
TEXT | Template text |
created_at |
TIMESTAMP | Creation time |
updated_at |
TIMESTAMP | Last update time |
Indexes:
- Primary key on
id - Index on
admin_id - Index on
(admin_id, created_at)
API Endpoints
Public Endpoints
POST /api/auth/tma/session- Create session from Telegram initDataGET /api/check_user/{token}/{telegramId}- Check user info (external API). Token is configured viaAPP_CHECK_USER_TOKEN(set on server only, not in repo).POST /api/deposit_webhook/{token}- 3rd party deposit completion (no auth). Body:user_id,usd_amount. Token viaAPP_DEPOSIT_WEBHOOK_TOKEN.
Authenticated Endpoints (Bearer Token)
Game (REST)
GET /api/game/room/{roomNumber}/completed-rounds- Last 10 completed rounds for a roomGET /api/game/history- Get game history for current user- Join and room state: Via WebSocket (see WebSocket section below), not REST.
User
GET /api/users/current- Get current user info (includes balance,paymentEnabled,payoutEnabledfrom feature switches)GET /api/users/referrals- Get referral infoPOST /api/users/deposit- Legacy/optional deposit flow
Tasks
GET /api/tasks?type=- Get available tasks (query:type= referral, follow, other, etc.)GET /api/tasks/daily-bonus- Daily bonus statusGET /api/tasks/daily-bonus/recent-claims- Recent daily bonus claims (optional query:timezone)POST /api/tasks/claim- Claim task reward (body:taskId)
Payments (deposits)
GET /api/payments/minimum-deposit- Min deposit USD from config (503 if payment disabled)GET /api/payments/deposit-methods- Crypto deposit methods from DB (503 if payment disabled)POST /api/payments/deposit-address- Get crypto deposit address/amount from external API (pid, usdAmount)POST /api/payments/create- Create payment invoice (crypto: usdAmount; legacy Stars no longer supported) (503 if payment disabled)POST /api/payments/cancel- Cancel payment by orderId
Payouts (withdrawals)
GET /api/payments/withdrawal-methods- Crypto withdrawal methods from DB (503 if payout disabled)GET /api/payments/withdrawal-method-details?pid=- Rate/fee for method from external API (503 if payout disabled)POST /api/payments/crypto-withdrawal- Create crypto withdrawal (pid, wallet, total in tickets); creates payout and deducts balance (503 if payout disabled)POST /api/payouts- Request STARS or GIFT payoutGET /api/payouts/history- Last 20 payouts for current user
Support
GET /api/support/tickets- Get user's ticketsPOST /api/support/tickets- Create ticketGET /api/support/tickets/{ticketId}- Get ticket with messagesPOST /api/support/tickets/{ticketId}/messages- Send messagePOST /api/support/tickets/{ticketId}/close- Close ticket
Transactions
GET /api/transactions- Get current user's transaction history
Admin Endpoints (JWT Token)
All admin paths are under /api/admin/. Role requirements: dashboard, rooms, configurations, bots, users, payments, payouts, feature-switches, analytics require ADMIN; payouts also allow ROLE_PAYOUT_SUPPORT; tickets and quick-answers allow ROLE_TICKETS_SUPPORT.
POST /api/admin/login- Admin loginGET /api/admin/dashboard/stats- Dashboard stats (users, active players, revenue/payouts in Stars and crypto USD, rounds, support tickets)GET /api/admin/rooms- List all game roomsGET /api/admin/rooms/{roomNumber}- Room detail (participants, phase, etc.)POST /api/admin/rooms/{roomNumber}/repair- Repair stuck roundGET /api/admin/configurations- App configurationsGET /api/admin/bots- List lottery bot configsGET /api/admin/bots/{id}- Get bot config by idPOST /api/admin/bots- Create bot configPUT /api/admin/bots/{id}- Update bot configDELETE /api/admin/bots/{id}- Delete bot configPOST /api/admin/bots/shuffle?roomNumber=- Shuffle bot time windows for room (query:roomNumber= 2 or 3)GET /api/admin/users- Paginated users list (50 per page; sort supported)GET /api/admin/users/{id}- User detailGET /api/admin/users/{id}/transactions- User transactionsGET /api/admin/users/{id}/game-rounds- User game roundsGET /api/admin/users/{id}/tasks- User task claimsPATCH /api/admin/users/{id}/ban- Ban/unban user (body:banned)POST /api/admin/users/{id}/balance/adjust- Manual balance adjustmentGET /api/admin/feature-switches- List all feature switchesPATCH /api/admin/feature-switches/{key}- Update feature switch (body:enabled)GET /api/admin/payments- Paginated payments (filter by userId, status)GET /api/admin/payouts- Paginated payouts (filter by userId, status, type)POST /api/admin/payouts/{id}/complete- Mark payout COMPLETEDPOST /api/admin/payouts/{id}/cancel- Mark payout CANCELLED (refund)GET /api/admin/analytics/revenue- Revenue/payout time series (query:range= 7d, 30d, 90d, 1y, all)GET /api/admin/analytics/activity- Activity metrics for chartsGET /api/admin/quick-answers- List quick answers for current adminPOST /api/admin/quick-answers- Create quick answer (body:text)PUT /api/admin/quick-answers/{id}- Update quick answer (own only)DELETE /api/admin/quick-answers/{id}- Delete quick answer (own only)
WebSocket
- Endpoint:
/ws(STOMP over SockJS or WebSocket) - Subscribe:
/topic/room/{roomNumber}/state- Room state updates (full state on subscribe; broadcasts on phase/participant changes) - Send (join round):
/app/game/join- Payload: roomNumber, amount (tickets in bigint). Join is handled via WebSocket, not REST.
Key Business Logic
Balance Format
All monetary values in balance/transaction/payout totals are stored in bigint format with 6 decimal places:
- 1 Ticket = 1,000,000 (in database)
- Crypto deposits: 1 USD = 1,000 tickets → 1,000,000,000 in database per USD
- Legacy: 1 Telegram Star = 900,000 (0.9 conversion; no longer used for new deposits)
- Example: 50 tickets = 50,000,000 in database
Winner Selection Algorithm
- Calculate total tickets in round
- Generate random number between 0 and total_tickets
- Iterate through participants, accumulating ticket counts
- First participant whose accumulated tickets >= random number wins
- This creates a weighted lottery (more tickets = higher chance)
House Commission
- Rate: 20% of total pool
- Calculation:
commission = total_tickets × 0.2 - Winner Payout:
payout = total_tickets - commission
Referral Commission Calculation
When Referral Wins:
net_profit = (total_pool - house_commission) - referral_bet
commission = net_profit × 0.01 // 1% for all levels
When Referral Loses:
Level 1: commission = referral_bet × 0.04 // 4%
Level 2: commission = referral_bet × 0.02 // 2%
Level 3: commission = referral_bet × 0.01 // 1%
Data Cleanup
- Transactions: Cleaned up after 30 days (cron job)
- Game Rounds: Old rounds cleaned up periodically
- Sessions: Expired sessions cleaned up in batches
Crypto API Integration
- Deposits: External API base URL and API key via
app.crypto-api.base-urlandapp.crypto-api.api-key. Deposit methods synced every 10 min (cron); deposit address on demand (POST deposit-address). Completion viaPOST /api/deposit_webhook/{token}(token:app.deposit-webhook.token). - Withdrawals: Withdrawal methods synced every 30 min (cron). POST withdrawal creates payout; status sync cron every minute calls GET withdrawals-info for PROCESSING/WAITING CRYPTO payouts and updates status (COMPLETED/CANCELLED trigger balance and transaction updates).
Security Features
- Telegram Authentication: Validates Telegram Mini App initData
- Session Management: Secure Bearer token sessions
- Rate Limiting: Per-user and per-endpoint rate limiting
- CORS Protection: Configured for specific origins
- Admin Authentication: Separate JWT-based admin system
- Input Validation: All user inputs validated
- SQL Injection Protection: JPA/Hibernate parameterized queries
- XSS Protection: Content Security Policy headers
Performance Optimizations
- Database Indexes: Comprehensive indexing for fast queries
- Connection Pooling: HikariCP with optimized pool size
- WebSocket Keep-Alive: Efficient real-time communication
- Batch Operations: Bulk cleanup operations
- Caching: In-memory caching for active game rounds
- Nginx Caching: Static asset caching (1 year TTL)
- Composite Indexes: Optimized for common query patterns
Deployment
- Backend: Docker container on VPS
- Frontend: Static files served by Nginx
- Admin Panel: Static files at
win-spin.live/{secret-path}/ - Database: MySQL on VPS
- SSL: Let's Encrypt certificates
- Domain:
win-spin.live
This document provides a comprehensive overview of the Lottery Application. For specific implementation details, refer to the source code in the respective service classes and repositories.