促销卡券系统基本设计:从架构到落地的技术实践
一、卡券类型与生命周期管理
1.1 卡券类型定义
促销卡券系统需支持多种卡券类型以满足不同业务场景需求,主要包括:
- 折扣券:按比例减免订单金额(如满100减20%)
- 满减券:订单金额达阈值后直接减免固定金额(如满200减50)
- 兑换券:用于兑换指定商品或服务(如1积分兑换咖啡)
- 礼品卡:预存金额可分次使用的储值卡(如500元面值礼品卡)
每种卡券需定义核心属性:有效期(绝对时间/相对天数)、使用范围(全品类/指定品类)、叠加规则(是否可与其他优惠同享)、发放渠道(API/页面领取/短信推送)等。例如,某电商平台的”618大促专属券”可设置为仅限6月18日当天使用,且不可与会员折扣叠加。
1.2 生命周期管理
卡券状态机设计需覆盖全流程:
graph TDA[创建] --> B[待领取]B --> C[已领取]C --> D[已使用]C --> E[已过期]C --> F[已作废]D --> G[核销完成]
关键状态转换规则:
- 领取限制:同一用户对同类卡券的领取上限(如每人限领3张)
- 过期处理:到期未使用的卡券自动标记为”已过期”并触发回收逻辑
- 核销验证:使用前需校验卡券状态、有效期、适用范围及用户身份
二、系统架构设计
2.1 分层架构
采用经典三层架构:
┌───────────────┐ ┌───────────────┐ ┌───────────────┐│ Presentation│ │ Application │ │ Data Access ││ Layer │←──→│ Layer │←──→│ Layer │└───────────────┘ └───────────────┘ └───────────────┘↑ ↑ ↑┌─────────────────────────────────────────────────────┐│ Infrastructure Layer ││ (Cache/MQ/DB/Monitor) │└─────────────────────────────────────────────────────┘
- 表现层:提供H5/小程序/APP等多端接入能力
- 应用层:处理卡券创建、发放、核销等核心业务逻辑
- 数据层:实现卡券元数据、用户卡券包、使用记录的持久化
2.2 数据库设计
核心表结构示例:
-- 卡券模板表CREATE TABLE coupon_template (id BIGINT PRIMARY KEY,name VARCHAR(100) NOT NULL,type TINYINT NOT NULL COMMENT '1:折扣 2:满减 3:兑换',discount DECIMAL(5,2) COMMENT '折扣率',reduce_amount DECIMAL(10,2) COMMENT '满减金额',total_count INT DEFAULT 0 COMMENT '总发行量',remaining_count INT DEFAULT 0 COMMENT '剩余数量',start_time DATETIME NOT NULL,end_time DATETIME NOT NULL,status TINYINT DEFAULT 0 COMMENT '0:未生效 1:生效中 2:已下架');-- 用户卡券表CREATE TABLE user_coupon (id BIGINT PRIMARY KEY,template_id BIGINT NOT NULL,user_id BIGINT NOT NULL,code VARCHAR(32) NOT NULL UNIQUE,status TINYINT DEFAULT 0 COMMENT '0:未使用 1:已使用 2:已过期',obtained_time DATETIME NOT NULL,used_time DATETIME,order_id VARCHAR(32) COMMENT '关联订单号');
三、安全与风控机制
3.1 防刷设计
- 领取频率限制:同一IP/设备/用户ID的领取间隔(如每小时最多3次)
- 验证码校验:关键操作(如批量领取)前需完成短信/图形验证码验证
- 行为分析:通过用户行为日志识别异常模式(如短时间内大量领取)
3.2 核销验证
核销接口需实现多重校验:
public boolean verifyCoupon(String couponCode, Long userId, BigDecimal orderAmount) {// 1. 校验卡券是否存在UserCoupon coupon = couponRepository.findByCode(couponCode);if (coupon == null) return false;// 2. 校验卡券状态if (coupon.getStatus() != CouponStatus.UNUSED) return false;// 3. 校验有效期if (isExpired(coupon.getEndTime())) return false;// 4. 校验用户绑定if (!coupon.getUserId().equals(userId)) return false;// 5. 校验使用条件(满减券需满足最低金额)CouponTemplate template = templateRepository.findById(coupon.getTemplateId());if (template.getType() == CouponType.FULL_REDUCTION &&orderAmount.compareTo(template.getThreshold()) < 0) {return false;}return true;}
四、API接口规范
4.1 核心接口列表
| 接口名称 | 请求方法 | 路径 | 关键参数 |
|---|---|---|---|
| 创建卡券模板 | POST | /api/coupon/template | name,type,discount,start_time |
| 发放卡券 | POST | /api/coupon/issue | template_id,user_ids,channel |
| 查询用户卡券列表 | GET | /api/coupon/list | user_id,status,page_num |
| 核销卡券 | POST | /api/coupon/use | coupon_code,order_id,user_id |
4.2 接口响应示例
成功核销响应:
{"code": 200,"message": "success","data": {"coupon_id": 123456,"template_id": 7890,"discount_amount": 50.00,"remaining_amount": 150.00}}
五、性能优化方案
5.1 缓存策略
- 模板缓存:使用Redis缓存卡券模板信息(TTL=5分钟)
- 库存预热:大促前将卡券库存加载至本地缓存
- 分布式锁:使用Redisson实现发放接口的并发控制
5.2 异步处理
关键场景采用消息队列:
// 发放卡券后发送MQ消息rabbitTemplate.convertAndSend("coupon.issue.exchange","coupon.issue.routingKey",new CouponIssueEvent(templateId, userIds));
六、实施建议
- 渐进式上线:先实现基础发放/核销功能,再逐步扩展风控、数据分析模块
- 监控体系:建立卡券使用率、核销率、作废率等核心指标监控
- 灾备方案:数据库主从+定时备份,关键操作记录操作日志
- 合规性:确保卡券规则符合《规范促销行为暂行规定》等法规要求
通过上述设计,可构建一个高可用、高安全的促销卡券系统,既能支撑日常营销活动,也能应对大促期间的流量高峰。实际开发中需根据业务规模调整架构复杂度,中小型业务可采用单体架构简化部署,大型平台建议采用微服务架构实现各模块解耦。