# Оценка готовности IoT к production (2026-10-05) > Три взгляда на один репозиторий: анализ A, анализ B и моё мнение. > Все три — только чтением кода и документации, без сборки и запуска тестов > (правила репо: команды — только через SSH на ВМ; сборку/прогоны не выполняли). --- ## 1. Анализ A (первый) — итог 5/10 **Вердикт:** цельный MVP, но по коду не считать production-ready для надёжной multi-tenant эксплуатации. ### Блокеры - **Не проверяется принадлежность namespace пользователю.** Middleware проверяет JWT, но не передаёт `sub` обработчикам для сравнения с namespace из URL. CRUD и выдача пароля устройства берут namespace из запроса. Валидный токен не ограничивает пользователя его tenant-ом: `auth.go:20`, `router.go:54`, `devices.go:179`. `exp` фактически необязателен (`auth.go:120`). - **Путь потери уже принятых сообщений.** Flusher заменяет буфер на пустой ДО записи в PG, при ошибке только логирует. Consumer при этом удаляет сообщения из SQS после добавления в буфер: `iot_telemetry_store.go:129`, `:135`, `consumer.go:81`. - **Health зелёный при остановившемся pipeline.** Ошибки запуска bridge/consumer только логируются; горутина завершается, а `/health` всегда отдаёт `ok`: `main.go:106`, `router.go:74`. - **Доставка допускает потери и дубли.** Переполненная RAM-очередь bridge сбрасывает сообщения; исчерпание SQS-ретраев заканчивается drop. При at-least-once нет идемпотентного ключа против дублей: `sender.go:70`, `:112`. ### Что хорошо Компоненты сведены в понятный единый сервис; есть MQTT-reconnect с повторной подпиской, SQS-ретраи, graceful shutdown, разделение хранения устройств и телеметрии, широкий набор нагрузочных сценариев. ### Чего не хватает до уверенного релиза - Автоматических Go-тестов (`*_test.go` не найдено) и CI. - Согласованности доков с кодом: гайд деплоя — `iot-service:v0.1.2`, Makefile — `v0.1.13`; loadtest README описывает уже исправленную блокировку MQTT-обработчика и visibility 30с, код задаёт 120с: `deployment-nubes-production.md:3`, `Makefile:4`, `README.md:85`, `config.go:114`. --- ## 2. Анализ B (второй) — итог ~60–65% **Вердикт:** рабочий MVP / технический прототип, не продакшн-готовый сервис. ### Что хорошо - Конвейер устройство → EMQX → мост → SQS → consumer → PG (per-tenant) работает end-to-end; подтверждено HISTORY и нагрузочными прогонами. - Прогоны: baseline 2390/2390 без потерь/дублей; ACL-нарушения отсекаются; reconnect-storm прошёл чисто. - Код небольшой (~2,4 тыс. строк в монолите), аккуратный: graceful shutdown, асинхронный SQS-диспатчер с ретраями, batch-insert, backoff, constant-time сравнение паролей. - Документация подробная: деплой без kubectl, интеграция с SQS, лог ревью и фиксов, 10 нагрузочных сценариев. - Auth и ACL в EMQX работают напрямую через PostgreSQL, без зависимости от монолита. ### Что мешает назвать готовым 1. **Нет ни одного Go-теста и нет CI.** Только Python-нагрузочные скрипты; в `.github/` одни правила. 2. **Изоляция тенантов слабая.** JWT проверяет только `sub` и `exp`; namespace из URL не сверяется с токеном. Без `JWT_HMAC_SECRET` подпись не проверяется. Любой «валидный» токен читает устройства и пароли любого namespace. 3. **Пароли устройств в БД открытым текстом** и отдаются через GET. EMQX — `password_hash_algorithm = plain`. 4. **`AUTH_TEST_MODE=true`** (любой Bearer) был включён на проде для диагностики. HISTORY §38 — «вернуть false»; закрытия не видно. 5. **`/internal/mqtt/auth` и `/internal/mqtt/acl`** открыты на публичном порту без авторизации; дублируют PG-auth в EMQX и уже не нужны. ACL выдаёт права моста любому клиенту с `clientid`, совпадающим с мостовым. 6. **Нерешённая платформенная проблема:** плавающий обрыв ответов >~15–64 КБ и WebSocket-обрывы ~150с; стабильного воспроизведения нет, разбор с DevOps идёт. В коде обходится пагинацией. 7. **Отложено:** whitelist тенантских БД (любой namespace создаёт базу), DLQ, soak 24ч. 8. **Легаси не вычищено:** `cmd/iot-operator`, `controllers/`, `internal/api/`, `cmd/mqtt-bridge`, `cmd/sqs-consumer`; в `go.mod` 12 строк k8s/controller-runtime; бинарники в `bin/` и `ws-probe/ws-probe`. `LEGACY.md` обещает убрать после переписывания хендлеров, а оно сделано. 9. **Дрейф конфигурации:** `cookie = "iot-emqx-cookie-mvp"` захардкожен в `emqx.conf`; параметры EMQX задаются только через env в deck-UI. 10. **Нет TLS-верификации** к PG (`verify_none`). Нет rate limiting и метрик (только `/health` и admin-статистика). ### Минимум для продакшна - привязать namespace к JWT, сделать `JWT_HMAC_SECRET` обязательным; - убедиться, что `AUTH_TEST_MODE` выключен; - хешировать пароли устройств или не отдавать повторно; - удалить `/internal/mqtt/*` и легаси; - добавить тесты и CI; - закрыть вопрос обрывов на платформе. --- ## 3. Моё мнение (перепроверено по коду) Оба анализа компетентны и в главном совпадают. Расхождение 5/10 vs 60–65% — не в фактах, а в весе, который они дают одним и тем же находкам. Спорные места я перепроверил сам — оба правы по существу. ### Подтверждается кодом (не предположение) 1. **Изоляция тенантов слабая** — верно. `middleware/auth.go` проверяет JWT только на `sub`+`exp`; `sub` не сверяется с `{namespace}` (claims не передаются в обработчики, `router.go` не извлекает `sub`). `exp` необязателен (`if claims.Exp > 0`), без `JWT_HMAC_SECRET` подпись не проверяется. 2. **Путь потери принятых сообщений** — верно. `processTelemetry` → `InsertTelemetry` кладёт в in-memory буфер и возвращает nil, после чего consumer безусловно удаляет сообщение из SQS. `flushAll` подменяет буфер на пустой ДО записи в PG и при ошибке только логирует. Данные могут молча пропасть. 3. **`/health` зелёный при упавшем pipeline** — верно. `main.go` ошибки bridge/consumer только логирует; горутина завершается, `healthHandler` всегда отдаёт `ok`. 4. **Нет Go-тестов и CI** — верно. `*_test.go` отсутствует, `.github/` — правила. 5. **`AUTH_TEST_MODE` и пароли plaintext** — верно и задокументировано (`password_hash_algorithm=plain`, `AUTH_TEST_MODE=true` для DevOps, §38). 6. **Дрейф доков** — верно: гайд `v0.1.2` vs Makefile `v0.1.13`; loadtest README 30с vs код 120с. Анализ A зафиксировал точнее. ### Где анализ B точнее/дополняет - Явно оговорил, что сборку/тесты не запускал (ограничение правил — SSH). - Глубже разобрал открытые `/internal/mqtt/*`, TLS `verify_none`, захардкоженный `cookie`, невычищенное легаси и k8s-зависимости в `go.mod`. ### Где я бы поправил обоих - **Проценты условны.** Оба дают один вывод «MVP/прототип, не production-ready»; цифры — риторика, а не измерение. - **Приоритет блокеров:** главные технические — потеря сообщений и tenant-граница. Plaintext-пароли и unauthed `/internal/mqtt/*` — важные, но второго эшелона (периметр платформы + EMQX уже на PG-auth напрямую снижают остроту). ### Итог **Рабочий MVP, пригодный для демо/пилота, но не production-ready.** Главные блокеры: слабая tenant-изоляция, гарантированная потеря сообщений при сбое flush, «слепой» health, отсутствие Go-тестов/CI и не закрытая платформенная проблема wss ~150с / MTU. Моя оценка — между A и B, ближе к «функционально готов, эксплуатационно — нет».