# Ether 物业管理系统 - 概要设计文档

**文档版本**: v1.0
**编制日期**: 2026-05-18
**数据来源**: REVERSE-AUTH/MDM/ASSET/OPS/FINANCE 反推设计文档 + BEST-PRACTICES-REPORT + CONSISTENCY-REPORT
**系统版本**: ether-pms v1.x (Spring Boot 3.x)

---

## 一、系统架构设计

### 1.1 总体架构

Ether 物业管理系统采用**单体模块化**架构，后端为 Spring Boot 3.x 单体应用，通过 Maven 多模块组织业务边界；前端为 Vue3 SPA 应用，按角色拆分为三套独立前端。

**技术栈总览**：

| 层次 | 技术选型 | 说明 |
|------|---------|------|
| 后端框架 | Spring Boot 3.x + Spring Security 6 | Java 17+，Servlet 容器 |
| 持久层 | Spring Data JPA + Hibernate | ORM 框架，自动建表 |
| 数据库 | PostgreSQL 15+ | JSONB/UUID/ltree 扩展 |
| 缓存 | Redis | 登录锁定、Session、热数据 |
| 认证 | JWT (HMAC-SHA256) | 无状态 Token 认证 |
| 前端框架 | Vue3 + TypeScript + Vite | Composition API + `<script setup>` |
| UI 组件库 | Ant Design Vue 4.x | 统一视觉风格 |
| 状态管理 | Pinia | Composition API 风格 |
| HTTP 客户端 | Axios | 请求/响应拦截器封装 |
| 构建工具 | Maven (后端) / npm (前端) | 多模块构建 |

**架构图**：

```
┌──────────────────────────────────────────────────────────────────────┐
│                          客户端层                                    │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │
│  │ ether-admin  │  │ether-app-    │  │ether-app-    │              │
│  │  (管理后台)   │  │ employee     │  │ owner        │              │
│  │  :5175       │  │ (员工H5)     │  │ (业主H5)     │              │
│  │  Vue3+AntD   │  │ :5174        │  │ :5176        │              │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘              │
│         │                 │                 │                       │
│         └─────────────────┼─────────────────┘                       │
│                           │ RESTful API (JSON)                      │
│                           │ Authorization: Bearer {JWT}            │
│                           │ X-Project-ID: {projectId}              │
└───────────────────────────┼──────────────────────────────────────────┘
                            │
┌───────────────────────────┼──────────────────────────────────────────┐
│                     后端服务层 (ether-pms :8080)                      │
│                           │                                          │
│  ┌────────────────────────┼────────────────────────────────────┐    │
│  │              Spring Security Filter Chain                    │    │
│  │  JwtAuthenticationFilter → LoginAttemptFilter → ...         │    │
│  └────────────────────────┼────────────────────────────────────┘    │
│                           │                                          │
│  ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐          │
│  │module- │ │module- │ │module- │ │module- │ │module- │          │
│  │common  │ │auth    │ │mdm     │ │asset   │ │wo      │          │
│  │        │ │        │ │        │ │        │ │        │          │
│  │公共工具│ │认证授权│ │主数据  │ │设备资产│ │运维工单│          │
│  │异常/响应│ │用户/角色│ │项目/空间│ │设备/健康│ │工单/维保│          │
│  └────────┘ └────────┘ └────────┘ └────────┘ └────────┘          │
│                           │                                          │
│  ┌────────────────────────┼────────────────────────────────────┐    │
│  │              JPA / Hibernate / Repository                    │    │
│  └────────────────────────┼────────────────────────────────────┘    │
│                           │                                          │
└───────────────────────────┼──────────────────────────────────────────┘
                            │
┌───────────────────────────┼──────────────────────────────────────────┐
│                        数据层                                        │
│  ┌──────────────┐  ┌──────────────┐                                │
│  │ PostgreSQL   │  │   Redis      │                                │
│  │ 15+          │  │              │                                │
│  │ JSONB/UUID   │  │ 登录锁定     │                                │
│  │ B-tree/GIN   │  │ Token缓存    │                                │
│  └──────────────┘  └──────────────┘                                │
└──────────────────────────────────────────────────────────────────────┘
```

### 1.2 模块划分

| 模块 | 职责 | 核心实体 | API 前缀 |
|------|------|---------|---------|
| **module-common** | 公共工具、异常体系、统一响应、基础配置 | ErrorCode、ApiResponse | — |
| **module-auth** | 身份认证、用户管理、RBAC 权限、审计日志 | User、Role、Permission、Dept、AuditLog | `/api/auth` |
| **module-mdm** | 项目管理、空间节点、巡检标准、备件库存、能耗计量 | Project、SpaceNode、InspectionItem、SparePart、EnergyMeter | `/api/mdm`、`/api/ops` |
| **module-asset** | 设备台账、健康评分、故障历史、归属主体 | Equipment、EquipmentElevator/Hvac/Fire/Energy、EquipmentHealthScore | `/api/asset` |
| **module-wo** | 工单管理、维保计划、维保任务、巡检模板 | WorkOrder、MaintenancePlan、MaintenanceTask、InspectionTemplate | `/api/wo`、`/api/ops` |
| **module-finance** | 收费项目、账单管理、支付记录（**待实现**） | FeeItem、FeeBill、FeePayment（未实现） | `/api/finance`（待定） |

**模块依赖关系**：

```
module-common ← module-auth ← module-mdm ← module-asset
                    ↑              ↑            ↑
                    └──────────────┴────────────┘
                              module-wo
```

- module-common 是所有模块的基础依赖
- module-auth 提供用户/权限基础数据，被其他业务模块引用
- module-mdm 提供项目/空间基础数据，被 asset/wo 模块引用
- module-asset 和 module-wo 存在交叉引用（设备-工单关联）

### 1.3 前后端交互架构

**认证流程**：

```
1. 客户端 POST /api/auth/login {username, password}
2. 后端验证 → 生成 JWT Token（含 userId/username/roles）
3. 客户端存储 Token → 后续请求 Header: Authorization: Bearer {token}
4. 后端 JwtAuthenticationFilter 拦截 → 验证签名和过期 → 设置 SecurityContext
```

**项目隔离机制**：

```
1. 登录后获取用户项目列表 GET /api/auth/users/{id}/projects
2. 用户选择项目 → 后续请求携带 X-Project-ID Header
3. 后端 ProjectContextInterceptor 拦截 → 设置 ThreadLocal
4. 业务层 DataScopeService 过滤数据 → 按 projectId 限定数据范围
```

**统一响应格式**：

```json
{
  "code": 0,
  "message": "success",
  "data": { ... }
}
```

**错误响应格式**：

```json
{
  "code": 1001,
  "message": "用户名或密码错误",
  "data": null
}
```

**错误码分段规则**：

| 段号 | 模块 | 示例 |
|------|------|------|
| 1xxx | 认证 | 1001 用户名或密码错误 |
| 2xxx | 用户 | 2001 用户不存在 |
| 3xxx | 角色 | 3001 角色代码已存在 |
| 4xxx | 权限 | 4001 权限代码已存在 |
| 5xxx | 项目 | 5001 项目编码已存在 |
| 6xxx | 空间/能耗 | 6101 仪表不存在 |
| 7xxx | 文件 | 7001 文件格式不支持 |

### 1.4 部署架构

