docs: copilot-instructions, архитектура, API, progress, decisions

This commit is contained in:
Naeel
2026-04-12 14:34:34 +03:00
parent 1a94241c62
commit e70c164203
5 changed files with 302 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
# IoT API Endpoints
## Публичные (без auth)
| Метод | Путь | Описание |
|-------|------|----------|
| GET | `/console` | IoT Консоль (HTML SPA) |
| GET | `/iot-admin` | Страница администратора (HTML) |
## Защищённые JWT (/v1/)
| Метод | Путь | Описание |
|-------|------|----------|
| POST | `/v1/namespaces/{ns}/iot/devices` | Создать IoT устройство |
| GET | `/v1/namespaces/{ns}/iot/devices` | Список устройств (без паролей) |
| GET | `/v1/namespaces/{ns}/iot/devices/{name}` | Устройство + MQTT password |
| DELETE | `/v1/namespaces/{ns}/iot/devices/{name}` | Удалить устройство |
| PATCH | `/v1/namespaces/{ns}/iot/devices/{name}` | Обновить (enabled) |
| GET | `/v1/namespaces/{ns}/iot/telemetry` | Телеметрия (?device=&limit=) |
## Внутренние (без JWT, только из кластера)
| Метод | Путь | Описание |
|-------|------|----------|
| POST | `/internal/mqtt/auth` | MQTT auth для EMQX |
| POST | `/internal/mqtt/acl` | MQTT ACL для EMQX |
## Администратор (ADMIN_STATS_TOKEN)
| Метод | Путь | Описание |
|-------|------|----------|
| GET | `/iot-admin/stats` | JSON статистика (PG, Kafka lag, pods) |
+66
View File
@@ -0,0 +1,66 @@
# IoT Managed Service — Архитектура
## Общая схема
```
IoT Device (MQTT CONNECT)
│ username="{ns}_{deviceId}", password=hex
EMQX 5.5.1 (sless/emqx)
│ POST /internal/mqtt/auth → iot-operator:9090
│ POST /internal/mqtt/acl → iot-operator:9090
│ MQTT PUBLISH → topic: "{ns}/telemetry/{deviceId}"
iot-mqtt-bridge (cmd/mqtt-bridge)
│ подписка на "+/telemetry/+"
│ → Kafka topic "iot.telemetry"
Kafka
iot-kafka-consumer (cmd/kafka-consumer)
│ consumer group "iot-pg-consumer"
│ → per-tenant Postgres DB
IoT Postgres (iot-postgres.sless.svc)
│ DB: tenant_{namespace}
│ Table: iot_telemetry
REST API (iot-operator:9090)
│ GET /v1/namespaces/{ns}/iot/telemetry
Пользователь (Terraform / UI Console)
```
## Компоненты
| Компонент | Бинарник | Порт | Назначение |
|-----------|----------|------|------------|
| iot-operator | cmd/iot-operator | :9090 (API), :8081 (health) | Controller-manager + REST API |
| mqtt-bridge | cmd/mqtt-bridge | — | MQTT→Kafka bridge |
| kafka-consumer | cmd/kafka-consumer | — | Kafka→Postgres pipeline |
## CRD
- **IoTDevice** (`iot.kube5s.ru/v1alpha1`)
- Создание: пользователь через API / Terraform
- Controller генерирует MQTT credentials → k8s Secret
- Secret удаляется каскадно через OwnerReference
## Хранение
- **IoT Postgres** — отдельный от sless PG
- Management DB: `iot_platform` (таблица `tenant_credentials`)
- Per-tenant DB: `tenant_{namespace}` (таблица `iot_telemetry`)
## Аутентификация
- REST API (/v1/): Bearer JWT (middleware.Auth)
- MQTT Auth (/internal/): вызывается EMQX, без JWT
- Admin (/iot-admin/stats): ADMIN_STATS_TOKEN
## Docker образ
- `naeel/iot-operator` (Docker Hub)
- Все 3 бинарника в одном образе
- `command: ["/iot-operator"]` или `["/mqtt-bridge"]` или `["/kafka-consumer"]`
+41
View File
@@ -0,0 +1,41 @@
# Решение: Вынос IoT в отдельную репу
**Дата:** 2026-04-12
**Статус:** Принято и реализовано
## Контекст
IoT managed service был частью sless (основной serverless operator).
Код IoT жил в нескольких местах:
- `iot/` — CRD types, controller, cmd (bridge, consumer)
- `internal/storage/iotpg/` — Postgres store
- `internal/api/handler/iot_*.go` — REST handlers
- `internal/api/ui/iot-*.html` — UI
- `main.go`, `Dockerfile` — IoT интегрирован в основной бинарник
## Проблемы
1. IoT и sless — разные домены с разными циклами разработки
2. Сборка sless включала IoT — лишние зависимости (Kafka, MQTT)
3. Деплой любого IoT изменения требовал пересборки всего sless
## Решение
Вынести IoT в отдельную репу `gitea.services.ngcloud.ru/Nail/IoT`:
- Свой Go модуль, go.mod, Dockerfile
- 3 бинарника в одном образе (`naeel/iot-operator`)
- Свой controller-manager + REST API (cmd/iot-operator)
- Независимый CI/CD цикл
## Что перенесено
- CRD types, controller, mqtt-bridge, kafka-consumer — as-is
- Handler struct упрощён (убраны S3, PG от sless)
- Router — только IoT маршруты
- Middleware (auth, logging) — скопированы как есть
- K8s manifests, CRD YAML, документация, примеры
## Риски
- IoT код в sless нужно будет убрать (или оставить заглушки)
- K8s manifests могут требовать обновления (новое имя образа)
+37
View File
@@ -0,0 +1,37 @@
# IoT Managed Service — Трекер прогресса
## 2026-04-12: Перенос из sless в отдельную репу
### Выполнено
- [x] Создана репа https://gitea.services.ngcloud.ru/Nail/IoT
- [x] Go модуль: `gitea.services.ngcloud.ru/Nail/IoT`
- [x] Перенесены все IoT-компоненты из sless:
- `iot/api/v1alpha1/``api/v1alpha1/` (CRD types: IoTDevice)
- `iot/controllers/``controllers/` (IoTDevice reconciler)
- `iot/cmd/mqtt-bridge/``cmd/mqtt-bridge/` (MQTT→Kafka)
- `iot/cmd/kafka-consumer/``cmd/kafka-consumer/` (Kafka→Postgres)
- `internal/storage/iotpg/``internal/storage/iotpg/` (per-tenant PG)
- `internal/api/handler/iot_*.go``internal/api/handler/` (REST handlers)
- `internal/api/ui/iot-*.html``internal/api/ui/` (embedded HTML)
- `internal/api/middleware/``internal/api/middleware/` (auth, logging)
- `deployments/k8s/iot-*.yaml` + `kafka.yaml``deployments/k8s/`
- `config/crd/bases/``config/crd/bases/`
- `doc/iot/`, `examples/IOT/``doc/`, `examples/`
- [x] Созданы новые файлы:
- `cmd/iot-operator/main.go` — точка входа (controller-manager + REST API)
- `internal/api/handler/handler.go` — упрощённый Handler (без S3/PG от sless)
- `internal/api/router.go` — только IoT маршруты
- `Dockerfile` — multi-stage build, 3 бинарника, distroless
- `Makefile` — build/docker/deploy команды
- `.gitignore`
- `.github/copilot-instructions.md`
- [x] Все import paths заменены: `sless/iot/...``Nail/IoT/...`
- [x] Все 3 бинарника собираются без ошибок (go build ./...)
- [x] Запушено в Gitea
### Следующие шаги
- [ ] Docker build + push на Docker Hub (`naeel/iot-operator`)
- [ ] Обновить k8s manifests для нового образа
- [ ] Деплой в кластер
- [ ] E2E тест: создание устройства → MQTT → Kafka → Postgres → API
- [ ] Убрать IoT-код из sless (опционально, после подтверждения что всё работает)