Backend Development 20 min read

Design and Implementation of a Coupon System for a Rental Platform

This article details the design and implementation of a coupon system for a rental platform, covering business flow, database schema, backend services, caching strategies, state management, and future optimization directions to ensure reliable coupon distribution and redemption.

Architecture Digest
Architecture Digest
Architecture Digest
Design and Implementation of a Coupon System for a Rental Platform

Background

The platform is a rental listing service that provides merchants with listing and C‑end exposure functions. It needs a coupon system for holiday marketing, where merchants bind coupons to listings to offer price discounts and attract tenants.

1. Business Overview

The overall process is illustrated in the diagram below. Merchants create activities on the B‑end, sign up for discount campaigns, generate coupons, bind coupons to listings, and users can claim coupons on the C‑end and complete contracts using the coupons.

2. Technical Design

Each step of the workflow is designed with specific data structures and mechanisms.

2.1 Create Activity

2.1.1 Data Table

Activity information requires the following fields:

Registration time window

Activity time window

Coupon type and discount amount

Applicable cities

The concrete table definition is:

CREATE TABLE `t_activity` (
  `activeId` bigint(20) NOT NULL COMMENT '活动ID',
  `title` varchar(256) NOT NULL COMMENT '活动名称',
  `applyStartTime` timestamp NULL DEFAULT NULL COMMENT '报名开始时间',
  `applyEndTime` timestamp NULL DEFAULT NULL COMMENT '报名停止时间',
  `activityStartTime` timestamp NULL DEFAULT NULL COMMENT '活动开始时间',
  `activityEndTime` timestamp NULL DEFAULT NULL COMMENT '活动结束时间',
  `cityIds` varchar(256) NOT NULL COMMENT '覆盖城市,多个逗号分隔',
  `couponType` tinyint(4) NOT NULL DEFAULT '0' COMMENT '优惠类型,1 直减;2 折扣;3免费住N天;4免押金;5特价房',
  `lowerLimit` int NOT NULL DEFAULT 0 COMMENT '优惠数值下限',
  `upperLimit` int NOT NULL DEFAULT 0 COMMENT '优惠数值上限',
  `description` text COMMENT '活动描述',
  `cubeType` smallint(6) NOT NULL DEFAULT '1001' COMMENT '活动类型',
  `foreignId` bigint(20) NOT NULL DEFAULT '0' COMMENT '外部ID',
  `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '活动状态',
  `createTime` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  `updateTime` timestamp NULL DEFAULT NULL COMMENT '更新时间',
  `recordStatus` tinyint(4) NOT NULL DEFAULT '0' COMMENT '数据状态',
  PRIMARY KEY (`activeId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='活动信息表';

2.1.2 Data Retrieval

Merchants filter activities by status and cityIds . The C‑end reads data through a proxy‑pattern cache layer, pushing active data into cache for fast reads.

2.1.3 Activity State Transition

A crontab job runs every minute to check time windows and update the status field accordingly.

2.2 Merchant Coupon Creation

2.2.1 Data Table

CREATE TABLE `t_couponmeta` (
  `couponMetaId` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '券id',
  `appId` int(11) NOT NULL DEFAULT '1' COMMENT '区分建立来源',
  `activeId` bigint(20) NOT NULL DEFAULT '0' COMMENT '活动ID',
  `companyId` bigint(20) NOT NULL COMMENT '公司编号',
  `cityId` int(11) NOT NULL COMMENT '城市id',
  `companyName` varchar(255) DEFAULT NULL COMMENT '公司名称',
  `companyShortName` varchar(255) DEFAULT NULL COMMENT '公司简称',
  `couponType` tinyint(4) NOT NULL COMMENT '优惠券类型',
  `title` varchar(256) NOT NULL COMMENT '优惠券名称',
  `directDiscount` int(11) NOT NULL DEFAULT '0' COMMENT '直减券优惠力度',
  `discount` int(11) NOT NULL DEFAULT '0' COMMENT '折扣力度',
  `freeLive` int(11) NOT NULL DEFAULT '0' COMMENT '免费住n天券',
  `threshold` varchar(256) NOT NULL COMMENT '使用门槛',
  `deduction` tinyint(4) NOT NULL DEFAULT '1' COMMENT '抵扣说明 1首月抵扣,2 平摊到月',
  `totalAmount` int(11) NOT NULL DEFAULT '0' COMMENT '券总数',
  `applyAmount` int(11) NOT NULL DEFAULT '0' COMMENT '已领取总数',
  `activityStartTime` timestamp NULL DEFAULT NULL COMMENT '活动开始时间',
  `activityEndTime` timestamp NULL DEFAULT NULL COMMENT '活动结束时间',
  `startTime` timestamp NULL DEFAULT NULL COMMENT '券使用开始时间',
  `expireTime` timestamp NULL DEFAULT NULL COMMENT '券使用结束时间',
  `status` int(11) NOT NULL DEFAULT '10' COMMENT '10:新建未启用,20:已启用,30:过期, 40 已结束 50 已中止',
  `expireType` tinyint(4) NOT NULL DEFAULT '1' COMMENT '类型:1固定有效期类型,2浮动有效期类型',
  `validPeriod` tinyint(4) NOT NULL DEFAULT '0' COMMENT '浮动有效期(单位:天)',
  `tenantRange` tinyint(1) NOT NULL DEFAULT '1' COMMENT '租客范围枚举值',
  `customScope` varchar(256) NOT NULL DEFAULT '' COMMENT '自定义租客范围',
  `comment` varchar(50) DEFAULT NULL COMMENT '备注',
  `cubeType` smallint(6) NOT NULL DEFAULT '1001' COMMENT '活动类型',
  `updateTime` timestamp NULL DEFAULT NULL COMMENT '更新时间',
  `createTime` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  `recordStatus` tinyint(4) DEFAULT '0' COMMENT '状态 0默认 -1删除',
  PRIMARY KEY (`couponMetaId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='优惠券表';

2.2.2 Data Retrieval

Read operations also use a proxy‑pattern cache to reduce DB pressure for high‑concurrency C‑end queries.

2.2.3 State Transition

Coupon state changes are triggered by the activity state crontab; a message is sent via MQ to update coupon status asynchronously.

2.3 Coupon Binding to Listings

2.3.1 Data Table

CREATE TABLE `t_bindcoupon` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `couponMetaId` int(11) NOT NULL COMMENT '券id',
  `companyId` bigint(20) NOT NULL COMMENT '公司编号',
  `activityStatus` tinyint(4) NOT NULL COMMENT '状态 0 准备中 1 活动中 2 活动结束 券未失效 3 活动结束券失效',
  `houseId` bigint(20) NOT NULL DEFAULT '0' COMMENT '房源id',
  `recordStatus` tinyint(4) NOT NULL COMMENT '数据状态 0 有效,-1 失效',
  `createTime` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  `updateTime` timestamp NULL DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_companyId_couponMetaId` (`companyId`,`couponMetaId`),
  KEY `idx_planeId` (`planeId`),
  KEY `idx_houseid_activitystatus` (`houseId`,`activityStatus`)
) ENGINE=InnoDB AUTO_INCREMENT=17379 DEFAULT CHARSET=utf8 COMMENT='优惠券绑定范围表';

The table records the many‑to‑many relationship between listings and coupons and enforces limits on the number of active coupons per listing.

Binding operations use a distributed lock to avoid concurrent over‑binding.

2.4 C‑End Coupon Claiming

The claim flow consists of request validation, Redis stock deduction, and a transactional MySQL write for the claim record and stock update.

Key points:

Validate request using a Bloom filter in Redis.

Check coupon status from cached data.

If stock data is missing, send an async initialization task via MQ.

Stock deduction is performed atomically in Redis; the DB update is off‑loaded to a message‑driven task to avoid lock contention.

Four scenarios are discussed: normal success, Redis failure, DB failure after Redis success (leading to under‑claim), and Redis master‑slave inconsistency (leading to over‑claim). Mitigation strategies include asynchronous reconciliation, monitoring stock thresholds, and using CP‑style storage when strong consistency is required.

2.5 Coupon Redemption

A microservice exposes APIs for coupon acquisition and state transition. States are "unused", "locked", and "used". When an order is placed, the coupon is locked; on order completion it becomes used, otherwise it rolls back to unused.

Future Optimization Directions

Shard user coupon data across databases for read/write scalability.

Deploy Redis as a sharded cluster to increase capacity and availability.

Split service clusters so each handles a subset of coupons, routing via a gateway.

Introduce a hot‑key component to sync hot keys to local caches, reducing remote cache hits.

Use Canal to sync binlog changes to caches and trigger downstream updates.

Conclusion

The complete coupon system follows the principle of "read‑heavy, write‑light": cache for frequent reads, queue for writes. Multi‑level caching, proxy pattern, state‑pattern with observer pattern, and MQ‑driven asynchronous updates ensure data consistency and high performance.

Stock deduction relies on Redis atomicity, while DB stock updates are serialized via a transactional message table to avoid over‑claim.

Source: https://juejin.cn/post/7160643319612047367

Distributed Systemsbackend designMicroservicescachingcoupon systemdatabase schema
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.