餐饮 SaaS 优惠券系统架构演进(一):从“券配置”到“用户权益”——领域模型与数据建模复盘
本文基于真实后端代码做工程复盘。业务标识、账号、域名、门店/商户数据均做脱敏类名与通用表名用于说明真实技术结构。本文重点不是教你“建一张 coupon 表”而是解释为什么优惠券一旦进入生产系统就必须区分模板、范围、用户权益、规则快照与订单计价。1. 背景与问题优惠券为什么很快就不再是 CRUD最初需求通常只是“配置一张券、用户领取、下单减钱”。但当前项目已经支持折扣券、满减券、商品兑换券并进一步叠加门店范围、场景范围、商品白名单/黑名单、分类范围、会员领取限制、转赠、周期使用、分享与首页弹窗等能力。维度当前代码中的代表字段/对象为什么会变复杂券类型DiscountCoupon / FullReductionCoupon / ProductExchangeCoupon不同优惠动作需要不同计算模型适用范围storeScope / sceneMask / productScopeType一张券并不是对整个订单无条件生效发放限制totalIssueCount / perUserReceiveLimit / audienceType领取本身就是受约束的权益生成历史规则UserClaim.couponSnapshot模板会变但已经发给用户的权益不能跟着漂移订单关联usedOrderId / orderSerialNumber / status券进入订单后有独立生命周期2. 目标与约束这套模型实际需要同时满足五个目标可配置、可领取、可计算、可追溯、可演进。其中最关键的约束是运营配置允许修改但历史用户权益和订单计价口径必须稳定。图 1当前优惠券领域架构基于真实代码关系抽象3. 真实领域模型三类券不是一个“大而全 coupon 表”当前项目没有使用单表 type 字段承载所有规则而是为三类券分别建立模板表和用户领取表。这种设计牺牲了一部分公共代码复用但换来了字段语义清晰和类型隔离。券类型模板实体 / 表用户权益实体 / 表核心优惠动作折扣券DiscountCoupon / discount_couponDiscountCouponUserClaim / discount_coupon_user_claim按折扣率计算可限制最大优惠数量/金额满减券FullReductionCoupon / full_reduction_couponFullReductionCouponUserClaim / full_reduction_coupon_user_claim达到门槛后减固定金额商品兑换券ProductExchangeCoupon / product_exchange_couponProductExchangeCouponUserClaim / product_exchange_coupon_user_claim兑换指定商品/规格4. ERD模板、范围关系与用户领取实例图 2折扣券表族 ERD其余两类券采用相同模式这里需要纠正一个很容易误判的点项目没有独立的 coupon_snapshot 表。coupon_snapshot是用户领取表上的 JSON 字段由DiscountCouponSnapshotTypeHandler/ 对应 TypeHandler 完成对象与 JSON 的映射。5. 为什么快照必须跟着用户券走在DiscountCouponUserClaim中couponSnapshot的注释明确写着“在领取时固化用于后续展示与使用逻辑按照领取时的规则执行”。领取实现会把门店 ID、商品白/黑名单、分类 ID、门槛、折扣率、最大优惠、使用周期等一起复制进快照。图 3模板修改与历史用户权益之间的隔离机制领取时的数据写入顺序1. SELECT discount_coupon ... FOR UPDATE 2. 校验 status / canUserClaim / activity time / audience 3. 校验每人限领次数、总发行上限 4. 计算 validStartTime / validEndTime 5. 查询 store/product/category 关系 6. 构建 DiscountCouponRuleSnapshot 7. INSERT discount_coupon_user_claim(coupon_snapshot...) 8. 发布用户券过期延迟消息6. 方案取舍为什么当前设计“合理但开始出现演进压力”图 4当前数据模型的主要收益与技术债从 Code Review 看当前建模已经解决了“模板与权益混淆”这个最关键的问题但新的边界问题已经出现例如DiscountCoupon同时包含 popupEnabled、popupImageUrl、shareImageUrl、shareTitle 等展示字段说明营销展示能力正在向券模板实体渗透。7. Troubleshooting / RCA为什么修改模板不能影响已领券Symptoms典型症状是运营后台修改了券的门槛、折扣或适用范围后历史用户在券包看到的说明或下单优惠发生变化。Investigation排查重点不是“前端缓存”而是确认展示和计价到底读取模板当前值还是读取user_claim.coupon_snapshot。当前实现中用户券 VO 与优惠计算服务都已经优先从领取快照读取规则。Root Cause如果系统直接以模板作为唯一事实来源本质上是把“可变配置”误当成“已经授予用户的业务事实”。Resolution领取时固化快照订单计价与用户券展示读取快照模板只控制未来领取实例。Verification修改模板后验证两组用户修改前已领取用户保持旧规则修改后新领取用户获得新规则订单计算与券包展示应分别与各自快照一致。Lessons Learned配置数据 ≠ 业务事实。只要一个配置会影响已经产生的订单、权益、合同或结算结果就应该考虑版本化或快照化。8. 后续优化方向当前信号建议展示职责拆分coupon 实体已包含 popup/share 字段考虑 CouponDisplayConfig / CampaignPresentation 边界避免模板继续膨胀公共能力抽象三类券存在大量同构字段和同构 Service先抽公共领域接口与策略不急于合并数据库表快照兼容性JSON TypeHandler 强依赖 DTO 结构快照增加 schemaVersion变更字段保持向后兼容审计目前核心事实分散在 claim/status/order 关联中补充统一权益操作日志或事件流水9. 总结当前优惠券系统的核心价值不在“支持三种券”而在于已经形成了模板配置 → 适用范围 → 用户领取实例 → 规则快照 → 订单计价的业务事实链。后面的并发、计价、补偿和营销平台化都是建立在这个数据模型之上。下一篇《餐饮 SaaS 优惠券系统架构演进二领券链路——行锁、限领、快照、过期消息与批量发券》