| 组件 | 端口 | 部署方式 | 说明 |
|------|------|---------|------|
| ether-pms | 8080 | JAR 包部署 | 后端单体服务 |
| ether-admin | 5175 | Nginx 静态托管 | 管理后台前端 |
| ether-app-employee | 5174 | Nginx 静态托管 | 员工 H5 前端 |
| ether-app-owner | 5176 | Nginx 静态托管 | 业主 H5 前端 |
| ether-app-commercial | 5177 | Nginx 静态托管 | 商办 H5 前端 |
| PostgreSQL | 5432 | 独立部署 | 主数据库 |
| Redis | 6379 | 独立部署 | 缓存/登录锁定 |

**启动脚本**：项目根目录提供 `start-services.sh` / `stop-services.sh` 统一管理服务启停。

---

## 二、业务域划分与边界

### 2.1 六大业务域定义

| 域编号 | 域名称 | 核心职责 | 对应模块 | 核心实体数 |
|--------|--------|---------|---------|-----------|
| D1 | 身份与权限域 | 用户认证、RBAC 权限、项目隔离、审计日志 | module-auth | 14 |
| D2 | 空间与项目域 | 项目管理、空间节点树、项目配置、项目统计 | module-mdm | 13 |
| D3 | 设备与资产域 | 设备台账、专业扩展、健康评分、故障历史、归属管理 | module-asset | 8 |
| D4 | 运营与服务域 | 工单管理、维保计划/任务、巡检模板、备件库存 | module-wo + module-mdm(部分) | 6 |
| D5 | 财务与收费域 | 收费项目、账单管理、支付记录、能耗计费 | module-finance(待实现) | 0(待实现) |
| D6 | 前端交互域 | 管理后台、员工端、业主端、商办端 | ether-admin + ether-app-* | — |

### 2.2 域间依赖关系图

```mermaid
graph TD
    D1[D1 身份与权限域<br/>module-auth]
    D2[D2 空间与项目域<br/>module-mdm]
    D3[D3 设备与资产域<br/>module-asset]
    D4[D4 运营与服务域<br/>module-wo]
    D5[D5 财务与收费域<br/>module-finance]
    D6[D6 前端交互域<br/>ether-admin/apps]

    D1 -->|用户/角色/权限| D2
    D1 -->|用户/角色/权限| D3
    D1 -->|用户/角色/权限| D4
    D1 -->|用户/角色/权限| D5

    D2 -->|项目/空间节点| D3
    D2 -->|项目/空间节点| D4
    D2 -->|项目/空间节点| D5

    D3 -->|设备信息| D4
    D3 -->|设备健康数据| D5

    D4 -->|工单费用| D5

    D1 -.->|API调用| D6
    D2 -.->|API调用| D6
    D3 -.->|API调用| D6
    D4 -.->|API调用| D6
    D5 -.->|API调用| D6
```

**依赖说明**：

| 依赖关系 | 依赖内容 | 实现方式 |
|---------|---------|---------|
| D2 → D1 | 项目成员管理需要用户数据 | UserProject 关联 + ProjectStaff 扩展 |
| D3 → D2 | 设备关联空间节点 | Equipment.spaceNodeId → SpaceNode.id |
| D4 → D2 | 工单关联项目和空间 | WorkOrder.projectId / spaceId |
| D4 → D3 | 工单关联设备 | WorkOrder.equipmentId → Equipment.id |
| D4 → D3 | 维保任务完成后更新设备 | MaintenanceTask → Equipment 联动更新 |
| D5 → D2 | 账单关联项目和空间 | FeeBill.projectId / spaceNodeId |
| D5 → D3 | 能耗费用对接设备 | EnergyConsumption → Equipment |

### 2.3 域间数据流图

```mermaid
flowchart LR
    subgraph D1[身份与权限域]
        User[User]
        Role[Role]
    end

    subgraph D2[空间与项目域]
        Project[Project]
        SpaceNode[SpaceNode]
        EnergyMeter[EnergyMeter]
    end

    subgraph D3[设备与资产域]
        Equipment[Equipment]
        HealthScore[HealthScore]
        FailureHistory[FailureHistory]
    end

    subgraph D4[运营与服务域]
        WorkOrder[WorkOrder]
        MaintenancePlan[MaintenancePlan]
        MaintenanceTask[MaintenanceTask]
        SparePart[SparePart]
    end

    subgraph D5[财务与收费域]
        FeeItem[FeeItem]
        FeeBill[FeeBill]
        FeePayment[FeePayment]
    end

    User -->|项目成员| Project
    Project -->|1:N| SpaceNode
    SpaceNode -->|spaceNodeId| Equipment
    Equipment -->|equipmentId| WorkOrder
    Equipment -->|equipmentId| MaintenanceTask
    MaintenancePlan -->|planId| MaintenanceTask
    MaintenanceTask -->|完成后联动| Equipment
    WorkOrder -->|relatedOrderId| SparePart
    EnergyMeter -->|费用计算| FeeBill
    Equipment -->|健康数据| HealthScore
    Equipment -->|故障记录| FailureHistory
    FailureHistory -->|关联工单| WorkOrder
```

### 2.4 域间接口契约

| 接口 | 提供方 | 消费方 | 契约内容 |
|------|--------|--------|---------|
| 用户项目列表 | D1 (auth) | D2 (mdm) | `GET /api/auth/users/{id}/projects` → `List<UserProject>` |
| 项目成员管理 | D2 (mdm) | D1 (auth) | `GET/POST/DELETE /api/mdm/projects/{id}/members` |
| 空间节点查询 | D2 (mdm) | D3 (asset) | Equipment.spaceNodeId → SpaceNode.id，通过 JPA 关联 |
| 设备查询 | D3 (asset) | D4 (wo) | WorkOrder.equipmentId → Equipment.id，通过 JPA 关联 |
| 维保完成后设备更新 | D4 (wo) | D3 (asset) | MaintenanceTask 完成时更新 Equipment.maintenanceVendor/nextInspectionDate |
| 备件出库关联工单 | D4 (wo) | D2 (mdm) | SparePartRecord.relatedOrderId → WorkOrder.id |
| 能耗数据对接账单 | D2 (mdm) | D5 (finance) | EnergyConsumption.amount → FeeBill 数据来源（待实现） |

---

## 三、核心技术实现路径

### 3.1 多租户数据隔离

**隔离策略**：共享数据库 + projectId 字段隔离

**实现机制**：

| 层次 | 机制 | 实现细节 |
|------|------|---------|
| 数据层 | projectId 字段 | 所有业务表均含 project_id 列，索引覆盖 |
| 请求层 | X-Project-ID Header | 前端每次请求携带当前项目 ID |
| 拦截层 | ProjectContextInterceptor | 拦截请求，将 projectId 存入 ThreadLocal |
| 服务层 | DataScopeService | 提供 canAccessAllData()、getPermittedProjectIds() 等判断方法 |
| 查询层 | Repository 方法 | findByProjectIdAndXxx() 系列方法，强制带项目条件 |

**数据范围过滤**：

```java
// 四级数据范围
ALL         → 不做数据过滤，可查看所有项目数据
PROJECT     → 过滤 project_id = 当前项目
DEPARTMENT  → 过滤 project_id + dept_id = 用户部门
SELF        → 过滤 assigned_to / creator = 当前用户
```

