Files
TGLotteryBot/README.md
T
Stardream eace48732d
Build and Push Docker Images / build (push) Successful in 17s
Initial release
2026-06-02 12:02:02 +10:00

316 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<div align="center"><a name="readme-top"></a>
# 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]
</div>
---
- [✨ 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_<id>` 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
```
<div align="right">
[![][back-to-top]](#readme-top)
</div>
## 🤖 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.
<div align="right">
[![][back-to-top]](#readme-top)
</div>
## 📡 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.
<div align="right">
[![][back-to-top]](#readme-top)
</div>
## 💻 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.
<div align="right">
[![][back-to-top]](#readme-top)
</div>
## ⚙️ 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.
<div align="right">
[![][back-to-top]](#readme-top)
</div>
## 🐳 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/`.
<div align="right">
[![][back-to-top]](#readme-top)
</div>
## 📁 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
```
<div align="right">
[![][back-to-top]](#readme-top)
</div>
## 🤝 Contributing
Issues and pull requests are welcome. Please open an issue first for major changes so the direction can be discussed.
<div align="right">
[![][back-to-top]](#readme-top)
</div>
## 📝 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.
---
<!-- LINK GROUP -->
[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/