# 数据模型 **本文档引用的文件** - [internal/model/brand.go](file://internal/model/brand.go) - [internal/model/model.go](file://internal/model/model.go) - [internal/model/ota.go](file://internal/model/ota.go) - [internal/model/share_code.go](file://internal/model/share_code.go) - [internal/model/target.go](file://internal/model/target.go) - [internal/model/user_device.go](file://internal/model/user_device.go) - [internal/model/user_active.go](file://internal/model/user_active.go) - [internal/repository/brand.go](file://internal/repository/brand.go) - [internal/repository/model.go](file://internal/repository/model.go) - [internal/repository/ota.go](file://internal/repository/ota.go) - [internal/repository/share_code.go](file://internal/repository/share_code.go) - [internal/repository/curve.go](file://internal/repository/curve.go) - [internal/repository/device.go](file://internal/repository/device.go) - [internal/handler/brand.go](file://internal/handler/brand.go) - [internal/handler/model.go](file://internal/handler/model.go) - [internal/handler/model_list.go](file://internal/handler/model_list.go) - [internal/handler/ota.go](file://internal/handler/ota.go) - [internal/handler/share_code.go](file://internal/handler/share_code.go) - [internal/handler/device.go](file://internal/handler/device.go) - [internal/handler/curve.go](file://internal/handler/curve.go) - [internal/router/router.go](file://internal/router/router.go) - [internal/config/database.go](file://internal/config/database.go) - [internal/config/share_code_ttl.go](file://internal/config/share_code_ttl.go) - [internal/response/response.go](file://internal/response/response.go) - [internal/task/device_persist.go](file://internal/task/device_persist.go) - [internal/task/share_code_persist.go](file://internal/task/share_code_persist.go) - [pkg/encode/base64.go](file://pkg/encode/base64.go) - [sql/model.sql](file://sql/model.sql) - [sql/ota.sql](file://sql/ota.sql) - [sql/ota_target_device.sql](file://sql/ota_target_device.sql) - [sql/black_list.sql](file://sql/black_list.sql) - [sql/share_code_log.sql](file://sql/share_code_log.sql) - [sql/user_device.sql](file://sql/user_device.sql) - [sql/user_active.sql](file://sql/user_active.sql) - [cmd/server/main.go](file://cmd/server/main.go) ## 更新摘要 **变更内容** - OTA模型字段简化:移除了pawVerCode、pawVerName、pawUrl、pawMd5四个冗余字段,OTA结构现在更加简洁 - OTA灰度升级设备模型重构:从包含Type字段的定向设备改为不包含类型字段的灰度升级设备,简化了设备管理逻辑 - 数据库表结构同步更新:ota_target_device表移除了type字段,OTATargetDevice结构体不再包含Type字段 - 业务逻辑调整:OTA升级策略从"定向设备"概念转变为"灰度升级设备"概念,简化了升级控制逻辑 ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖分析](#依赖分析) 7. [性能考虑](#性能考虑) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本文件面向 Luxsin 应用 API 的数据模型,系统性梳理 Brand、Model、OTA、ShareCode、Target、UserDevice 和 UserActive 七类数据模型的设计理念、字段定义、约束条件、业务含义以及与数据库表结构的映射关系。文档还覆盖 ORM 映射配置(基于原生 sql.DB 的扫描映射)、模型验证与序列化机制、模型在各层之间的传递方式与性能考量,并给出扩展、版本管理与向后兼容的最佳实践建议。内容兼顾初学者与高级开发者,既提供高层概览,也包含代码级的可视化图示与来源标注。 ## 项目结构 该项目采用分层架构:路由层负责请求入口与中间件;处理器层处理业务逻辑与参数解析;仓库层封装数据库访问;模型层承载数据结构;响应层统一返回格式;编码层提供可选的响应体压缩编码;配置层加载数据库、Redis等外部服务配置。新增的分享码功能、目标曲线模型和增强的OTA模型进一步完善了系统的数据模型体系。 ```mermaid graph TB subgraph "应用入口" MAIN["cmd/server/main.go"] end subgraph "路由层" ROUTER["internal/router/router.go"] end subgraph "处理器层" BRAND_H["internal/handler/brand.go"] MODEL_H["internal/handler/model.go"] MODEL_LIST_H["internal/handler/model_list.go"] OTA_H["internal/handler/ota.go"] DEVICE_H["internal/handler/device.go"] SHARE_CODE_H["internal/handler/share_code.go"] CURVE_H["internal/handler/curve.go"] end subgraph "仓库层" BRAND_R["internal/repository/brand.go"] MODEL_R["internal/repository/model.go"] OTA_R["internal/repository/ota.go"] DEVICE_R["internal/repository/device.go"] SHARE_CODE_R["internal/repository/share_code.go"] CURVE_R["internal/repository/curve.go"] end subgraph "模型层" MODEL_M["internal/model/brand.go"] MODEL_M2["internal/model/model.go"] MODEL_M3["internal/model/ota.go"] MODEL_M4["internal/model/user_device.go"] MODEL_M5["internal/model/user_active.go"] MODEL_M6["internal/model/share_code.go"] MODEL_M7["internal/model/target.go"] end subgraph "缓存层" CACHE["internal/cache/*"] end subgraph "响应与编码" RESP["internal/response/response.go"] ENCODE["pkg/encode/base64.go"] end subgraph "配置与数据库" DB_CFG["internal/config/database.go"] SHARE_TTL["internal/config/share_code_ttl.go"] DB_SQL["sql/*.sql"] end subgraph "任务处理" DEVICE_TASK["internal/task/device_persist.go"] SHARE_TASK["internal/task/share_code_persist.go"] end MAIN --> ROUTER ROUTER --> BRAND_H ROUTER --> MODEL_H ROUTER --> MODEL_LIST_H ROUTER --> OTA_H ROUTER --> DEVICE_H ROUTER --> SHARE_CODE_H ROUTER --> CURVE_H BRAND_H --> BRAND_R MODEL_H --> MODEL_R MODEL_LIST_H --> MODEL_R OTA_H --> OTA_R DEVICE_H --> DEVICE_R SHARE_CODE_H --> CACHE SHARE_CODE_H --> SHARE_CODE_R CURVE_H --> CURVE_R BRAND_R --> MODEL_M MODEL_R --> MODEL_M2 OTA_R --> MODEL_M3 DEVICE_R --> MODEL_M4 DEVICE_R --> MODEL_M5 SHARE_CODE_R --> MODEL_M6 CURVE_R --> MODEL_M7 BRAND_H --> RESP MODEL_H --> RESP MODEL_LIST_H --> RESP OTA_H --> RESP DEVICE_H --> RESP SHARE_CODE_H --> RESP CURVE_H --> RESP DEVICE_H --> ENCODE SHARE_CODE_H --> ENCODE SHARE_TASK --> SHARE_CODE_R DEVICE_TASK --> DEVICE_R DB_CFG --> DB_SQL CACHE --> SHARE_TTL ``` **图表来源** - [cmd/server/main.go:22-64](file://cmd/server/main.go#L22-L64) - [internal/router/router.go:14-82](file://internal/router/router.go#L14-L82) - [internal/handler/brand.go:19-50](file://internal/handler/brand.go#L19-L50) - [internal/handler/model.go:19-51](file://internal/handler/model.go#L19-L51) - [internal/handler/model_list.go:19-57](file://internal/handler/model_list.go#L19-L57) - [internal/handler/ota.go:14-145](file://internal/handler/ota.go#L14-L145) - [internal/handler/device.go:15-83](file://internal/handler/device.go#L15-L83) - [internal/handler/share_code.go:1-383](file://internal/handler/share_code.go#L1-L383) - [internal/handler/curve.go:1-582](file://internal/handler/curve.go#L1-L582) - [internal/repository/brand.go:16-51](file://internal/repository/brand.go#L16-L51) - [internal/repository/model.go:16-95](file://internal/repository/model.go#L16-L95) - [internal/repository/ota.go:11-159](file://internal/repository/ota.go#L11-L159) - [internal/repository/device.go:11-88](file://internal/repository/device.go#L11-L88) - [internal/repository/share_code.go:1-59](file://internal/repository/share_code.go#L1-L59) - [internal/repository/curve.go:1-66](file://internal/repository/curve.go#L1-L66) - [internal/model/brand.go:3-7](file://internal/model/brand.go#L3-L7) - [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15) - [internal/model/ota.go:5-63](file://internal/model/ota.go#L5-L63) - [internal/model/user_device.go:5-12](file://internal/model/user_device.go#L5-L12) - [internal/model/user_active.go:5-13](file://internal/model/user_active.go#L5-L13) - [internal/model/share_code.go:14-25](file://internal/model/share_code.go#L14-L25) - [internal/model/target.go:5-14](file://internal/model/target.go#L5-L14) - [internal/response/response.go:9-37](file://internal/response/response.go#L9-L37) - [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52) - [internal/config/database.go:17-72](file://internal/config/database.go#L17-L72) - [internal/config/share_code_ttl.go:12-60](file://internal/config/share_code_ttl.go#L12-L60) - [sql/model.sql:20-38](file://sql/model.sql#L20-L38) - [sql/ota.sql:23-40](file://sql/ota.sql#L23-L40) - [sql/ota_target_device.sql:23-31](file://sql/ota_target_device.sql#L23-L31) - [sql/black_list.sql:23-30](file://sql/black_list.sql#L23-L30) - [sql/share_code_log.sql:8-23](file://sql/share_code_log.sql#L8-L23) - [sql/user_device.sql:23-32](file://sql/user_device.sql#L23-L32) - [sql/user_active.sql:23-32](file://sql/user_active.sql#L23-L32) - [internal/task/device_persist.go:14-167](file://internal/task/device_persist.go#L14-L167) - [internal/task/share_code_persist.go:1-232](file://internal/task/share_code_persist.go#L1-L232) **章节来源** - [cmd/server/main.go:22-64](file://cmd/server/main.go#L22-L64) - [internal/router/router.go:14-82](file://internal/router/router.go#L14-L82) ## 核心组件 - **传统模型层(Model)** - Brand:承载品牌标识与名称,用于品牌列表查询。 - Model:承载型号信息,包含品牌名、型号名、形态、设备类型、来源、等价键、创建时间等。 - **OTA固件升级模型层** - OTA:固件升级记录,包含版本信息、下载地址、MD5校验、强制升级标志、灰度发布状态、定向升级配置等。 - BlackList:OTA黑名单,记录被禁止升级的设备MAC地址。 - OTATargetDevice:OTA灰度升级设备,记录允许参与灰度升级的设备列表。 - **分享码模型层** - ShareCodeLog:分享码操作日志,记录导出/导入操作及EQ数据快照。 - ShareCodeData:分享码缓存数据,包含分享码、MAC地址、设备型号、EQ数据、过期时间等。 - **目标曲线模型层** - Target:目标曲线配置,包含标签、CSV读取标志、文件路径、贝斯增强配置等。 - **用户设备跟踪模型层** - UserDevice:用户设备信息,包含设备MAC地址、型号、添加时间、当前版本等。 - UserActive:用户活动记录,包含设备活跃信息、IP地址、活跃日期等。 - **仓库层(Repository)** - BrandRepository:提供按品牌名模糊查询的品牌列表。 - ModelRepository:提供按品牌名或型号名模糊查询的型号列表,并处理可空字段的扫描。 - OTARepository:提供OTA升级信息查询、黑名单检查、灰度升级设备查询等功能。 - DeviceRepository:提供设备信息查询、插入、更新以及活动记录管理。 - ShareCodeRepository:提供分享码日志插入、导出记录检查等功能。 - CurveRepository:提供型号和目标曲线查询功能。 - **处理器层(Handler)** - BrandHandler:接收查询参数,调用仓库层,支持可选的响应体 Base64 编码。 - ModelHandler:接收品牌与型号查询参数,调用仓库层,支持可选的响应体 Base64 编码。 - ModelListHandler:通过搜索客户端返回模型列表,支持可选的响应体 Base64 编码。 - OTAHandler:获取OTA升级信息,支持黑名单检查、灰度升级设备检查等功能。 - DeviceHandler:处理设备信息上报,将设备活动信息写入Redis缓存。 - ShareCodeHandler:处理分享码创建、查询、导入、删除等操作,支持Redis缓存和数据库持久化。 - CurveHandler:处理曲线数据获取,支持目标曲线配置和EQ参数化。 - **任务处理层** - DevicePersistTask:定时从Redis缓存批量持久化设备信息到数据库。 - ShareCodePersistTask:定时从Redis缓存批量持久化分享码日志到数据库。 **章节来源** - [internal/model/brand.go:3-7](file://internal/model/brand.go#L3-L7) - [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15) - [internal/model/ota.go:5-63](file://internal/model/ota.go#L5-L63) - [internal/model/share_code.go:14-25](file://internal/model/share_code.go#L14-L25) - [internal/model/target.go:5-14](file://internal/model/target.go#L5-L14) - [internal/model/user_device.go:5-12](file://internal/model/user_device.go#L5-L12) - [internal/model/user_active.go:5-13](file://internal/model/user_active.go#L5-L13) - [internal/repository/brand.go:20-51](file://internal/repository/brand.go#L20-L51) - [internal/repository/model.go:20-95](file://internal/repository/model.go#L20-L95) - [internal/repository/ota.go:19-159](file://internal/repository/ota.go#L19-L159) - [internal/repository/device.go:19-88](file://internal/repository/device.go#L19-L88) - [internal/repository/share_code.go:12-59](file://internal/repository/share_code.go#L12-L59) - [internal/repository/curve.go:11-66](file://internal/repository/curve.go#L11-L66) - [internal/handler/brand.go:26-50](file://internal/handler/brand.go#L26-L50) - [internal/handler/model.go:26-51](file://internal/handler/model.go#L26-L51) - [internal/handler/model_list.go:26-57](file://internal/handler/model_list.go#L26-L57) - [internal/handler/ota.go:23-145](file://internal/handler/ota.go#L23-L145) - [internal/handler/device.go:27-83](file://internal/handler/device.go#L27-L83) - [internal/handler/share_code.go:15-383](file://internal/handler/share_code.go#L15-L383) - [internal/handler/curve.go:27-582](file://internal/handler/curve.go#L27-L582) - [internal/task/device_persist.go:24-167](file://internal/task/device_persist.go#L24-L167) - [internal/task/share_code_persist.go:14-232](file://internal/task/share_code_persist.go#L14-L232) ## 架构总览 下图展示了从请求到响应的关键路径,包括处理器、仓库、数据库与可选编码流程,以及新增的分享码功能、目标曲线配置和增强的OTA固件升级功能。 ```mermaid sequenceDiagram participant C as "客户端" participant R as "路由层" participant H as "处理器层" participant Repo as "仓库层" participant Cache as "缓存层" participant DB as "数据库" participant Enc as "编码层" C->>R : "POST /audio/shareCreate" R->>H : "ShareCodeHandler.ExportShareCode" H->>Cache : "Create(分享码, EQ数据)" Cache-->>H : "ShareCodeData" H->>Repo : "InsertLog(分享码日志)" Repo->>DB : "插入分享码日志" DB-->>Repo : "确认插入" Repo-->>H : "确认" H-->>C : "200 OK + 分享码信息" C->>R : "GET /audio/shareQuery?shareCode=ABCDE" R->>H : "ShareCodeHandler.QueryShareCode" H->>Cache : "Get(分享码)" Cache-->>H : "ShareCodeData" H-->>C : "200 OK + EQ数据" C->>R : "GET /audio/shareAccept?mac=xx&model=Luxsin-X9&shareCode=ABCDE" R->>H : "ShareCodeHandler.ImportShareCode" H->>Cache : "EnqueueImportLog(导入日志)" Cache-->>H : "排队成功" H-->>C : "200 OK + EQ数据" C->>R : "GET /audio/getCurve?brand=xxx&name=xxx&target=xxx" R->>H : "CurveHandler.GetCurve" H->>Repo : "GetTargetByLabel(目标曲线)" Repo->>DB : "查询目标曲线" DB-->>Repo : "Target配置" Repo-->>H : "Target配置" H->>Cache : "GetWithFR(缓存)" Cache-->>H : "曲线数据" H-->>C : "200 OK + parametric_eq" ``` **图表来源** - [internal/router/router.go:73-77](file://internal/router/router.go#L73-L77) - [internal/handler/share_code.go:40-125](file://internal/handler/share_code.go#L40-L125) - [internal/handler/share_code.go:192-211](file://internal/handler/share_code.go#L192-L211) - [internal/handler/share_code.go:228-279](file://internal/handler/share_code.go#L228-L279) - [internal/handler/curve.go:145-198](file://internal/handler/curve.go#L145-L198) - [internal/repository/curve.go:44-66](file://internal/repository/curve.go#L44-L66) - [internal/cache/curve_cache.go:27-102](file://internal/cache/curve_cache.go#L27-L102) ## 详细组件分析 ### Brand 数据模型 - **设计理念** - 轻量级品牌实体,仅包含标识与名称,用于品牌筛选与列表展示。 - **字段定义与约束** - id:整数,主键,自增。 - name:字符串,非空,用于品牌名匹配与排序。 - **业务含义** - 作为 Model 的上游维度,配合 Model 的 brandName 字段形成关联。 - **数据库映射** - 表名:brand(未在本文直接列出,但与 Model 的 brand_name 关联一致)。 - 字段:id、name。 - **ORM 映射配置** - 使用原生 sql.DB 扫描,通过结构体标签与 Scan 对齐。 - **验证与序列化** - 无显式校验逻辑,依赖数据库约束与上层参数清洗。 - JSON 标签用于序列化输出。 - **查询流程** - 支持按品牌名模糊查询,使用 LIKE 匹配并按名称升序排列。 - 返回 []Brand 列表。 ```mermaid classDiagram class Brand { +int id +string name } class BrandRepository { -db *sql.DB +List(ctx, brandName) []Brand } BrandRepository --> Brand : "返回" ``` **图表来源** - [internal/model/brand.go:3-7](file://internal/model/brand.go#L3-L7) - [internal/repository/brand.go:12-51](file://internal/repository/brand.go#L12-L51) **章节来源** - [internal/model/brand.go:3-7](file://internal/model/brand.go#L3-L7) - [internal/repository/brand.go:20-51](file://internal/repository/brand.go#L20-L51) ### Model 数据模型 - **设计理念** - 型号实体承载品牌名、型号名及可选属性(形态、设备类型、来源、等价键),并记录创建时间。 - **字段定义与约束** - id:整数,主键,自增。 - brandName:字符串,非空,与品牌维度关联。 - name:字符串,非空,型号名。 - form、rig、source、eqKey:字符串(指针),可空,表示形态、设备类型、来源、等价键。 - createAt:时间戳,非空,记录创建时间。 - **业务含义** - 作为核心产品维度,支持按品牌或型号名检索,可为空的扩展属性满足多样化设备描述。 - **数据库映射** - 表名:model。 - 字段:id、brand_name、name、form、rig、source、eq_key、create_at。 - 约束:唯一索引 (brand_name, name),保证同品牌下型号名唯一。 - **ORM 映射配置** - 使用 sql.NullString 扫描可空列,再转换为指针字符串,避免零值歧义。 - JSON 标签用于序列化输出,可空字段支持 omitempty。 - **验证与序列化** - 无显式校验逻辑,依赖数据库约束与上层参数清洗。 - JSON 标签用于序列化输出。 - **查询流程** - ostartTime 支持按品牌名精确匹配或按型号名模糊匹配,返回 []Model 列表。 - 默认返回空切片而非 nil,便于前端处理。 ```mermaid classDiagram class Model { +int id +string brandName +string name +*string form +*string rig +*string source +*string eqKey +time createAt } class ModelRepository { -db *sql.DB +List(ctx, brandName, modelName) []Model } ModelRepository --> Model : "返回" ``` **图表来源** - [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15) - [internal/repository/model.go:12-95](file://internal/repository/model.go#L12-L95) - [sql/model.sql:24-35](file://sql/model.sql#L24-L35) **章节来源** - [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15) - [internal/repository/model.go:20-95](file://internal/repository/model.go#L20-L95) - [sql/model.sql:24-35](file://sql/model.sql#L24-L35) ### OTA 固件升级模型 - **设计理念** - OTA模型用于管理固件升级信息,支持强制升级、灰度发布、灰度升级设备等功能。 - **更新**:OTA模型已简化,移除了pawVerCode、pawVerName、pawUrl、pawMd5四个冗余字段,现在只包含核心升级信息字段。 - **更新**:OTATargetDevice模型已重构,移除了Type字段,从"定向设备"概念转变为"灰度升级设备"概念。 - **字段定义与约束** - OTA模型: - id:整数,主键,自增。 - VerCode:整数,版本号,用于排序。 - VerName:字符串,版本名称。 - URL:字符串,固件下载地址。 - MD5:字符串,固件MD5校验值。 - Force:BoolInt,是否强制升级(true/false)。 - Desc:字符串指针,升级描述。 - Model:字符串指针,对应设备型号。 - HW:整数,硬件版本号。 - Target:BoolInt,是否定向升级(true/false)。 - Beta:BoolInt,是否灰度发布(true/false)。 - StartTime:时间戳指针,升级开始时间。 - EndTime:时间戳指针,升级结束时间。 - Status:整数,状态(1-可用,0-不可用)。 - BlackList模型: - id:整数,主键,自增。 - OTAID:整数,关联OTA记录ID。 - Mac:字符串,设备MAC地址。 - CreateAt:时间戳,创建时间。 - OTATargetDevice模型: - id:整数,主键,自增。 - OTAID:整数,关联OTA记录ID。 - MacAddr:字符串,设备MAC地址。 - CreateAt:时间戳,创建时间。 - **业务含义** - 支持复杂的固件升级策略,包括强制升级、灰度发布、灰度升级设备管理等功能。 - 简化的字段结构提高了数据模型的清晰度和维护性。 - 灰度升级设备概念简化了设备管理逻辑,不再区分白名单和黑名单类型。 - **数据库映射** - 表名:ota、black_list、ota_target_device。 - 字段:完整映射关系详见数据库表结构。 - **更新**:OTA表不再包含pawVerCode、pawVerName、pawUrl、pawMd5字段。 - **更新**:ota_target_device表不再包含type字段。 - **ORM 映射配置** - 使用 sql.NullString 和 sql.NullTime 扫描可空列。 - BoolInt类型支持数据库整型与JSON布尔值的双向转换。 - JSON 标签用于序列化输出,可空字段支持 omitempty。 - **查询流程** - 支持多种查询策略:最新OTA记录、非黑名单OTA记录、非定向OTA记录等。 - 支持黑名单检查和灰度升级设备检查。 ```mermaid classDiagram class OTA { +int ID +int VerCode +string VerName +string URL +string MD5 +BoolInt Force +*string Desc +*string Model +int HW +BoolInt Target +BoolInt Beta +*time StartTime +*time EndTime +int Status } class BlackList { +int ID +int OTAID +string Mac +time CreateAt } class OTATargetDevice { +int ID +int OTAID +string MacAddr +time CreateAt } class OTARepository { -db *sql.DB +GetLatestOTA(ctx, model, hw, beta) *OTA +GetLatestOTANotInBlackList(ctx, model, hw, beta, mac) *OTA +GetLatestOTANotTarget(ctx, model, hw, beta) *OTA +IsInBlackList(ctx, otaID, mac) bool +FindTargetDevice(ctx, otaID, mac) *OTATargetDevice } OTARepository --> OTA : "返回" OTARepository --> BlackList : "返回" OTARepository --> OTATargetDevice : "返回" ``` **图表来源** - [internal/model/ota.go:29-63](file://internal/model/ota.go#L29-L63) - [internal/repository/ota.go:19-159](file://internal/repository/ota.go#L19-L159) - [sql/ota.sql:24-40](file://sql/ota.sql#L24-L40) - [sql/ota_target_device.sql:24-31](file://sql/ota_target_device.sql#L24-L31) **章节来源** - [internal/model/ota.go:5-63](file://internal/model/ota.go#L5-L63) - [internal/repository/ota.go:19-159](file://internal/repository/ota.go#L19-L159) - [sql/ota.sql:23-40](file://sql/ota.sql#L23-L40) - [sql/ota_target_device.sql:23-31](file://sql/ota_target_device.sql#L23-L31) ### 分享码数据模型 - **设计理念** - ShareCodeLog用于记录分享码的操作日志,支持导出和导入两种操作类型。 - ShareCodeData用于Redis缓存中的分享码数据,包含完整的分享码信息和缓存状态。 - **字段定义与约束** - ShareCodeLog模型: - ID:整数,主键,自增。 - MacAddr:字符串,设备MAC地址。 - ShareCode:字符串,5位分享码。 - Action:枚举,操作类型(export/import)。 - Model:枚举,设备型号(Luxsin-X9/Luxsin-X8)。 - IpAddr:字符串,用户IP地址。 - EqData:JSON,EQ数据快照。 - ExpireAt:时间戳指针,分享码到期时间。 - CreateAt:时间戳,创建时间。 - ShareCodeData结构: - ShareCode:字符串,5位分享码。 - MacAddr:字符串,创建者MAC地址。 - IpAddr:字符串,创建者IP地址。 - Model:字符串,设备型号。 - EqData:字符串,EQ参数JSON。 - ExpireAt:时间戳,过期时间。 - Persisted:布尔值,是否已刷入数据库。 - **业务含义** - 支持EQ数据的分享与导入功能,提供完整的操作审计和数据快照。 - **数据库映射** - 表名:share_code_log。 - 字段:完整映射关系详见数据库表结构。 - 索引:对mac_addr、share_code、create_at建立索引。 - **ORM 映射配置** - 使用 sql.NullString 和 sql.NullTime 扫描可空列。 - JSON 标签用于序列化输出,支持复杂JSON数据存储。 - **查询流程** - 支持按分享码查询导出记录存在性检查。 - 支持分享码日志的插入和查询。 ```mermaid classDiagram class ShareCodeLog { +int ID +string MacAddr +string ShareCode +string Action +string Model +string IpAddr +[]byte EqData +*time ExpireAt +time CreateAt } class ShareCodeData { +string ShareCode +string MacAddr +string IpAddr +string Model +string EqData +time ExpireAt +bool Persisted } class ShareCodeRepository { -db *sql.DB +InsertLog(ctx, log) error +HasExportLog(ctx, shareCode) bool } ShareCodeRepository --> ShareCodeLog : "返回" ``` **图表来源** - [internal/model/share_code.go:14-25](file://internal/model/share_code.go#L14-L25) - [internal/repository/share_code.go:20-59](file://internal/repository/share_code.go#L20-L59) - [sql/share_code_log.sql:9-23](file://sql/share_code_log.sql#L9-L23) **章节来源** - [internal/model/share_code.go:14-25](file://internal/model/share_code.go#L14-L25) - [internal/repository/share_code.go:12-59](file://internal/repository/share_code.go#L12-L59) - [sql/share_code_log.sql:8-23](file://sql/share_code_log.sql#L8-L23) ### 目标曲线数据模型 - **设计理念** - Target模型用于定义目标曲线配置,支持从CSV文件读取目标数据和贝斯增强配置。 - **字段定义与约束** - ID:整数,主键,自增。 - Label:字符串,目标曲线标签。 - ReadCSV:BoolInt,是否从CSV文件读取目标数据。 - File:字符串指针,CSV文件路径。 - BassBoost:字符串指针,贝斯增强配置JSON。 - AddTime:时间戳,添加时间。 - **业务含义** - 支持灵活的目标曲线配置,可以使用预定义的曲线名称或从CSV文件读取自定义曲线。 - **数据库映射** - 表名:target。 - 字段:完整映射关系详见数据库表结构。 - **ORM 映射配置** - 使用 BoolInt 类型支持布尔值序列化。 - JSON 标签用于序列化输出,可空字段支持 omitempty。 - **查询流程** - 支持按标签查询目标曲线配置。 - 支持CSV文件路径和贝斯增强配置的动态加载。 ```mermaid classDiagram class Target { +int ID +string Label +BoolInt ReadCSV +*string File +*string BassBoost +time AddTime } class CurveRepository { -db *sql.DB +GetTargetByLabel(ctx, label) *Target } CurveRepository --> Target : "返回" ``` **图表来源** - [internal/model/target.go:5-14](file://internal/model/target.go#L5-L14) - [internal/repository/curve.go:44-66](file://internal/repository/curve.go#L44-L66) **章节来源** - [internal/model/target.go:5-14](file://internal/model/target.go#L5-L14) - [internal/repository/curve.go:44-66](file://internal/repository/curve.go#L44-L66) ### 用户设备跟踪模型 - **设计理念** - UserDevice模型用于跟踪用户设备信息,支持设备注册、版本更新等功能。 - UserActive模型用于记录用户设备的活跃信息,支持按日期分区存储。 - **字段定义与约束** - UserDevice模型: - id:整数,主键,自增。 - mac_addr:字符串,设备MAC地址,唯一索引。 - model:字符串,设备型号。 - add_time:时间戳,默认当前时间。 - ver:字符串指针,设备当前版本。 - UserActive模型: - id:整数,主键。 - mac_addr:字符串,设备MAC地址。 - model:字符串,设备型号。 - active_date:日期,活跃日期,联合主键。 - ip_addr:字符串,设备IP地址。 - create_at:时间戳,默认当前时间。 - **业务含义** - 支持设备信息的实时上报和历史活动记录追踪。 - **数据库映射** - 表名:user_device、user_active。 - 字段:完整映射关系详见数据库表结构。 - 索引:user_device的mac_addr唯一索引,user_active的(mac_addr, active_date)联合索引。 - **ORM 映射配置** - 使用 sql.NullString 扫描可空列。 - JSON 标签用于序列化输出。 - **查询流程** - 支持按MAC地址查询设备信息。 - 支持按MAC地址和日期查询活跃记录。 - 支持设备信息的插入、更新和活跃记录的插入、更新。 ```mermaid classDiagram class UserDevice { +int id +string mac_addr +string model +time add_time +*string ver } class UserActive { +int id +string mac_addr +string model +date active_date +string ip_addr +time create_at } class DeviceRepository { -db *sql.DB +FindDeviceByMac(ctx, macAddr) *UserDevice +InsertDevice(ctx, device) error +UpdateDeviceVer(ctx, id, ver) error +FindActiveByMacAndDate(ctx, macAddr, activeDate) *UserActive +InsertActive(ctx, active) error +UpdateActiveIp(ctx, id, ipAddr) error } DeviceRepository --> UserDevice : "返回" DeviceRepository --> UserActive : "返回" ``` **图表来源** - [internal/model/user_device.go:5-12](file://internal/model/user_device.go#L5-L12) - [internal/model/user_active.go:5-13](file://internal/model/user_active.go#L5-L13) - [internal/repository/device.go:19-88](file://internal/repository/device.go#L19-L88) - [sql/user_device.sql:24-32](file://sql/user_device.sql#L24-L32) - [sql/user_active.sql:24-32](file://sql/user_active.sql#L24-L32) **章节来源** - [internal/model/user_device.go:5-12](file://internal/model/user_device.go#L5-L12) - [internal/model/user_active.go:5-13](file://internal/model/user_active.go#L5-L13) - [internal/repository/device.go:19-88](file://internal/repository/device.go#L19-L88) - [sql/user_device.sql:23-32](file://sql/user_device.sql#L23-L32) - [sql/user_active.sql:23-32](file://sql/user_active.sql#L23-L32) ### 处理器与序列化机制 - **统一响应体** - 统一响应体包含 code、message、data 字段,便于前端统一处理。 - **可选 Base64 编码** - 支持通过 base64Resp 参数控制是否对 JSON 响应进行自定义 Base64 编码。 - 自定义映射表将标准 Base64 字符集映射为更紧凑的字符集,减少体积。 - **OTA处理器特殊逻辑** - 支持参数校验、黑名单检查、灰度升级设备检查等复杂业务逻辑。 - 根据不同情况返回不同的OTA升级信息。 - **更新**:OTA处理器现在处理简化的字段结构,移除了对paw*字段的处理。 - **更新**:OTA处理器现在使用灰度升级设备概念,不再区分白名单和黑名单类型。 - **设备处理器特殊逻辑** - 将设备信息写入Redis缓存,支持异步持久化。 - 提供设备信息上报接口。 - **分享码处理器特殊逻辑** - 支持分享码创建、查询、导入、删除等完整生命周期管理。 - 使用Redis缓存提高性能,支持分布式锁保证数据一致性。 - 提供分享码数量限制和过期时间控制。 - **曲线处理器特殊逻辑** - 支持目标曲线配置查询和EQ参数化计算。 - 使用Redis缓存优化曲线数据访问性能。 - **错误处理** - 处理器捕获仓库层错误,记录日志并通过统一响应体返回内部错误。 ```mermaid sequenceDiagram participant C as "客户端" participant H as "ShareCodeHandler" participant Cache as "ShareCodeCache" participant Repo as "ShareCodeRepository" participant DB as "数据库" participant Enc as "编码层" C->>H : "POST /audio/shareCreate" H->>Cache : "Create(mac, model, eqData)" Cache-->>H : "ShareCodeData" H->>Repo : "InsertLog(export)" Repo->>DB : "插入日志" DB-->>Repo : "确认" Repo-->>H : "确认" H-->>C : "200 OK + 分享码信息" C->>H : "GET /audio/shareAccept?shareCode=ABCDE" H->>Cache : "EnqueueImportLog(mac, model, eqData)" Cache-->>H : "排队成功" H-->>C : "200 OK + EQ数据" ``` **图表来源** - [internal/handler/share_code.go:40-125](file://internal/handler/share_code.go#L40-L125) - [internal/handler/share_code.go:228-279](file://internal/handler/share_code.go#L228-L279) - [internal/repository/share_code.go:20-59](file://internal/repository/share_code.go#L20-L59) - [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52) - [internal/response/response.go:9-37](file://internal/response/response.go#L9-L37) **章节来源** - [internal/handler/brand.go:26-50](file://internal/handler/brand.go#L26-L50) - [internal/handler/model.go:26-51](file://internal/handler/model.go#L26-L51) - [internal/handler/model_list.go:26-57](file://internal/handler/model_list.go#L26-L57) - [internal/handler/ota.go:23-145](file://internal/handler/ota.go#L23-L145) - [internal/handler/device.go:27-83](file://internal/handler/device.go#L27-L83) - [internal/handler/share_code.go:15-383](file://internal/handler/share_code.go#L15-L383) - [internal/handler/curve.go:27-582](file://internal/handler/curve.go#L27-L582) - [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52) - [internal/response/response.go:9-37](file://internal/response/response.go#L9-L37) ### 查询与过滤逻辑 - **Brand 查询** - 支持按品牌名模糊匹配,使用 LIKE 并按名称升序排列。 - **Model 查询** - 优先按品牌名精确匹配;若为空则按型号名模糊匹配;否则返回空切片。 - 扫描时将 sql.NullString 转换为指针字符串,避免零值歧义。 - **OTA 查询** - 支持按model+hw+beta+status=1查询最新OTA记录。 - 支持黑名单检查和灰度升级设备检查。 - 提供多种查询策略以适应不同的升级场景。 - **更新**:OTA查询现在使用简化的字段列表,移除了对paw*字段的查询。 - **更新**:OTA查询现在使用灰度升级设备概念,简化了设备匹配逻辑。 - **设备查询** - 支持按MAC地址查询设备信息。 - 支持按MAC地址和日期查询活跃记录。 - 扫描时将 sql.NullString 转换为指针字符串,避免零值歧义。 - **分享码查询** - 支持按MAC地址查询未过期的分享码列表。 - 支持按分享码查询单个分享码详情。 - 支持分享码导入操作的日志排队和持久化。 - **目标曲线查询** - 支持按标签查询目标曲线配置。 - 支持CSV文件路径和贝斯增强配置的动态加载。 ```mermaid flowchart TD Start(["进入分享码查询"]) --> Params["参数校验"] Params --> CheckMac{"mac参数是否非空?"} CheckMac --> |是| ListByMac["ListByMac 查询"] CheckMac --> |否| CheckCode{"shareCode参数是否5位?"} CheckCode --> |是| GetByCode["Get 查询"] CheckCode --> |否| Error["返回错误"] ListByMac --> CleanExpired["清理过期条目"] CleanExpired --> GetDetails["逐个获取详情"] GetDetails --> ReturnList["返回分享码列表"] GetByCode --> ReturnDetail["返回分享码详情"] ReturnList --> End(["返回结果"]) ReturnDetail --> End Error --> End ``` **图表来源** - [internal/handler/share_code.go:138-177](file://internal/handler/share_code.go#L138-L177) - [internal/handler/share_code.go:192-211](file://internal/handler/share_code.go#L192-L211) - [internal/cache/share_code_cache.go:281-319](file://internal/cache/share_code_cache.go#L281-L319) **章节来源** - [internal/repository/model.go:20-61](file://internal/repository/model.go#L20-L61) - [internal/repository/brand.go:20-51](file://internal/repository/brand.go#L20-L51) - [internal/repository/ota.go:19-159](file://internal/repository/ota.go#L19-L159) - [internal/repository/device.go:19-88](file://internal/repository/device.go#L19-L88) - [internal/repository/share_code.go:20-59](file://internal/repository/share_code.go#L20-L59) - [internal/repository/curve.go:44-66](file://internal/repository/curve.go#L44-L66) - [internal/handler/share_code.go:138-177](file://internal/handler/share_code.go#L138-L177) ## 依赖分析 - **层间耦合** - Handler 依赖 Repository;Repository 依赖 sql.DB;Model 为纯数据结构。 - 统一响应体与编码层被 Handler 调用,降低重复逻辑。 - 新增的Redis依赖用于分享码缓存和设备信息缓存。 - 分享码功能依赖Redis缓存和数据库的双重存储。 - 目标曲线功能依赖CurveRepository和CurveCache。 - **外部依赖** - 数据库:MySQL,通过 sql.DB 访问。 - 日志:zap。 - Web 框架:Gin。 - 搜索:Meilisearch(ModelListHandler)。 - 缓存:Redis(Device、ShareCode、Curve相关处理器)。 - 对象存储:S3(曲线数据CSV文件)。 - 任务调度:定时任务用于设备信息和分享码持久化。 - **潜在循环依赖** - 当前结构清晰,无循环导入迹象。 - **新增依赖关系** - 分享码功能依赖Redis缓存和数据库的双重存储。 - 目标曲线功能依赖CurveRepository和CurveCache。 - OTA功能依赖多个表的关联查询。 ```mermaid graph LR H_Brand["BrandHandler"] --> Repo_Brand["BrandRepository"] H_Model["ModelHandler"] --> Repo_Model["ModelRepository"] H_ModelList["ModelListHandler"] --> Search["Meilisearch 客户端"] H_OTA["OTAHandler"] --> Repo_OTA["OTARepository"] H_Device["DeviceHandler"] --> Repo_Device["DeviceRepository"] H_ShareCode["ShareCodeHandler"] --> Cache_Share["ShareCodeCache"] H_ShareCode --> Repo_Share["ShareCodeRepository"] H_Curve["CurveHandler"] --> Repo_Curve["CurveRepository"] Repo_Brand --> DB["sql.DB"] Repo_Model --> DB Repo_OTA --> DB Repo_Device --> DB Repo_Share --> DB Repo_Curve --> DB H_Device --> Redis["Redis Client"] H_ShareCode --> Redis H_Curve --> Redis H_Curve --> S3["S3 Storage"] H_Brand --> Resp["统一响应体"] H_Model --> Resp H_ModelList --> Resp H_OTA --> Resp H_Device --> Resp H_ShareCode --> Resp H_Curve --> Resp H_Brand --> Encode["Base64 编码"] H_Model --> Encode H_ModelList --> Encode Task_Device["DevicePersistTask"] --> Repo_Device Task_Device --> Redis Task_Share["ShareCodePersistTask"] --> Repo_Share Task_Share --> Redis ``` **图表来源** - [internal/handler/brand.go:14-50](file://internal/handler/brand.go#L14-L50) - [internal/handler/model.go:14-51](file://internal/handler/model.go#L14-L51) - [internal/handler/model_list.go:14-57](file://internal/handler/model_list.go#L14-L57) - [internal/handler/ota.go:14-145](file://internal/handler/ota.go#L14-L145) - [internal/handler/device.go:15-83](file://internal/handler/device.go#L15-L83) - [internal/handler/share_code.go:15-383](file://internal/handler/share_code.go#L15-L383) - [internal/handler/curve.go:27-582](file://internal/handler/curve.go#L27-L582) - [internal/repository/brand.go:12-51](file://internal/repository/brand.go#L12-L51) - [internal/repository/model.go:12-95](file://internal/repository/model.go#L12-L95) - [internal/repository/ota.go:11-159](file://internal/repository/ota.go#L11-L159) - [internal/repository/device.go:11-88](file://internal/repository/device.go#L11-L88) - [internal/repository/share_code.go:12-59](file://internal/repository/share_code.go#L12-L59) - [internal/repository/curve.go:11-66](file://internal/repository/curve.go#L11-L66) - [internal/response/response.go:9-37](file://internal/response/response.go#L9-L37) - [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52) - [internal/task/device_persist.go:14-167](file://internal/task/device_persist.go#L14-L167) - [internal/task/share_code_persist.go:14-232](file://internal/task/share_code_persist.go#L14-L232) **章节来源** - [internal/router/router.go:14-82](file://internal/router/router.go#L14-L82) - [internal/config/database.go:17-72](file://internal/config/database.go#L17-L72) ## 性能考虑 - **查询优化** - Model 表对 (brand_name, name) 建有唯一索引,有利于去重与快速定位。 - OTA表对(model, hw, beta, status)建立索引,支持快速查询最新OTA记录。 - UserDevice表对(mac_addr)建立唯一索引,支持快速设备查询。 - UserActive表对(mac_addr, active_date)建立联合索引,支持按日期分区查询。 - share_code_log表对(mac_addr, share_code, create_at)建立索引,支持分享码查询。 - 查询时优先按品牌名匹配,减少 LIKE 的范围。 - **更新**:OTA查询现在使用简化的字段列表,减少了不必要的字段扫描。 - **更新**:OTA查询现在使用灰度升级设备概念,简化了设备匹配逻辑,提高了查询性能。 - **扫描与内存** - 使用 sql.NullString 扫描可空列,避免零值歧义;转换为指针字符串减少冗余存储。 - OTA模型使用BoolInt类型处理布尔值,支持数据库整型与JSON布尔值的双向转换。 - ShareCodeLog模型使用[]byte存储JSON数据,减少字符串处理开销。 - **缓存策略** - 设备信息先写入Redis缓存,通过定时任务批量持久化到数据库,减少数据库压力。 - 品牌和型号信息使用Redis缓存提升查询性能。 - 分享码数据使用Redis缓存,支持TTL自动过期和分布式锁保证一致性。 - 目标曲线数据使用Redis缓存,支持fr数据独立存储优化缓存空间。 - **编码策略** - 可选的自定义 Base64 编码可降低响应体积,适合大列表传输场景。 - **并发与超时** - 服务器设置读写超时与优雅关闭,保障稳定性。 - 设备持久化任务和分享码持久化任务使用定时器定期执行,避免阻塞主线程。 - 分布式锁机制保证Redis操作的原子性和数据一致性。 **章节来源** - [sql/model.sql:34-35](file://sql/model.sql#L34-L35) - [sql/ota.sql:24-40](file://sql/ota.sql#L24-L40) - [sql/share_code_log.sql:20-23](file://sql/share_code_log.sql#L20-L23) - [sql/user_device.sql:24-32](file://sql/user_device.sql#L24-L32) - [sql/user_active.sql:24-32](file://sql/user_active.sql#L24-L32) - [internal/repository/model.go:63-95](file://internal/repository/model.go#L63-L95) - [internal/repository/ota.go:20-159](file://internal/repository/ota.go#L20-L159) - [internal/repository/device.go:19-88](file://internal/repository/device.go#L19-L88) - [internal/repository/share_code.go:20-59](file://internal/repository/share_code.go#L20-L59) - [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52) - [cmd/server/main.go:66-95](file://cmd/server/main.go#L66-L95) - [internal/task/device_persist.go:24-91](file://internal/task/device_persist.go#L24-L91) - [internal/task/share_code_persist.go:24-113](file://internal/task/share_code_persist.go#L24-L113) ## 故障排查指南 - **常见问题** - 数据库连接失败:检查环境变量与配置加载逻辑。 - 查询无结果:确认查询参数是否为空或大小写敏感;Model 查询默认返回空切片而非 nil。 - 编码异常:确认 base64Resp 参数与 JSON 序列化是否成功。 - OTA查询失败:检查model、hw参数是否正确,确认OTA记录状态是否为1。 - 设备信息未持久化:检查Redis连接和数据库连接,确认定时任务是否正常运行。 - 分享码创建失败:检查Redis连接、分享码生成算法、TTL配置。 - 分享码导入失败:检查导入日志队列、数据库连接、分布式锁状态。 - 目标曲线查询失败:检查目标曲线配置、CSV文件路径、S3访问权限。 - **更新**:OTA灰度升级设备查询失败:检查ota_target_device表结构,确认type字段已被移除。 - **排查步骤** - 查看日志:处理器记录错误日志,统一响应体返回错误码。 - 核对数据库:确认表结构与索引是否存在。 - 验证参数:确认查询参数是否符合预期。 - 检查Redis:确认设备信息、分享码数据是否正确写入Redis缓存。 - 监控任务:确认设备持久化任务和分享码持久化任务是否按预期执行。 - 检查分布式锁:确认分享码操作的分布式锁状态和超时处理。 - **更新**:检查OTA表结构,确认paw*字段不存在,验证简化的字段结构。 - **更新**:检查ota_target_device表结构,确认type字段已被移除,验证灰度升级设备查询逻辑。 **章节来源** - [internal/config/database.go:57-72](file://internal/config/database.go#L57-L72) - [internal/handler/brand.go:31-35](file://internal/handler/brand.go#L31-L35) - [internal/handler/model.go:33-36](file://internal/handler/model.go#L33-L36) - [internal/handler/model_list.go:39-42](file://internal/handler/model_list.go#L39-L42) - [internal/handler/ota.go:31-48](file://internal/handler/ota.go#L31-L48) - [internal/handler/device.go:33-39](file://internal/handler/device.go#L33-L39) - [internal/handler/share_code.go:46-81](file://internal/handler/share_code.go#L46-L81) - [internal/handler/curve.go:302-368](file://internal/handler/curve.go#L302-L368) - [internal/response/response.go:30-37](file://internal/response/response.go#L30-L37) ## 结论 本项目的数据模型设计简洁明确:Brand 与 Model 分别承担品牌与型号的维度,通过仓库层的原生 SQL 访问实现高效查询;处理器层统一响应与可选编码,提升传输效率与前端体验。新增的分享码功能、目标曲线模型和增强的OTA模型进一步完善了系统的数据模型体系,支持复杂的固件升级策略、设备信息跟踪、用户行为分析和EQ数据分享功能。数据库层面通过唯一索引与合理字段设计保障一致性与性能。Redis缓存层提供了高性能的临时数据存储和分布式锁机制。 **更新**:OTA模型经过简化重构,移除了pawVerCode、pawVerName、pawUrl、pawMd5四个冗余字段,现在只包含核心升级信息,提高了数据模型的清晰度和维护性。同时,OTATargetDevice模型从"定向设备"概念重构为"灰度升级设备"概念,移除了Type字段,简化了设备管理逻辑,提高了系统的易用性和维护性。新的字段结构更加简洁,减少了不必要的数据冗余,同时保持了完整的升级策略支持能力。 建议在后续迭代中引入显式的校验与转换层,增强健壮性与可维护性,同时考虑添加更多的监控指标和告警机制。 ## 附录 ### 数据库表结构与模型映射对照 - **表:model** - 字段:id(主键)、brand_name、name、form、rig、source、eq_key、create_at。 - 约束:唯一索引 (brand_name, name)。 - **表:ota** - 字段:id(主键)、verCode、verName、url、md5、force、desc、model、hw、target、beta、startTime、endTime、status。 - 约束:无显式约束。 - **更新**:移除了pawVerCode、pawVerName、pawUrl、pawMd5字段。 - **表:black_list** - 字段:id(主键)、ota_id、mac、create_at。 - 约束:无显式约束。 - **表:ota_target_device** - 字段:id(主键)、ota_id、mac_addr、create_at。 - 约束:无显式约束。 - **更新**:移除了type字段,简化了灰度升级设备管理。 - **表:user_device** - 字段:id(主键)、mac_addr、model、add_time、ver。 - 约束:唯一索引 (mac_addr)。 - **表:user_active** - 字段:id、mac_addr、model、active_date、ip_addr、create_at。 - 约束:联合主键 (id, active_date),联合索引 (mac_addr, active_date)。 - **表:share_code_log** - 字段:id(主键)、mac_addr、share_code、action、model、ip_addr、eq_data、expire_at、create_at。 - 约束:索引 idx_mac_addr、idx_share_code、idx_create_at。 - **表:target** - 字段:id(主键)、label、read_csv、file、bassBoost、addtime。 - 约束:无显式约束。 - **映射关系** - Model.id ↔ model.id - Model.brandName ↔ model.brand_name - Model.name ↔ model.name - OTA.ID ↔ ota.id - OTA.VerCode ↔ ota.verCode - OTA.VerName ↔ ota.verName - OTA.URL ↔ ota.url - OTA.MD5 ↔ ota.md5 - OTA.Force ↔ ota.force - OTA.Desc ↔ ota.desc - OTA.Model ↔ ota.model - OTA.HW ↔ ota.hw - OTA.Target ↔ ota.target - OTA.Beta ↔ ota.beta - OTA.StartTime ↔ ota.startTime - OTA.EndTime ↔ ota.endTime - OTA.Status ↔ ota.status - BlackList.ID ↔ black_list.id - BlackList.OTAID ↔ black_list.ota_id - BlackList.Mac ↔ black_list.mac - BlackList.CreateAt ↔ black_list.create_at - OTATargetDevice.ID ↔ ota_target_device.id - OTATargetDevice.OTAID ↔ ota_target_device.ota_id - OTATargetDevice.MacAddr ↔ ota_target_device.mac_addr - OTATargetDevice.CreateAt ↔ ota_target_device.create_at - UserDevice.id ↔ user_device.id - UserDevice.mac_addr ↔ user_device.mac_addr - UserDevice.model ↔ user_device.model - UserDevice.add_time ↔ user_device.add_time - UserDevice.ver ↔ user_device.ver - UserActive.id ↔ user_active.id - UserActive.mac_addr ↔ user_active.mac_addr - UserActive.model ↔ user_active.model - UserActive.active_date ↔ user_active.active_date - UserActive.ip_addr ↔ user_active.ip_addr - UserActive.create_at ↔ user_active.create_at - ShareCodeLog.ID ↔ share_code_log.id - ShareCodeLog.MacAddr ↔ share_code_log.mac_addr - ShareCodeLog.ShareCode ↔ share_code_log.share_code - ShareCodeLog.Action ↔ share_code_log.action - ShareCodeLog.Model ↔ share_code_log.model - ShareCodeLog.IpAddr ↔ share_code_log.ip_addr - ShareCodeLog.EqData ↔ share_code_log.eq_data - ShareCodeLog.ExpireAt ↔ share_code_log.expire_at - ShareCodeLog.CreateAt ↔ share_code_log.create_at - Target.ID ↔ target.id - Target.Label ↔ target.label - Target.ReadCSV ↔ target.read_csv - Target.File ↔ target.file - Target.BassBoost ↔ target.bassBoost - Target.AddTime ↔ target.addtime **章节来源** - [sql/model.sql:24-35](file://sql/model.sql#L24-L35) - [sql/ota.sql:24-40](file://sql/ota.sql#L24-L40) - [sql/ota_target_device.sql:24-31](file://sql/ota_target_device.sql#L24-L31) - [sql/black_list.sql:24-30](file://sql/black_list.sql#L24-L30) - [sql/user_device.sql:24-32](file://sql/user_device.sql#L24-L32) - [sql/user_active.sql:24-32](file://sql/user_active.sql#L24-L32) - [sql/share_code_log.sql:9-23](file://sql/share_code_log.sql#L9-L23) - [sql/target.sql:24-31](file://sql/target.sql#L24-L31) - [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15) - [internal/model/ota.go:29-63](file://internal/model/ota.go#L29-L63) - [internal/model/user_device.go:5-12](file://internal/model/user_device.go#L5-L12) - [internal/model/user_active.go:5-13](file://internal/model/user_active.go#L5-L13) - [internal/model/share_code.go:14-25](file://internal/model/share_code.go#L14-L25) - [internal/model/target.go:5-14](file://internal/model/target.go#L5-L14) ### 请求与响应示例(路径参考) - **获取品牌列表** - 路由:/audio/getBrand - 方法:GET - 参数:brandName(可选),base64Resp(可选) - 返回:[]Brand 或 Base64 编码后的 JSON - 参考路径:[internal/handler/brand.go:26-50](file://internal/handler/brand.go#L26-L50) - **获取型号列表** - 路由:/audio/getModel - 方法:GET - 参数:brandName(可选)、modelName(可选)、base64Resp(可选) - 返回:[]Model 或 Base64 编码后的 JSON - 参考路径:[internal/handler/model.go:26-51](file://internal/handler/model.go#L26-L51) - **搜索模型列表** - 路由:/audio/modelList - 方法:GET - 参数:key(必需)、count(可选)、base64Resp(可选) - 返回:[]Model 或 Base64 编码后的 JSON - 参考路径:[internal/handler/model_list.go:26-57](file://internal/handler/model_list.go#L26-L57) - **获取OTA升级信息** - 路由:/audio/ota - 方法:GET - 参数:model(必需)、hw(必需)、mac(可选)、beta(可选)、base64Resp(可选) - 返回:OTA对象或 Base64 编码后的 JSON - **更新**:返回的OTA对象现在包含简化的字段结构 - **更新**:OTA查询现在使用灰度升级设备概念,简化了设备匹配逻辑 - 参考路径:[internal/handler/ota.go:23-145](file://internal/handler/ota.go#L23-L145) - **设备信息上报** - 路由:/audio/reportDevInfo - 方法:GET - 参数:mac(必需)、model(必需)、ver(可选) - 返回:操作结果 - 参考路径:[internal/handler/device.go:27-83](file://internal/handler/device.go#L27-L83) - **创建分享码** - 路由:/audio/shareCreate - 方法:POST - 参数:mac(必需)、model(必需,Luxsin-X9或Luxsin-X8)、eq_data(必需,JSON) - 返回:分享码信息和过期时间 - 参考路径:[internal/handler/share_code.go:40-125](file://internal/handler/share_code.go#L40-L125) - **查询分享码** - 路由:/audio/shareQuery - 方法:GET - 参数:shareCode(必需,5位) - 返回:EQ数据和设备型号 - 参考路径:[internal/handler/share_code.go:192-211](file://internal/handler/share_code.go#L192-L211) - **导入分享码** - 路由:/audio/shareAccept - 方法:GET - 参数:mac(必需)、model(必需,Luxsin-X9或Luxsin-X8)、shareCode(必需,5位) - 返回:EQ数据和设备型号 - 参考路径:[internal/handler/share_code.go:228-279](file://internal/handler/share_code.go#L228-L279) - **获取目标曲线** - 路由:/audio/getCurve - 方法:GET - 参数:brand(必需)、name(必需)、target(必需)、base64Resp(可选) - 返回:parametric_eq数据 - 参考路径:[internal/handler/curve.go:145-198](file://internal/handler/curve.go#L145-L198) **章节来源** - [internal/router/router.go:63-78](file://internal/router/router.go#L63-L78) - [internal/handler/brand.go:26-50](file://internal/handler/brand.go#L26-L50) - [internal/handler/model.go:26-51](file://internal/handler/model.go#L26-L51) - [internal/handler/model_list.go:26-57](file://internal/handler/model_list.go#L26-L57) - [internal/handler/ota.go:23-145](file://internal/handler/ota.go#L23-L145) - [internal/handler/device.go:27-83](file://internal/handler/device.go#L27-L83) - [internal/handler/share_code.go:40-125](file://internal/handler/share_code.go#L40-L125) - [internal/handler/share_code.go:192-211](file://internal/handler/share_code.go#L192-L211) - [internal/handler/share_code.go:228-279](file://internal/handler/share_code.go#L228-L279) - [internal/handler/curve.go:145-198](file://internal/handler/curve.go#L145-L198) ### 最佳实践建议 - **模型扩展** - 引入显式的校验与转换层,如参数清洗、长度限制、正则校验等。 - 对可空字段提供默认值策略,避免前端空值判断复杂化。 - OTA模型支持复杂的升级策略,建议在业务层添加更多的参数验证。 - 分享码模型支持多种设备型号,建议添加设备型号验证和限制。 - **更新**:OTA模型简化后,减少了字段验证的复杂度,但仍需确保核心字段的完整性。 - **更新**:OTATargetDevice模型简化后,灰度升级设备管理更加直观,减少了类型判断的复杂性。 - **版本管理与向后兼容** - 通过 API 版本号(如 /api/v1)隔离变更;新增字段采用可选策略,保持旧字段必填。 - 对于破坏性变更,提供迁移脚本与双写策略。 - OTA升级策略的变更需要谨慎处理,确保向后兼容性。 - 分享码功能的新增不影响现有API,保持向前兼容。 - **更新**:OTA模型的简化属于向后兼容的重构,不会影响现有API调用。 - **更新**:OTATargetDevice模型的重构属于概念性重构,从"定向设备"到"灰度升级设备",保持了API的向后兼容性。 - **性能优化** - 为高频查询字段建立索引;避免 SELECT *,仅选择必要字段。 - 对大列表启用可选 Base64 编码;结合分页与缓存策略。 - 设备信息使用Redis缓存,定期批量持久化到数据库。 - OTA查询使用复合索引,支持快速定位最新OTA记录。 - 分享码使用Redis缓存,支持TTL自动过期和分布式锁。 - 目标曲线使用Redis缓存,优化fr数据的独立存储。 - **更新**:OTA查询现在使用简化的字段列表,减少了查询开销。 - **更新**:OTA查询现在使用灰度升级设备概念,简化了设备匹配逻辑,提高了查询性能。 - **错误处理与可观测性** - 统一错误码与消息格式;记录关键链路日志;对数据库与外部服务增加超时与重试。 - OTA查询失败需要详细的日志记录,包括参数、查询结果等。 - 设备持久化任务需要监控执行状态和错误日志。 - 分享码持久化任务需要监控Redis队列状态和数据库插入结果。 - 目标曲线查询需要监控S3访问权限和CSV文件读取。 - **更新**:OTA灰度升级设备查询失败需要详细的日志记录,包括设备MAC地址和OTA ID。 - **安全考虑** - OTA下载链接需要安全性验证,防止恶意下载。 - 设备信息上报需要参数验证,防止注入攻击。 - 黑名单和灰度升级设备管理需要权限控制和审计日志。 - 分享码功能需要防止暴力破解,建议添加频率限制。 - 分享码删除操作需要MAC地址验证,防止越权操作。 - EQ数据存储需要JSON格式验证,防止恶意数据注入。 - **更新**:灰度升级设备管理需要MAC地址验证,防止越权访问。 - **监控与运维** - 添加Redis连接池监控,确保缓存层稳定运行。 - 添加数据库连接池监控,避免连接泄漏。 - 添加任务调度监控,确保持久化任务正常执行。 - 添加分布式锁监控,防止死锁和资源竞争。 - 添加S3访问监控,确保CSV文件读取正常。 - **更新**:监控OTA表结构变化,确保简化的字段结构得到正确应用。 - **更新**:监控ota_target_device表结构变化,确保type字段已被移除,验证灰度升级设备查询逻辑。