**已知不足与改进方向**：

- 当前 DataScopeService 仅提供判断方法，未实现 SQL 自动注入，数据过滤依赖业务层手动调用，存在遗漏风险
- 改进方案：通过 JPA Specification 或 MyBatis Interceptor 自动拼接数据过滤条件

### 3.2 RBAC 权限模型

**模型结构**：User ←M2M→ Role ←M2M→ Permission

**三级角色体系**：

| 角色类型 | 枚举值 | 说明 | 数据范围 |
|---------|--------|------|---------|
| 系统级 | SYSTEM | 跨项目全局角色 | ALL |
| 项目级 | PROJECT | 绑定特定项目的角色 | PROJECT |
| 部门级 | DEPARTMENT | 部门范围角色 | DEPARTMENT |

**双层角色分配**：

```
用户所有角色 = 用户直接角色(auth_user_role) ∪ 项目员工角色(ProjectStaffRole)
```

- 用户直接角色：通过 `auth_user_role` 中间表关联，用户创建时或 UserController.assignRoles 分配
- 项目员工角色：通过 `ProjectStaffRole` 关联，项目成员管理时分配

**权限类型**：

| 类型 | 说明 | 示例 |
|------|------|------|
| MENU | 菜单权限 | 系统管理、设备管理 |
| BUTTON | 按钮权限 | 新增设备、删除工单 |
| API | 接口权限 | POST /api/asset/equipment |

**权限代码格式**：`module:resource:action`，如 `asset:equipment:create`

**四级数据范围**：

| 数据范围 | 编码 | 过滤逻辑 |
|---------|------|---------|
| 全部数据 | ALL | 不做数据过滤 |
| 本项目数据 | PROJECT | WHERE project_id = ? |
| 本部门数据 | DEPARTMENT | WHERE project_id = ? AND dept_id = ? |
| 仅本人数据 | SELF | WHERE assigned_to = ? OR created_by = ? |

### 3.3 树形结构管理

**适用实体**：SpaceNode（空间节点）、Dept（部门）、SparePartCategory（备件分类）

**实现方案**：treePath 字符串路径 + parentId 自引用

**核心字段**：

| 字段 | 类型 | 说明 |
|------|------|------|
| parentId | UUID | 父节点 ID（NULL=顶级） |
| treePath | String(1000) | 物理路径，格式 `id1.id2.id3` |
| treePathName | String(1000) | 名称路径，格式 `项目/楼栋/单元/房间` |
| level | Integer | 层级深度，根节点为 0 |

**SpaceNode 空间层级**：

```
项目 (Project)
├── 楼栋 (BUILDING)       ← NodeCategory.BUILDING, level=1
│   ├── 单元 (UNIT)       ← NodeCategory.BUILDING, level=2
│   │   ├── 楼层 (FLOOR)  ← NodeCategory.BUILDING, level=3
│   │   │   └── 房间 (ROOM) ← NodeCategory.BUILDING, level=4
│   │   └── 房间 (ROOM)   ← 可跳过楼层直接挂房间
│   └── 公共用房 (PUBLIC_ROOM)
├── 商铺 (SHOP)           ← NodeCategory.BUILDING, level=2
├── 车库 (GARAGE)         ← NodeCategory.PARKING, level=1
│   ├── 停车区域 (PARKING_AREA) ← level=2
│   │   └── 车位 (PARKING_SPACE) ← level=3
├── 设备房 (EQUIPMENT_ROOM) ← NodeCategory.FACILITY, level=1
├── 公共区域 (PUBLIC_AREA) ← NodeCategory.AREA, level=1
└── 绿化区域 (GREEN_AREA) ← NodeCategory.AREA, level=1
```

**查询模式**：

| 查询需求 | 实现方式 | SQL 示例 |
|---------|---------|---------|
| 查子节点 | parentId 查询 | `WHERE parent_id = ?` |
| 查所有子孙 | treePath LIKE | `WHERE tree_path LIKE 'parentPath.%'` |
| 查祖先链 | treePath 解析 | 应用层拆分 treePath 获取祖先 ID 列表 |
| 构建完整树 | 扁平列表 + 递归 | Controller 层递归构建树形 VO |

**索引设计**：

```sql
idx_space_node_tree_path (tree_path)        -- 路径前缀查询
idx_sn_project_parent (project_id, parent_id) -- 项目+父节点
idx_sn_project_type (project_id, node_type)   -- 项目+类型
```

**已知不足**：treePath LIKE 查询在大数据量下性能不佳，未使用 PostgreSQL ltree 扩展或闭包表方案。后续可评估升级。

### 3.4 设备扩展表模式

**设计原则**：主表存储公共字段，扩展表存储专业参数，通过 equipmentType 决定扩展表。

**模式结构**：

```
Equipment (主表, ~40个公共字段)
├── EquipmentElevator (电梯扩展) ← equipment_id UNIQUE
├── EquipmentHvac (暖通扩展)     ← equipment_id UNIQUE
├── EquipmentFire (消防扩展)     ← equipment_id UNIQUE
└── EquipmentEnergy (能源计量扩展) ← equipment_id UNIQUE
```

**设备类型与扩展表映射**：

| 设备类型 | 枚举值 | 扩展表 | 无扩展表时 |
|---------|--------|--------|-----------|
| 电梯系统 | ELEVATOR | EquipmentElevator | — |
| 暖通空调 | HVAC | EquipmentHvac | — |
| 消防系统 | FIRE_PROTECTION | EquipmentFire | — |
| 能源计量 | ENERGY_METER | EquipmentEnergy | — |
| 给排水系统 | PLUMBING | — | 使用 attributes JSON |
| 电气系统 | ELECTRICAL | — | 使用 attributes JSON |
| 弱电系统 | SECURITY | — | 使用 attributes JSON |
| 景观绿化 | LANDSCAPE | — | 使用 attributes JSON |
| 厨余设备 | KITCHEN | — | 使用 attributes JSON |
| 其他设备 | OTHER | — | 使用 attributes JSON |

**扩展表服务接口模式**：

```java
public interface EquipmentElevatorService {
    Optional<EquipmentElevator> getByEquipmentId(UUID equipmentId);
    EquipmentElevator saveOrUpdate(EquipmentElevator elevator);
}
```

**扩展表 API 路径**：

```
GET  /api/asset/equipment/{id}/elevator   → 获取电梯扩展
PUT  /api/asset/equipment/{id}/elevator   → 更新电梯扩展
GET  /api/asset/equipment/{id}/hvac       → 获取暖通扩展
PUT  /api/asset/equipment/{id}/hvac       → 更新暖通扩展
GET  /api/asset/equipment/{id}/fire       → 获取消防扩展
PUT  /api/asset/equipment/{id}/fire       → 更新消防扩展
GET  /api/asset/equipment/{id}/energy     → 获取能源扩展
PUT  /api/asset/equipment/{id}/energy     → 更新能源扩展
```

**已知问题**：module-mdm 的 SpaceNode 也内嵌了设备扩展字段（isEquipment 标记），与 module-asset 的独立 Equipment 实体形成双体系并存，需统一。

### 3.5 工单状态机

**WorkOrder 状态机（6 状态）**：

