|
| 1 | +# Agent Instructions |
| 2 | + |
| 3 | +This is a Telegram bot project. |
| 4 | + |
| 5 | +## Project Structure |
| 6 | + |
| 7 | +The project has a modular structure where each component has a clearly defined responsibility. |
| 8 | + |
| 9 | +- `/bot/callbacks/`: Contains `CallbackData` factories for handling inline button clicks. |
| 10 | +- `/bot/configs/`: Manages configuration using `pydantic-settings`. Settings are loaded from environment variables and a |
| 11 | + `.env` file. |
| 12 | +- `/bot/handlers/`: The main logic for processing incoming messages and callbacks from Telegram. The `Handlers` class |
| 13 | + contains all the handler methods. |
| 14 | +- `/bot/i18n/`: Implements internationalization (i18n). Contains translation files (`ru.py`, `en.py`) and the `Lexicon` |
| 15 | + class for accessing texts in the desired language. |
| 16 | +- `/bot/keyboards/`: The `Keyboards` class for generating Reply and Inline keyboards. |
| 17 | +- `/bot/middlewares/`: Middleware. |
| 18 | + - `i18n.py`: Determines the user's language. |
| 19 | + - `throttling.py`: Limits the rate of user requests. |
| 20 | + - `context.py`: Gathers dependencies into a single context object. |
| 21 | +- `/bot/services/`: The service layer and business logic. |
| 22 | + - `bot_service.py`: An example of a service with business logic (e.g., `upper()`). |
| 23 | + - `context.py`: The `HandlerContext` `dataclass` which aggregates all major dependencies. |
| 24 | +- `/bot/states/`: State definitions for the FSM (Finite State Machine) using `StatesGroup`. |
| 25 | +- `main.py`: The application's entry point. This is where the initialization of `FastAPI`, the bot, the dispatcher, and |
| 26 | + the registration of all handlers, middlewares, and dependencies occurs. |
| 27 | + |
| 28 | +## Architecture Overview |
| 29 | + |
| 30 | +The project is built on the **aiogram 3**, **FastAPI**, and **Pydantic** stack. It uses webhooks to receive updates from |
| 31 | +Telegram, which is the preferred method for a production environment. |
| 32 | + |
| 33 | +### Dependency Injection (DI) with a Context Object |
| 34 | + |
| 35 | +Instead of passing multiple dependencies into each handler, we use a single context object. |
| 36 | + |
| 37 | +**How it works:** |
| 38 | + |
| 39 | +1. **Singleton Initialization:** In `main.py`, within the `register_workflow_data` function, we create a single instance |
| 40 | + of all key services (`Keyboards`, `BotService`, `Lexicon`) and store them in `dp.workflow_data`. |
| 41 | +2. **Context Assembly:** The `ContextMiddleware` runs with every incoming update. It retrieves the previously created |
| 42 | + services from `data` and packs them into the `HandlerContext` `dataclass`. |
| 43 | +3. **Injection into Handler:** The prepared `ctx: HandlerContext` object is automatically passed as an argument to any |
| 44 | + handler that requests it via a type hint. |
| 45 | + |
| 46 | +**Agent Instruction:** |
| 47 | +> When adding new functionality that requires access to services (e.g., a database), follow this |
| 48 | +> pattern: |
| 49 | +> 1. Create a new service class (e.g., `DatabaseService`). |
| 50 | +> 2. Add an instance of it to `workflow_data` in `main.py`. |
| 51 | +> 3. Add a new field to the `HandlerContext` `dataclass`. |
| 52 | +> 4. Add the initialization for this field in `ContextMiddleware`. |
| 53 | +> 5. You can now access your service in any handler via `ctx.database_service`. |
| 54 | +
|
| 55 | +### Update Flow |
| 56 | + |
| 57 | +1. Telegram sends a JSON update to the FastAPI endpoint (`/webhook/tg`). |
| 58 | +2. The `webhook_handler` in `main.py` validates the data and passes it to `dispatcher.feed_update()`. |
| 59 | +3. The dispatcher sequentially runs the **outer middlewares**: |
| 60 | + - `I18nMiddleware` determines the `user_lang`. |
| 61 | + - `ThrottlingMiddleware` checks the request frequency. |
| 62 | + - `ContextMiddleware` assembles the `ctx` object. |
| 63 | +4. The dispatcher finds a suitable handler based on filters (`CommandStart`, `F.text`, etc.). |
| 64 | +5. The dispatcher calls the found handler, passing it all necessary data, including `message`, `state`, and our `ctx`. |
| 65 | + |
| 66 | +## Coding Style & Naming Conventions |
| 67 | + |
| 68 | +Maintaining a consistent code style is critically important for the project's readability and maintainability. |
| 69 | + |
| 70 | +- **Language:** Python 3.12+, line length 120. Strict typing is non-negotiable. |
| 71 | +- **Type Hinting:** **Mandatory.** All new functions, methods, and variables must have strict type annotations. This is |
| 72 | + the foundation for DI and static analysis. |
| 73 | +- **Naming:** |
| 74 | + - Classes: `PascalCase` (e.g., `BotService`, `HandlerContext`). |
| 75 | + - Functions, methods, variables: `snake_case` (e.g., `start_command`, `user_lang`). |
| 76 | + - Constants: `UPPER_SNAKE_CASE` (e.g., `LEXICON_RU`). |
| 77 | + - Modules: `snake_case` (e.g., `bot_service.py`). |
| 78 | +- **Internationalization:** All user-visible strings (messages, button text) must be moved to the lexicon files in |
| 79 | + `/i18n/` and retrieved using `ctx.lexicon.get_text()`. Do not hardcode strings in handlers and keyboards. |
0 commit comments