# Ether PMS 行业最佳实践评估报告 > **评估日期**: 2026-04-23 > **评估范围**: Ether 物业管理系统全栈(ether-pms + ether-admin) > **对标体系**: 物业管理行业标杆(万物云、绿城服务)、RESTful API 最佳实践、OWASP Top 10、Vue3 生态最佳实践、Clean Code 原则 > **数据来源**: 5份反推设计文档 + 实际代码审查 --- ## 评估总览 | 评估维度 | 评分 | 等级 | |---------|------|------| | 数据模型设计 | 3.0/5 | ⭐⭐⭐ | | API设计 | 2.5/5 | ⭐⭐½ | | 安全设计 | 3.5/5 | ⭐⭐⭐½ | | 业务流程 | 2.5/5 | ⭐⭐½ | | 前端架构 | 3.0/5 | ⭐⭐⭐ | | 代码质量 | 2.5/5 | ⭐⭐½ | | **综合评分** | **2.8/5** | **⭐⭐⭐** | --- ## 一、数据模型设计评估 **评分: 3.0/5** ### 1.1 优点 1. **主表+扩展表模式设计合理**:设备模块采用 Equipment 主表 + 4张专业扩展表(Elevator/Hvac/Fire/Energy)的设计,既保证了公共字段的统一管理,又支持了专业参数的灵活扩展,符合物业管理行业设备分类管理的实际需求 2. **多租户项目隔离机制完善**:通过 UserProject 关联 + ProjectStaff 扩展 + X-Project-ID Header + DataScopeService 四层隔离,实现了项目级数据隔离,满足物业公司多项目运营的核心需求 3. **四级数据范围设计**:ALL / PROJECT / DEPARTMENT / SELF 四级数据范围,覆盖了物业管理行业从集团到个人的权限层级 4. **逻辑删除策略统一**:Equipment、OwnershipEntity、SpaceNode 等核心实体均采用 isDeleted 软删除,避免数据误删导致业务中断 5. **JSONB 扩展字段**:Equipment.attributes、Equipment.photos、Equipment.documents 使用 JSONB 存储,为非结构化数据提供了灵活扩展能力 6. **树形结构支持**:SpaceNode 采用 treePath 字符串路径模式,支持层级空间管理(项目→楼栋→单元→楼层→房间) ### 1.2 不足 1. **未使用 PostgreSQL JSONB 原生类型**:SpaceNode.attributes 定义为 String(2000) 而非 JSONB 类型,无法利用 PostgreSQL 的 GIN 索引和 JSON 查询能力,查询性能和灵活性受限 2. **缺少数据库索引设计文档**:除 AuditLog 外,其他实体未见明确的索引策略定义。WorkOrder、Equipment 等高频查询表缺少复合索引规划 3. **树形结构方案选型欠佳**:SpaceNode 使用 treePath 字符串(如 `/1/2/3/`),查询子孙节点需 LIKE 匹配,大数据量下性能堪忧。未考虑 PostgreSQL ltree 扩展或闭包表方案 4. **数据冗余未受控**:Equipment 表同时存储 owningEntityId 和 owningEntityName,属于非规范化的冗余设计,缺乏同步更新机制 5. **审计字段不一致**:部分实体(User、Dept)手动管理 createdAt/updatedAt,部分(SysConfig、AuditLog)使用 @CreationTimestamp/@UpdateTimestamp,策略不统一 6. **缺少唯一约束**:SpaceNode 原设计有 UNIQUE(project_id, code),实际实现中无 code 列也无唯一约束,数据完整性依赖应用层 7. **财务域实体完全缺失**:FeeItem、FeeBill、FeePayment、FeeRefund 四大核心财务实体未实现,无法支撑收费管理业务 ### 1.3 改进建议 | 优先级 | 建议 | 说明 | |--------|------|------| | P0 | 将 SpaceNode.attributes 改为 JSONB 类型 | 利用 PostgreSQL 原生 JSON 查询能力,添加 GIN 索引 | | P0 | 为高频查询表添加复合索引 | WorkOrder(project_id, status)、Equipment(project_id, equipment_type)、SpaceNode(project_id, node_type) | | P0 | 实现财务域四大核心实体 | FeeItem / FeeBill / FeePayment / FeeRefund,对标万物云收费管理模型 | | P1 | 评估 SpaceNode 树形结构升级方案 | 考虑 ltree 扩展或闭包表,支持高效祖先/子孙查询 | | P1 | 统一审计字段策略 | 全部采用 JPA Auditing(@CreatedDate/@LastModifiedDate + AuditorAware) | | P1 | 消除 Equipment 冗余字段 | 移除 owningEntityName,通过 JOIN 查询获取 | | P2 | 添加数据库唯一约束 | SpaceNode(project_id, code)、Equipment(project_id, equipment_code) | | P2 | 引入数据库迁移工具 | 使用 Flyway/Liquibase 管理数据库版本演进 | --- ## 二、API设计评估 **评分: 2.5/5** ### 2.1 优点 1. **RESTful 风格基本遵循**:CRUD 操作使用 POST/GET/PUT/DELETE 对应创建/读取/更新/删除,资源路径命名合理(如 `/api/wo/work-orders`) 2. **统一错误响应格式**:通过 ErrorCode 枚举 + BusinessException + GlobalExceptionHandler 实现了统一的错误响应结构(code + message + data) 3. **错误码体系设计合理**:按模块分段(1xxx 认证、2xxx 用户、3xxx 角色、4xxx 权限、5xxx 项目、6xxx 空间、7xxx 文件),便于定位问题 4. **工单状态操作使用子资源**:`POST /{id}/assign`、`POST /{id}/start`、`POST /{id}/complete` 等状态变更操作采用子资源路径,语义清晰 5. **设备扩展表 API 设计优雅**:`GET /{id}/elevator`、`PUT /{id}/hvac` 通过主设备 ID 路径访问扩展表,RESTful 风格良好 ### 2.2 不足 1. **无 API 版本管理**:原设计使用 `/api/v1/auth`,实际实现为 `/api/auth`,缺少版本号。API 变更时无法向后兼容,将影响所有客户端 2. **分页不统一**:WorkOrder 返回 `List` 全量数据(代码注释标注"高风险,可能导致 OOM"),而 User 使用 Page 分页。分页参数和响应格式不统一 3. **HTTP 状态码使用不当**:GlobalExceptionHandler 中,非标准 HTTP 状态码的业务错误码(如 1001、2001)默认返回 HTTP 200,客户端无法通过 HTTP 状态码判断请求是否成功 4. **缺少 HATEOAS 支持**:API 响应无链接信息,客户端需硬编码 URL 路径 5. **部分 API 绕过 Service 层**:OwnershipEntityController 直接注入 Repository,违反分层架构原则 6. **前后端 API 不一致**:维保计划存在两套前端 API(maintenance.ts + maintenance-plan.ts),触发类型枚举前后端不匹配 7. **缺少 API 文档**:未集成 Swagger/SpringDoc,API 文档依赖人工维护的反推设计文档 ### 2.3 改进建议 | 优先级 | 建议 | 说明 | |--------|------|------| | P0 | 统一分页查询 | 所有列表接口使用 Pageable 参数 + PageResponse 响应,WorkOrder 优先改造 | | P0 | 修复 HTTP 状态码映射 | 业务错误码 4xx/5xx 应映射为对应 HTTP 状态码,非标准码保持 200 但在 body 中体现 | | P1 | 引入 API 版本管理 | URL 路径版本 `/api/v2/` 或 Header 版本 `Accept: application/vnd.ether.v2+json` | | P1 | 集成 SpringDoc/OpenAPI | 自动生成 API 文档,确保文档与代码同步 | | P1 | 修复 OwnershipEntityController 分层违规 | 补充 Service 层 | | P2 | 统一前后端枚举定义 | 维保触发类型、设备类型等枚举前后端对齐 | | P2 | 添加 HATEOAS 链接 | 至少在分页响应中添加 next/prev 链接 | --- ## 三、安全设计评估 **评分: 3.5/5** ### 3.1 优点 1. **BCrypt 密码加密**:使用 Spring Security PasswordEncoder(BCrypt),自动处理盐值,安全性高 2. **旧密码格式检测与强制重置**:PasswordService 检测非 BCrypt 格式密码(MD5/SHA-1),返回 false 强制用户重置,支持密码算法平滑迁移 3. **密码强度校验完善**:支持可配置的长度、大小写、数字、特殊字符要求,弱密码黑名单检测 4. **登录失败锁定机制**:基于 Redis 实现,5次失败锁定10分钟,防止暴力破解 5. **JWT 认证流程完整**:Token 生成→验证→刷新流程闭环,Claims 包含 userId/username/roles 6. **审计日志异步持久化**:通过 `@OperationLog` 注解 + AOP 切面 + 线程池异步保存,不影响业务性能 7. **密码字段 @JsonIgnore**:User.password 和 User.salt 使用 @JsonIgnore,防止序列化泄露 8. **SQL 注入防护**:使用 JPA + 参数化查询,天然防止 SQL 注入 9. **数据库异常信息脱敏**:GlobalExceptionHandler 捕获 DataAccessException 时不暴露 SQL 语句和数据库细节 ### 3.2 不足 1. **JWT 无刷新 Token 机制**:仅有单一 Access Token,无 Refresh Token 体系。Token 过期后需重新登录,用户体验差且安全性不足(长有效期 Token 被窃取风险高) 2. **JWT Secret 硬编码风险**:JwtTokenProvider 的密钥配置需确认是否外置到环境变量,若硬编码在源码中则存在泄露风险 3. **审计日志可篡改**:sys_audit_log 表无防篡改机制(如签名校验、只追加约束),管理员可直接修改或删除日志 4. **90天归档策略为直接删除**:审计日志归档实际实现为删除,不符合合规要求(物业管理行业审计日志需保留3-5年) 5. **CORS 配置未明确**:未见明确的 CORS 策略配置,可能存在跨域安全风险 6. **CSRF 防护缺失**:使用 JWT + Bearer Token 方式,虽 CSRF 风险较低,但未做额外防护 7. **敏感数据未脱敏**:用户手机号、身份证号等敏感字段无脱敏处理,API 响应中明文返回 8. **DataScopeService 仅提供判断方法**:未实现 SQL 自动注入,数据过滤依赖业务层手动调用,存在遗漏风险 9. **登录响应返回角色列表**:LoginService 在响应中返回 roles 列表,信息量偏多,可能被利用进行权限探测 ### 3.3 改进建议 | 优先级 | 建议 | 说明 | |--------|------|------| | P0 | 实现 Refresh Token 机制 | Access Token 短有效期(15-30分钟)+ Refresh Token 长有效期(7天),Redis 存储 Refresh Token | | P0 | 审计日志改为只追加 | 数据库层面添加触发器或应用层约束,禁止 UPDATE/DELETE 审计日志 | | P0 | 审计日志归档而非删除 | 90天后导出至对象存储(OSS/S3),保留3-5年 | | P1 | 敏感数据脱敏 | 手机号中间4位掩码、身份证号掩码,使用 Jackson 自定义序列化器 | | P1 | JWT Secret 外置 | 密钥存储在环境变量或 Vault 中,禁止硬编码 | | P1 | DataScopeService 实现 SQL 自动注入 | 通过 MyBatis Interceptor 或 JPA Specification 自动拼接数据过滤条件 | | P2 | 配置 CORS 策略 | 明确允许的 Origin、Methods、Headers | | P2 | 登录响应精简 | 移除 roles 列表,改为独立接口查询 | --- ## 四、业务流程评估 **评分: 2.5/5** ### 4.1 优点 1. **工单状态机设计清晰**:PENDING → ASSIGNED → IN_PROGRESS → COMPLETED → VERIFIED 六状态流转,覆盖物业管理核心工单流程 2. **维保任务自动优先级判定**:基于触发类型 + 紧急关键词(困人/漏水/停电/火灾等)自动判定 URGENT/HIGH/MEDIUM 优先级,符合物业管理应急响应需求 3. **维保任务完成后联动更新设备**:完成维保后自动更新设备维保商和下次巡检日期,实现业务闭环 4. **设备健康评分算法完整**:基于故障扣分 + 维保扣分 + 年龄扣分的综合评分,含 MTBF/MTTR 计算,对标行业设备管理标准 5. **设备导入校验完善**:文件类型、大小、行数、编码四重校验,防止批量导入异常数据 6. **巡检模板管理**:支持模板复制、必检项标记、排序控制,满足标准化巡检需求 ### 4.2 不足 1. **工单状态机缺少关键状态**:无 SUSPENDED(挂起)、RETURNED(退回)状态,无法处理工单暂停和退回重分配场景,这是物业管理行业常见需求 2. **无工单流转记录**:WorkOrderFlow 实体未实现,无法追溯工单状态变更历史,影响问题排查和绩效统计 3. **SLA 管理完全缺失**:无响应时间、处理时间、超时升级机制。万物云等标杆企业均有 SLA 体系(如紧急工单30分钟响应、一般工单2小时响应) 4. **消息通知系统未实现**:NotificationChannel/Template/Rule/History 四大实体均未实现,工单派单、超时、完成等关键节点无通知,严重影响运营效率 5. **财务收费流程完全缺失**:FeeItem/FeeBill/FeePayment 未实现,无账单生成、支付流程、欠费催缴能力,这是物业管理最核心的业务流程 6. **设备二维码未实现**:原需求要求设备二维码标识,实际未实现,影响设备巡检扫码和业主报修体验 7. **IoT 集成未实现**:设备监控、自动告警、数据采集等 IoT 能力缺失,无法实现预测性维保 8. **维保到期定时提醒未实现**:仅前端展示下次维保日期,无后端定时任务推送提醒 9. **健康评分算法存在 Bug**:calculateEquipmentAge() 错误使用 SpaceNode.maintenanceContractStart 而非 Equipment.installationDate;projectId 硬编码为全零 UUID 10. **前后端状态不一致**:前端维保任务含 ACCEPTED 状态,后端无此状态;前端触发类型(MANUAL/SCHEDULED/AUTOMATIC)与后端(PLAN/INSPECTION/FAULT/MANUAL)不匹配 ### 4.3 改进建议 | 优先级 | 建议 | 说明 | |--------|------|------| | P0 | 实现财务收费核心流程 | FeeItem → FeeBill → FeePayment,支持按面积/用量/固定金额计费 | | P0 | 实现消息通知系统 | 工单派单/超时/完成通知,支持站内信、短信、推送 | | P0 | 修复健康评分算法 Bug | 修正设备年龄计算和 projectId 硬编码问题 | | P1 | 添加工单挂起/退回状态 | SUSPENDED + RETURNED,支持工单暂停和退回重分配 | | P1 | 实现工单流转记录 | WorkOrderFlow 实体,记录每次状态变更的操作人、时间、备注 | | P1 | 实现 SLA 管理 | 定义各类型工单的响应时间和处理时间,超时自动升级 | | P1 | 统一前后端状态和枚举 | 维保任务状态、触发类型等前后端对齐 | | P2 | 实现设备二维码 | 生成二维码关联设备,支持扫码巡检和报修 | | P2 | 实现维保到期定时提醒 | Spring Scheduled 任务 + 消息通知 | | P2 | IoT 集成规划 | 设计 IoT 数据接入层,支持设备监控和自动告警 | --- ## 五、前端架构评估 **评分: 3.0/5** ### 5.1 优点 1. **Vue3 Composition API + TypeScript**:使用 `