Устранение неполадок
Типичные проблемы WASH PRO CRM и решения — запуск Docker, вход, MQTT, порты, пути DATA_DIR и проверка состояния сервисов.
Обновление Dynamic API Platform
In-app updater в панели :8080 отключён в WASH. Используйте:
./scripts/update-dynamic-api.sh
docker compose up -d --build dynamic-api dynamic-api-panel
Актуальная vendored-версия: v1.5.13.
Обновление CRM не проходит / неверные пути
В WASH автообновление из Dashboard выполняет update-bridge (не in-app updater панели Dynamic API).
- Откройте Dashboard → Настройки → Целостность и исправление (администратор).
- Нажмите Проверить целостность — пути (
WASH_HOST_PROJECT_ROOT,DATA_DIR), отсутствующие файлы, Docker socket, зависшие задачи. - Выберите исправления и нажмите Применить исправления (синхронизация
.env, Mosquitto,init-seed, сброс job). - При необходимости пересоберите:
docker compose up -d --build update-bridge dashboard
Ручной fallback:
./scripts/fix-mqtt.sh
docker compose run --rm init-seed
Проверьте .env: WASH_HOST_PROJECT_ROOT — абсолютный путь к проекту на хосте; DATA_DIR — каталог данных на хосте (./data, /var/lib/wash-pro-crm, /mnt/hdd/data и т.п.).
Ложное предупреждение «Подозрительный DATA_DIR» (v1.1.19+)
Симптомы: в Целостность и исправление предупреждение про DATA_DIR, хотя путь корректный (например /mnt/hdd/data).
Причина (до v1.1.19): проверка считала подозрительным любой абсолютный DATA_DIR, не совпадающий с {проект}/data.
Решение (v1.1.19+): внешние пути на хосте допустимы; предупреждение только если DATA_DIR указывает внутрь mount контейнера /deploy. Обновитесь и пересоберите:
git pull
docker compose up -d --build update-bridge dashboard
Не применяйте исправление «Установить DATA_DIR=./data», если данные уже лежат на внешнем диске.
Обновления не видны / сбрасываются при загрузке (v1.1.18+)
Симптомы: баннер «доступно обновление» пропадает после F5; в карточках компонентов пустая «последняя версия»; ошибка «Превышен лимит GitHub API».
Причина (до v1.1.18): без GITHUB_TOKEN лимит GitHub REST API — 60 запросов/ч с IP; Dashboard принудительно опрашивал API при каждой загрузке и каждые 3 с во время обновления.
Решение (v1.1.18+):
update-bridgeпри лимите API переключается наgit ls-remote— токен не обязателен для публичных репозиториев- обычная загрузка страницы и опрос прогресса job читают кэш; GitHub — только кнопка «Проверить сейчас»
- при ошибке API сохраняются последние известные версии в
DATA_DIR/update-bridge/state.json
Обновитесь до v1.1.18 и пересоберите:
git pull
docker compose up -d --build update-bridge dashboard
GITHUB_TOKEN в .env опционален (release notes и лимит 5000/ч). Для публичных установок не требуется.
Локальные правки на сервере блокируют git pull
Симптомы: обновление из Dashboard «сразу сбрасывается» — прогресс исчезает через 1–2 с, в истории статус failed, шаг «Загрузка из GitHub».
Причина (до v1.1.20): git pull --ff-only отказывается при любых локальных изменениях отслеживаемых файлов (ошибка «local changes would be overwritten»). На localhost репозиторий часто чистый; на production после ручных правок или scp — нет.
Решение (v1.1.20+): апдейтер выполняет git fetch + git reset --hard origin/main — сбрасывает только отслеживаемые файлы; не трогает .env, docker-compose.override.yml, local/, DATA_DIR.
Рекомендуемый паттерн (серверные правки без блокировки обновлений):
cp docker-compose.override.yml.example docker-compose.override.yml # MongoDB 4.4 без AVX и др.
mkdir -p local
cp local/apply-server-patches.sh.example local/apply-server-patches.sh
chmod +x local/apply-server-patches.sh
git checkout -- docker-compose.yml # если уже были правки
docker-compose.override.yml— не в git, подключаетсяscripts/start.shlocal/apply-server-patches.sh— вызывается апдейтером послеgit pull
Подробнее: Развёртывание, Конфигурация.
«text/html is not a valid JavaScript MIME type» (v1.1.29+)
Симптомы: экран «Ошибка интерфейса» или «Не удалось загрузить страницу» с текстом про text/html и JavaScript MIME type; часто после docker compose up -d --build dashboard или обновления CRM из Dashboard.
Причина: браузер (часто Safari) держит старый index.html со ссылками на удалённые JS-файлы (/assets/index-….js). До v1.1.29 nginx мог отдавать HTML вместо 404 — браузер пытался выполнить HTML как JS.
Решение:
- Жёсткая перезагрузка:
⌘⇧R(Mac) или закройте вкладку и откройте CRM заново. - Обновитесь до v1.1.29+ и пересоберите dashboard:
docker compose up -d --build dashboard. - Не смешивайте localhost:80 (Docker) и localhost:5173 (
npm run dev) в одной вкладке. - При разработке UI используйте только
npm run devили только Docker — не оба сразу.
Обновление падает на сборке: таймаут Docker Hub (Mac / localhost)
Симптомы: в Dashboard обновление CRM доходит до шага «Сборка» и падает с failed; в логе job — DeadlineExceeded, registry-1.docker.io, failed to resolve source metadata или «Команда завершилась с кодом 1». GitHub (загрузка исходников) проходит успешно.
Причина: Docker на Mac не может вовремя скачать базовые образы (node:20-alpine, nginx:alpine) с Docker Hub — сеть, VPN, DNS Docker Desktop или блокировка registry. Это не ошибка логики CRM; на сервере с нормальным доступом к Hub (например 192.168.1.151) тот же релиз собирается.
Диагностика на хосте:
docker pull node:20-alpine
docker pull nginx:alpine
Если команды тоже зависают или падают с DeadlineExceeded — проблема в доступе к Docker Hub, не в WASH.
Что сделать:
- Проверьте интернет и отключите/смените VPN, если он режет
registry-1.docker.io. - Docker Desktop → Settings → Docker Engine — при проблемах с DNS можно временно добавить
"dns": ["8.8.8.8", "1.1.1.1"]и перезапустить Docker. - После успешного
docker pullповторите обновление из Dashboard (Настройки → Обновления ПО). - Для разработки UI без полной пересборки:
cd dashboard && npm run dev(порт 5173) — CRM в Docker можно не обновлять на каждый коммит. - Ручная сборка на хосте (когда pull работает):
cd /path/to/WASH-PRO-CRM # или каталог с docker-compose.yml
git fetch origin && git checkout v1.1.66 # нужный тег
docker compose up -d --build dashboard update-bridge
v1.1.25: update-bridge показывает понятное сообщение вместо сырого хвоста лога при таймауте Hub.
Зависший спиннер обновления (v1.1.50+)
Симптомы: в шапке или Настройки → Обновления ПО крутится спиннер бесконечно; задача в статусе queued, хотя целевая версия уже установлена.
Причина: зависшая задача в DATA_DIR/update-bridge/state.json после прерванного обновления.
Решение:
- Обновитесь до v1.1.50+ (автозакрытие stale-задач).
- Настройки → Целостность и восстановление → Применить исправления — действие
clear_stuck_job, или API:
curl -X POST http://localhost/api/crm/updates/repair \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"actions":["clear_stuck_job"]}'
- При необходимости:
docker compose restart update-bridge
v1.1.51+: перед новым обновлением update-bridge снимает зависшую активную задачу.
Медленная или зависающая страница поста (v1.1.48+)
Большой объём телеметрии (сотни тысяч записей на пост) замедляет старые версии Dashboard, загружавшие всю телеметрию CRM в браузер.
Решение: v1.1.48+ (индексы MongoDB), v1.1.51+ (история поста: серверный фильтр, 100 строк, «Загрузить ещё» над таблицей, count=false). При необходимости — Архив для очистки старой телеметрии.
«/deploy не git-репозиторий» в целостности (v1.1.21+)
Симптомы: предупреждение «Каталог /deploy не является git-репозиторием» или «Git в /deploy недоступен», хотя установка через git clone.
Причина: Git 2.35+ блокирует доступ при dubious ownership — .git на хосте принадлежит другому пользователю, чем процесс в контейнере update-bridge (root). Репозиторий есть, проверка ошибалась.
Решение (v1.1.21+): update-bridge регистрирует safe.directory /deploy при старте; проверка целостности делает то же. Или вручную:
docker exec wash-update-bridge git config --global --add safe.directory /deploy
Без .git на хосте (копия файлов без clone) — автообновление из Dashboard не работает; нужен git clone или ручное обновление.
init-seed: статус Exited
Exited (0) — норма (одноразовый контейнер).
При ошибке:
docker logs wash-init-seed
./scripts/run-init-seed.sh
Миграция с RabbitMQ на MQTT
Если раньше использовался RabbitMQ (AMQP, порт 5672):
./scripts/migrate-to-mqtt.sh
docker compose up -d --build message-processor
В .env замените RABBITMQ_* на MQTT_*. Контроллеры должны публиковать в топик wash/telemetry/{тип} (QoS 1), не в exchange AMQP.
Подробнее: MQTT.
MQTT
Проблемы с пользователем / паролем
./scripts/fix-mqtt.sh
docker compose up -d --build message-processor
Скрипт обновляет conf Mosquitto; существующий passwd не перезаписывается из .env (чтобы не ломать sync постов). Учётки постов — через «Синхронизировать MQTT» или старт processor. Принудительно сбросить пароль system из .env: FORCE_MQTT_SYSTEM_PASS=1 ./scripts/fix-mqtt.sh.
Пост не может подключиться / «not authorised»
- Логин/пароль на панели =
settings.mqttLogin/settings.mqttPasswordиз CRM (неsystem). - Топик публикации:
washpro/{serial}/state/..., где{serial}=posts.serialNumber. - После смены MQTT-данных в CRM — синхронизация MQTT.
./scripts/fix-mqtt.sh— если сбилсяsystemдля CRM.- (до v1.1.54) сохранение названия на странице поста могло стереть MQTT-учётки из
posts.settings; после рестарта/sync-usersMosquitto оставался толькоsystem. Обновитесь до v1.1.54+, восстановите логин/пароль в карточке поста и снова синхронизируйте MQTT.
ACL / чужой serial в топике
Пост не может публиковать в топик с чужим serial — Mosquitto отклонит. Если CRM получает сообщение с несовпадающим payload — учитывается только serial из топика.
Полный сброс MQTT (данные в DATA_DIR, не в Docker volume):
docker compose stop mosquitto mosquitto-init
rm -rf "${DATA_DIR:-./data}/mosquitto/data"/* "${DATA_DIR:-./data}/mosquitto/config"/*
./scripts/start.sh
Проверка подключения:
docker exec wash-mosquitto mosquitto_sub -h 127.0.0.1 -p 1884 -t '$SYS/broker/version' -C 1 -W 3
Страница «Пользователи» пустая
- Убедитесь, что вы Administrator (
manage_usersилиview_logs) - Проверьте API:
curl -H "Authorization: Bearer TOKEN" http://localhost:3001/api/users?page=1&limit=5 - Обновите Dashboard:
docker compose up -d --build dashboard - Перелогиньтесь (истёкший JWT)
Telegram: «Нет новостей» / «Новости (N)» без текста
- Dashboard → Публикации — статус Опубликовано (не «Черновик»)
- Поле Скрыть после — оставьте пустым или дата позже публикации
- Пересборка и перезапуск информационного бота:
docker compose -f docker-compose.yml -f docker-compose.pyorchestrator.yml up -d --build pyorch-bridge
# Dashboard → Telegram → ▶ у информационного бота
- В Telegram:
/startв личном чате (не в группе), затем 📰 Новости - URL изображения — прямая ссылка на jpg/png, до 10 МБ, доступная из интернета
Telegram: нет автоматической рассылки новостей
- Пользователь должен написать боту
/startв личном чате (регистрация подписчика) - Новость — статус Опубликовано; дата публикации подставится автоматически
- Подождите до 30 с после публикации
- Новости, созданные до первого
/startпользователя, приходят только по кнопке 📰 Новости, не push-рассылкой
Dashboard: серый экран при переходе между разделами
С v1.1.12 добавлены retry загрузки JS-чанков и RouteErrorBoundary. Если экран пустой:
- Обновите страницу (F5)
- Пересоберите dashboard:
docker compose up -d --build dashboard - Очистите кэш браузера для
localhost
Telegram: бот отвечает в группе / видны чужие сообщения
С v1.1.11 боты работают только в личных чатах. Откройте бота по QR или ссылке t.me/... → /start. В группах бот не отвечает.
Telegram: «Unauthorized» при создании бота
PYORCHESTRATOR_ENABLED=trueв.envи./scripts/start.sh- Health:
curl http://localhost/api/telegram-bots/health - Пересборка:
docker compose … up -d --build dashboard pyorch-bridge - Обновите страницу / перелогиньтесь
- Логи:
docker logs wash-pyorch-bridge --tail 50
Telegram: «PyOrchestrator недоступен»
docker compose ps | grep pyorch
docker logs wash-pyorch-backend
curl -s http://localhost:8000/health
Учётные данные bridge: PYORCH_DASHBOARD_EMAIL / PYORCH_DASHBOARD_PASSWORD.
Telegram-бот молчит / runtime: redis ConnectionError
После пересборки pyorch-redis или pyorch-backend runtime может остаться со старым соединением к Redis.
chmod +x ./scripts/fix-pyorch.sh
./scripts/fix-pyorch.sh
Или вручную:
docker compose -f docker-compose.yml -f docker-compose.pyorchestrator.yml restart pyorch-runtime pyorch-scheduler pyorch-bridge
Затем Dashboard → Telegram — Стоп → Запуск у бота.
Telegram: дублирующиеся ответы (старый + новый формат)
Причина — два процесса polling одного токена (старый demo-скрипт PyOrchestrator + новый шаблон bridge).
docker compose -f docker-compose.yml -f docker-compose.pyorchestrator.yml up -d --build pyorch-bridge
# через API или Dashboard: POST /api/telegram-bots/bots/refresh
Bridge останавливает legacy-боты и применяет lock по токену. В подвале ответа бота должно быть Шаблон бота v2.7.
Telegram: «Частный бот» для сотрудника
- Dashboard → Пользователи — укажите Telegram user_id (число от @userinfobot)
- Пользователь должен быть active, с назначенной группой (Viewer / Operator / Administrator)
- Перезапустите бота или дождитесь обновления кэша сессии (до 5 мин)
Telegram: Viewer не может создать объект
Ожидаемое поведение RBAC — группа Viewer имеет только view. Для создания автомоек и команд постов назначьте Operator или Administrator.
Бот молчит, в логах run: Temporary failure in name resolution: sandbox runtime был только в сети wash-internal (без интернета) и не мог достучаться до api.telegram.org. После обновления docker-compose.pyorchestrator.yml пересоздайте runtime:
docker compose -f docker-compose.yml -f docker-compose.pyorchestrator.yml up -d --build pyorch-runtime pyorch-backend pyorch-bridge
Удаление бота падает с 500: в PyOrchestrator оставались уведомления, ссылающиеся на run. Исправлено в delete_script_record — пересоберите pyorch-backend.
docker exec wash-pyorch-runtime python -c "import urllib.request; urllib.request.urlopen('https://api.telegram.org', timeout=10); print('telegram ok')"
docker logs wash-pyorch-runtime --tail 30
PyOrchestrator MCP: «unreachable» / не стартует
В WASH сервис называется pyorch-mcp, а backend по умолчанию обращается к http://mcp:8010. В overlay заданы MCP_INTERNAL_URL и сетевой alias mcp.
docker compose -f docker-compose.yml -f docker-compose.pyorchestrator.yml up -d pyorch-mcp pyorch-backend
docker logs wash-pyorch-mcp --tail 30
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8010/mcp # 200/405/406 — норма
Проверка из API (нужен JWT admin):
curl -s http://localhost:8000/api/v1/mcp/info -H "Authorization: Bearer TOKEN" | jq .status
# ожидается: "ok"
Resources: PyOrchestrator «Остановлен»
Индикатор проверяет /api/telegram-bots/health. Если PyOrch выключен — это ожидаемо. Dynamic API проверяется через /api/health.
Статус поста «Офлайн» при работающей панели
Пост онлайн, если lastMessageAt в /api/crm/post-states не старше 30 секунд. Проверьте:
- Телеметрия приходит в топик
washpro/{serial}/state/process(или другой suffix). docker logs wash-message-processor— ошибки обработки.- Серийный номер в топике =
serialNumberв CRM.
ETH «MQTT OK», CRM «Офлайн» (v1.1.57+)
Частая причина — не пароль поста, а рассинхрон пароля CRM system:
- ETH подключается своим
mqttLogin/mqttPasswordи публикует телеметрию. - CRM (
message-processor) входит какsystem. Если в Настройки → MQTT остался seed-парольwashpro, а в.env/ Mosquitto — другойMQTT_PASSWORD, процессор получаетNot authorizedи не обновляетlastMessageAt.
С v1.1.57: при старте processor подтягивает seed/washpro к MQTT_PASSWORD, синхронизирует passwd до подключения; mosquitto-init больше не перезаписывает существующий passwd из .env на каждый рестарт.
Проверка:
docker logs wash-message-processor --tail 50 | grep -E 'Connected|Not authorized|Healed|passwd synced'
./scripts/fix-mqtt.sh
docker compose up -d --build message-processor
Телеметрия не обновляется
- Серийный номер в топике (
{dt_pref}/{serial}/state/...) илиpostSerialв legacy JSON =serialNumberпоста в CRM docker logs wash-message-processor- DLQ
wash/dlq - Журнал MQTT: Dashboard → Логи или
/api/crm/telemetry
Команды и цены не доходят до поста
- Префикс MQTT в CRM (
dt_pref) совпадает с настройкой панели (get_settings.remote) docker logs wash-message-processor— ошибки публикации- Проверка с сервера:
mosquitto_pub -h localhost -p 1883 -u system -P 'PASSWORD' -q 1 \ -t 'washpro/SERIAL/set/command' -m '{"cmd":1}' - HTTP API:
curl http://localhost/api/crm/post-device/posts/SERIAL/commandс JWT (см. MQTT) - Пересборка после обновления:
docker compose up -d --build message-processor dashboard
CORS
Добавьте origin в CORS_ORIGIN, перезапустите dynamic-api.
Dashboard не открывается
docker compose ps
docker logs wash-dashboard
Бэкап
docker logs wash-backup
Ручной запуск — Dashboard → Резервные копии.
Полный перезапуск
docker compose down
docker compose up -d --build
Данные MongoDB и остальные сервисы лежат в DATA_DIR (по умолчанию ./data), см. data/README.md.
Помощь
docker compose logs > logs.txt- Issue на GitHub с
APP_VERSION,docker compose ps, шаги воспроизведения