# 企业能耗管理平台 (EMS) 技术架构实施方案

## 1. 总体技术架构设计 (System Architecture)

系统采用 **B/S 架构**，前后端分离，后端采用**模块化单体 (Modular Monolith)** 架构（便于部署与维护，内部模块解耦），数据层采用**冷热分离**策略。

### 1.1 拓扑分层

* **接入层 (Edge Layer):** 负责协议解析、长连接维持 (MQTT/WS)、数据清洗。
* **服务层 (Service Layer):** 业务逻辑核心，包含 API 服务、计算引擎、权限拦截。
* **数据层 (Data Layer):** 关系型数据 (Meta) + 时序数据 (TimeSeries) + 缓存 (Cache)。
* **表现层 (Client Layer):** PC Web SPA (单页应用)。

### 1.2 技术栈清单 (Tech Stack)

| 领域 | 技术选型 | 版本/备注 |
| --- | --- | --- |
| **后端语言** | **Golang** | 1.21+ |
| **Web 框架** | **Gin** | 高性能 HTTP 框架 |
| **ORM 框架** | **GORM** | 支持 PG JSONB 与 关联查询 |
| **前端框架** | **Vue 3** | Composition API + TypeScript |
| **构建工具** | **Vite 5** | + Pinia (状态管理) |
| **UI 组件** | **Element Plus** | + ECharts 5 (图表) + AntV L7 (GIS) |
| **关系型库** | **PostgreSQL** | 15+ (利用 JSONB, CTE 递归特性) |
| **时序数据库** | **TDengine** | 3.0+ (核心，存储电力数据) |
| **缓存/队列** | **Redis** | 7.0 (缓存/PubSub) |
| **消息中间件** | **EMQX** | 5.0 (MQTT Broker) |
| **反向代理** | **Nginx** | 1.24+ (静态托管/网关) |

---

## 2. 核心数据模型设计 (Database Schema)

### 2.1 关系型数据库 (PostgreSQL)

*利用 PG 的高级特性处理复杂属性与层级。*

```sql
-- 1. 接入源配置 (存敏感信息与异构配置)
CREATE TABLE integration_source (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    driver_type VARCHAR(32) NOT NULL, -- 'HOME_ASSISTANT', 'MODBUS_TCP', 'MQTT'
    config JSONB NOT NULL,            -- e.g. {"ip":"192.168.1.10", "token":"eyJ...", "port":502}
    status SMALLINT DEFAULT 0,        -- 0:Offline, 1:Online
    sync_policy JSONB,                -- 同步策略配置
    updated_at TIMESTAMP
);

-- 2. 统一设备表 (核心资产)
CREATE TABLE device (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    source_id UUID REFERENCES integration_source(id),
    external_id VARCHAR(128) NOT NULL, 
    
    -- 属性
    name VARCHAR(128),
    device_type VARCHAR(32),          -- 'SWITCH', 'METER', 'SENSOR'
    
    -- 计量核心逻辑
    metering_mode VARCHAR(16),        -- 'REAL', 'VIRTUAL', 'COMPOUND'
    rated_power NUMERIC(10, 2),       -- 虚拟计量额定功率 (W)
    attribute_mapping JSONB,          -- 复合映射: {"power": "sensor.p1", "temp": "sensor.t1"}
    
    -- 关联关系
    location_id UUID REFERENCES sys_location(id),
    dept_id UUID REFERENCES sys_dept(id),
    
    is_active BOOLEAN DEFAULT TRUE,
    UNIQUE (source_id, external_id)   -- 防止重复导入
);

-- 3. 空间拓扑表 (支持无限层级)
CREATE TABLE sys_location (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    parent_id UUID,
    name VARCHAR(64),
    type VARCHAR(16),                 -- 'PARK', 'BUILDING', 'FLOOR', 'ROOM'
    ancestors TEXT,                   -- 祖级列表 "0,uuid1,uuid2" (便于快速搜索子孙)
    sort INT
);
-- 索引优化: CREATE INDEX idx_loc_ancestors ON sys_location(ancestors);

```

### 2.2 时序数据库 (TDengine)

*利用超级表 (Super Table) 实现降维聚合。*

```sql
-- 电力数据超级表
CREATE STABLE power_readings (
    ts TIMESTAMP,
    power FLOAT,       -- 瞬时功率 (W)
    voltage FLOAT,     -- 电压 (V)
    current FLOAT,     -- 电流 (A)
    energy_acc DOUBLE, -- 累计能耗 (kWh, 可选，若设备自身有读数)
    is_virtual BOOL    -- 是否为虚拟计算值
) TAGS (
    device_id BINARY(36),  -- 对应 PG device.id
    location_id BINARY(36),-- 冗余存储，加速空间聚合查询
    dept_id BINARY(36)     -- 冗余存储，加速部门聚合查询
);

-- 自动建表策略: 写入时自动根据 device_id 创建子表
-- INSERT INTO d_uuid123 USING power_readings TAGS ('uuid123', 'loc01', 'dept01') VALUES (NOW, 100.5, 220, 0.5, 0, false);

```

---

## 3. 关键模块技术实现细节

### 3.1 南向驱动层 (Driver Interface Pattern)

