Skip to content

Repository files navigation

Multi-Bot Telegram Platform

A multi-bot Telegram platform on a single domain. A bot-agnostic Core layer hosts self-contained bot modules under src/Bot/<Name>/. The first module is the AI sticker bot, which generates stickers with OpenAI's image generation.

Adding a bot is near-zero-ops: per-bot Telegram credentials live in the database (not env/secrets), so a new bot that reuses an existing module is just a row in the admin UI — no env changes, no redeploy.

Architecture

src/
├── Core/            # bot-agnostic platform: webhook routing, command dispatch,
│                    #   per-bot API clients, DB-backed bot config, user scoping
└── Bot/Sticker/     # the sticker bot module (reference implementation)
  • One webhook endpointPOST /webhook/{bot}. The {bot} segment selects the bot from the bot DB table; the row supplies the token and the webhook secret.
  • Per-bot users — a single user table scoped by a bot column; each module's repository always queries by bot, so users never leak across bots.
  • Telegram SDKirazasyed/telegram-bot-sdk wrapped in a small Symfony integration (no framework bundle).

Usage (sticker bot)

In a chat with the bot:

/sticker 🐱 happy orange cat --pixel   # generate a sticker (optional style flag)
/remix <photo caption>                  # turn a photo into a sticker
/pack                                   # manage your sticker packs

Tech Stack

  • Framework: Symfony 7
  • Database: MySQL
  • Telegram: irazasyed/telegram-bot-sdk
  • Image Processing: Intervention Image
  • Runtime: Docker (php-fpm + nginx), reverse-proxied by Plesk
  • Deployment: GitHub Actions → GHCR images → Docker Compose on the host

Adding a bot

Reusing an existing module (e.g. a second sticker bot) — no deploy:

  1. Create the bot with @BotFather.
  2. In the admin UI (/admin/bots) → Add bot (name, username, token). The webhook secret is generated automatically.
  3. Click Register webhook. Done — it serves at /webhook/<name>.

CLI equivalent: bin/console app:bot:add <name> <token> <username> then bin/console app:telegram:webhook set --bot=<name>.

A new bot type (new commands) — deploy once, then the steps above:

  1. Create src/Bot/<Name>/:
    • <Name>Module.php with public const NAME = '<name>';
    • Telegram/Abstract<Name>Command.php extending Core\Telegram\BotCommand with public const BOT = <Name>Module::NAME;
    • Entity/<Name>User.php extends Core\Entity\BotUser (can add its own fields)
    • command classes extending the module's abstract command
  2. If the module has entities, add a doctrine.yaml mapping and run bin/console doctrine:migrations:diff / migrate.
  3. Deploy, then add the bot row + register its webhook as above.

No new domain, no routing edits, no per-bot env vars or deploy secrets.

Environment Variables

Only app-global values — not per-bot Telegram credentials (those live in the DB):

Variable Description
APP_BASE_URL Public base URL, used to build webhook URLs (no trailing slash)
OPENAI_API_KEY OpenAI API key (sticker module)
DATABASE_URL MySQL connection string
APP_SECRET Random 64-char hex string (openssl rand -hex 32)
SENTRY_DSN Sentry DSN (optional)

Local Development

docker compose up --build          # php (:8000) + mysql
docker compose exec php composer install
docker compose exec php bin/console doctrine:migrations:migrate
docker compose exec php bin/console app:bot:add sticker <token> <username>
docker compose exec php bin/console app:dev:webhook   # ngrok + register webhooks

Or run the app directly with symfony server:start against a local MySQL.

Deployment

Pushes to master build the php/web images, push them to GHCR, and deploy via Docker Compose on the Plesk host (reachable at the loopback port Plesk proxies). Required repository secrets:

Secret Description
SERVER_HOST Server IP / hostname
SERVER_USER SSH username
SERVER_SSH_KEY Private SSH key
DEPLOY_PATH Directory on the host holding compose.prod.yaml + .env.prod.local
TELEGRAM_BOT_TOKEN Sticker bot token — used once to seed the DB row on first deploy
TELEGRAM_BOT_USERNAME Sticker bot username — same

On the host, create .env.prod.local from .env.prod.example (app-global vars only). After the sticker bot's row is seeded, the TELEGRAM_BOT_* secrets and the seed step can be removed — bots are managed from /admin/bots.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages