Integration Guide
The current codebase is small enough to understand quickly, but it already has boundaries that are worth preserving. This guide describes how to integrate new bot behavior without pushing everything into the Telegram handler layer.
Start from the owning layer
Use these responsibilities as your default rule:
internal/botowns Telegram update matching, input parsing, and Telegram API callsinternal/sessionowns per-chat state persistenceinternal/configowns environment-derived behaviorinternal/appowns runtime composition and lifecycle
If you add business rules, they should usually become a new package that the bot layer calls into, instead of turning internal/bot/service.go into the entire application.
Adding a new command
The current command registration happens in registerHandlers().
Important detail: the go-telegram/bot library command pattern does not include the leading slash. Register start, not /start.
Use these match types intentionally:
MatchTypeCommandStartOnlyfor commands that should only match at the start of the messageMatchTypeCommandfor commands that need arguments, such as/echo <text>MatchTypePrefixfor callback data prefixes likemenu:
Recommended flow for a new command:
- Register the handler in
registerHandlers() - Add a dedicated
handle...method - Update
helpMessage() - Add the command to
syncCommands()if it should appear in Telegram's command menu - Write a focused test for the behavior or the routing rule
Keeping transport and business logic separate
If a handler starts doing more than parsing input and formatting a response, extract the core behavior into a new package. For example:
internal/usecasefor application rulesinternal/storefor domain-specific persistenceinternal/servicefor integration-oriented orchestration
The bot layer should remain the place where Telegram models are translated into application inputs and application outputs are translated back into Telegram responses.
Working with session state
The session store is intentionally small:
Increment()for countersSet()for string valuesGet()for reading string valuesBackend()for diagnostics and output
This is enough for lightweight bot state such as:
- Visit counts
- Last command tracking
- Menu flow checkpoints
- Short-lived conversational state
If you need more complex state, either wrap the existing store or introduce a dedicated persistence layer instead of expanding the store blindly.
Choosing polling or webhook for integrations
Use polling when:
- You are developing locally
- You do not yet have a public endpoint
- Simplicity matters more than horizontal scale
Use webhook mode when:
- The bot runs behind a public HTTPS endpoint
- You want Telegram to push updates directly to your service
- Your deployment already exposes HTTP reliably
The rest of the application is intentionally similar across both modes. Only the delivery mechanism changes.
Handling callback and inline workflows
The template already demonstrates two common Telegram interaction patterns:
- Inline keyboard buttons using callback data with the
menu:prefix - Inline query responses using article results
When you extend these flows:
- Keep callback data structured and prefix-based
- Validate and normalize any user-controlled data before using it
- Keep inline query results small and predictable
- Use session state only when the interaction is actually chat-scoped
Recommended extension path
If you are evolving the template into a real product, this is a reasonable sequence:
- Add new commands and extract reusable formatting
- Introduce a use-case layer for business logic
- Add external APIs or domain storage behind interfaces
- Add metrics, tracing, or audit logging where needed
- Move from polling to webhook mode when deployment requires it