Go 语言中使用 `Interface` 实现多协议适配。

```go
// 定义标准驱动接口
type IDriver interface {
    // 连通性测试
    TestConnection(config string) error
    // 服务发现 (返回标准化的临时设备结构)
    Discover() ([]DiscoveredDevice, error)
    // 启动监听 (长连接或轮询)
    StartWatch(dataChan chan<- StandardDataPoint)
}

// 统一数据点结构 (归一化)
type StandardDataPoint struct {
    DeviceExternalID string
    Timestamp        int64
    Type             string // "STATE", "POWER", "TEMP"
    Value            interface{}
}

// 工厂模式获取实例
func NewDriver(type string, configJSON string) IDriver { ... }

```

### 3.2 虚实结合计量引擎 (Virtual Metering Engine)

**逻辑流程：**

1. **Event:** 接收到 `StandardDataPoint`。
2. **Check:** 查询内存缓存 (Redis) 获取该设备的 `metering_mode`。
3. **Process:**
* **Case REAL:** 直接将 Value 写入 TDengine。
* **Case VIRTUAL:**
* 若 Type == "STATE":
* State = "ON" -> 取 `device.rated_power` -> 写入 TDengine (Power=Rated)。
* State = "OFF" -> 写入 TDengine (Power=0)。




* **Case COMPOUND:**
* 根据 `attribute_mapping` 解析，将多个 sensor 消息合并或分别写入。





### 3.3 数据权限拦截器 (Data Scope Middleware)

利用 GORM 的 Scope 或 Gin 中间件实现 SQL 注入。

**实现逻辑：**

1. 用户登录后，计算其 `ScopeSQL` 并存入 Redis。
* Level 2 (A栋): `location_id IN ('uuid-a-building', 'uuid-room-101', ...)`
* Level 4 (个人): `location_id = 'uuid-my-office'`


2. **GORM Hook:**
```go
// 定义 GORM Scope
func DataScope(user *User) func(db *gorm.DB) *gorm.DB {
    return func(db *gorm.DB) *gorm.DB {
        if user.IsSuperAdmin {
            return db
        }
        // 自动注入 WHERE 条件
        return db.Where(user.DataScopeSQL) 
    }
}

// 业务代码调用 (完全无感)
db.Scopes(DataScope(currentUser)).Find(&devices)

```



### 3.4 实时状态推送 (WebSocket Manager)

用于前端大屏实时跳变、告警弹窗。

* **技术:** `github.com/gorilla/websocket`
* **架构:**
* **Hub:** 维护所有 Client 连接。
* **Channel:** 基于 Redis Pub/Sub 订阅后端 Go 服务的消息。
* **Filter:** 推送前判断 Client 的 `DataScope`，A栋的用户不推B栋的告警。



---

## 4. API 接口设计规范

采用 RESTful 风格，统一响应封装。

**Request Header:**
`Authorization: Bearer <JWT_TOKEN>`

**Response Struct:**

```json
{
  "code": 200,      // 业务状态码
  "msg": "success", // 提示信息
  "data": { ... }   // 业务数据
}

```

**Core API Definitions:**

* `POST /api/v1/auth/login` -> JWT Token
* `GET  /api/v1/sources/{id}/scan` -> `[]DiscoveredDevice` (带 Filter 逻辑)
* `POST /api/v1/devices/import` -> (批量 Upsert 逻辑)
* `GET  /api/v1/analysis/energy` -> (查询 TDengine 聚合数据)
* Query Params: `group_by=location`, `interval=1d`, `start_ts=...`


* `GET  /api/v1/monitor/dashboard` -> (混合数据：Redis在线数 + TDengine实时功率)

---

## 5. 部署架构 (Deployment)

基于 **Docker Compose** 的单机微服务化部署。

**`docker-compose.yaml` 配置摘要:**

```yaml
version: '3.8'

services:
  # 1. 前端网关
  nginx:
    image: nginx:alpine
    ports: ["80:80", "443:443"]
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./dist:/usr/share/nginx/html # Vue Build Output
    depends_on:
      - app-server

  # 2. Go 后端服务
  app-server:
    build: .
    restart: always
    environment:
      - DB_DSN=host=postgres user=ems password=pass dbname=ems port=5432 sslmode=disable
      - TD_DSN=root:root@tcp(tdengine:6030)/power_db
      - REDIS_ADDR=redis:6379
    volumes:
      - ./logs:/app/logs

  # 3. 基础组件
  postgres:
    image: postgres:15-alpine
    volumes:
      - pg_data:/var/lib/postgresql/data
  
  tdengine:
    image: tdengine/tdengine:3.0
    ports: ["6030:6030"]
    volumes:
      - taos_data:/var/lib/taos

  redis:
    image: redis:7-alpine
  
  emqx:
    image: emqx/emqx:5.0
    ports: ["1883:1883", "8083:8083"]

volumes:
  pg_data:
  taos_data:

```

## 6. 开发环境要求

* **Golang SDK:** 1.21+ (开启 Go Modules)
* **Node.js:** 18+ (pnpm 推荐)
* **IDE:** VS Code (前端) / GoLand (后端)
* **OS:** Linux (推荐 Ubuntu 22.04 LTS) 用于生产环境部署。