# TGLotteryBot **Telegram lottery bot with built-in Mini App - create, announce, and draw lotteries without leaving Telegram** **English** · [简体中文](./README.zh-CN.md) [![][license-shield]][license-link] [![][python-shield]][python-link] [![][docker-shield]][docker-link] [![][postgres-shield]][postgres-link]
--- - [✨ Features](#-features) - [🚀 Quick Start](#-quick-start) - [🤖 Bot Setup](#-bot-setup) - [📡 Bot Commands](#-bot-commands) - [💻 Local Development](#-local-development) - [⚙️ Configuration](#️-configuration) - [🐳 Services](#-services) - [📁 Project Structure](#-project-structure) - [🤝 Contributing](#-contributing) - [📝 License](#-license) ## ✨ Features - **Telegram Mini App** - full lottery management UI embedded inside Telegram; no external website required - **Lottery lifecycle** - Draft → Active → Finished flow; prizes stay editable while the lottery is in Draft or Active - **Multi-prize draws** - each lottery supports multiple prizes with independent quantities; the draw algorithm pairs participants with prizes fairly using a shuffle-based random selection - **Membership requirements** - optionally restrict participation to members of specific groups or channels; supports passphrase verification per chat - **Multi-chat announcement** - announce to multiple groups or channels simultaneously; messages stay in sync as lottery details change - **Scheduled auto-draw** - set an exact date and time for the draw to run automatically - **Deep-link joining** - announcement messages carry a `/start lottery_` deep link; users tap once to open the Mini App and join - **Winner notifications** - each winner receives a private congratulatory message from the bot with their prize details - **Invite links** - the bot can generate and cache persistent invite links for required chats; participants see the link before they join ## 🚀 Quick Start **1. Download the required files** ```bash curl -LO https://git.stdm.moe/Stardream/TGLotteryBot/raw/branch/main/docker-compose.yml curl -LO https://git.stdm.moe/Stardream/TGLotteryBot/raw/branch/main/.env.example mkdir -p nginx curl -o nginx/nginx.conf https://git.stdm.moe/Stardream/TGLotteryBot/raw/branch/main/nginx/nginx.conf ``` **2. Configure environment** ```bash cp .env.example .env ``` Open `.env` and fill in the required values: ```env BOT_TOKEN=123456:ABC-your-bot-token-from-BotFather MINI_APP_URL=https://your-domain.com POSTGRES_PASSWORD=change-me ``` > [!IMPORTANT] > `BOT_TOKEN` and `MINI_APP_URL` are required. The Mini App URL must be an HTTPS address that Telegram can reach. For production, also set `WEBHOOK_URL` and `WEBHOOK_SECRET`. **3. Start** ```bash docker compose up -d ``` **4. Register the Mini App** In [@BotFather](https://t.me/BotFather), send `/newapp` and point the Web App URL to `https://your-domain.com`. Users can then open the lottery manager directly from bot messages. **5. Open the bot** Send `/start` to your bot in Telegram to open the Mini App. > [!TIP] > For production deployments, set `WEBHOOK_URL` to your public HTTPS URL. Without it, the bot falls back to long-polling, which is fine for development but less efficient in production. **Updating to a newer version** ```bash docker compose pull docker compose up -d ```
[![][back-to-top]](#readme-top)
## 🤖 Bot Setup After adding the bot to your groups or channels, configure the following in [@BotFather](https://t.me/BotFather): **Disable Privacy Mode** (`/setprivacy` - Disabled) Required if you use passphrase verification. By default, Telegram bots only receive messages that start with `/`. Disabling Privacy Mode allows the bot to read all messages in the group so it can detect passphrases sent by users. **Grant Admin rights for anonymous admin detection** If your group has anonymous administrators (members who toggled "Hide my name"), Telegram does not expose their user ID to bots via the standard `getChatMember` API. Granting the bot administrator rights in the group allows it to verify anonymous admins when checking membership. > [!NOTE] > These settings only affect groups where you use membership requirements or passphrase verification. For channels or public lotteries without requirements, they are not needed.
[![][back-to-top]](#readme-top)
## 📡 Bot Commands | Command | Description | |---|---| | `/start` | Open the lottery manager Mini App | | `/newlottery` | Create a new lottery (shortcut into the Mini App) | | `/mylotteries` | View your lotteries | | `/help` | Show help and project info | All lottery management (creating, editing, announcing, drawing) happens inside the Mini App. Bot commands are entry points that open the appropriate Mini App screen.
[![][back-to-top]](#readme-top)
## 💻 Local Development **Prerequisites:** Docker and Docker Compose The project ships a `docker-compose.override.yml` that activates automatically for development: - Backend mounts the source tree and runs uvicorn with `--reload` - Frontend runs the Vite dev server with filesystem polling (safe for NAS / network volumes) - nginx serves the Vite output and proxies `/api` and `/webhook` to the backend ```bash cp .env.example .env # Edit .env - set BOT_TOKEN, MINI_APP_URL; leave WEBHOOK_URL empty for polling mode docker compose up --build ``` The development stack is accessible at `http://localhost` (or whatever `PORT` you set). Backend hot-reloads on file save. Frontend hot-reloads are handled by Vite.
[![][back-to-top]](#readme-top)
## ⚙️ Configuration All configuration is read from environment variables (or `.env` in the project root). | Variable | Default | Required | Description | |---|---|---|---| | `BOT_TOKEN` | - | **Yes** | Telegram bot token from [@BotFather](https://t.me/BotFather) | | `MINI_APP_URL` | - | **Yes** | Public HTTPS URL where the Mini App frontend is served | | `WEBHOOK_URL` | *(empty)* | No | Public HTTPS base URL for webhook mode. Leave empty to use long-polling | | `WEBHOOK_SECRET` | *(empty)* | No | Secret token sent by Telegram in the `X-Telegram-Bot-Api-Secret-Token` header | | `POSTGRES_PASSWORD` | `postgres` | No | PostgreSQL password | | `PORT` | `80` | No | Host port exposed by nginx | | `DEBUG` | `false` | No | Enable FastAPI debug mode | | `AVATAR_CACHE_TTL` | `3600` | No | Seconds to cache user and chat avatars server-side | > [!WARNING] > Always change `POSTGRES_PASSWORD` and generate a strong `WEBHOOK_SECRET` before exposing the deployment to the internet.
[![][back-to-top]](#readme-top)
## 🐳 Services The default compose stack starts four containers: | Container | Image | Purpose | |---|---|---| | `backend` | `tglotterybot-backend:latest` | FastAPI REST API + aiogram Telegram bot | | `frontend` | `tglotterybot-frontend:latest` | React + Vite Mini App (built static files) | | `nginx` | `nginx:alpine` | Reverse proxy; routes `/api/*` and `/webhook/*` to backend, everything else to frontend | | `postgres` | `postgres:16-alpine` | PostgreSQL persistent database | Persistent data is stored in `./postgres_data/`.
[![][back-to-top]](#readme-top)
## 📁 Project Structure ``` TGLotteryBot/ ├── backend/ # Python FastAPI + aiogram bot │ ├── app/ │ │ ├── main.py # FastAPI app entrypoint + lifespan setup │ │ ├── core/ │ │ │ ├── config.py # Pydantic settings (reads from env / .env) │ │ │ ├── database.py # Async SQLAlchemy engine and session factory │ │ │ └── security.py # Telegram initData HMAC-SHA256 validation │ │ ├── api/ │ │ │ ├── deps.py # FastAPI dependencies (authentication) │ │ │ ├── schemas.py # Pydantic request / response models │ │ │ └── routers/ │ │ │ ├── lotteries.py # Lottery CRUD, draw, and announce endpoints │ │ │ ├── prizes.py # Prize management endpoints │ │ │ ├── participants.py # Join / leave endpoints │ │ │ ├── chats.py # Managed chat list, links, and avatars │ │ │ └── users.py # User profile and avatar endpoints │ │ ├── bot/ │ │ │ ├── router.py # aiogram dispatcher and router registration │ │ │ ├── handlers/ # Bot command and event handlers │ │ │ └── keyboards/ # Inline keyboard builders │ │ ├── models/ # SQLAlchemy 2.0 ORM models │ │ │ ├── lottery.py # Lottery (status enum, all lottery fields) │ │ │ ├── prize.py # Prize (name, quantity, sort order) │ │ │ ├── participant.py # Lottery participants │ │ │ ├── winner.py # Draw results │ │ │ ├── user.py # Telegram users │ │ │ ├── managed_chat.py # Groups / channels the bot manages │ │ │ └── passphrase_verification.py │ │ └── services/ │ │ ├── draw_service.py # Draw algorithm (shuffle-based, SELECT FOR UPDATE) │ │ └── scheduler.py # Auto-draw scheduler + winner notifications │ ├── alembic/ # Alembic database migrations │ │ └── versions/ │ ├── requirements.txt │ └── Dockerfile ├── frontend/ # React 18 + Vite Telegram Mini App │ ├── src/ │ │ ├── pages/ # Route-level page components │ │ ├── components/ # Shared UI components │ │ ├── hooks/ # Custom React hooks │ │ ├── lib/ # API client, Telegram SDK wrapper, utilities │ │ └── types/ # TypeScript type definitions │ ├── package.json │ ├── vite.config.ts │ ├── Dockerfile # Production build │ └── Dockerfile.dev # Dev server (Vite) ├── nginx/ │ ├── nginx.conf # Production reverse proxy config │ └── nginx.dev.conf # Development config ├── docker-compose.yml # Production service definitions ├── docker-compose.override.yml # Development overrides (auto-applied) └── .env.example # Environment variable template ```
[![][back-to-top]](#readme-top)
## 🤝 Contributing Issues and pull requests are welcome. Please open an issue first for major changes so the direction can be discussed.
[![][back-to-top]](#readme-top)
## 📝 License Copyright © 2026 [Stardream](https://git.stdm.moe/Stardream). This project is licensed under the [GNU Affero General Public License v3.0](./LICENSE). **Permissions** | | | |---|---| | ✅ | Commercial use | | ✅ | Modification | | ✅ | Distribution | | ✅ | Private use | **Conditions** | | | |---|---| | ⚠️ | Disclose source - modified versions must also be open-source | | ⚠️ | Same license - derivative works must use AGPL-3.0 | | ⚠️ | Network use = distribution - if you run a modified version as a network service, you must make the source available to users | | ⚠️ | State changes - modifications must be documented | In short: you are free to use, modify, and self-host TGLotteryBot. If you distribute or offer a modified version as a hosted service, you must publish the full source under AGPL-3.0. --- [back-to-top]: https://img.shields.io/badge/-BACK_TO_TOP-black?style=flat-square [license-shield]: https://img.shields.io/badge/license-AGPL--3.0-white?labelColor=black&style=flat-square [license-link]: ./LICENSE [python-shield]: https://img.shields.io/badge/python-3.12-blue?labelColor=black&logo=python&logoColor=white&style=flat-square [python-link]: https://www.python.org/ [docker-shield]: https://img.shields.io/badge/docker-compose-2496ED?labelColor=black&logo=docker&logoColor=white&style=flat-square [docker-link]: https://docs.docker.com/compose/ [postgres-shield]: https://img.shields.io/badge/postgres-16-336791?labelColor=black&logo=postgresql&logoColor=white&style=flat-square [postgres-link]: https://www.postgresql.org/