Skip to content

Latest commit

 

History

History
207 lines (157 loc) · 7.17 KB

File metadata and controls

207 lines (157 loc) · 7.17 KB

tg-bot-todo

CI Python aiogram License: MIT Code style: ruff Docker

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.


✨ Features

  • 📝 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.

📸 Preview

┌─────────────────────────────────┐
│ 📝 Your personal To-Do.         │
│                                 │
│ [ 📋 My tasks ] [ ➕ New task ] │
│ [ 🏷 Categories] [ 🔍 Search ]  │
│ [ 📊 Stats    ] [ ⚙️ Settings ] │
└─────────────────────────────────┘

🚀 Quick start

1. Create a bot

Open @BotFather/newbot → save the token.

2. Pick your deploy target

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

🐳 Docker (local or VPS)

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 bot

Stop with docker compose down. Data lives in ./data/bot.db.

🚂 Railway

Deploy on Railway

  1. Fork this repo.
  2. Railway → New Project → Deploy from GitHub → pick the fork.
  3. VariablesBOT_TOKEN.
  4. Settings → Volumes → mount one at /app/data (1 GB).
  5. Deploy.

🎨 Render

  1. Fork this repo.
  2. render.comNew → Blueprint → point at the fork.
  3. Render reads render.yaml and prompts for BOT_TOKEN.
  4. Apply. Worker deploys with a 1 GB attached disk.

🎈 Fly.io

fly launch --copy-config --no-deploy
fly volumes create bot_data --size 1
fly secrets set BOT_TOKEN=xxxxxx
fly deploy

⚙️ Configuration

All 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.

🎮 How to use

/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 ⚠️ marker.


🧑‍💻 Local development

make dev         # create .venv + install runtime & dev deps
cp .env.example .env
make run
make lint         # ruff check
make fmt          # ruff format + auto-fix
make typecheck    # mypy strict
make test         # pytest
make cov          # tests with HTML coverage

Project layout

src/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

🌍 Adding a new language

  1. Copy src/bot/locales/en/main.ftl into src/bot/locales/<lang>/main.ftl.
  2. Translate values. Keep keys identical.
  3. Extend the language keyboard in keyboards/common.py with the new locale.
  4. Restart the bot.

🗺️ Roadmap ideas

  • 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).

🤝 Contributing

PRs and issues welcome. Before submitting:

  1. make lint fmt typecheck test all green.
  2. Update CHANGELOG.md under [Unreleased].

📄 License

MIT — do whatever, just keep the notice.