```
┌─────────────┐
│   PENDING   │ ← 创建工单（默认状态）
│   (待分配)   │
└──────┬──────┘
       │ assign (派单)
       ▼
┌─────────────┐
│  ASSIGNED   │ ← 分配负责人/服务商
│   (已派单)   │
└──────┬──────┘
       │ start (开始执行)
       ▼
┌─────────────┐
│ IN_PROGRESS │ ← 记录 actualStart
│   (执行中)   │
└──────┬──────┘
       │ complete (完成)
       ▼
┌─────────────┐
│  COMPLETED  │ ← 记录故障原因/解决方案/费用
│   (已完成)   │
└──────┬──────┘
       │ verify (验收)
       ▼
┌─────────────┐
│  VERIFIED   │ ← 记录验收人/评分/备注
│   (已验收)   │
└─────────────┘

特殊: CANCELLED ← PENDING/ASSIGNED/IN_PROGRESS 可取消
      COMPLETED/VERIFIED 不可取消
```

**状态流转约束**：

| 当前状态 | 允许操作 | 下一状态 | 自动处理 |
|---------|---------|---------|---------|
| PENDING | assign | ASSIGNED | 设置 assignedTo/assignedVendor/assignedDate |
| ASSIGNED | start | IN_PROGRESS | 设置 actualStart = now() |
| IN_PROGRESS | complete | COMPLETED | 设置 actualEnd = now()，自动计算 actualHours |
| COMPLETED | verify | VERIFIED | 设置 verifiedBy/verifiedDate/rating |
| PENDING/ASSIGNED/IN_PROGRESS | cancel | CANCELLED | — |

**MaintenanceTask 状态机（6 状态，与工单类似但有差异）**：

| 差异点 | WorkOrder | MaintenanceTask |
|--------|-----------|-----------------|
| 完成方式 | 仅一种 complete | 两种：complete（简版）+ complete-details（详版） |
| 评分方式 | 验收时评分 | 验收时评分 + 独立 rate 接口 |
| 删除策略 | 物理删除 | 逻辑删除（设为 CANCELLED） |
| 完成后联动 | 无 | 自动更新设备维保记录 |

**工单编号生成规则**：

| 类型 | 格式 | 示例 |
|------|------|------|
| 工单 | WO-YYYYMMDD-XXXX | WO-20260518-0001 |
| 维保任务 | EQ-YYYYMMDD-XXXX | EQ-20260518-0001 |

**已知风险**：编号生成使用 findMaxWorkNoByPrefix 查询最大编号 +1，并发场景可能生成重复编号，需改用数据库序列或 Redis INCR。

### 3.6 健康评分算法 [Beta]

**评分公式**：

```
健康度 = 基础分(100) - 故障扣分 - 维保扣分 - 年龄扣分
最低分 = 0（不会为负数）
```

**三维扣分规则**：

| 扣分项 | 计算公式 | 参数 | 上限 |
|--------|----------|------|------|
| 故障扣分 | 故障次数(近30天) x 5 | FAILURE_DEDUCTION_PER_COUNT = 5 | 无上限 |
| 维保扣分 | (1 - 维保完成率) x 20 | MAINTENANCE_DEDUCTION_FACTOR = 20 | 20 分 |
| 年龄扣分 | 设备年龄(年) x 2 | AGE_DEDUCTION_PER_YEAR = 2 | 10 分 (MAX_AGE_DEDUCTION) |

**5 级健康等级**：

| 等级 | 枚举值 | 分数范围 | 前端颜色 |
|------|--------|---------|---------|
| 优秀 | EXCELLENT | [90, 100) | 绿色 |
| 良好 | GOOD | [75, 90) | 青色 |
| 一般 | FAIR | [60, 75) | 橙色 |
| 较差 | POOR | [40, 60) | 红色 |
| 危急 | CRITICAL | [0, 40) | 红色 |

**MTBF 计算（平均故障间隔时间）**：

```
MTBF = 运行时间(小时) / 故障次数
```

- 计算周期：默认 30 天，可自定义
- 运行时间：从第一个故障到最后一个故障的时间跨度
- 仅 1 次故障：使用默认期间天数 x 24 小时
- 无故障时返回 0

**MTTR 计算（平均修复时间）**：

```
MTTR = 总修复时间(小时) / 修复次数
```

- 仅统计已完成修复的故障记录（repairDurationHours 不为空）
- 无修复记录时返回 0

**已知问题**：

1. calculateEquipmentAge() 错误使用 SpaceNode.maintenanceContractStart 而非 Equipment.installationDate
2. projectId 硬编码为全零 UUID `00000000-0000-0000-0000-000000000000`
3. 维保完成率固定返回 1.0（TODO 标记）
4. 扣分系数（5、20、2、10）硬编码在代码中，未提取为配置

**Beta → 正式演进路径**：

| 阶段 | 时间 | 目标 |
|------|------|------|
| Beta（当前） | 2026 Q2 | 修复已知 Bug，提取配置项 |
| V1 | 2026 Q3 | 完善维保完成率计算，积累真实数据校准系数 |
| V2 | 2026 Q4 | 引入 IoT 数据，增加运行参数扣分维度 |
| V3 | 2027 Q1 | 机器学习模型，基于历史数据预测故障概率 |

### 3.7 审计日志

**记录方式**：`@OperationLog` 注解 + AOP 切面

```java
@OperationLog(operation = "创建用户", module = "USER", action = AuditLog.ActionType.CREATE)
public User createUser(User user) { ... }
```

**异步持久化**：通过 `auditLogExecutor` 线程池异步保存，避免影响业务性能

**核心字段**：

| 字段 | 说明 |
|------|------|
| userId / username | 操作人 |
| operation | 操作描述 |
| module | 模块标识（USER/ROLE/PERMISSION/PROJECT/AUTH/DEPT） |
| action | 操作类型（CREATE/UPDATE/DELETE/QUERY/VIEW/LOGIN/LOGOUT/EXPORT/IMPORT/ASSIGN/REVOKE） |
| targetType / targetId | 操作目标 |
| content | 操作内容 |
| params / result | 请求参数 / 操作结果 |
| executionTimeMs | 执行耗时 |
| status | SUCCESS / FAIL |

**查询窗口**：强制限制 30 天，超过 30 天的查询自动截断起始时间

**归档策略**：90 天以上日志归档（当前实现为直接删除，TODO: 导出至对象存储保留 3-5 年）

**索引设计**：

```sql
idx_audit_log_created_at (created_at)
idx_audit_log_user_id (user_id)
idx_audit_log_module (module)
idx_audit_log_action (action)
idx_al_user_createdat (user_id, created_at DESC)
```

**已知不足**：

1. 审计日志可篡改（无防篡改机制），需改为只追加
2. 90 天归档实为删除，不符合合规要求（物业行业需保留 3-5 年）
3. 改进方案：数据库触发器禁止 UPDATE/DELETE + 90 天后导出至 OSS/S3

### 3.8 编码生成规则

