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
+126
View File
@@ -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
Коммитить и пушить после каждого завершённого этапа.
+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 (опционально, после подтверждения что всё работает)