# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview This is an **IoT Energy Storage Management Platform** (储能运营平台), originally based on RuoYi v3.9.0 but now stripped down to a standalone Spring Boot module focused on IoT device telemetry ingestion, MQTT messaging, time-series data storage, and vehicle/equipment tracking. - **Backend**: Spring Boot 2.5.15, Java 8, Spring Security 5.7.12, JWT authentication - **Frontend**: Vue 2 + Element UI (separate repository, not in this workspace) - **Database**: MySQL 8 (dual datasource via Druid), TDengine 3.x for time-series - **Cache**: Redis (localhost:6379) - **Message Broker**: MQTT (EMQX on 47.104.204.180:1883) ## Build & Run Commands ```bash # Build the iot-platform module mvn clean package -pl iot-platform -am -Dmaven.test.skip=true # Run locally with .env source .env && cd iot-platform/target && java -jar iot-platform.jar # Or use the convenience script ./start.sh start ``` The application starts on **port 8887**. The executable JAR is `iot-platform/target/iot-platform.jar`. ## Module Architecture This is now a **single-module Spring Boot application** (previously a multi-module RuoYi project). ``` iot-platform/ ├── controller → REST API endpoints, Swagger config ├── service → Business logic: IoT data sync, MQTT consumers, TDengine ops ├── domain → Entity classes, DTOs, VO objects ├── mapper → MyBatis mapper interfaces + XML in resources/mapper/ ├── mqtt → MQTT consumers (AbstractMqttConsumer base class) ├── task → Scheduled tasks (VehicleSyncTask, etc.) ├── config → Spring configuration classes ├── common → Shared constants (RedisKeys), utilities └── datasource → Dynamic datasource configuration ``` ## Data Architecture ### Dual MySQL Databases (Druid connection pool) - **Master** (`data`): System tables (users, roles, menus) + business tables - **Slave** (`cnc`): Secondary data — configured in `application-druid.yml` - Both hosted on `47.104.204.180:3306` - Dynamic datasource switching via `@DataSource` annotation ### TDengine (Time-Series Database) - Used for high-frequency IoT telemetry ingestion - Connection pool: HikariCP via `TDengineService` - Connects to `jdbc:TAOS://localhost:6030/` - Super-table pattern with column caching (`stableColumnCache`) ### Redis - Host: `localhost:6379` - Key patterns (defined in `common/RedisKeys.java`): - `DSB:active:devices` — Set of active IoT device keys - `DSB::` — Hash storing device telemetry - `workorder:coordinate:` — GPS coordinates - `:` — MQTT topic metadata ## Key Configuration Files - `iot-platform/src/main/resources/application.yml` — Main config (port 8887, Redis, MyBatis, Actuator) - `iot-platform/src/main/resources/application-druid.yml` — Database connection (Druid pool, master/slave) - `iot-platform/src/main/resources/logback-spring.xml` — Logging config with rolling - `.env` — Environment variables (passwords, credentials) loaded by systemd or start.sh ## Environment Variables All sensitive credentials are externalized to `.env`: ```bash MYSQL_USERNAME=root MYSQL_PASSWORD="..." REDIS_PASSWORD= MQTT_USERNAME=... MQTT_PASSWORD=... TDENGINE_USERNAME=root TDENGINE_PASSWORD=taosdata DRUID_STAT_ENABLED=false DRUID_USERNAME=ruoyi DRUID_PASSWORD=... ``` Spring Boot config uses `${ENV_NAME:default}` syntax for all sensitive values. ## IoT Data Flow ``` MQTT Broker (47.104.204.180:1883) ↓ subscribes to "+/generics", "+/status", "+/fault" MqttGenericConsumer / MqttStatusConsumer / MqttFaultConsumer ↓ parse JSON → ControllerData ├─→ Redis (DSB:active:devices, DSB:: hashes) ├─→ MySQL (sys_controller, sys_device tables) └─→ TDengine (time-series telemetry tables) VehicleSyncTask (@Scheduled every 30s) ↓ reads Redis DSB:* keys ├─→ syncs to sysrealtime (MySQL) ├─→ updates vehicle GPS in sys_car (MySQL) ├─→ updates sys_indicators KPIs (MySQL) └─→ triggers external webhook ``` ## MQTT Consumers All MQTT consumers extend `AbstractMqttConsumer` which provides: - Connection management (reconnect, keepalive) - `checkServerAvailability()` with retry limits - Graceful shutdown via `@PreDestroy` Implementations: - `MqttGenericConsumer` — General telemetry ingestion - `MqttStatusConsumer` — Device status messages - `MqttFaultConsumer` — Fault/alarm messages ## Deployment Production deployment uses systemd on online180 (47.104.204.180). ```bash # Deploy from local cd deploy ./deploy.sh --build # Build and deploy ./deploy.sh --jar # Deploy specific jar # Server management systemctl status iot-platform systemctl restart iot-platform journalctl -u iot-platform -f ``` See `deploy/README.md` for full deployment documentation. ## Authentication & Security - JWT-based stateless auth (header: `Authorization`) - Spring Security config in `config/SecurityConfig.java` - Password max retry: 5 attempts, lock time: 10 minutes - XSS filtering enabled - SQL injection prevention: field whitelist + parameterized queries in TDengineService - Table name validation: regex `^[a-zA-Z_][a-zA-Z0-9_]*$` in SysrealtimeService ## API Response Format All controllers return `AjaxResult`: ```java { "code": 200, "msg": "操作成功", "data": { ... } } ``` Page queries use `TableDataInfo`: ```java { "code": 200, "msg": "查询成功", "rows": [ ... ], "total": 100 } ``` ## Health Check Spring Boot Actuator is enabled at `/actuator/health`: ```bash curl http://localhost:8887/actuator/health # {"status":"UP"} ``` ## Important Implementation Notes - **MyBatis mappers are Java interfaces** with XML mapping files in `src/main/resources/mapper/` - **Service naming**: Custom IoT services often use concrete classes directly (no `I` prefix) - **TDengine SQL**: Built with string concatenation but protected by field whitelist (`ALLOWED_COLUMNS`) and `escapeValue()` - **No distributed locks**: `VehicleSyncTask` scheduled tasks may duplicate in clustered environments - **Alibaba Maven mirror** (`https://maven.aliyun.com/repository/public`) configured in root `pom.xml`