- Python 86.6%
- HTML 12.8%
- Dockerfile 0.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| services | ||
| .env.example | ||
| .gitignore | ||
| .python-version | ||
| docker-compose.override.example.yml | ||
| docker-compose.yml | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
Telegram Marketing Automation Platform
Automated lead generation and conversion system for courier service business through Telegram.
Services
| Service | Port | Stack |
|---|---|---|
| Backend API | ${API_PORT} (8008) |
FastAPI + Uvicorn |
| Dashboard | ${WEB_PORT} (8088) |
Flask |
| Main Bot | — | Aiogram 3.x |
| Userbot Service | ${USERBOT_SERVICE_PORT} (8010) |
FastAPI + Telethon |
Infrastructure: PostgreSQL 18, RabbitMQ 4.0 (Redis planned).
Prerequisites
Setup
cp .env.example .env
# Edit .env with your credentials
uv sync # install all dependencies into .venv
Development (local)
Run infrastructure in Docker, services locally for hot reload and debugger access. The .env file is tuned for local dev out of the box — no edits needed.
# 1. Start infrastructure (PostgreSQL + RabbitMQ)
docker compose up -d db rabbitmq
# 2. Run migrations
uv run --package backend-api alembic -c services/backend-api/alembic.ini upgrade head
# 3. Run the service(s) you're working on
uv run --package backend-api fastapi dev services/backend-api/app/main.py --port 8008
uv run --package userbot-service fastapi dev services/userbot-service/app/main.py --port 8010
uv run --package dashboard flask --app services.dashboard.app run --port 8088 --reload --debug
uv run --package main-bot python services/main-bot/app/main.py
# 4. (Optional) Start the TaskIQ worker for async DM message processing
uv run --package backend-api taskiq worker app.tasks.broker:broker app.tasks --app-dir services/backend-api
Locally, services resolve each other on localhost (backend-api → localhost:8010 for userbot-service, and vice versa). RabbitMQ runs on localhost:5672 (AMQP) with the management UI at http://localhost:15672 (default credentials from .env: guest/guest).
docker-compose.override.yml is gitignored (dev-only). Create it once after cloning to expose infrastructure ports to localhost:
cp docker-compose.override.example.yml docker-compose.override.yml
Running tests
Tests use pytest + pytest-asyncio with Hypothesis for property-based testing. No live database needed — unit tests mock the DB layer.
# Run all backend-api tests (from project root)
uv run --package backend-api python -m pytest services/backend-api/tests/ -v
# Run all userbot-service tests
uv run --package userbot-service python -m pytest services/userbot-service/tests/ -v
# Run all dashboard tests
uv run --package dashboard python -m pytest services/dashboard/tests/ -v
# Or from the service directory
cd services/backend-api
uv run python -m pytest tests/ -v
# Run a specific test file
uv run python -m pytest tests/test_userbots_service.py -v
# Run with Hypothesis statistics
uv run python -m pytest tests/ -v --hypothesis-show-statistics
Managing dependencies
This project uses a uv workspace — one .venv at the root shared by all services.
# Add a dependency to a specific service
uv add --package backend-api redis
# Sync .venv (installs all workspace packages + their deps)
uv sync --all-packages
# Rebuild .venv from scratch (if corrupted or switching Python versions)
rm -rf .venv
uv sync --all-packages
# Export for Docker builds (production deps only, no test/dev packages)
uv export --package backend-api --no-hashes --no-dev > services/backend-api/requirements.txt
uv export --package userbot-service --no-hashes --no-dev > services/userbot-service/requirements.txt
uv export --package dashboard --no-hashes --no-dev > services/dashboard/requirements.txt
uv export --package main-bot --no-hashes --no-dev > services/main-bot/requirements.txt
After adding/removing deps, always:
uv sync --all-packages— update.venvuv export --package <name> --no-hashes --no-dev > services/<name>/requirements.txt— update the Docker export
Use --no-dev to keep test deps (pytest, hypothesis, etc.) out of production images. Without it, dev dependencies leak into requirements.txt.
Quick sanity checks:
# Verify .venv matches lockfile (no install, just check)
uv sync --all-packages --dry-run
# Check what's installed
uv pip list
# Verify a specific package is importable
uv run --package backend-api python -c "import taskiq; print(taskiq.__version__)"
Production (Docker)
All services run in containers. Docker Compose overrides host-specific vars (POSTGRES_HOST=db, USERBOT_SERVICE_URL, BACKEND_API_URL) so .env stays unchanged.
The external proxy network must exist before starting:
docker network create proxy_network
# Start everything
docker compose up -d --build
# Rebuild a specific service
docker compose build backend-api
# View logs
docker compose logs -f
# Stop
docker compose down
# Run migrations (when configured)
docker compose exec api alembic upgrade head
Backend API Endpoints
Userbots CRUD, status management, Telegram auth flow, proxy assignment, group posting, schedules, templates, and health monitoring are all implemented. Key routes:
POST/GET /api/userbots— register, list (paginated, filterable by status/search)GET/PATCH/DELETE /api/userbots/{id}— detail, update, deletePATCH /api/userbots/{id}/status— status transitions (inactive → authorizing → authorized → active, etc.)POST /api/userbots/{id}/auth/request-code|verify-code|verify-2fa— Telegram auth flowPUT /api/userbots/{id}/auto-reply— toggle auto-reply with real-time syncPUT /api/userbots/{id}/dm-logging— toggle DM conversation logging per userbotPUT/DELETE /api/userbots/{id}/proxy— proxy assignmentPOST/GET /api/proxies,GET/PATCH/DELETE /api/proxies/{id}— proxy managementPOST /api/proxies/{id}/check-health— single proxy health check (persisted)POST /api/proxies/check-health-all— batch health check for all proxiesGET /api/proxies/countries— list supported countries for proxy taggingGET /api/proxies?country_code=DE&health_status=healthy— filtered proxy listPOST/GET /api/groups,GET/PATCH/DELETE /api/groups/{id}— saved group management (friendly names, usernames, notes, last_posted_at)GET /api/groups/{id}/posts— paginated posts for a specific group (with group name)GET /api/groups?search=moscow— search groups by name, username, or group IDPOST /api/userbots/{id}/posts,GET /api/posts— send & list group posts (with group name resolution)POST /api/userbots/{id}/posts/record— record scheduled post result (internal, called by Userbot Service)POST/GET /api/schedules,GET/PATCH/DELETE /api/schedules/{id},PATCH /api/schedules/{id}/status— posting schedules (withgroup_idsFK linkage to groups and optionaltemplate_idlinkage)POST /api/schedules/{id}/executed— mark schedule executed (internal, called by Userbot Service)POST/GET /api/templates,GET/PATCH/DELETE /api/templates/{id}— reusable message templates with{bot_link}placeholder supportGET /api/conversations/overview— per-userbot conversation stats (thread count, message count, last activity)GET /api/conversations/{userbot_id}/threads— paginated conversation thread list per userbotGET /api/conversations/{userbot_id}/threads/{telegram_user_id}/messages— paginated message history within a threadGET /api/conversations/{userbot_id}/threads/{telegram_user_id}/last-outgoing— last outgoing DM to a user (used by auto-reply cooldown)GET /api/userbots/{id}/health,GET /api/health/userbots— health monitoring
Project Structure
services/
├── backend-api/ # FastAPI — REST API (userbots, proxies, posts, templates, conversations, health modules)
│ ├── app/core/ # Config, logging, exceptions, pagination, http_client, telegram utils
│ ├── app/modules/ # userbots, proxies, posts, groups, templates, conversations, health (router/service/schemas/repository each)
│ ├── app/models/ # SQLAlchemy: userbot, proxy, group_post, posting_schedule, schedule_group (M2M), group, message_template, direct_message
│ ├── app/tasks/ # TaskIQ broker + async tasks (DM message persistence)
│ ├── alembic/ # DB migrations
│ └── tests/ # Unit & property-based tests
├── dashboard/ # Flask — admin web interface (pure API consumer)
│ ├── app/ # Blueprints: auth, userbots, proxies, posts, schedules, health, groups, templates_bp, conversations, overview
│ ├── templates/ # Jinja2 templates
│ └── tests/ # Unit tests
├── main-bot/ # Aiogram — Telegram bot (stub)
└── userbot-service/ # FastAPI + Telethon — internal API, auto-reply (with per-user cooldown), DM logging, reconnection, scheduled posting (with random spread)
├── app/api/ # Internal API routes & inter-service schemas
├── app/core/ # Config, logging, ClientManager (Telethon lifecycle, resolve_placeholders)
├── app/services/ # DM publisher, startup catch-up, reconnection handler, APScheduler (per-group random spread via SCHEDULE_RANDOM_SPREAD_SECONDS)
└── tests/ # Unit tests
Each service has its own pyproject.toml, requirements.txt, Dockerfile, and app/ directory. The root pyproject.toml ties them together as a uv workspace with a single .venv.