A Telegram bot tailored for a fish store. This application bridges a sleek Telegram customer interface with a powerful Strapi CMS backend for real-time inventory management, product updates, and order processing. By leveraging Redis, the bot maintains lightning-fast user session states (FSM), allowing customers to seamlessly browse products, manage their shopping carts, and place orders directly from their phones.
- βοΈ Tech Stack
- π Project Structure
- π οΈ Installation & Setup
- π Quick Start Guide
- π Database Models Architecture
- π Strapi v5 Backend Configuration
- π Managing PostgreSQL via Adminer
- π Inspecting Redis Data via Docker
- Python 3.10+: Core bot logic.
- Node.js v20/v22/v24: Runtime environment for running the Strapi CMS backend.
- Strapi v5: Headless CMS for managing products.
- Docker & Docker Compose: For containerizing PostgreSQL and Redis services (optional).
- Database: Supports PostgreSQL (via Docker) and SQLite.
- python-telegram-bot v13.15: Framework for Telegram Bot API.
- Redis: In-memory data structure store for managing user conversation states (via Docker or local).
After creation, your project should look like this:
.
βββ strapi/ # Strapi files
β βββ config/ # Strapi configuration files
β βββ database/ # Local database migration files
β βββ dist/ # Production build outputs
β βββ public/ # Static assets for Strapi
β βββ scripts/ # Automation and helper scripts
β βββ src/ # Strapi backend source code
β βββ types/ # TypeScript type definitions
β βββ package.json # Node.js project manifest and Strapi dependencies
β βββ package-lock.json # Locked versions of Node.js dependencies
β βββ tsconfig.json # TypeScript configuration
βββ database.py # Connection pool setup for Redis
βββ keyboards.py # Centralized module for reusable reply and inline menu button configurations
βββ screens.py # Bot screens management and UI rendering
βββ strapi_api.py # Client for executing requests against the Strapi REST API
βββ logging_config.py # Logging configuration for the Python bot
βββ main.py # Main entry point for the Python bot
βββ requirements.txt # Python dependencies
- Node.js (v20, v22, or v24)
- Python (v3.10 or higher)
- Redis server (running locally or via Docker)
- Telegram bot token (from @BotFather)
- Basic knowledge of Strapi CMS
- Strapi API token
git clone https://github.com/VictoriaL-dev/fish-store-bot.git
cd fish-store-botCreate 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:
# 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
# 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
# Telegram
TG_BOT_TOKEN=your_bot_tokenFrom the root directory, create a Strapi app inside the strapi folder:
cd fish-store-bot
npx create-strapi-app@5.48.1 strapiIn the automatically created .env file in the strapi folder configure your database choice (toggle between sqlite and postgres).
Make sure the database variables in strapi/.env and the root .env match:
# Database
DATABASE_CLIENT=postgres # Replace with 'sqlite' if you don't plan to use PostgreSQL
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.txt1. Spin up PostgreSQL and Redis using Docker (or, if you're not using Docker, SQLite and locally running Redis instead):
docker-compose -f docker-compose-dev.yaml up -dcd strapi
npm run developYou can access the admin panel at http://localhost:1337/admin.
Open a new terminal in the root directory, activate your Python virtual environment, and start the bot:
python main.pyOpen Telegram, find your bot, and send the /start command.
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.
username(String) β Unique Telegram identifier.email(Email) β Customer's email.password(Password) β Auto-generated secure password.cart(Relation) β Cart has many Users linkage.
Stores the shop's assortment data.
title(String) β Name of the fish / seafood item.description(Long Text) β Detailed product description.price(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(String / BigInt) β Unique Telegram Chat ID.users_permissions_users(Relation) β Cart belongs to many Users.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(Integer) β The weight of items added.
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:
3. Look at your browser's address bar. The URL will end with a specific number (e.g., .../users-permissions/roles/1).
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)
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)
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-cli127.0.0.1:6379> AUTH your_redis_password
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.