🐝 BeeX 活动规则引擎(ECA)· 实现版文档

v1.2 当前实现2026-07-27一套代码 · 按国家部署
活动 / 券 / 展示位三套机制统一为一个 「事件 → 条件 → 动作」(ECA)规则引擎。 一个活动 campaign = 时间窗 + 人群 + 一组规则 campaign_rule;每条规则 = 某事件(WHEN)发生、满足条件(IF) → 执行某动作(THEN)(发券 / 发现金 / 佣金加成 / 点亮展示位 / WA 推送)。当前 BeeX 业务身份只有 USER;本文是实现说明,产品口径以 BeeX PRD v2.0 为准。
目录
  1. 核心模型 · 三张表
  2. 活动 campaign(谁 · 何时)
  3. 事件 trigger_event(WHEN)
  4. 条件 Condition(IF)
  5. 动作 action_type ×6(THEN)+ 配置
  6. 时机与释放(T+N)
  7. 券模板 · 返现 vs 抵扣(rewardMode)
  8. 展示位子系统
  9. 执行语义 · 幂等 / 预算 / 每人次数
  10. 后台配置流程(5 步)
  11. 接口清单
  12. 前端集成(H5 / Flutter)
  13. 部署与运维

1核心模型 · 三张表

合一前是三条并行筒仓(activity_campaign* / invite_coupon_* / campaign_placements),各有各的表与后台、彼此不串。现统一为三张表:

角色关键含义
campaign活动头WHO(人群)+ WHEN(时间窗)+ 状态 + 优先级。是展示位/奖励的人群与时间唯一来源。
campaign_rule一条 ECA事件 → 条件 → 动作 + 动作配置;挂在某活动下(campaign_id)。
campaign_action_record执行记录每次动作落一行:幂等(idempotency_key)+ 预算累计(sum amount)+ 每人次数(count by rule+user)。

另两张支撑表:coupon_template(可复用的券定义,被 ISSUE_COUPON 引用)、user_coupons(发到用户的券实例)。

事件发生 ──► 找该国 LIVE 活动下、该事件的规则 ──► 逐条:活动在窗? 人群命中? 条件满足? 预算/次数够?
        ──► 执行动作(发券/现金/佣金/展示位/WA)──► 落 campaign_action_record(幂等)

2活动 campaign(谁 · 何时)

字段含义
id / code内部标识;code 创建时自动生成 CMP_…(运营不填)。
name / description活动名 / 备注。
statusDRAFT SCHEDULED LIVE PAUSED ARCHIVED。仅 LIVE 参与供数/触发。
start_at / end_at时间窗(end 空=长期)。展示位与奖励都继承这一份
audience_json人群,结构化:{roles:["USER"], newUserOnly:bool, minAppVersion, maxAppVersion}。空=全部。roles 是兼容字段,当前只能填写 USER。
priority多活动抢同一展示位/同事件时,数字大者优先。
边界(当前实现):活动 audience_json 目前是展示位供数的人群来源(继承生效);奖励规则引擎仍按规则自身条件执行,按活动人群门控。「活动人群也门控奖励」属后续单独改动。

3事件 trigger_event(WHEN)

枚举运营含义可用条件允许动作
USER_REGISTERED用户账号首次创建成功无事件专属条件发券 / 现金 / WA 通知
VALID_NEW_USER用户绑定有效邀请人邀请码发券 / 现金 / WA 通知
WHATSAPP_OFFICIAL_MESSAGE_SENT用户向 BeeX 官方 WhatsApp 发送活动口令固定文案、成功回复、重复/不符合资格回复发券 / 现金
AFFILIATE_ORDER_CREATED联盟订单首次进入 BeeX平台 / 最低 GMVWA 通知
AFFILIATE_ORDER_DONE平台确认联盟订单完成第 N 单 / 平台 / 最低 GMV发券 / 现金 / 返佣加成 / 基金券核销 / WA 通知
AFFILIATE_ORDER_CANCELLED平台确认联盟订单取消平台 / 最低 GMVWA 通知
AFFILIATE_ORDER_REFUNDED平台确认联盟订单退款或退货完成平台 / 最低 GMVWA 通知
事件目录由后端下发:管理后台读取 GET /api/v1/admin/campaigns/optionseventCatalog,动态生成场景、条件和动作。事件只有在业务侧已有真实触发源并登记到目录后才会出现;不能再配置“保存成功但永远不触发”的哑炮规则。

TikTok、Shopee、Lazada、Traveloka 的订单都通过统一订单仓储事件接入。平台重复同步时,规则引擎按规则 + 订单 + 用户幂等,不会重复发放。

WhatsApp 活动口令领奖