| 实体 | 编码格式 | 生成方式 | 唯一性保障 |
|------|---------|---------|-----------|
| 项目编码 | 正则 `^[a-zA-Z0-9_-]+$` | 后端 generateCode() | 数据库 UNIQUE |
| 空间编码 | **未实现** | — | — |
| 设备编码 | equipmentCode | 创建时指定 | 数据库 UNIQUE |
| 工单编号 | WO-YYYYMMDD-XXXX | findMaxWorkNoByPrefix + 1 | 应用层（有并发风险） |
| 维保任务编号 | EQ-YYYYMMDD-XXXX | 同上 | 应用层（有并发风险） |
| 计划编码 | planCode | 创建时指定 | 数据库 UNIQUE |
| 备件编码 | sparePartCode | 创建时指定 | 数据库 UNIQUE |
| 计量点编码 | EM + yyyyMMddHHmmss | generateMeterCode() | 冲突时追加后缀 |
| 记录编码 | recordCode | 创建时指定 | 数据库 UNIQUE |

**改进方向**：

1. 空间编码需实现自动生成规则（如 项目编码-楼栋号-单元号-房号）
2. 工单/任务编号改用数据库序列或 Redis INCR 保障并发安全
3. 统一编码生成服务，避免各模块各自实现

---

## 四、难点识别与应对

### 4.1 跨域业务流程的一致性保障

**难点描述**：维保任务完成后需联动更新设备信息（维保商、下次巡检日期），工单完成后需关联备件出库，能耗数据需对接账单生成。这些跨域操作需要保证数据一致性。

**应对方案**：

| 方案 | 适用场景 | 实现方式 | 一致性级别 |
|------|---------|---------|-----------|
| 同步调用 + 事务 | 强一致性要求 | @Transactional 跨模块 Service 调用 | 强一致 |
| 事件驱动 + 最终一致性 | 弱一致性可接受 | Spring ApplicationEvent + 异步监听 | 最终一致 |
| 补偿事务 | 需要回滚能力 | Saga 模式，失败时执行补偿操作 | 最终一致 |

**当前实现**：维保任务完成后同步调用 EquipmentService 更新设备，异常容错（更新设备失败不影响工单完成）。

**改进计划**：

1. 短期（Q2 2026）：保持同步调用，增加重试机制（@Retryable）
2. 中期（Q3 2026）：引入 Spring ApplicationEvent，关键操作发布领域事件
3. 远期（Q4 2026）：评估引入消息队列（RabbitMQ/Kafka）解耦跨域通信

### 4.2 工单状态机的并发控制

**难点描述**：多个用户可能同时对同一工单执行状态变更操作（如同时派单、同时完成），需要保证状态流转的正确性和幂等性。

**应对方案**：

| 机制 | 实现方式 | 说明 |
|------|---------|------|
| 乐观锁 | version 字段 + @Version | JPA 自动版本控制，更新时检查版本号 |
| 状态校验 | 业务层前置检查 | 状态变更前校验当前状态是否允许该操作 |
| 幂等性 | 幂等键 + 去重 | 重复请求返回当前状态而非报错 |
| 分布式锁 | Redis SETNX | 防止同一工单被并发操作 |

**当前实现**：仅业务层前置状态校验，无乐观锁和分布式锁。

**改进计划**：

1. 为 WorkOrder 和 MaintenanceTask 添加 version 字段（@Version）
2. 状态变更操作使用 Redis 分布式锁（key: `work_order:lock:{id}`）
3. 状态变更接口设计为幂等：重复操作返回当前状态

### 4.3 树形结构的高效查询

**难点描述**：SpaceNode 使用 treePath 字符串路径（如 `uuid1.uuid2.uuid3`），查询子孙节点需 LIKE 匹配，大数据量下性能堪忧。

**应对方案**：

| 方案 | 查询性能 | 维护成本 | 适用场景 |
|------|---------|---------|---------|
| treePath LIKE（当前） | O(n) 全表扫描 | 低 | 数据量 < 1万 |
| PostgreSQL ltree 扩展 | O(log n) 索引扫描 | 中 | 数据量 1-10万 |
| 闭包表 (Closure Table) | O(1) 直接查询 | 高（需额外表） | 数据量 > 10万 |
| 递归 CTE | O(depth) | 低 | 深度有限（< 10层） |

**当前实现**：treePath LIKE + B-tree 索引

**改进计划**：

1. 短期（Q2 2026）：确保 treePath 索引存在，添加 GIN 索引支持前缀查询
2. 中期（Q3 2026）：评估迁移至 PostgreSQL ltree 扩展，利用专用的 ltree 索引
3. 远期（Q4 2026）：若数据量超过 10 万节点，考虑闭包表方案

**递归 CTE 查询示例**（当前可用的优化方案）：

```sql
WITH RECURSIVE space_tree AS (
    SELECT * FROM mdm_space_node WHERE id = :rootId
    UNION ALL
    SELECT n.* FROM mdm_space_node n
    JOIN space_tree st ON n.parent_id = st.id
)
SELECT * FROM space_tree;
```

### 4.4 健康评分的数据积累与算法迭代

**难点描述**：健康评分算法当前为 Beta 版，扣分系数基于经验设定，缺乏真实数据校准。维保完成率固定为 1.0，影响评分准确性。

**应对方案**：

| 阶段 | 目标 | 具体措施 |
|------|------|---------|
| Beta → V1 | 修复 Bug + 提取配置 | 修正设备年龄计算、projectId 硬编码；提取扣分系数为 @ConfigurationProperties |
| V1 → V2 | 数据校准 + 完善计算 | 实现维保完成率真实计算；积累 3 个月数据后用线性回归校准系数 |
| V2 → V3 | 引入 IoT + 预测模型 | 增加运行参数扣分维度；基于历史数据训练故障预测模型 |

**配置化改进**：

```yaml
# application.yml
equipment:
  health:
    failure-deduction-per-count: 5
    maintenance-deduction-factor: 20
    age-deduction-per-year: 2
    max-age-deduction: 10
    calculation-period-days: 30
    default-inspection-cycle-days: 30
```

### 4.5 备件库存的并发出入库

**难点描述**：多个工单可能同时使用同一备件，导致库存超卖或数据不一致。

**应对方案**：

| 机制 | 实现方式 | 说明 |
|------|---------|------|
| 乐观锁 | currentStock + @Version | 出库时检查版本号，冲突时重试 |
| 库存校验 | 出库前检查 currentStock >= quantity | 防止库存为负 |
| 事务隔离 | @Transactional(isolation = SERIALIZABLE) | 最高隔离级别，性能影响大 |
| Redis 原子操作 | DECRBY 命令 | 原子性扣减，性能最优 |

**当前实现**：出库时校验库存不能为负，但无乐观锁。

**改进计划**：

1. 为 SparePart 添加 version 字段（@Version）
2. 出库操作使用 Redis DECRBY 原子扣减，成功后异步同步到数据库
3. 引入库存预占机制：工单创建时预占库存，完成时确认扣减，取消时释放

### 4.6 能耗数据的 IoT 接入

**难点描述**：当前能耗数据仅支持手动录入（MANUAL），IoT 自动采集（IOT）枚举已定义但未实现对接。

**当前状态**：

```java
public enum RecordMethod {
    MANUAL,  // 手动录入 — 已实现
    IOT      // IoT自动采集 — 枚举已定义，对接未实现
}
```

**扩展路径**：

| 阶段 | 目标 | 技术方案 |
|------|------|---------|
| Phase 1（当前） | 手动录入 | 前端表单 + 后端 API |
| Phase 2 | IoT 数据接入 | MQTT Broker + Spring Integration 消费消息 |
| Phase 3 | 实时监控 | WebSocket 推送 + 时序数据库（TimescaleDB） |
| Phase 4 | 智能告警 | 规则引擎 + 异常检测算法 |

