Envelope получил MessageID (UUID); таблица iot_telemetry — столбец message_id +
UNIQUE(device_id,message_id); батч-INSERT ON CONFLICT DO NOTHING. Дубли при
at-least-once повторе из SQS больше не вставляются. Пустой message_id → NULL
(без ложного дедупа).
InsertTelemetry лишь буферизует и возвращает nil до фактической записи. Consumer
удалял сообщение сразу после processTelemetry == nil — краш/flush-ошибка в этом
окне = безвозвратная потеря. Теперь: копим receipt handles, вызываем store.Flush,
и только при успехе DeleteMessage; при ошибке flush — не удаляем (сообщения
вернутся после visibility timeout). Добавлен iotpg.Flush().
- MQTTAuth: replaced Get(Name=deviceID) with List+filter by Spec.DeviceID
(K8s object name != deviceID — caused deny for all devices)
- EnsureTenantDB: added GRANT role TO CURRENT_USER before CREATE DATABASE OWNER
(PG15+ requires SET ROLE privileges for target owner)
- Image: naeel/iot-operator:v0.2.5
- E2E test passed: device create → MQTT publish → SQS → Postgres → REST API