An asynchronous Telegram bot tailored for a fish store. This application bridges a sleek
and highly interactive Telegram customer interface with a powerful Strapi CMS backend for real-time
inventory management, catalog distribution, and secure user processing.
By leveraging an asynchronous Redis connection pool, the bot manages independent customer session
states (FSM) and high-speed memory locks to guarantee a non-blocking user experience under request concurrency.
The entire network architecture is built on cooperative multitasking, utilizing aiohttp and python-telegram-bot v22.x
to enable customers to seamlessly browse fresh product assortments, modify shopping carts, and finalize order details
dynamically right from their devices.
- βοΈ Tech Stack
- π Project Structure
- π οΈ Installation and Setup
- π Quick Start Guide
- π Database Models Architecture
- π Strapi v5 Backend Configuration
- π Managing PostgreSQL via Adminer
- π Inspecting Redis Data via Docker
- Operating System: Linux, macOS, or Windows (via WSL2)
- Language:
Python 3.11+ - Database:
PostgreSQL&Redis(via Docker) - Configuration:
pydantic-settings&pydantic - Backend:
Node.js v24.x&Strapi - Async Telegram Bot Framework:
python-telegram-bot v22.x - Async HTTP Framework:
aiohttp - Containerization & Orchestration:
Docker&Docker Compose
.
βββ logs/ # Dynamically generated application logs folder
βββ strapi/ # Strapi files
βββ .env.example # Example of environment variable configuration
βββ config.py # Central application settings mapper
βββ database.py # Connection pool setup for Redis
βββ logging_config.py # Non-blocking async queue logger
βββ keyboards.py # Dynamic InlineKeyboardMarkup factories for navigation controls
βββ screens.py # Interface rendering functions layer for message transitions
βββ handlers.py # Core asynchronous FSM step handlers routing user navigation
βββ strapi_api.py # Asynchronous Strapi CMS HTTP integration engine
βββ main.py # Main entry point for the Telegram bot
βββ Dockerfile.strapi.dev # Strapi container blueprint
βββ docker-compose-dev.yaml # Docker services orchestration
βββ requirements.txt # Python dependencies
- Node.js (v20, v22, or v24)
- Python (v3.11 or higher)
- WSL2 (if you're on Windows and plan to use Docker Compose)
- Redis server (running locally or via Docker Desktop)
- Telegram bot token (from @BotFather)
- Basic knowledge of Strapi CMS
- Strapi API token
git clone https://github.com/...
cd project-directoryCreate a .env file in the root directory based on .env.example and fill in the variables for PostgreSQL if you plan
to run it through Docker, or leave them blank:
# PostgreSQL
DATABASE_PORT=5433
DATABASE_NAME=postgres_db
DATABASE_USERNAME=postgres_user
DATABASE_PASSWORD=your_postgres_password
# Adminer
ADMINER_PORT=8080
# Redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=your_redis_password
# Logging
LOG_LEVEL=INFO
# Strapi API
STRAPI_TOKEN=your_full_access_or_custom_token
STRAPI_URL=http://localhost:1337
STRAPI_USER_ROLE=1 # Authenticated user role id
STRAPI_USER_PASSWORD=your_password_for_strapi_user_creation
# Telegram
TG_BOT_TOKEN=your_bot_tokenFrom the root directory, create a Strapi app inside the strapi folder:
cd project-directory
npx create-strapi-app@5.48.1 strapiIn the automatically created .env file in the strapi folder configure your database choice.
Make sure the database variables in strapi/.env and the root .env match:
# Database
DATABASE_CLIENT=postgres
DATABASE_HOST=127.0.0.1
DATABASE_PORT=5433
DATABASE_NAME=fish_store
DATABASE_USERNAME=fish_store_user
DATABASE_PASSWORD=your_postgres_passwordpython -m venv venv
venv\Scripts\activate # on Windows
source venv/bin/activate # on Linux / macOSpip install -r requirements.txtMake sure your environment variables are configured in the root .env and strapi/.env files. Then, run the following command from the root directory to build and launch all backend services in development mode:
docker compose -f docker-compose-dev.yaml up --buildβΉοΈ Note: The infrastructure automatically configures internal networking. Strapi will wait until PostgreSQL is healthy before initialization.
You can access the admin panel at http://localhost:1337/admin.
Open a new terminal window or tab in the project root directory, activate your Python virtual environment, and boot up the bot application:
python main.pyOpen Telegram, find your bot, and send the /start command.
docker compose -f docker-compose-dev.yaml down- Stop and remove all containers and networks defined in the dev configuration.docker compose -f docker-compose-dev.yaml up -d- Start all containers in detached background mode.docker compose -f docker-compose-dev.yaml restart- Restart all containers.docker compose -f docker-compose-dev.yaml logs -f strapi- View and follow real-time logs from Strapi.
The database relies on a junction model (CartProduct) to handle a custom Many-to-Many relationship between Carts and Products, allowing the bot to store unique metadata like product quantities.
Extends the standard Strapi user model to associate customers with their active sessions.
cart(Relation) - User has and belongs to one Cart.orders(Relation) - User belongs to many Orders.
Stores the shop's assortment data.
title(Short Text) - Name of the fish / seafood item.description(Long Text) - Detailed product description.price(Decimal Number) - Price per 1 kilogram.picture(Media: Single Media) - Image file uploaded to the Media Library.cart_products(Relation) - Product belongs to many CartProducts.
Maintains live Telegram user sessions.
tg_id(Short Text) - Unique Telegram Chat ID.users_permissions_users(Relation) - Cart has and belongs to one User.cart_products(Relation) - Cart belongs to many CartProducts.
Acts as a pivot table to keep track of dynamic quantities for items inside specific carts.
cart(Relation) - Cart has many CartProducts.product(Relation) - Product has many CartProducts.quantity(Decimal Number) - The weight of items added.
Stores order data.
order_id(Short Text) - Unique order identifier.users_permissions_users(Relation) - User has many Orders.phone_number(Short Text) - The phone number provided by the user.active(Boolean) - Order status (active or inactive). Only one order can be active at a time.order_items(JSON) - A list of products including the item name, quantity, and price at the time of the order in JSON format.
To ensure the Telegram bot can successfully communicate with Strapi v5, you need to configure specific roles and permissions in your Strapi Admin Panel http://localhost:1337/admin.
When the bot automatically registers a new customer using their email during checkout, it forces Strapi to assign them to a default system role (typically Authenticated). To find the exact ID of this role for your strapi_api configuration:
- Navigate to Settings β Roles (under the Users & Permissions Plugin section).
- Click on the Authenticated role to open its settings.
- Look at your browser's address bar. The URL will end with a specific number (e.g.,
.../users-permissions/roles/1). - This number is your Authenticated Role ID. Set this value in your
.envfile.
If you are connecting your Telegram bot to Strapi using a Custom API Token (generated via Settings β API Tokens with token type set to Custom), you must explicitly check the boxes for the following permissions at the bottom of the token settings page:
Cart:
- find (allows checking if a user already has a shopping cart)
- create (allows creating a new shopping cart for a first-time user)
- update (allows linking a Strapi User to an existing Cart during checkout)
Cart-Product:
- find (allows reading cart items to display them in the telegram cart screen)
- create (allows adding a new item to the cart)
- update (allows incrementing or decrementing product quantities)
- delete (allows removing an item from the cart)
Order:
- find (allows locating an active order)
- create (allows creating a new order)
Product:
- find (allows pulling the full list of products for the catalog)
- findOne (allows opening a detailed product description card)
Users-Permissions (under the User subsection)
- find (allows looking up if a customer's email is already registered)
- create (allows registering a new user profile with their email during checkout)
- update (allows updating the user's email)
Upload (Media Library plugin):
- find (allows the bot to deep-populate and extract relative URLs for fish images stored inside product relations)
This project includes Adminer, a lightweight and fast database management interface available via web browser. It
is configured to run inside a Docker container alongside PostgreSQL.
docker-compose -f docker-compose-dev.yaml up -d2. Open your web browser and navigate to: http://localhost:8080.
- System:
PostgreSQL - Server:
postgres(This must match the service name defined in yourdocker-compose-dev.yamlfile) - Username:
[Your DATABASE_USERNAME] - Password:
[Your DATABASE_PASSWORD] - Database:
[Your DATABASE_NAME]
4. Click login. You can now view tables, run custom SQL queries, and manage data directly from your browser.
Run the following command to open the interactive Redis CLI inside your running container:
docker compose -f docker-compose-dev.yaml exec redis redis-cli
127.0.0.1:6379> AUTH <your_redis_password>Or you can log in via the CLI arguments:
docker compose -f docker-compose-dev.yaml exec redis redis-cli -a <your_redis_password>
β οΈ Use this command only for local development.
Once inside the CLI, you can use these basic commands to inspect the bot's state:
KEYS *- List all keys currently stored in the database.GET <key>- View the content of a specific text key.TTL <key>- Check the remaining Time-To-Live for temporary keys.DEL <key>orDEL <key1> <key2>- Remove specific keys from the database.UNLINK <huge_key>- Asynchronously delete huge keys without blocking the main thread.FLUSHDB- Clear all data from current database.FLUSHALL- Clear all data from all databases.
Type exit or press Ctrl + C to return to your local terminal.
