Перейти к содержанию

Архитектура

Общая схема

                         ┌─────────────────────────────────────┐
   МойСклад вебхуки ─────▶│  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 и т.д.) игнорируются — они оставлены для совместимости, но не влияют на роутинг.