docs: copilot-instructions, архитектура, API, progress, decisions
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
# Правила работы агента в проекте IoT
|
||||
|
||||
## ГЛАВНОЕ ПРАВИЛО
|
||||
|
||||
**НЕ "СОВЕРШЕНСТВОВАТЬ" РАБОЧИЙ КОД БЕЗ ЯВНОГО УКАЗАНИЯ.**
|
||||
|
||||
---
|
||||
|
||||
## ЗАПРЕТ НА ВЫДУМКИ
|
||||
|
||||
**КАТЕГОРИЧЕСКИ ЗАПРЕЩАЕТСЯ придумывать, догадываться или предполагать:**
|
||||
- значения параметров, которые не видны в коде или документации
|
||||
- допустимые значения enum/ролей/типов — если не взяты из реального источника
|
||||
- поведение API, провайдеров, библиотек — если не подтверждено кодом или документацией
|
||||
- любые факты о системе, которые агент "знает" из общих соображений
|
||||
|
||||
**Если информации нет — спросить у пользователя. Не угадывать.**
|
||||
|
||||
Если код работает — не трогать. Никаких:
|
||||
- рефакторингов "попутно"
|
||||
- улучшений стиля
|
||||
- добавления комментариев / docstring
|
||||
- переименований переменных
|
||||
- "пока уж заодно поправлю"
|
||||
|
||||
Делай только то, о чём явно попросили. Ничего лишнего.
|
||||
|
||||
---
|
||||
|
||||
## О проекте
|
||||
|
||||
IoT managed service — отдельная репа, вынесенная из sless.
|
||||
Go модуль: `gitea.services.ngcloud.ru/Nail/IoT`
|
||||
Репа: https://gitea.services.ngcloud.ru/Nail/IoT
|
||||
|
||||
### Компоненты (3 бинарника из одного образа):
|
||||
1. **iot-operator** (`cmd/iot-operator/`) — controller-manager (IoTDevice CRD) + REST API на :9090
|
||||
2. **mqtt-bridge** (`cmd/mqtt-bridge/`) — MQTT (EMQX) → Kafka bridge
|
||||
3. **kafka-consumer** (`cmd/kafka-consumer/`) — Kafka → Postgres pipeline
|
||||
|
||||
### Стек:
|
||||
- Go 1.25, controller-runtime v0.14, gorilla/mux
|
||||
- CRD: `iot.kube5s.ru/v1alpha1` (IoTDevice)
|
||||
- EMQX — MQTT брокер, Kafka — очередь телеметрии
|
||||
- PostgreSQL — per-tenant databases для телеметрии
|
||||
- Docker Hub: `naeel/iot-operator`
|
||||
|
||||
### Структура:
|
||||
```
|
||||
cmd/iot-operator/ — точка входа (controller + API сервер)
|
||||
cmd/mqtt-bridge/ — MQTT→Kafka bridge
|
||||
cmd/kafka-consumer/ — Kafka→Postgres
|
||||
api/v1alpha1/ — CRD Go types (IoTDevice)
|
||||
controllers/ — IoTDevice reconciler
|
||||
internal/api/ — REST handlers, router, middleware, UI (go:embed)
|
||||
internal/storage/ — iotpg (per-tenant Postgres)
|
||||
config/crd/ — CRD YAML manifests
|
||||
deployments/k8s/ — k8s deployment YAMLs
|
||||
doc/ — документация
|
||||
examples/ — примеры (Terraform, handler.py)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Комментарии в коде
|
||||
|
||||
Комментарии — обязательны:
|
||||
- В начале каждого файла при создании или правке — дата и время изменения
|
||||
- На каждой функции/методе — краткое назначение
|
||||
- На нетривиальной логике — **почему** сделано именно так (не "что делает", а "зачем")
|
||||
|
||||
Цель: любой агент в новом чате должен понять логику без дополнительных вопросов.
|
||||
|
||||
---
|
||||
|
||||
## Темп работы
|
||||
|
||||
Не спешить. Перед каждым шагом — убедиться что предыдущий понят и согласован.
|
||||
|
||||
---
|
||||
|
||||
## Документация
|
||||
|
||||
Всё важное фиксировать в `doc/`:
|
||||
- `doc/architecture/` — архитектура, стек, схемы
|
||||
- `doc/api/` — дизайн API
|
||||
- `doc/decisions/` — принятые решения с обоснованием
|
||||
- `doc/infrastructure/` — инфраструктура, кластер, сервисы
|
||||
- `doc/errors/` — ошибки и как решили
|
||||
- `doc/progress.md` — трекер задач
|
||||
|
||||
Обновлять после каждого значимого изменения.
|
||||
|
||||
---
|
||||
|
||||
## Именование
|
||||
|
||||
Имена должны быть **уникальными и осмысленными по всему проекту**:
|
||||
- имена файлов
|
||||
- имена функций/методов
|
||||
- имена переменных/констант
|
||||
- имена ресурсов (Terraform, Kubernetes и т.д.)
|
||||
|
||||
Цель: чтобы поиск по проекту находил нужные сущности без неоднозначности, а имя сразу отражало назначение.
|
||||
|
||||
Запрещены безликие и повторяющиеся имена вида `handler.py`, `handle`, `data`, `value`, `temp` без контекста.
|
||||
|
||||
---
|
||||
|
||||
## Лог мышления (обязательно)
|
||||
|
||||
Каждый агент в каждом чате **обязан** вести лог своих рассуждений:
|
||||
- Папка: `doc/thinking/`
|
||||
- Файл: `ГГГГ-ММ-ДД.md` (по дате сессии)
|
||||
- В начале файла указать имя агента и модель
|
||||
- Если файл на текущую дату уже существует — дописывать в конец, добавив разделитель `---` и имя агента
|
||||
- Записывать **полный** ход мыслей: что анализирую, какие гипотезы, что нашёл, что отбросил, к чему пришёл, почему
|
||||
- Записывать **до** начала действий (план) и **после** (результат)
|
||||
|
||||
Цель: пользователь должен видеть весь процесс рассуждений в читаемом виде.
|
||||
|
||||
---
|
||||
|
||||
## Git
|
||||
|
||||
Коммитить и пушить после каждого завершённого этапа.
|
||||
@@ -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) |
|
||||
@@ -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"]`
|
||||
@@ -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 могут требовать обновления (новое имя образа)
|
||||
@@ -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 (опционально, после подтверждения что всё работает)
|
||||
Reference in New Issue
Block a user