相关新闻

【车间调度】基于卷积神经网络的柔性作业车间调度问题的两阶段算法附Matlab代码

【车间调度】基于卷积神经网络的柔性作业车间调度问题的两阶段算法附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、算法改进、程序设计科研仿真。🍎 往期回顾关注个人主页:完整代码获取 定制创新 论文复现私信🍊个人信条:做科研&#xff0c…

2026/10/4 7:43:09 阅读更多 →
单视频三维实时重构支撑口岸突发事件平战快速切换

单视频三维实时重构支撑口岸突发事件平战快速切换

一、方案背景陆路口岸、港区码头、界河限定管控区是国门安全核心节点,常态业务涵盖通关查验、集装箱装卸、船舶靠离泊、口岸巡逻值守,核心目标为有序通关、日常边界监测、隐患排查;一旦发生偷渡闯关、人员非法登轮、围网破损越界、危险品夹带…

2026/10/4 7:40:59 阅读更多 →
算法 --模拟

算法 --模拟

什么是模拟算法? 模拟算法,顾名思义,就是按照题目描述的规则,一步一步地用代码“扮演”或“重演”整个过程,最终得到结果。 它通常没有特别高深的数学公式或复杂的算法推导,核心难点在于理清逻辑、处理边…

2026/10/4 7:40:58 阅读更多 →

最新新闻

字节的 manus 来了!扣子空间邀请码你拿到了吗?TaoToken 统一 Key 接入 MCP 智能体实战

字节的 manus 来了!扣子空间邀请码你拿到了吗?TaoToken 统一 Key 接入 MCP 智能体实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:54:41 阅读更多 →
Jev本地部署实战:从硬件算账到Agent编排的完整指南

Jev本地部署实战:从硬件算账到Agent编排的完整指南

1. 从热搜词里读懂"Jev本地部署"到底在解决什么问题最近一段时间,后台被问得最多的一类问题就是"Jev 能不能本地跑""开源版 Jev 部署难不难""有没有一份能照着抄的部署流程"。热搜词里同时出现了 Jev、Laya、本地部署、Age…

2026/10/4 9:54:41 阅读更多 →
Mooncake Store 的 NVMe KV 后端设计:从逻辑对象到固定尺寸 KV 命令的落地实践

Mooncake Store 的 NVMe KV 后端设计:从逻辑对象到固定尺寸 KV 命令的落地实践

人工智能大模型模型推理服务后端 【免费下载链接】Mooncake Mooncake is the serving platform for Kimi, a leading LLM service provided by Moonshot AI. 项目地址: https://gitcode.com/gh_mirrors/mo/Mooncake 点击查看 免费下载 导读 本文基于 Mooncake 开源…

2026/10/4 9:54:41 阅读更多 →
DsHidMiniInteropUnavailableException 详解:DsHidMini IPC 不可用时的异常处理与排查指南

DsHidMiniInteropUnavailableException 详解:DsHidMini IPC 不可用时的异常处理与排查指南

驱动开发硬件开发 【免费下载链接】DsHidMini Virtual HID Mini-user-mode-driver for Sony DualShock 3 Controllers 项目地址: https://gitcode.com/gh_mirrors/ds/DsHidMini 点击查看 免费下载 导读 DsHidMiniInteropUnavailableException 是 DsHidMini 驱动 I…

2026/10/4 9:54:41 阅读更多 →
openwifi 全双工 WiFi 传感雷达实战:基于 Self-TX 信号 CSI 的联合雷达与通信(Joint Radar and Communication)

openwifi 全双工 WiFi 传感雷达实战:基于 Self-TX 信号 CSI 的联合雷达与通信(Joint Radar and Communication)

通信网络硬件开发嵌入式 【免费下载链接】openwifi open-source IEEE 802.11 WiFi baseband FPGA (chip) design: driver, software 项目地址: https://gitcode.com/gh_mirrors/op/openwifi 点击查看 免费下载 openwifi 平台的基带具备"全双工(Ful…

2026/10/4 9:54:41 阅读更多 →
如何在5分钟内搭建Cloudflare OS工作空间?新手必备的完整指南

如何在5分钟内搭建Cloudflare OS工作空间?新手必备的完整指南

如何在5分钟内搭建Cloudflare OS工作空间?新手必备的完整指南 【免费下载链接】cloudflare-os Agent workspace built on Cloudflare Workers for creating documents, building apps, and running agents with your company’s context and systems. 项目地址: h…

2026/10/4 9:53:40 阅读更多 →

日新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/3 9:42:36 阅读更多 →