更新了前端构建产物包括JavaScript、CSS和HTML文件,主要涉及以下变更: 1. 新增了多个组件和工具函数,包括异常页面组件、iframe组件等 2. 更新了活动管理、产品管理、优惠券管理等业务模块 3. 优化了构建配置和依赖管理 4. 修复了一些样式和功能问题 5. 更新了测试相关文件 同时更新了部分后端服务接口和测试用例。这些变更主要是为了支持新功能和改进现有功能的用户体验。
6.1 KiB
项目架构对齐
-
后端框架:
gin(internal/pkg/core),统一中间件与响应封装 -
路由分组:
internal/router/router.go下 APP 公开/鉴权分组可扩展products资源 -
鉴权:APP 端采用
core.WrapAuthHandler(intc.AppTokenAuthVerify),Authorization: Bearer <token> -
ORM/DB:
gorm+gorm/gen(internal/repository/mysql/dao/Query),读写分离GetDbR/GetDbW -
Swagger:通过注释生成(
swaggo/swag),挂载GET /swagger/*any -
商品相关模型:
product(SPU)、sku、category、spec、spec_option、product_spec、sku_spec_value、推荐位recommendation_slot/item
接口设计
1) 商品列表
-
路径:
GET /api/app/products -
鉴权:需要(App Token)
-
请求参数:
-
page(默认1)pageSize(默认20,最大50) -
categoryId(可选) -
priceMin、priceMax(可选,闭区间) -
salesMin(可选) -
inStock(布尔,可选,默认true,仅展示可售) -
sortBy(sales|price|createdAt)order(asc|desc,默认desc)
-
-
业务规则:只返回
status=上架的 SPU;inStock=true时需至少一个 SKUstock-stock_locked>0 -
响应结构:
{
"total": 1234,
"currentPage": 1,
"pageSize": 20,
"list": [
{
"id": 1001,
"name": "羽绒服",
"mainImage": "https://.../xx.jpg",
"price": 299.00,
"sales": 5230,
"inStock": true,
"categoryId": 12
}
]
}
-
过滤/排序实现:
-
基于
product表status/category_id/sales_count/created_at/price_min/price_max组合条件 -
inStock通过子查询/EXISTS 关联sku计算有效库存
-
2) 商品详情
-
路径:
GET /api/app/products/:id -
鉴权:需要(App Token)
-
业务规则:SPU
status=上架且可售;下架/缺货返回业务态错误码 -
响应结构:
{
"id": 1001,
"name": "羽绒服",
"album": ["https://.../1.jpg", "https://.../2.jpg"],
"priceRange": {"min": 199.00, "max": 399.00},
"sales": 5230,
"stock": {"total": 235, "available": 220},
"specs": [
{"name": "颜色", "options": ["黑色", "白色"]},
{"name": "尺码", "options": ["M", "L", "XL"]}
],
"description": "高蓬松保暖...",
"service": ["7天无理由", "运费险"],
"recommendations": [
{"id": 1002, "name": "羽绒马甲", "mainImage": "...", "price": 199.00}
]
}
-
规格/相册/描述来源:
-
相册:
product.images_json或关联表(若存在),解析为数组 -
规格:
product_spec+spec+spec_option聚合; -
描述/服务保障:从
product富文本字段(或扩展表)读取
-
-
推荐逻辑:
-
优先使用
recommendation_slot.scene='detail_related'的绑定数据 -
兜底:同类目类目内
sales_countTop N(去重当前商品)
-
路由与代码结构
-
路由注册:
internal/router/router.go-
appAuthGroup := router.Group("/api/app", core.WrapAuthHandler(intc.AppTokenAuthVerify)) -
appAuthGroup.GET("/products", product.New(repo, logger).List) -
appAuthGroup.GET("/products/:id", product.New(repo, logger).Detail)
-
-
Handler:
internal/api/product/list_app.go、internal/api/product/detail_app.go- 统一入参校验、容错与错误码
-
Service:
internal/service/product/service.go- 封装查询、库存计算、推荐聚合、缓存命中
-
DAO查询:使用
dao.Query与GetDbR -
DTO:
internal/api/product/dto.go(列表项与详情结构体)
鉴权与权限
-
使用现有 APP Token 验证中间件;Swagger
@Security LoginVerifyToken -
接口动作无需RBAC(面向APP用户),但保留限流与风控扩展点
性能与优化(500ms SLA)
-
索引:
-
product(status, category_id, sales_count, created_at)复合索引 -
sku(product_id, status)、sku(stock, stock_locked)参与计算库存
-
-
查询:
-
列表:单次查询 +
EXISTS子查询校验库存;分页使用LIMIT/OFFSET(页码≤100) -
详情:读取 SPU + 聚合
SUM(stock-stock_locked)+ 规格与相册多表查询
-
-
缓存:
-
本地 TTL 缓存:
-
列表:键
list:{filters}:{page}:{pageSize},TTL 30s,命中后直接返回 -
详情:键
detail:{id},TTL 60s;库存变更事件可主动失效(后续扩展)
-
-
并发合并:使用
singleflight避免热点详情击穿
-
-
传输:仅必要字段;GZIP 已由中间件统一处理
-
限流:
/products每用户每秒 ≤10(后续中间件实现,可选)
错误码与校验
-
下架:
PRODUCT_OFFSHELF(HTTP 200,业务码),提示“商品已下架” -
缺货:
PRODUCT_OUT_OF_STOCK -
参数错误:
INVALID_PARAM(页码、价格区间校验) -
统一响应封装沿用
internal/pkg/core/context.go
Swagger文档
-
在两个 Handler 顶部添加注释:
-
@Summary、@Description、@Tags products -
@Param(列出查询参数与类型) -
@Success 200 {object} ListResp/DetailResp -
@Router /api/app/products [get]、/api/app/products/{id} [get] -
@Security LoginVerifyToken
-
-
生成后可在
http://127.0.0.1:9991/swagger/index.html查看
单元测试
-
Handler:
httptest.NewServer+ 构造Authorization头,校验分页与过滤、错误码 -
Service:使用内存/模拟 DAO(或事务性测试库)覆盖:库存计算、规格聚合、推荐兜底
-
覆盖率目标:核心逻辑 ≥70%
压力测试
-
工具:
hey或wrk -
示例:
-
列表:
hey -n 5000 -c 100 'http://localhost:9991/api/app/products?page=1&pageSize=20' -
详情:
wrk -t4 -c200 -d30s 'http://localhost:9991/api/app/products/1001'
-
-
目标:P95 ≤ 500ms,错误率 < 0.1%
联调与交付
-
与前端约定字段与筛选参数;提供响应示例与错误码表
-
提供 Swagger 文档与可复用的 Postman/HTTP 文件
-
完成线上/测试环境联调回归
验收标准
-
两个接口完成并通过单元与压力测试
-
Swagger 文档完整,含请求/响应示例
-
P95 响应时间 ≤ 500ms(测试环境数据量下)
-
鉴权与状态校验生效;缓存命中率提升热点访问性能