
# [Bot Name] · Telegram bot

A Telegram bot. Webhook-driven so it scales without polling. Inline keyboards, conversation state in Redis, payments via Telegram Stars.

## Source of truth
GitHub. Deployed as a webhook receiver on Cloudflare Workers (small bots) or Fly.io (larger). Telegram's BotFather is the source of truth for token + commands list.

## Tech stack
Node 22 + TypeScript + grammY 1.x (the modern Telegram framework). Redis for conversation state (sessions, multi-turn flows). Postgres for persistent data. Optional: `@grammyjs/conversations` for state-machine flows, `@grammyjs/menu` for inline keyboards.

## Deploy
- Set webhook: `curl 'https://api.telegram.org/bot<TOKEN>/setWebhook?url=https://yourdomain.com/webhook'`
- Verify: `curl 'https://api.telegram.org/bot<TOKEN>/getWebhookInfo'`
- Code: `fly deploy` or `wrangler deploy`

## File map
- `src/bot.ts` grammY instance + plugin registration
- `src/webhook.ts` HTTP entrypoint (Express, Hono, or Cloudflare Worker fetch)
- `src/handlers/commands/` one file per command (`/start.ts`, `/help.ts`)
- `src/handlers/callbacks/` callback query handlers (inline keyboard taps)
- `src/conversations/` multi-turn flows (signup, booking)
- `src/menus/` reusable inline menus
- `src/lib/db.ts`, `src/lib/redis.ts`

## .env keys
- `TELEGRAM_BOT_TOKEN` from BotFather
- `TELEGRAM_WEBHOOK_SECRET` for signature verification
- `DATABASE_URL`
- `REDIS_URL`

## Hard rules
- Webhook secret in the URL path (e.g. `/webhook/<secret>`) OR validated via `X-Telegram-Bot-Api-Secret-Token`. Anyone can hit your URL otherwise.
- Telegram expects a 200 response within 60 seconds. Long work goes to a queue; reply with a placeholder message immediately.
- File downloads via `bot.api.getFile` -> URL. Large files (>20MB) need bot API "local mode" or a different transport.
- Inline keyboard callback data is a 64-byte limit. Don't shove JSON in there; use IDs and look up state in Redis.
- Set bot commands via `bot.api.setMyCommands` once on deploy. Updates Telegram's `/` autocomplete UI.
- Privacy mode (default ON) means the bot only sees commands and messages mentioning it. Disable only if you need to read all group messages, and disclose it.

## Recent significant changes
- 2026-04-28: Scaffolded. Locked: grammY over node-telegram-bot-api (modern, ESM, types), webhook over polling (scale), Redis for conversation state.

## Next session: start here
1. Talk to @BotFather. Create bot. Save `TELEGRAM_BOT_TOKEN`.
2. Set commands: `/start`, `/help`, plus your domain-specific ones.
3. Implement `/start` handler. Test via DM with the bot.
4. Set webhook to ngrok URL during dev. Confirm Telegram fires it.
5. Deploy to prod, repoint webhook to prod URL.
