Архитектура
Общая схема
┌─────────────────────────────────────┐
МойСклад вебхуки ─────▶│ Traefik (file-provider) │
POST /vendor_... │ Host: rb.the-progress-machine.ru │
│ TLS Let's Encrypt │
└───────────────┬─────────────────────┘
│
┌──────▼───────┐
│ rb-backend │ :8080 (FastAPI/uvicorn)
│ app.py │
│ rb_router │
└───┬──────┬───┘
┌──────────────┘ └──────────────┐
┌────▼─────┐ ┌──────▼──────┐
│ МойСклад │ │ Google │
│ API │ │ Sheets │
└──────────┘ └─────────────┘
┌──────────────────────────────────────────────────────────────┐
│ rb-cron (cron -f -L 2) │
│ 30 3 * * * update_products │
│ 30 3 * * * update_counterparty_list │
│ 12 12 * * 1-5 check_positions_status (файл. кэш) │
│ 11 11 1 * * load_all │
└──────────────────────────────────────────────────────────────┘
Слои кода
.
├── app.py FastAPI, монтирует только rb_router (+ /docs статикой)
├── cron.py CLI-точка входа cron-задач
└── src/
├── env.py / constants.py / enums.py конфиг и константы
├── endpoints/
│ └── replace_buyer.py роутер (префикс /vendor_endpoint/rb)
├── services/replace_buyer/
│ ├── bot.py Telegram (send_message_ext_sync.delay)
│ ├── mail.py email (send_email_double.delay)
│ ├── status.py логика статусов (Done / Trouble)
│ ├── stocks.py остатки (Stocks, is_stock_enough)
│ ├── regular.py / regular_buy.py тяжёлые обработчики
│ ├── table_from_doc.py TableApp (processingplan UPDATE)
│ ├── approve.py / setup.py / const.py
├── moysklad/
│ ├── base.py chain_get, get_uuid, get_doc_type, format_sum
│ ├── entities/ base.py, webhook.py
│ └── reports/stock.py get_report_stock_all
├── google_/ клиент Google Sheets (base, spreadsheets/*)
└── utils/
├── celery.py заглушка @app.task / .delay
├── mail.py SMTP-отправка
└── redis.py файловый кэш (вместо redis)
Чем заменено «тяжёлое»
| Было (rep2) | Стало (rb) |
|---|---|
| PostgreSQL | не используется |
| Redis | файловый кэш RB_CACHE_DIR (src/utils/redis.py) |
| Celery + beat | cron-демон (rb-cron) + синхронные вызовы через заглушку |
@app.task → брокер |
@sync_task()/@async_task() → прямой вызов, .delay работает |
Рефакторинг: удаление legacy-кода rep2
При выделении rb из монорепо rep2 в src/ осталось много мёртвого кода
(роутеры backend.py/gui.py, пакеты endpoints/main|button|popup|widget,
services/* кроме replace_buyer, models, schemas, repositories,
database, moysklad/async_, moysklad/entities/* кроме base/webhook,
moysklad/reports/main.py, utils/database|repository|unitofwork|common).
Этот код не импортируется ни из app.py, ни из cron.py, ни из тестов
(проверено AST-анализом графа импортов). Он удалён:
src/backend.py,src/gui.py— старые FastAPI-приложения (в rb крутится толькоapp.py);- целые пакеты
database/,models/,schemas/,repositories/,endpoints/{main,button,popup,widget}/,services/{doc_from_table,expenseitems,set_prefix}/и модулиservices/{vendor,edocsuz,loss_and_enter,payments_linking,processingorder,salesreturn,set_project}.py; moysklad/async_/,moysklad/entities/{contract,customentity,metadata,organization,payment,processingorder}.py,moysklad/reports/main.py;utils/{database,repository,unitofwork,common}.py.
Живой граф импортов (точка входа app.py + cron.py + тесты) содержит
ровно 32 .py-файла в src/. Удаление покрыто тестами: docker compose run
rb-backend pytest → 110 passed.
src/moysklad/entities/__init__.pyочищен: оставлен толькоfrom .webhook import *(остальные подмодули пакета удалены как мёртвые).
Заглушка Celery
src/utils/celery.py предоставляет декораторы sync_task() / async_task(),
которые возвращают функцию «как есть», но добавляют атрибут .delay
(вызывает ту же функцию синхронно). Это сохраняет совместимость с кодом,
где везде используется func.delay(...).
@sync_task()
def send_message_ext_sync(chat_id, text, ...):
...
# вызов из роутера:
send_message_ext_sync.delay(chat_id=..., text=...)
Сетевой доступ
rb ходит в МойСклад API напрямую. Прокси не используется.
Traefik
Глобальный traefik на prod1 использует только file-provider (не docker).
Поэтому rb прописан вручную в traefik-data/config/dynamic.yml:
http:
routers:
rb:
rule: Host(`rb.the-progress-machine.ru`)
service: rb-service
entrypoints: websecure
tls:
certresolver: letsencrypt
domains:
- main: rb.the-progress-machine.ru
services:
rb-service:
loadBalancer:
servers:
- url: http://rb-backend:8080
Labels в compose.rb.yml (traefik.enable и т.д.) игнорируются —
они оставлены для совместимости, но не влияют на роутинг.