4 Commits

Author SHA1 Message Date
2995840376
4d8d38909d fix(I): HTTP 语义类异常返回真实 4xx 状态码, 不再兜底成 500
问题:GlobalExceptionHandler 只对业务异常/参数校验做了分类,其余异常一律被兜底的
      Exception handler 处理成 500「系统繁忙」。例如以 application/octet-stream 发送
      JSON 请求体本应返回 415 Unsupported Media Type,却得到 500,误导调用方与排障。

改动(iot-common,四个服务共用):
- ResultCode 新增:UNSUPPORTED_MEDIA_TYPE(415) / NOT_ACCEPTABLE(406) / PAYLOAD_TOO_LARGE(413)
- GlobalExceptionHandler 新增 HTTP 语义类异常处理:
    HttpMediaTypeNotSupportedException   -> 415
    HttpMediaTypeNotAcceptableException  -> 406
    HttpRequestMethodNotSupportedException-> 405
    MissingServletRequestParameterException / MethodArgumentTypeMismatchException
                                    / HttpMessageNotReadableException -> 400
    MaxUploadSizeExceededException       -> 413
- 响应约定:真实 HTTP 状态码 + body.code 与状态码保持一致(沿用 JwtAuthenticationEntryPoint 的
  401 约定);业务/参数异常维持 HTTP 200 + body.code 的历史约定,前端无需改动
- 这类异常属客户端错误,日志级别由 error 降为 warn,避免污染错误日志
- 新增单测 iot-common/src/test/java/com/iot/common/exception/GlobalExceptionHandlerHttpStatusTest.java
  (2 个用例全部通过)

生产验证:
  错误 Content-Type  -> HTTP 415  body.code=415
  错误请求方法       -> HTTP 405
  参数类型不匹配     -> HTTP 400
  请求体 JSON 非法   -> HTTP 400
  正常列表/物模型    -> HTTP 200
前端 axios 拦截器对非 401/403/500 的 4xx 走 data?.message 分支,提示更准确,无回归。
2026-10-27 19:31:56 +08:00
2995840376
b2d758be33 fix(F): 日志轮转治理 - 统一 logback 配置 + journald 限额
问题根因:
- iot-device.out 涨到 613MB:systemd StandardOutput=append: 无任何轮转
- DEBUG 刷屏(单日 11521 条):logging.level.com.iot=DEBUG 使 MyBatis 每条 SQL 打印两遍
- 涂鸦 open-mq-sdk jar 自带 logback.xml 抢占日志配置(iot-data/rule/alarm 未声明 logging.config),
  把日志写到 ./logs 相对目录且无总量上限

改动:
- 新增 backend/iot-common/src/main/resources/logback-spring.xml(4 服务共用唯一真相源):
  RollingFileAppender 按日 + 50MB 双触发切分,保留 7 天,主日志总量上限 2GB,
  错误日志单独一份(保留 30 天 / 512MB),并对涂鸦/MQTT/AMQP 等第三方 SDK 降噪
- 父 pom 增加 maven-resources-plugin,把该配置复制进各服务 BOOT-INF/classes
- 4 个服务 application.yml 统一声明 logging.config,并把 com.iot 级别收敛为 INFO
- 新增 backend/deploy/systemd/:4 个 unit 改为 StandardOutput=journal + 注入 LOG_DIR,
  附 journald 限额(SystemMaxUse=1G / SystemMaxFileSize=50M / MaxRetentionSec=7day)
- deploy-all.bat 增加日志治理步骤(同步 unit + journald + 清理历史 .out)

生产验证:日志落到 /opt/iotsaas/logs/app/*.log,DEBUG 计数 0,历史 .out 已清理,
journal 776M 降到 552M,4 服务 active,9081/9083 文档返回 200
2026-10-27 18:28:19 +08:00
2995840376
a932633c50 refactor(A): 产品/物模型/设备三层架构重构 - 地基批次
新增:
- iot-common/PlatformType: 平台维度单一真相源(枚举)
  统一 tuya/matter/local/xiaomi/huawei/dueros/alexa/google_home,
  提供 legacy 别名归一(miot|mi -> xiaomi)与已知性判定
- backend/sql/V22__product_device_arch_refactor.sql: 幂等迁移(153行)
  A. platform_type 平台字典表 + 种子数据(后台可维护)
  B. product 加 protocol 列; platform_product_id 空串清洗为 NULL;
     清洗 model/manufacturer 被涂鸦 productId 污染的历史脏数据;
     加 (platform, platform_product_id, deleted) 唯一约束
  C. product_property 加 grp/is_primary/enum_label + (product_id,code) 唯一约束
  D. product_event/product_action 加 (product_id,code) 唯一约束;
     product_action 加 completion_mode
  E. device 加 product_id 索引(OTA 物化目标设备此前全表扫); platform 归一

改造:
- DeviceAdapter 新增 platform() 显式声明平台
- DeviceAdapterManager 改为按 platform() 精确匹配,
  移除'类名是否包含平台字符串'的脆弱约定(类名与平台码不同名会静默降级)
- DevicePlatform 委托 PlatformType, 消除第四套平台取值域

验证: mvn -pl iot-common,iot-device -am compile 通过
2026-10-27 12:08:44 +08:00
2995840376
0ce191c448 chore: 初始化 iotsaas 版本库基线
纳入范围:
- backend/  Spring Boot 多模块后端(iot-common/device/rule/data/alarm/auth)
- frontend/admin/  Vue3 + Element Plus 管理后台
- Android/   涂鸦原生 APP (com.xhai.iot)
- backend/sql/  Flyway 风格迁移脚本(V2~V21)
- docs/       对接文档与设计文档

排除范围:
- 构建产物: node_modules/ target/ build/ dist/ .gradle/
- 签名密钥: *.jks *.keystore (严禁入库)
- 本机配置: Android/local.properties
- 运行日志: logs/ *.log
- AI 协作本地数据 .codebuddy/ 与第三方 demo tuya-demo/

.gitattributes 统一以 LF 存储, Windows 批处理保留 CRLF
2026-10-27 12:00:41 +08:00