**Phase 2 架构设计**：

```
IoT 设备 → MQTT Broker → Spring Integration → EnergyConsumptionService.recordConsumption()
                                    ↓
                            recordMethod = IOT
                            自动获取 previousReading
                            自动计算 consumption 和 amount
```

---

## 五、跨模块跨功能实现规范

### 5.1 API 设计规范

**路径前缀**：

```
/api/{module}/{resource}
```

| 模块 | 路径前缀 | 示例 |
|------|---------|------|
| auth | /api/auth | /api/auth/users, /api/auth/roles |
| mdm | /api/mdm | /api/mdm/projects, /api/mdm/space-nodes |
| asset | /api/asset | /api/asset/equipment |
| wo | /api/wo | /api/wo/work-orders |
| ops | /api/ops | /api/ops/maintenance-tasks, /api/ops/energy |

**版本管理**（待实现）：

```
当前: /api/{module}/{resource}
目标: /api/v1/{module}/{resource}
```

**分页规范**：

```java
// 请求参数
GET /api/mdm/projects?page=0&size=20&sortBy=createdAt&sortDirection=DESC

// 响应格式
{
  "code": 0,
  "message": "success",
  "data": {
    "content": [...],
    "totalElements": 100,
    "totalPages": 5,
    "number": 0,
    "size": 20
  }
}
```

**约束**：所有列表接口必须支持分页，禁止全量返回。WorkOrder 当前返回 `List<WorkOrder>` 全量数据需改造。

**错误码规范**：

| 段号 | 模块 | 范围 |
|------|------|------|
| 1xxx | 认证 | 1000-1999 |
| 2xxx | 用户 | 2000-2999 |
| 3xxx | 角色 | 3000-3999 |
| 4xxx | 权限 | 4000-4999 |
| 5xxx | 项目 | 5000-5999 |
| 6xxx | 空间/能耗 | 6000-6999 |
| 7xxx | 文件 | 7000-7999 |
| 8xxx | 工单 | 8000-8999（待分配） |
| 9xxx | 财务 | 9000-9999（待分配） |

**统一响应封装**：

```java
public class ApiResponse<T> {
    private int code;
    private String message;
    private T data;
}
```

### 5.2 数据模型规范

**主键策略**：

```java
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;  // 所有实体使用 UUID 主键
```

**软删除**：

```java
private Boolean isDeleted = false;  // 核心业务实体必须有此字段

// Repository 查询方法
findByIdAndIsDeletedFalse(UUID id);
findByProjectIdAndIsDeletedFalse(UUID projectId);
```

**约束**：WorkOrder 当前使用物理删除，需统一改为逻辑删除。

**审计字段**：

```java
@CreatedDate
@Column(nullable = false, updatable = false)
private LocalDateTime createdAt;

@LastModifiedDate
@Column(nullable = false)
private LocalDateTime updatedAt;

@Column(updatable = false)
private UUID createdBy;

private UUID updatedBy;
```

**约束**：所有实体必须有 createdAt 和 updatedAt 字段，使用 JPA Auditing 自动填充。

**JSONB 使用规范**：

| 场景 | 字段类型 | 说明 |
|------|---------|------|
| 照片列表 | JSONB | `List<String>` 或 `List<EquipmentPhoto>` |
| 文档列表 | JSONB | `List<EquipmentDocument>` |
| 扩展属性 | JSONB | `Map<String, Object>` 或 String 存储 JSON |
| 检查项结果 | JSONB | 结构化 JSON 数组 |

**约束**：SpaceNode.attributes 当前为 String(2000)，需改为 JSONB 类型以支持 GIN 索引和原生 JSON 查询。

**枚举策略**：

```java
// 数据库存储为字符串，JPA 实体使用枚举类型
@Enumerated(EnumType.STRING)
private UserStatus status;

// 枚举定义
public enum UserStatus {
    ACTIVE, LOCKED, DISABLED
}
```

**约束**：禁止使用 EnumType.ORDINAL，统一使用 EnumType.STRING。

### 5.3 异常处理规范

**三层异常体系**：

```
BusinessException (业务异常)
    ├── ErrorCode (错误码枚举)
    └── GlobalExceptionHandler (全局异常处理器)
```

**BusinessException 使用规范**：

```java
// 正确用法
throw new BusinessException(ErrorCode.USER_NOT_FOUND);

// 错误用法（禁止）
throw new RuntimeException("用户不存在");
```

**约束**：WorkOrderServiceImpl 中存在 `throw new RuntimeException("工单不存在")`，需替换为 BusinessException + ErrorCode。

**GlobalExceptionHandler 处理规则**：

| 异常类型 | HTTP 状态码 | 处理方式 |
|---------|-----------|---------|
| BusinessException | 200 (body 含错误码) | 返回 ApiResponse(code, message, null) |
| MethodArgumentNotValidException | 200 | 返回参数校验错误信息 |
| DataAccessException | 200 | 脱敏后返回数据库错误 |
| Exception | 200 | 通用异常兜底 |

**改进方向**：业务错误码 4xx/5xx 应映射为对应 HTTP 状态码，非标准码保持 200 但在 body 中体现。

### 5.4 权限控制规范

**注解式权限**：

```java
@PreAuthorize("hasAuthority('asset:equipment:create')")
public Equipment createEquipment(Equipment equipment) { ... }
```

**数据范围过滤**：

```java
// Service 层手动调用
if (!dataScopeService.canAccessAllData(currentUser)) {
    List<UUID> permittedProjectIds = dataScopeService.getPermittedProjectIds(currentUser);
    // 过滤查询结果
}
```

**改进方向**：通过 JPA Specification 自动拼接数据过滤条件，避免业务层遗漏。

**菜单动态渲染**（待实现）：

```
1. 前端登录后请求 GET /api/auth/users/{id}/menus
2. 后端根据用户角色返回有权限的菜单列表
3. 前端动态生成路由和菜单
```

### 5.5 前后端协作规范

**TypeScript 类型同步**：

```typescript
// 前端类型定义必须与后端枚举一致
// equipment.ts
export enum EquipmentType {
  ELEVATOR = 'ELEVATOR',
  HVAC = 'HVAC',
  FIRE_PROTECTION = 'FIRE_PROTECTION',
  // ... 与后端 EquipmentType 枚举完全一致
}
```

**约束**：当前前端能源类型（ELECTRICITY/WATER/GAS/CENTRAL_HEATING/CENTRAL_COOLING）与后端（LIGHTING/HVAC/POWER/SPECIAL/WATER/GAS）不一致，需统一。

**枚举一致性检查清单**：

| 枚举 | 前端文件 | 后端位置 | 是否一致 |
|------|---------|---------|---------|
| EquipmentType | equipment.ts | Equipment.java | 需校验 |
| EnergyType | energy.ts | EnergyMeter.java | 不一致（需修复） |
| WorkOrderStatus | work-order.ts | WorkOrder.java | 需校验 |
| MaintenanceTaskStatus | maintenance.ts | MaintenanceTask.java | 不一致（需修复） |
| TriggerType | maintenance.ts | MaintenanceTask.java | 不一致（需修复） |

**API 调用封装**：

```typescript
// src/api/xxx.ts
import request from '@/utils/request'

export function getEquipment(id: string) {
  return request.get<ApiResponse<Equipment>>(`/api/asset/equipment/${id}`)
}
```

