Cloud provider, application architecture, data storage, and device management powering the eCozy platform.
| Topic |
Summary |
| Infrastructure |
AWS eu-central-1, Docker Compose, GitLab CI |
| Backend API |
NestJS modular monolith (TypeScript), REST + Swagger |
| Domain Modules |
17 NestJS modules — auth, devices, rooms, scenarios, voice assistants |
| Heating Algorithm Service |
Python microservice — scheduler + worker for ML model retraining |
| Data Storage |
PostgreSQL 16, S3, CloudWatch Logs |
| Device Management |
CU registration, telemetry upload, command dispatch |
| OTA Updates |
Eclipse hawkBit (MySQL + RabbitMQ) |
| Authentication & Security |
JWT + refresh tokens, OAuth (Google / Apple / Amazon), device auth |
| Voice Assistants |
Amazon Alexa skill, Google Home Smart Home Action |
| Logging & Monitoring |
Winston → AWS CloudWatch |
| Parameter |
Value |
| Cloud provider |
AWS |
| Region |
EU (Frankfurt, eu-central-1) — GDPR-compliant data residency |
| Compute |
Docker containers (Docker Compose) — migration to ECS / EKS planned |
| Environments |
production · staging · development |
| CI/CD |
GitLab CI with Docker-based GitLab Runners on AWS |
| Node.js |
18 LTS (Alpine-based Docker image) |
| Python |
3.x (heating-algorithm microservice) |
| Service |
Image |
Port |
Purpose |
| api |
Custom (NestJS) |
APP_PORT |
Main backend API |
| scheduler |
Custom (Python) |
5008 |
ML retraining microservice |
| postgres |
postgres:16.0-alpine |
5432 |
Application database |
| hawkbit |
hawkbit/hawkbit-update-server:0.3.0-mysql |
8440 |
OTA firmware update server |
| mysql |
mysql:8.0 |
3306 |
hawkBit database |
| rabbitmq |
rabbitmq:3-management-alpine |
5672 / 15672 |
hawkBit message broker |
| maildev |
Custom |
1025 / 1080 |
Email testing (SMTP + web UI) |
| adminer |
adminer |
8080 |
Database admin UI |
| wiki |
ghcr.io/requarks/wiki:2 |
8088 |
Wiki.js documentation |
The backend is a modular monolith built with NestJS (Node.js + TypeScript). Every module follows the standard NestJS structure:
src/<module>/
├── dto/ ← Create / Update DTOs (class-validator)
├── entities/ ← TypeORM entities (DB schema)
├── <module>.controller.ts ← REST endpoints
├── <module>.service.ts ← Business logic
└── <module>.module.ts ← NestJS DI wiring
| Layer |
Technology |
| Framework |
NestJS 10 (TypeScript 5.2) |
| Database |
PostgreSQL 16 |
| ORM |
TypeORM 0.3 — code-first migrations, seeding |
| Auth |
Passport — JWT access/refresh + OAuth2 (Google / Apple / Amazon) |
| Push notifications |
Firebase Cloud Messaging (Admin SDK) |
| Email |
Nodemailer (production) · Maildev (development) |
| Logging |
Winston → AWS CloudWatch + console |
| API docs |
Swagger / OpenAPI at /docs |
| Localization |
nestjs-i18n (header-based language resolution) |
| Serialization |
class-transformer (role-based field exposure) |
| Validation |
class-validator (global ValidationPipe) |
| Versioning |
URI-based (/v1/) |
| Runtime |
Docker + Docker Compose |
¶ Domain Modules
| Module |
Route |
Description |
auth |
/auth/v1/ |
Email + password login, registration with email verification (4-digit code), password reset, JWT refresh, logout |
auth-google · auth-apple · auth-amazon |
/auth/{provider}/v1/ |
Social login — OAuth token exchange, automatic user creation |
central-units |
/central-units/v1/ |
CRUD for Central Units scoped to the authenticated user |
central-units-auth |
/central-units-auth/v1/ |
Device authentication — CU logs in with deviceId + secret (bcrypt), receives its own JWT |
thermostats |
/thermostats/v1/ |
CRUD for thermostats; on update triggers Google Home sync and state logging |
thermostat-logs |
/thermostat-logs/v1/ |
Batch upload of daily thermostat telemetry from CU; increments pendingLogCount to trigger ML retraining |
rooms |
/rooms/v1/ |
Room CRUD, thermostat assignment, scenario toggling; sends push notifications on smoke / fire / open-window alarms |
scenarios |
/scenarios/v1/ |
Heating schedules (JSONB: dayOfWeek, time, temperature); propagates changes to ML scenario clones |
heating-algorithm |
/heating-algorithm/v1/ |
Predicts heating time using polynomial regression; returns per-room trained coefficients |
alexa |
/alexa/v1/ |
Amazon Alexa skill handler — get/set temperature by room name (fuzzy match via Levenshtein) |
google-home |
/google-home/v1/ |
Google Smart Home fulfillment — SYNC, QUERY, EXECUTE intents for thermostat control |
users |
/users/v1/ |
User management (admin) |
me |
/me/v1/ |
Current user profile |
files |
/files/v1/ |
File upload (local or S3 driver) |
| Module |
Purpose |
central-units-session |
Manages active CU sessions with refresh tokens |
notifications |
Firebase Cloud Messaging — registers device tokens, sends push to Android (high priority) and iOS (mutable-content) |
locations |
Location CRUD (used internally by rooms) |
selected-thermostat-logs |
Snapshots thermostat state on every update for analytics |
room-logs |
Snapshots room state on every update for analytics |
session |
User session management |
forgot |
Password reset token management |
mail · mailer |
Email template rendering and sending (Handlebars + Nodemailer) |
A standalone Python microservice that runs alongside the NestJS backend. It retrains per-room ML models based on accumulated thermostat telemetry.
| Component |
Role |
| Scheduler |
Maintains a task queue, queries PostgreSQL for rooms that need retraining (pendingLogCount threshold), validates raw log batches, dispatches tasks to the worker |
| Worker |
Polls the scheduler for tasks, performs feature engineering (signed-sqrt transforms, degree-6 polynomial), trains a regression model (ElasticNet / Ridge / Lasso), submits coefficients back |
| Database layer |
SQLAlchemy — reads from thermostat_daily_log, writes to room_coefficients |
- CU uploads thermostat logs daily via
POST /thermostat-logs/v1/upload
pendingLogCount on the room entity increments — every 100 new logs the scheduler rescans
- Scheduler validates raw entries: filters out
indoorTemp == 0 or indoorTemp ≥ targetTemp, applies anchor-based session detection
- Worker trains a polynomial regression model (6 features: signed-sqrt of
tempIn, tempOut, targetDiff)
- Trained coefficients are stored in
room_coefficients table and used by GET /heating-algorithm/v1/:roomId for real-time predictions
|
|
| Language |
Python 3 |
| ML |
scikit-learn (LinearRegression / Ridge / Lasso / ElasticNet) |
| ORM |
SQLAlchemy + psycopg2 |
| Config |
pydantic-settings (.env files) |
| Runtime |
Docker container, port 5008 |
| Store |
Technology |
Purpose |
| Application DB |
PostgreSQL 16 |
Users, devices, rooms, schedules, telemetry logs, ML coefficients |
| OTA DB |
MySQL 8 |
hawkBit firmware distributions, rollout state |
| Object Storage |
AWS S3 |
File uploads, firmware images |
| Log Storage |
AWS CloudWatch |
Application logs (Winston transport) |
| Aspect |
Detail |
| Version |
16.0 (Alpine) |
| ORM |
TypeORM — code-first migrations |
| Schema management |
npm run migration:generate · migration:run · migration:revert |
| Seeding |
npm run seed:run (hygen-based seed generators) |
| Custom types |
thermostatLogEntry — registered at DataSource initialization |
| Connection pool |
Configurable via DATABASE_MAX_CONNECTIONS (default: 100) |
| SSL |
Optional — DATABASE_SSL_ENABLED, DATABASE_CA / DATABASE_KEY / DATABASE_CERT |
| Table |
Description |
user |
Accounts, roles, social provider links |
central_unit |
Registered CUs — deviceId (unique), hashed secret, location reference |
thermostat |
Devices — temperature, humidity, battery, mode, room assignment |
room |
Rooms — active scenario, lock mode, pendingLogCount for ML trigger |
scenario |
Heating schedules (JSONB), per-room ML scenario clones |
thermostat_daily_log |
Composite key (thermostatId + date), JSON array of log entries |
room_coefficients |
Per-room ML model: features, coefficients, metadata (JSONB) |
notification / notification_token |
Push history and per-device FCM tokens |
| Function |
Description |
| CU registration |
Central Unit created via /central-units/v1/ — stores deviceId + bcrypt-hashed secret |
| CU authentication |
Device logs in via /central-units-auth/v1/login with deviceId + secret → receives JWT (includes centralUnitId in payload) |
| CU session |
Refresh token rotation; session tracked in central_units_session table |
| Telemetry upload |
CU pushes daily thermostat logs via POST /thermostat-logs/v1/upload (batch of per-thermostat entries) |
| Command dispatch |
User scenario changes and heating-algorithm predictions routed to CU via REST |
| State logging |
Every thermostat and room update is snapshot-logged (selected-thermostat-logs, room-logs) for analytics |
| Aspect |
Detail |
| Server |
Eclipse hawkBit 0.3.0 |
| Database |
MySQL 8.0 (dedicated) |
| Message broker |
RabbitMQ 3 (management Alpine) |
| Port |
8440 |
| Base URL |
https://staging.ecozy.de/hawkbit/ |
| Scope |
Central Unit firmware rollouts; CU distributes edge device firmware locally via Thread |
| Aspect |
Detail |
| Strategy |
Passport.js — jwt, jwt-refresh, anonymous strategies |
| Access token |
JWT signed with AUTH_JWT_SECRET, expires in AUTH_JWT_TOKEN_EXPIRES_IN (default: 15 min) |
| Refresh token |
Signed with AUTH_REFRESH_SECRET, expires in AUTH_REFRESH_TOKEN_EXPIRES_IN (default: 3650 days) |
| JWT payload |
id, role, centralUnitId (optional), sessionId, iat |
| OAuth providers |
Google, Apple, Amazon — token exchange + automatic account creation |
| Device auth |
CU authenticates with deviceId + secret (bcrypt); receives its own JWT with centralUnitId |
| Authorization |
Role-based — Owner / Admin / Guest; field-level serialization via class-transformer groups |
| Validation |
Global ValidationPipe with class-validator on all incoming DTOs |
| CORS |
Enabled globally |
The Alexa skill is handled at POST /alexa/v1/. User accounts are linked via Amazon OAuth (accessToken from Alexa session → eCozy user lookup).
| Intent |
Action |
GetTemperatureIntent |
Query room or thermostat temperature by name (fuzzy match — Levenshtein distance ≤ 4) |
SetTemperatureIntent |
Set target temperature for a room by name |
GetTargetTemperatureIntent |
Query current target temperature |
AdjustTemperatureIntent |
Relative temperature adjustment (e.g., "2 degrees warmer") |
Google Smart Home fulfillment is handled at POST /google-home/v1/. Thermostats are exposed as THERMOSTAT device type (heat mode, 8–30 °C range).
| Intent |
Action |
action.devices.SYNC |
Returns all user thermostats with capabilities |
action.devices.QUERY |
Returns current temperature, humidity, thermostat mode |
action.devices.EXECUTE |
Handles ThermostatTemperatureSetpoint — updates rooms and thermostats |
action.devices.DISCONNECT |
Marks user as disconnected from Google Home |
| Aspect |
Detail |
| Library |
Winston |
| Transports |
Console (development) + AWS CloudWatch (production) |
| CloudWatch config |
AWS_REGION, CLOUDWATCH_GROUP_NAME, CLOUDWATCH_STREAM_NAME |
| ELK stack |
Elasticsearch + Logstash + Kibana + Filebeat config exists but is currently disabled (replaced by CloudWatch) |
|
|
| End-to-end System Overview |
High-level view of all system components and how they interconnect. |
| Hardware Layer |
Device inventory, chipsets, connectivity, and power design. |
| Firmware / Embedded Layer |
OS/RTOS, firmware architecture, OTA updates, and device security. |
| Edge AI Layer |
On-device machine learning — models, pipeline, and compute constraints. |
| Application Layer |
Mobile apps, dashboards, and API integrations. |
| Backend Infrastructure |
Detailed server architecture, APIs, and cloud services. |