No description
  • Python 86.6%
  • HTML 12.8%
  • Dockerfile 0.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
ilavir 479ea04227 chore(docker-compose): replace userbot_sessions volume with host path
- Replace Docker-managed userbot_sessions volume with host mount path
- Update volume mount from `userbot_sessions:/app/sessions` to `/home/veolan/docker/data/yacourier-user_flow/userbot_sessions:/app/sessions`
- Comment out userbot_sessions volume declaration in volumes section
- Allows persistent session data storage on host machine for easier management and backup
2026-06-08 12:16:54 +03:00
services refactor: replace schedule telegram_group_ids with groups M2M FK relationship 2026-04-19 13:13:17 +03:00
.env.example feat(scheduler): add per-group random spread for scheduled posts 2026-04-14 11:27:51 +03:00
.gitignore chore(gitignore): exclude docker-compose dev overrides from version control 2026-03-27 16:20:31 +03:00
.python-version modified workflow for development/production environment 2026-03-17 18:25:34 +03:00
docker-compose.override.example.yml feat(backend-api,userbot-service,dashboard): add direct message logging with async task processing 2026-04-03 16:54:12 +03:00
docker-compose.yml chore(docker-compose): replace userbot_sessions volume with host path 2026-06-08 12:16:54 +03:00
pyproject.toml modified workflow for development/production environment 2026-03-17 18:25:34 +03:00
README.md refactor: replace schedule telegram_group_ids with groups M2M FK relationship 2026-04-19 13:13:17 +03:00
uv.lock feat(backend-api,userbot-service): migrate DM logging to TaskIQ for async task processing 2026-04-03 17:19:21 +03:00

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

  • uv (Python package manager)
  • Docker & Docker Compose
  • Python 3.14+

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:

  1. uv sync --all-packages — update .venv
  2. uv 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, delete
  • PATCH /api/userbots/{id}/status — status transitions (inactive → authorizing → authorized → active, etc.)
  • POST /api/userbots/{id}/auth/request-code|verify-code|verify-2fa — Telegram auth flow
  • PUT /api/userbots/{id}/auto-reply — toggle auto-reply with real-time sync
  • PUT /api/userbots/{id}/dm-logging — toggle DM conversation logging per userbot
  • PUT/DELETE /api/userbots/{id}/proxy — proxy assignment
  • POST/GET /api/proxies, GET/PATCH/DELETE /api/proxies/{id} — proxy management
  • POST /api/proxies/{id}/check-health — single proxy health check (persisted)
  • POST /api/proxies/check-health-all — batch health check for all proxies
  • GET /api/proxies/countries — list supported countries for proxy tagging
  • GET /api/proxies?country_code=DE&health_status=healthy — filtered proxy list
  • POST/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 ID
  • POST /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 (with group_ids FK linkage to groups and optional template_id linkage)
  • 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 support
  • GET /api/conversations/overview — per-userbot conversation stats (thread count, message count, last activity)
  • GET /api/conversations/{userbot_id}/threads — paginated conversation thread list per userbot
  • GET /api/conversations/{userbot_id}/threads/{telegram_user_id}/messages — paginated message history within a thread
  • GET /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.