**约束**：维保计划存在两套前端 API（maintenance.ts + maintenance-plan.ts），需合并为统一 API 文件。

### 5.6 测试规范

**TDD 开发流程**：

```
1. 编写失败测试（Red）
2. 编写最小实现代码（Green）
3. 重构优化（Refactor）
```

**测试分层**：

| 层次 | 框架 | 覆盖范围 | 当前状态 |
|------|------|---------|---------|
| 单元测试 | JUnit 5 + Mockito | Service 层业务逻辑 | 仅 EnergyMeterServiceTest |
| API 测试 | Spring MockMvc | Controller 层接口 | 缺失 |
| 集成测试 | @SpringBootTest | 跨模块交互 | 缺失 |
| E2E 测试 | Playwright/Cypress | 前端用户流程 | 缺失 |

**优先补充的单元测试**：

1. WorkOrderService — 工单状态机流转
2. LoginService — 登录认证流程
3. EquipmentHealthService — 健康评分算法
4. SparePartService — 出入库库存校验

---

## 六、数据库设计概要

### 6.1 ER 图（核心实体关系）

```mermaid
erDiagram
    User ||--o{ Role : "auth_user_role"
    Role ||--o{ Permission : "auth_role_permission"
    User ||--|| EnterpriseUser : "共享主键1:1"
    User ||--|| ProjectStaff : "1:1"
    User ||--|| Resident : "共享主键1:1"
    ProjectStaff ||--o{ ProjectStaffRole : "1:N"
    ProjectStaffRole }o--|| Role : "N:1"
    Resident ||--o{ ResidentSpace : "1:N"
    ResidentSpace }o--|| Space : "N:1"
    User ||--o{ UserProject : "1:N"
    UserProject }o--|| Project : "N:1"
    Dept ||--o{ Dept : "parentId自引用"

    Project ||--|| ProjectConfig : "1:1"
    Project ||--|| ProjectStatistics : "1:1"
    Project ||--o{ ProjectStatusHistory : "1:N"
    Project ||--o{ SpaceNode : "1:N"
    SpaceNode ||--o{ SpaceNode : "parentId自引用"

    Equipment ||--o| EquipmentElevator : "1:1"
    Equipment ||--o| EquipmentHvac : "1:1"
    Equipment ||--o| EquipmentFire : "1:1"
    Equipment ||--o| EquipmentEnergy : "1:1"
    Equipment ||--o{ EquipmentHealthScore : "1:N"
    Equipment ||--o{ EquipmentFailureHistory : "1:N"
    Equipment }o--|| OwnershipEntity : "N:1"
    Equipment }o--o| SpaceNode : "spaceNodeId"

    MaintenancePlan ||--o{ MaintenanceTask : "1:N"
    WorkOrder ||--o{ WorkOrderItem : "1:N"
    WorkOrder }o--o| MaintenancePlan : "planId"
    WorkOrder }o--o| Equipment : "equipmentId"
    MaintenanceTask }o--o| Equipment : "equipmentId"

    SparePartCategory ||--o{ SparePartCategory : "parentId自引用"
    SparePartCategory ||--o{ SparePart : "1:N"
    SparePart ||--o{ SparePartRecord : "1:N"

    EnergyMeter ||--o{ EnergyConsumption : "1:N"
    EnergyMeter }o--o| SpaceNode : "spaceNodeId"
```

### 6.2 表命名规范

**格式**：`{模块前缀}_{实体名}`

| 模块前缀 | 示例 | 说明 |
|---------|------|------|
| auth_ | auth_user, auth_role, auth_permission | 认证授权模块 |
| mdm_ | mdm_project, mdm_space_node | 主数据模块 |
| asset_ | asset_equipment, asset_equipment_elevator | 设备资产模块 |
| ops_ | ops_work_order, ops_maintenance_plan | 运维工单模块 |
| fin_ | fin_fee_item, fin_fee_bill | 财务模块（待实现） |
| sys_ | sys_audit_log, sys_config | 系统级表 |

**列命名规范**：

- 使用 snake_case：`project_id`、`created_at`、`is_deleted`
- 外键列：`{关联实体}_id`：`equipment_id`、`space_node_id`
- 布尔列：`is_` 前缀：`is_deleted`、`is_equipment`
- 时间列：`_at` 后缀：`created_at`、`updated_at`
- 日期列：`_date` 后缀：`installation_date`、`next_inspection_date`

### 6.3 索引策略

**B-tree 索引**（等值查询、范围查询、排序）：

| 表 | 索引列 | 用途 |
|----|--------|------|
| ops_work_order | (project_id, status) | 按项目+状态查询工单 |
| ops_work_order | (status, created_at) | 按状态+时间查询 |
| ops_work_order | (created_at DESC) | 时间倒序 |
| asset_equipment | (project_id, status) | 按项目+状态查询设备 |
| asset_equipment | (project_id, equipment_type) | 按项目+类型查询设备 |
| asset_equipment | (equipment_code) UNIQUE | 编码唯一 |
| mdm_space_node | (project_id, parent_id) | 项目+父节点 |
| mdm_space_node | (project_id, node_type) | 项目+类型 |
| mdm_space_node | (tree_path) | 路径前缀查询 |
| ops_equipment_failure_history | (equipment_id, failure_time DESC) | 设备故障时间线 |
| sys_audit_log | (user_id, created_at DESC) | 用户操作时间线 |

**GIN 索引**（JSONB 查询，待添加）：

```sql
CREATE INDEX idx_equipment_attributes ON asset_equipment USING GIN (attributes);
CREATE INDEX idx_equipment_photos ON asset_equipment USING GIN (photos);
CREATE INDEX idx_space_node_attributes ON mdm_space_node USING GIN (attributes);
```

**JSONB 索引使用场景**：

| 表 | 字段 | 查询场景 |
|----|------|---------|
| asset_equipment | attributes | 按扩展属性筛选设备 |
| asset_equipment | photos | 按照片类型查询 |
| ops_maintenance_task | parts_used | 按备件 ID 查询使用该备件的工单 |
| mdm_inspection_record | items | 按检查项结果查询 |

### 6.4 数据迁移策略

**工具选型**：Flyway

**迁移脚本命名规范**：

```
V{版本号}__{描述}.sql
示例:
V1__init_auth_tables.sql
V2__init_mdm_tables.sql
V3__init_asset_tables.sql
V4__init_ops_tables.sql
V5__add_equipment_health_score.sql
V6__add_space_node_indexes.sql
```

**当前状态**：未使用 Flyway，依赖 JPA 自动建表（ddl-auto: update）。

**改进计划**：

1. 短期：在开发环境继续使用 JPA 自动建表
2. 中期：引入 Flyway，将现有 schema 导出为初始迁移脚本
3. 长期：生产环境禁止 ddl-auto: update，所有变更通过 Flyway 迁移脚本执行

---

## 七、技术选型与依赖

### 7.1 后端技术栈

