项目:RatingRecommend(卡牌评级小程序-推荐服务) 日期:2026-06-24 作者:gengjintao(大侠)/ Claude 协助 状态:已评审,待转实现计划
提供一个无状态的计算型 REST 接口:接收一批卡的识别特征(含图片),为每张卡推荐评级时效档位,再按时效将卡聚合为"多个订单建议",并给出每卡单价、订单数量与总计金额。
本期做:
本期不做(YAGNI):
| # | 决策 | 说明 |
|---|---|---|
| D1 | 时效档位直接用 EvaluateEfficiencyEnum.code |
普通=1 / 快速=2 / 闪评=3,天然有序,与现有订单口径一致。 |
| D2 | 交付形态 = 独立 REST 接口(全链路) | POST /api/recommend/efficiency。 |
| D3 | 匹配策略 = 全等优先 + 系列主导模糊降级 + 兜底 | 降级阶梯见 §6.1,命中即止。 |
| D4 | 分组 = 同时效精确分组 | 相同最终时效归一个订单建议,按档位升序出 groupNo,最多 3 单;分组逻辑抽象为纯类,容差聚类后续扩展。 |
| D5 | 价格来源 = 订单服务(order-service),实现预留口子 | 抽象 EfficiencyPriceProvider,本期可占位/降级;订单服务未接通时单价/总计为 null("待计算"),不阻断推荐。 |
| D6 | 降级查询实现 = 多次精确 SQL | Mapper 按 L1/L2/L3 提供 3 个查询,Service 逐级调用,走索引、DB 友好、逻辑直白。 |
| D7 | 接口不强制登录 | 纯计算无需用户上下文,沿用现有放行策略。 |
| D8 | 规则数据只读 | 规则表数据由数仓同步 / 人工维护;本功能不产生任何写库语句。 |
t_rating_recommend_rule),标注"⚠️ 需大侠评审确认后手动执行",执行器不主动对数据库运行任何写操作。POST /api/recommend/efficiencyRecommendRequest:
{
"cards": [
{
"clientCardId": "c1",
"player": "Jordan",
"year": "1986",
"series": "Fleer",
"cardSet": "Base",
"frontImageUrl": "http://x/c1f.jpg",
"backImageUrl": "http://x/c1b.jpg"
}
]
}
clientCardId:前端为每张卡生成的临时标识,仅透传、不入库,用于回指卡归属的订单。player / year / series / cardSet。frontImageUrl / backImageUrl,仅透传回显。AjaxResult.data = RecommendResultVO{
"totalCards": 3,
"orderCount": 2,
"grandTotal": 360.00,
"orders": [
{
"groupNo": 1,
"efficiency": 3,
"efficiencyDesc": "闪评",
"unitPrice": 120.00,
"cardCount": 2,
"totalAmount": 240.00,
"cards": [
{
"clientCardId": "c1",
"player": "Jordan", "year": "1986", "series": "Fleer", "cardSet": "Base",
"recommendEfficiency": 3,
"matchLevel": "EXACT",
"unitPrice": 120.00,
"frontImageUrl": "http://x/c1f.jpg",
"backImageUrl": "http://x/c1b.jpg"
}
]
}
]
}
字段说明:
groupNo、efficiency/efficiencyDesc(订单推荐时效)、unitPrice(该档单价)、cardCount(卡数量)、totalAmount(订单总计 = 单价 × 数量)。recommendEfficiency、matchLevel(命中层级 EXACT/L2/L3/DEFAULT)、unitPrice、图片透传。grandTotal(所有订单合计)。unitPrice/totalAmount/grandTotal = null(前端显示"待计算"),不阻断推荐主体结果。EXACT : player + year + series + cardSet 全等
L2 : series + cardSet + year
L3 : series + cardSet
DEFAULT: 兜底默认档(可配置,默认 普通=1)
series 为空,则 L2/L3 均无法命中 → 直接兜底)。(recommendEfficiency, matchLevel)。OrderGrouper)groupNo(普通→快速→闪评),最多 3 组。EfficiencyPriceProvider)Map<Integer, BigDecimal> loadEfficiencyPrices()(时效 code → 单价)。ProductServiceLevelCacheDTO:含 timeLimit 字符串 + price),按"timeLimit 字符串 → EvaluateEfficiencyEnum.code"映射(映射规则配置化)。com.mangoo.rating.recommend.*)mango-common
request/recommend/RecommendRequest.java、request/recommend/RecommendCardDTO.javaresponse/recommend/RecommendResultVO.java、response/recommend/OrderSuggestionVO.java、response/recommend/RecommendCardVO.javapo/RatingRecommendRulePO.javaenums/MatchLevelEnum.java(EXACT/L2/L3/DEFAULT)enums/EvaluateEfficiencyEnum.javamango-infrastructure
mapper/RatingRecommendRuleMapper.java + resources/mapper/RatingRecommendRuleMapper.xml(仅 SELECT)mango-manager
manager/RatingRecommendRuleManager.java + manager/impl/RatingRecommendRuleManagerImpl.javamango-domain
service/RecommendService.java + service/impl/RecommendServiceImpl.java(编排)service/recommend/OrderGrouper.java(纯类,分组)service/recommend/EfficiencyPriceProvider.java + 实现(价格口子 + 降级)mango-application
app/controller/RecommendController.javaconfig/RecommendProperties.java(默认兜底档 + 时效字符串映射配置)OrderGrouperTest、RecommendServiceImplTest(Mockito)DDL
docs/superpowers/specs/ddl/2026-06-24-rating-recommend-rule.sql(待评审执行)CREATE TABLE IF NOT EXISTS t_rating_recommend_rule (
id BIGSERIAL PRIMARY KEY,
player VARCHAR(255) NOT NULL,
year VARCHAR(64) NOT NULL,
series VARCHAR(255) NOT NULL,
card_set VARCHAR(255) NOT NULL,
recommend_efficiency SMALLINT NOT NULL,
effective_time TIMESTAMP,
create_time TIMESTAMP NOT NULL DEFAULT now(),
update_time TIMESTAMP NOT NULL DEFAULT now(),
del_flag SMALLINT NOT NULL DEFAULT 0
);
COMMENT ON TABLE t_rating_recommend_rule IS '评级时效推荐规则表(数仓沉淀,只读查询)';
-- 支撑系列主导降级查询
CREATE INDEX IF NOT EXISTS idx_rrr_series_set_year ON t_rating_recommend_rule (series, card_set, year);
-- 支撑全等命中查询
CREATE INDEX IF NOT EXISTS idx_rrr_feature ON t_rating_recommend_rule (player, year, series, card_set);
当前启动类 RatingRecommendApplication 上 exclude = {DataSourceAutoConfiguration.class},数据源未启用。本功能需查询规则表,实现计划第一步须先启用数据源、接通 PostgreSQL(移除排除项并校验既有配置)。
OrderGrouper:纯 JUnit5,TDD 先行,覆盖空/单卡/全同/多档乱序。@SpringBootTest 冒烟 + 手动接口验证;不写无断言的假测试。recommend.*)recommend:
default-efficiency: 1 # 兜底默认档(EvaluateEfficiencyEnum.code)
# 服务等级时效字符串 → 时效 code 映射(报价用),示例:
time-limit-mapping:
"普通": 1
"快速": 2
"闪评": 3
OrderGrouper 已抽象,便于扩展)。