A personal to-do Telegram bot that anyone can self-host. Multi-user, categories, priorities, due dates, search, JSON export — everything you need for a personal task inbox, nothing you don't.
- 📝 Add tasks with title, notes, priority (🟢/🟡/🔴), category, and a due date.
- 📋 Smart task list with filters (active / done / all) and pagination.
- 🏷 Categories — define your own, pick emojis, group tasks.
- 🔍 Search across titles and notes in a single tap.
- 📊 Stats — total, active, done, overdue.
- 📤 JSON export of your whole dataset. Data belongs to the user, always.
- 🧹 Clear completed in one action, with confirmation.
- 🌐 Multilingual — Russian & English out of the box; add a locale by dropping a folder.
- 👤 Multi-user by design — one bot instance serves many Telegram users, each with private data.
- 💾 SQLite default; swap to Postgres via
DATABASE_URL. - 🐳 Production Dockerfile — multi-stage, non-root, healthcheck, small image.
- 🚀 One-click deploy recipes for Railway / Render / Fly.io free tiers.
- ✅ Type-safe — ruff + mypy
strict+ pytest on Python 3.11 / 3.12 / 3.13 in CI.
┌─────────────────────────────────┐
│ 📝 Your personal To-Do. │
│ │
│ [ 📋 My tasks ] [ ➕ New task ] │
│ [ 🏷 Categories] [ 🔍 Search ] │
│ [ 📊 Stats ] [ ⚙️ Settings ] │
└─────────────────────────────────┘
Open @BotFather → /newbot → save the token.
| Target | Difficulty | Cost | Storage |
|---|---|---|---|
| Docker (local / VPS) | ⭐ | free | volume |
| Railway | ⭐ | free trial → $5/mo | volume |
| Render | ⭐⭐ | free worker | 1 GB disk |
| Fly.io | ⭐⭐ | free small VM | volume |
git clone https://github.com/arsenshahverdyanlavtxa228/tg-bot-todo.git
cd tg-bot-todo
cp .env.example .env # fill BOT_TOKEN
docker compose up -d --build
docker compose logs -f botStop with docker compose down. Data lives in ./data/bot.db.
- Fork this repo.
- Railway → New Project → Deploy from GitHub → pick the fork.
- Variables →
BOT_TOKEN. - Settings → Volumes → mount one at
/app/data(1 GB). - Deploy.
- Fork this repo.
- render.com → New → Blueprint → point at the fork.
- Render reads
render.yamland prompts forBOT_TOKEN. - Apply. Worker deploys with a 1 GB attached disk.
fly launch --copy-config --no-deploy
fly volumes create bot_data --size 1
fly secrets set BOT_TOKEN=xxxxxx
fly deployAll settings are environment variables. See .env.example.
| Variable | Required | Default | Description |
|---|---|---|---|
BOT_TOKEN |
✅ | — | Token from @BotFather. |
DATABASE_URL |
— | sqlite+aiosqlite:///./data/bot.db |
Any SQLAlchemy async URL. |
DEFAULT_LOCALE |
— | ru |
ru / en. User can change it anytime from settings. |
LOG_LEVEL |
— | INFO |
DEBUG / INFO / WARNING / ERROR. |
DROP_PENDING_UPDATES |
— | false |
Drop stale updates on startup. |
TASKS_PER_PAGE |
— | 5 |
Default page size (3–20). Per-user override from settings. |
/start → main menu
📋 My tasks — paginated list with Active/Done/All filters
↳ tap a task — view + actions (toggle, edit, delete)
➕ New task — title → notes → priority → category → due date
(any step can be skipped with the "Skip" button)
🏷 Categories — create, pick emoji, delete
🔍 Search — by title or notes
📊 Stats — total, active, done, overdue
⚙️ Settings — language, page size, JSON export, clear completed
Due date format: YYYY-MM-DD or YYYY-MM-DD HH:MM. Overdue tasks get a
make dev # create .venv + install runtime & dev deps
cp .env.example .env
make runmake lint # ruff check
make fmt # ruff format + auto-fix
make typecheck # mypy strict
make test # pytest
make cov # tests with HTML coveragesrc/bot/
__main__.py entrypoint
config.py pydantic-settings
handlers/
menu.py /start and main menu
tasks.py list / view / toggle / delete
add_task.py FSM for creating a task
edit_task.py per-field edit flows
categories.py CRUD
search.py full-text search
settings.py language, page size, export, clear
common.py shared helpers (cancel/skip/parse_due/format_task_view)
keyboards/common.py inline & reply keyboard builders
middlewares/
db.py opens session + ensures user + Repository
i18n.py per-user translator
database/
models.py User, Category, Task, Priority
repo.py user-scoped data access
session.py async engine + session factory
services/i18n.py Fluent-based translator
locales/ru/main.ftl
locales/en/main.ftl
states/todo.py FSM state groups
- Copy
src/bot/locales/en/main.ftlintosrc/bot/locales/<lang>/main.ftl. - Translate values. Keep keys identical.
- Extend the language keyboard in
keyboards/common.pywith the new locale. - Restart the bot.
- Recurring tasks (daily / weekly).
- Reminder notifications via APScheduler.
- Inline query: share a task to any chat.
- Postgres recipe verified in CI.
- Web dashboard (optional companion).
PRs and issues welcome. Before submitting:
make lint fmt typecheck testall green.- Update
CHANGELOG.mdunder[Unreleased].
MIT — do whatever, just keep the notice.