用户向官方号发送固定文案
  ──► Meta Webhook 入站去重
  ──► 按 WhatsApp 号码识别 BeeX 用户
  ──► 规范化文案后精确匹配活动口令
  ──► 校验活动时间窗 / 规则条件 / 每人次数 / 总预算
  ──► 发券或发现金,并写 campaign_action_record
  ──► 使用收到消息的同一个官方 WhatsApp 号码自动回复结果
配置项含义
whatsappMessageText用户必须发送的固定活动口令。匹配时忽略首尾空格、连续空格和英文字母大小写,不做模糊或包含匹配。
whatsappSuccessReply奖励动作真实执行成功后回复的内容。
whatsappRepeatReply口令命中,但用户已领取、超过次数、预算不足或不符合其他规则时回复的内容。
路由优先级:登录码、注册/绑定、账号删除等系统指令优先于活动口令。普通文案未命中任何活动口令时,才进入原有 WhatsApp Bot 流程。即时回复发生在用户主动消息开启的服务窗口内,不需要额外配置 Authentication Template。

4条件 Condition(IF)

高频条件作为提出(可索引),其余放 condition_json

字段(列)含义
platform限定平台(Shopee/TikTok…),空=全平台。仅订单事件。
order_no第几单(0=任意单)。仅订单事件。
min_gmv_minor订单最低金额(minor)。
max_issue_per_user每人最多触发次数(0=不限)。
budget_amount_minor该规则总预算上限(0=不限)。

5动作 action_type ×6(THEN)+ 配置

动作类型 action_type 决定执行器,参数放 action_config_json:

动作运营含义action_config 字段
ISSUE_COUPON发优惠券couponTemplateId(券模板)、quantitybeneficiary(SELF/INVITER)
GRANT_CASH发现金到钱包amountMinor(>0)
GRANT_COMMISSION_BONUS佣金加成(返佣加倍)basis(COMMISSION/GMV/USER_CASHBACK)、bps(10000=100%)、maxRewardMinor(0=不封顶)
SETTLE_REBATE_COUPON订单完成后核销余额式返佣功能券couponTypebasisbpsmaxRewardMinor;只能用于订单完成事件
SHOW_PLACEMENT在展示位曝光§8 展示位:placement/content/action/frequency
NOTIFY_WA发 WhatsApp 模板templateNamelanguageCodeparams[]

管理后台不会把所有动作无差别展示给每个事件。每个事件的 allowedActionTypes 由后端目录控制,保存时服务端再次校验。

示例(新人返佣加倍):活动 NEW_USER_CASHBACK_MULT(人群 newUserOnly)+ 3 条规则,事件 AFFILIATE_ORDER_DONE 第 1/2/3 单,动作 GRANT_COMMISSION_BONUS basis=USER_CASHBACK,bps 20%/30%/50%,T+30 释放。

6时机与释放(T+N)

字段含义
timingIMMEDIATE(发券/通知)· DELAYED(现金/佣金加成,需结算窗)· CONTINUOUS(展示位曝光)。缺省按动作类型推导。
release_delay_days延迟到账天数(如 T+30 防退款)。
effective_from / effective_to规则自身的细粒度生效窗(可选);为空=跟随活动窗。展示位场景一律留空(继承活动)。
enabled规则启用开关。

7券模板 · 返现 vs 抵扣(rewardMode)

coupon_template 是可复用的券定义,被 ISSUE_COUPON 引用。核心是 rewardMode = 券的真实行为(显式选,不靠场景猜):

rewardMode行为生效场景兑付
CASHBACK 返现把券的 %/固定额作用在返佣基数上,多返钱进钱包只在联盟订单完成AffiliateCouponRewardService.creditPending(role=COUPON_CASHBACK)
DISCOUNT 抵扣减价(原价 − 券)只在当前明确启用的付费业务由对应支付业务结算

防死券守卫 enforceRewardMode(couponType, requested):严格类型按唯一可用场景强制(CASHBACK_RATE→CASHBACK,COURSE/SERVICE_FEE_DISCOUNT→DISCOUNT),双场景类型(USER_DISCOUNT/ACQUISITION/DEVELOPMENT)尊重所选。供数 requiredRewardMode(bizType) 保证:CASHBACK 券绝不在购买场景当抵扣、DISCOUNT 券绝不在联盟单返现。

8展示位子系统

展示位 = 一条 SHOW_PLACEMENT 规则,绑定一个真实活动关键 人群 + 时间窗一律继承所绑活动(展示位本身不带 condition/effective 窗;供数读 campaign.audience_json + start/end)。缺省绑「常驻位容器」cmp_<country>_placements(恒 LIVE / 全人群 / 窗常开),用于无专属活动的纯展示。

展示位目录(单一真相源 · CampaignPlacementSlot 枚举)