| 技术 | 版本 | 用途 | 说明 |
|------|------|------|------|
| Spring Boot | 3.x | 应用框架 | Java 17+，Servlet 容器 |
| Spring Security | 6.x | 安全框架 | JWT 认证 + RBAC 授权 |
| Spring Data JPA | 3.x | ORM 框架 | Hibernate 实现，自动建表 |
| Hibernate | 6.x | JPA 实现 | 实体映射、懒加载、审计 |
| MapStruct | — | 对象映射 | Entity ↔ DTO 转换 |
| Lombok | — | 代码简化 | @Data、@Builder、@RequiredArgsConstructor |
| BCrypt | — | 密码加密 | Spring Security PasswordEncoder |
| JJWT | — | JWT 工具 | Token 生成与验证 |
| Spring AOP | — | 切面编程 | 审计日志 @OperationLog |
| Spring Validation | — | 参数校验 | @NotNull、@Size、@Pattern |
| Spring Web | — | REST API | @RestController、@RequestMapping |

### 7.2 前端技术栈

| 技术 | 版本 | 用途 | 说明 |
|------|------|------|------|
| Vue | 3.x | 前端框架 | Composition API + `<script setup>` |
| TypeScript | 5.x | 类型系统 | 类型安全 |
| Ant Design Vue | 4.x | UI 组件库 | 统一视觉风格 |
| Pinia | 2.x | 状态管理 | Composition API 风格，支持持久化 |
| Vite | 5.x | 构建工具 | 快速 HMR |
| Axios | 1.x | HTTP 客户端 | 请求/响应拦截器封装 |
| Vue Router | 4.x | 路由管理 | 路由守卫 + 权限控制 |
| ECharts | 5.x | 图表库 | 健康评分趋势图 |

### 7.3 数据库

| 技术 | 版本 | 用途 | 说明 |
|------|------|------|------|
| PostgreSQL | 15+ | 主数据库 | JSONB、UUID、ltree 扩展 |
| JSONB | — | 半结构化数据 | 照片列表、文档列表、扩展属性、检查项结果 |
| UUID | — | 主键类型 | 所有实体主键使用 UUID |
| Redis | 7+ | 缓存 | 登录失败锁定、Token 缓存 |

**PostgreSQL 特性使用**：

| 特性 | 使用场景 | 当前状态 |
|------|---------|---------|
| JSONB | Equipment.photos/documents/attributes、InspectionRecord.items/problems | 部分使用（SpaceNode.attributes 降级为 String） |
| UUID | 所有实体主键 | 已使用 |
| ltree | 空间树形结构 | 未使用（使用 treePath 字符串替代） |
| GIN 索引 | JSONB 字段查询 | 未使用（待添加） |
| PostGIS | 地图空间查询 | 未使用 |

### 7.4 开发工具

| 工具 | 用途 | 说明 |
|------|------|------|
| Maven | 后端构建 | 多模块项目管理 |
| npm | 前端构建 | 依赖管理 |
| Git | 版本控制 | 分支管理 |
| Flyway | 数据库迁移 | 待引入 |
| SpringDoc/OpenAPI | API 文档 | 待引入 |

---

## 附录 A：实现状态总览

| 功能模块 | 实现状态 | 核心实体 | 说明 |
|---------|---------|---------|------|
| 用户管理 | 已实现 | User/EnterpriseUser/ProjectStaff/Resident | 4 种用户类型扩展 |
| 角色权限 | 已实现 | Role/Permission/ProjectStaffRole | 三级角色 + 四级数据范围 |
| 部门管理 | 已实现 | Dept | 树形结构，5 种部门类型 |
| 项目管理 | 已实现 | Project/ProjectConfig/ProjectStatistics | 状态流转 + 配置 + 统计 |
| 空间节点 | 已实现 | SpaceNode | 统一空间模型 + 设备扩展字段 |
| 设备台账 | 已实现 | Equipment + 4 张扩展表 | 主表 + 扩展表模式 |
| 健康评分 | 已实现(Beta) | EquipmentHealthScore | MTBF/MTTR + 三维扣分 |
| 故障历史 | 已实现 | EquipmentFailureHistory | 4 级故障 + 4 种修复结果 |
| 归属管理 | 已实现 | OwnershipEntity | 4 种归属 + 3 种主体 |
| 工单管理 | 已实现 | WorkOrder/WorkOrderItem | 6 状态状态机 |
| 维保计划 | 已实现 | MaintenancePlan | 周期性维保调度 |
| 维保任务 | 已实现 | MaintenanceTask | 6 状态 + 自动优先级判定 |
| 巡检标准 | 已实现 | InspectionItem/InspectionTemplate | 标准项库 + 模板管理 |
| 巡检记录 | 已实现 | InspectionRecord | 签到 + JSONB 结果 |
| 备件库存 | 已实现 | SparePart/SparePartCategory/SparePartRecord | 出入库 + 低库存预警 |
| 能耗计量 | 已实现 | EnergyMeter/EnergyConsumption | 手动录入 + 简单费用计算 |
| 审计日志 | 已实现 | AuditLog | AOP + 异步 + 30 天窗口 |
| 系统配置 | 已实现 | SysConfig | 键值对配置 |
| 消息通知 | **未实现** | — | NotificationChannel/Template/Rule/History |
| 收费项目 | **未实现** | — | FeeItem |
| 账单管理 | **未实现** | — | FeeBill |
| 支付记录 | **未实现** | — | FeePayment |
| 设备二维码 | **未实现** | — | 原需求有但未实现 |
| IoT 集成 | **未实现** | — | 枚举已定义，对接未实现 |
| 地图服务 | **未实现** | — | PostGIS + 高德地图 |
| SLA 管理 | **未实现** | — | 响应时间/处理时间/超时升级 |

## 附录 B：关键风险与优先行动

| 优先级 | 风险 | 行动项 | 预估工作量 |
|--------|------|--------|-----------|
| P0 | 财务域核心功能完全缺失 | 创建 module-finance，实现 FeeItem/FeeBill/FeePayment | 5 天 |
| P0 | 消息通知系统完全缺失 | 实现 NotificationChannel/Template/Rule/History | 8 天 |
| P0 | 工单全量查询 OOM 风险 | 改为分页查询 | 1 天 |
| P0 | 健康评分算法 Bug | 修正设备年龄计算和 projectId 硬编码 | 1 天 |
| P1 | 工单状态机缺少挂起/退回 | 增加 SUSPENDED/RETURNED 状态 | 3 天 |
| P1 | 工单流转记录缺失 | 实现 WorkOrderFlow | 2 天 |
| P1 | 前后端枚举不一致 | 统一能源类型/维保状态/触发类型 | 1 天 |
| P1 | 权限相关端点缺失 | 实现权限树/权限校验/用户菜单 | 3 天 |
| P2 | API 无版本管理 | 引入 /api/v1/ 前缀 | 3 天 |
| P2 | SpaceNode.attributes 非 JSONB | 改为 JSONB + GIN 索引 | 2 天 |
| P2 | 审计日志可篡改 | 改为只追加 + 归档而非删除 | 2 天 |
| P2 | 设备模型双体系并存 | 统一 MDM SpaceNode 内嵌设备与 ASSET Equipment | 3 天 |

---

> **文档说明**：本概要设计文档基于 REVERSE-AUTH/MDM/ASSET/OPS/FINANCE 五份反推设计文档、BEST-PRACTICES-REPORT 行业最佳实践评估报告、CONSISTENCY-REPORT 需求一致性评估报告综合编制，反映 2026-05-18 代码库状态。财务域（D5）核心功能标注为"待实现"，需优先启动开发。
