Files
app-api/.qoder/repowiki/zh/content/核心模块/数据模型.md
T
2026-06-22 13:35:37 +08:00

1179 lines
54 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 数据模型
<cite>
**本文档引用的文件**
- [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/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)
- [sql/ota_target_device.sql](file://sql/ota_target_device.sql)
- [cmd/server/main.go](file://cmd/server/main.go)
</cite>
## 更新摘要
**变更内容**
- 新增分享代码数据模型(ShareCodeData)和相关处理流程
- 新增目标数据模型(Target),支持曲线目标配置
- 增强OTA模型,支持布尔值序列化和更多字段
- 新增分享码持久化任务和Redis缓存机制
- 扩展路由配置以支持分享码相关API端点
## 目录
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-133](file://internal/handler/ota.go#L14-L133)
- [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-67](file://internal/model/ota.go#L5-L67)
- [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-44](file://sql/ota.sql#L23-L44)
- [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)
- [sql/ota_target_device.sql:23-31](file://sql/ota_target_device.sql#L23-L31)
- [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地址。
- OTATargetDeviceOTA定向设备,记录允许特定设备升级的白名单或黑名单。
- **分享码模型层**
- 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-67](file://internal/model/ota.go#L5-L67)
- [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-133](file://internal/handler/ota.go#L23-L133)
- [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 标签用于序列化输出。
- **查询流程**
- 支持按品牌名精确匹配或按型号名模糊匹配,返回 []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模型:
- id:整数,主键,自增。
- verCode:整数,版本号,用于排序。
- verName:字符串,版本名称。
- url:字符串,固件下载地址。
- md5:字符串,固件MD5校验值。
- forceBoolInt,是否强制升级(true/false)。
- desc:字符串指针,升级描述。
- model:字符串指针,对应设备型号。
- hw:整数,硬件版本号。
- targetBoolInt,是否定向升级(true/false)。
- betaBoolInt,是否灰度发布(true/false)。
- pawVerCode:整数,配套软件版本号。
- pawVerName:字符串,配套软件版本名称。
- pawUrl:字符串,配套软件下载地址。
- pawMD5:字符串,配套软件MD5校验值。
- startTime:时间戳指针,升级开始时间。
- endTime:时间戳指针,升级结束时间。
- status:整数,状态(1-可用,0-不可用)。
- BlackList模型:
- id:整数,主键,自增。
- ota_id:整数,关联OTA记录ID。
- mac:字符串,设备MAC地址。
- create_at:时间戳,创建时间。
- OTATargetDevice模型:
- id:整数,主键,自增。
- ota_id:整数,关联OTA记录ID。
- mac_addr:字符串,设备MAC地址。
- type:整数,类型(1-白名单,2-黑名单)。
- create_at:时间戳,创建时间。
- **业务含义**
- 支持复杂的固件升级策略,包括强制升级、灰度发布、定向升级和黑名单管理。
- **数据库映射**
- 表名:ota、black_list、ota_target_device。
- 字段:完整映射关系详见数据库表结构。
- **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
+int pawVerCode
+string pawVerName
+string pawUrl
+string pawMD5
+*time startTime
+*time endTime
+int status
}
class BlackList {
+int id
+int ota_id
+string mac
+time create_at
}
class OTATargetDevice {
+int id
+int ota_id
+string mac_addr
+int type
+time create_at
}
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-67](file://internal/model/ota.go#L29-L67)
- [internal/repository/ota.go:19-159](file://internal/repository/ota.go#L19-L159)
- [sql/ota.sql:24-44](file://sql/ota.sql#L24-L44)
- [sql/ota_target_device.sql:24-31](file://sql/ota_target_device.sql#L24-L31)
**章节来源**
- [internal/model/ota.go:5-67](file://internal/model/ota.go#L5-L67)
- [internal/repository/ota.go:19-159](file://internal/repository/ota.go#L19-L159)
- [sql/ota.sql:23-44](file://sql/ota.sql#L23-L44)
- [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地址。
- EqDataJSONEQ数据快照。
- 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:字符串,目标曲线标签。
- ReadCSVBoolInt,是否从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升级信息。
- **设备处理器特殊逻辑**
- 将设备信息写入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-133](file://internal/handler/ota.go#L23-L133)
- [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记录。
- 支持黑名单检查和定向设备检查。
- 提供多种查询策略以适应不同的升级场景。
- **设备查询**
- 支持按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 依赖 RepositoryRepository 依赖 sql.DBModel 为纯数据结构。
- 统一响应体与编码层被 Handler 调用,降低重复逻辑。
- 新增的Redis依赖用于分享码缓存和设备信息缓存。
- 分享码功能依赖Redis缓存和数据库的双重存储。
- 目标曲线功能依赖CurveRepository和CurveCache。
- **外部依赖**
- 数据库:MySQL,通过 sql.DB 访问。
- 日志:zap。
- Web 框架:Gin。
- 搜索:MeilisearchModelListHandler)。
- 缓存:RedisDevice、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-133](file://internal/handler/ota.go#L14-L133)
- [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 的范围。
- **扫描与内存**
- 使用 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-44](file://sql/ota.sql#L24-L44)
- [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访问权限。
- **排查步骤**
- 查看日志:处理器记录错误日志,统一响应体返回错误码。
- 核对数据库:确认表结构与索引是否存在。
- 验证参数:确认查询参数是否符合预期。
- 检查Redis:确认设备信息、分享码数据是否正确写入Redis缓存。
- 监控任务:确认设备持久化任务和分享码持久化任务是否按预期执行。
- 检查分布式锁:确认分享码操作的分布式锁状态和超时处理。
**章节来源**
- [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-81)
- [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缓存层提供了高性能的临时数据存储和分布式锁机制。建议在后续迭代中引入显式的校验与转换层,增强健壮性与可维护性,同时考虑添加更多的监控指标和告警机制。
## 附录
### 数据库表结构与模型映射对照
- **表: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、pawVerCode、pawVerName、pawUrl、pawMd5、startTime、endTime、status。
- 约束:无显式约束。
- **表:black_list**
- 字段:id(主键)、ota_id、mac、create_at。
- 约束:无显式约束。
- **表:ota_target_device**
- 字段:id(主键)、ota_id、mac_addr、type、create_at。
- 约束:无显式约束。
- **表: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.pawVerCode ↔ ota.pawVerCode
- OTA.pawVerName ↔ ota.pawVerName
- OTA.pawUrl ↔ ota.pawUrl
- OTA.pawMD5 ↔ ota.pawMD5
- OTA.startTime ↔ ota.startTime
- OTA.endTime ↔ ota.endTime
- OTA.status ↔ ota.status
- BlackList.id ↔ black_list.id
- BlackList.ota_id ↔ black_list.ota_id
- BlackList.mac ↔ black_list.mac
- BlackList.create_at ↔ black_list.create_at
- OTATargetDevice.id ↔ ota_target_device.id
- OTATargetDevice.ota_id ↔ ota_target_device.ota_id
- OTATargetDevice.mac_addr ↔ ota_target_device.mac_addr
- OTATargetDevice.type ↔ ota_target_device.type
- OTATargetDevice.create_at ↔ 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-44](file://sql/ota.sql#L24-L44)
- [sql/ota_target_device.sql:24-31](file://sql/ota_target_device.sql#L24-L31)
- [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-67](file://internal/model/ota.go#L29-L67)
- [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
- 参考路径:[internal/handler/ota.go:23-133](file://internal/handler/ota.go#L23-L133)
- **设备信息上报**
- 路由:/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-133](file://internal/handler/ota.go#L23-L133)
- [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模型支持复杂的升级策略,建议在业务层添加更多的参数验证。
- 分享码模型支持多种设备型号,建议添加设备型号验证和限制。
- **版本管理与向后兼容**
- 通过 API 版本号(如 /api/v1)隔离变更;新增字段采用可选策略,保持旧字段必填。
- 对于破坏性变更,提供迁移脚本与双写策略。
- OTA升级策略的变更需要谨慎处理,确保向后兼容性。
- 分享码功能的新增不影响现有API,保持向前兼容。
- **性能优化**
- 为高频查询字段建立索引;避免 SELECT *,仅选择必要字段。
- 对大列表启用可选 Base64 编码;结合分页与缓存策略。
- 设备信息使用Redis缓存,定期批量持久化到数据库。
- OTA查询使用复合索引,支持快速定位最新OTA记录。
- 分享码使用Redis缓存,支持TTL自动过期和分布式锁。
- 目标曲线使用Redis缓存,优化fr数据的独立存储。
- **错误处理与可观测性**
- 统一错误码与消息格式;记录关键链路日志;对数据库与外部服务增加超时与重试。
- OTA查询失败需要详细的日志记录,包括参数、查询结果等。
- 设备持久化任务需要监控执行状态和错误日志。
- 分享码持久化任务需要监控Redis队列状态和数据库插入结果。
- 目标曲线查询需要监控S3访问权限和CSV文件读取。
- **安全考虑**
- OTA下载链接需要安全性验证,防止恶意下载。
- 设备信息上报需要参数验证,防止注入攻击。
- 黑名单和白名单管理需要权限控制和审计日志。
- 分享码功能需要防止暴力破解,建议添加频率限制。
- 分享码删除操作需要MAC地址验证,防止越权操作。
- EQ数据存储需要JSON格式验证,防止恶意数据注入。
- **监控与运维**
- 添加Redis连接池监控,确保缓存层稳定运行。
- 添加数据库连接池监控,避免连接泄漏。
- 添加任务调度监控,确保持久化任务正常执行。
- 添加分布式锁监控,防止死锁和资源竞争。
- 添加S3访问监控,确保CSV文件读取正常。