key中文名类型单/多频率媒体渲染
HOME_BANNER商品列表首位 Banner常驻多张轮播H5
HOME_BRAND_BANNER品牌区 Banner常驻多张轮播H5
HOME_POPUP首页弹窗弹框单张H5
HOME_FLOATING_ENTRY首页悬浮入口常驻单张H5
APP_SPLASHApp 启动页启动页单张图/视频Flutter native

枚举元数据(kind/multi/frequencyApplicable/media)是单一真相源,后台下拉、供数校验、前端常量都对齐它。HOME_NEW_USER_EXCLUSIVEHOME_BRAND_BANNER 的旧名,后端供数保留旧→新 key 别名做零停机过渡(旧 App 仍取得到)。

展示位 action_config(展示物)

字段含义
placement展示位 key(上表)。
content图位 {imageUrl};启动页 {mediaType:IMAGE|VIDEO, mediaUrl, durationSec, skippable, muted}
action(跳转){type:"ROUTE", target:"/coupons"}{type:"URL", url:"https://…"}(前端自动识别站内/外链)。
frequency(频控)仅弹框/启动页:{mode: EVERY_TIME | ONCE_PER_DAY | ONCE_PER_CAMPAIGN}。常驻位忽略。
priority / status轮播排序 / 上架(ACTIVE)下架。

占用提示(选展示位时红黄绿)

data-slot:H5 每个展示位容器、Flutter 启动页根节点都盖上 slot key(data-slot/Key('slot_APP_SPLASH')),与后端 key 对齐,端到端可追溯/埋点。

9执行语义 · 幂等 / 预算 / 每人次数

每次动作执行落一行 campaign_action_record:

10后台配置流程(5 步)

配什么后台字段
① 选业务场景从后端事件目录选择真实可触发的场景trigger_event
② 配活动与人群名称 / 状态 / 时间 / 全部 USER 或指定人群campaign.* / audience_json
③ 配触发条件只显示该事件支持的平台、第 N 单、GMV、邀请码等条件campaign_rule 条件字段
④ 配执行动作只显示该事件允许的发券、现金、加成、基金核销或 WA 通知action_type / action_config_json
⑤ 体检并保存确认业务摘要、预算、次数、动作配置和风险提示规则体检 + 保存

运营全程不碰内部 code/id:活动码自动生成、展示位友好下拉、环境由全局 host 开关定(不入业务字段)。后台 = admin.beexofficial.com 的「活动列表 / 券模板 / 展示位」页面 + 创建期「体检」(动作配置校验 + 展示位占用/券复用提示)。

11接口清单

公开(App / H5 拉取)

接口用途
GET /api/v1/campaigns/placements?countryCode&placements&userId&role&appVersion按展示位拉内容(分组返回;人群/时间已在后端按所绑活动判定)。role 为兼容参数,当前只接受 USER,新调用可省略。
GET /api/v1/activity-campaigns/cards?countryCode活动卡片(奖励类规则的进度/已发)。

后台(admin,X-Operator 头)

接口前缀能力
/api/v1/admin/campaigns活动 CRUD + 规则(/rules)+ 创建期体检(/rules/check)+ /options
/api/v1/admin/coupon-templates券模板 CRUD + /options(含 rewardModes)。
/api/v1/admin/campaign-placements展示位 CRUD + /slots(展示位目录)+ /occupancy(占用)+ /{id}/preview(命中预览)。

12前端集成(H5 / Flutter)

13部署与运维

组件位置
公开供数与事件执行beex-service:面向 App/H5 的查询、活动命中和业务事件执行。
配置与运营管理beex-admin-service:活动、规则、券模板、展示位、审计与发布管理;与业务服务独立部署。
配置后台前端beex-admin-page → OSS/CDN admin.beexofficial.com(云效 5052020 / 本地白名单脚本发布)。
建表/种子PrdSchemaInitializer:建 campaign/campaign_rule/campaign_action_record + 种子(新人返佣加倍、常驻位容器)+ 旧 key 改名迁移。
改展示位 key 须知:先查前端主分支和已发布 H5 包实际使用的 key;rename 用后端供数别名做零停机过渡(旧包仍取得到,迁移完再删别名)。数据库和接口变更分别通过业务服务、管理服务流水线发布,并校验交付物对应同一 commit。
新增事件如何发布:若新事件沿用现有条件字段和动作类型,只需在业务代码发布真实事件、登记后端 eventCatalog,再部署业务服务与管理服务;管理后台页面会自动显示,不需要重新开发或发布管理后台前端。只有新增全新的条件控件、动作类型或动作配置表单时,才需要同时修改并发布管理后台前端。

本文随实现演进维护。配套:展示位设计 · 配置目录 · BeeX PRD v2.0