合一前是三条并行筒仓(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(幂等)
| 字段 | 含义 |
|---|---|
id / code | 内部标识;code 创建时自动生成 CMP_…(运营不填)。 |
name / description | 活动名 / 备注。 |
status | DRAFT SCHEDULED LIVE PAUSED ARCHIVED。仅 LIVE 参与供数/触发。 |
start_at / end_at | 时间窗(end 空=长期)。展示位与奖励都继承这一份。 |
audience_json | 人群,结构化:{roles:["USER"], newUserOnly:bool, minAppVersion, maxAppVersion}。空=全部。roles 是兼容字段,当前只能填写 USER。 |
priority | 多活动抢同一展示位/同事件时,数字大者优先。 |
audience_json 目前是展示位供数的人群来源(继承生效);奖励规则引擎仍按规则自身条件执行,未按活动人群门控。「活动人群也门控奖励」属后续单独改动。| 枚举 | 运营含义 | 可用条件 | 允许动作 |
|---|---|---|---|
USER_REGISTERED | 用户账号首次创建成功 | 无事件专属条件 | 发券 / 现金 / WA 通知 |
VALID_NEW_USER | 用户绑定有效邀请人 | 邀请码 | 发券 / 现金 / WA 通知 |
WHATSAPP_OFFICIAL_MESSAGE_SENT | 用户向 BeeX 官方 WhatsApp 发送活动口令 | 固定文案、成功回复、重复/不符合资格回复 | 发券 / 现金 |
AFFILIATE_ORDER_CREATED | 联盟订单首次进入 BeeX | 平台 / 最低 GMV | WA 通知 |
AFFILIATE_ORDER_DONE | 平台确认联盟订单完成 | 第 N 单 / 平台 / 最低 GMV | 发券 / 现金 / 返佣加成 / 基金券核销 / WA 通知 |
AFFILIATE_ORDER_CANCELLED | 平台确认联盟订单取消 | 平台 / 最低 GMV | WA 通知 |
AFFILIATE_ORDER_REFUNDED | 平台确认联盟订单退款或退货完成 | 平台 / 最低 GMV | WA 通知 |
GET /api/v1/admin/campaigns/options 的 eventCatalog,动态生成场景、条件和动作。事件只有在业务侧已有真实触发源并登记到目录后才会出现;不能再配置“保存成功但永远不触发”的哑炮规则。TikTok、Shopee、Lazada、Traveloka 的订单都通过统一订单仓储事件接入。平台重复同步时,规则引擎按规则 + 订单 + 用户幂等,不会重复发放。
用户向官方号发送固定文案 ──► Meta Webhook 入站去重 ──► 按 WhatsApp 号码识别 BeeX 用户 ──► 规范化文案后精确匹配活动口令 ──► 校验活动时间窗 / 规则条件 / 每人次数 / 总预算 ──► 发券或发现金,并写 campaign_action_record ──► 使用收到消息的同一个官方 WhatsApp 号码自动回复结果
| 配置项 | 含义 |
|---|---|
whatsappMessageText | 用户必须发送的固定活动口令。匹配时忽略首尾空格、连续空格和英文字母大小写,不做模糊或包含匹配。 |
whatsappSuccessReply | 奖励动作真实执行成功后回复的内容。 |
whatsappRepeatReply | 口令命中,但用户已领取、超过次数、预算不足或不符合其他规则时回复的内容。 |
高频条件作为列提出(可索引),其余放 condition_json。
| 字段(列) | 含义 |
|---|---|
platform | 限定平台(Shopee/TikTok…),空=全平台。仅订单事件。 |
order_no | 第几单(0=任意单)。仅订单事件。 |
min_gmv_minor | 订单最低金额(minor)。 |
max_issue_per_user | 每人最多触发次数(0=不限)。 |
budget_amount_minor | 该规则总预算上限(0=不限)。 |
动作类型 action_type 决定执行器,参数放 action_config_json:
| 动作 | 运营含义 | action_config 字段 |
|---|---|---|
ISSUE_COUPON | 发优惠券 | couponTemplateId(券模板)、quantity、beneficiary(SELF/INVITER) |
GRANT_CASH | 发现金到钱包 | amountMinor(>0) |
GRANT_COMMISSION_BONUS | 佣金加成(返佣加倍) | basis(COMMISSION/GMV/USER_CASHBACK)、bps(10000=100%)、maxRewardMinor(0=不封顶) |
SETTLE_REBATE_COUPON | 订单完成后核销余额式返佣功能券 | couponType、basis、bps、maxRewardMinor;只能用于订单完成事件 |
SHOW_PLACEMENT | 在展示位曝光 | 见 §8 展示位:placement/content/action/frequency… |
NOTIFY_WA | 发 WhatsApp 模板 | templateName、languageCode、params[] |
管理后台不会把所有动作无差别展示给每个事件。每个事件的 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 释放。
| 字段 | 含义 |
|---|---|
timing | IMMEDIATE(发券/通知)· DELAYED(现金/佣金加成,需结算窗)· CONTINUOUS(展示位曝光)。缺省按动作类型推导。 |
release_delay_days | 延迟到账天数(如 T+30 防退款)。 |
effective_from / effective_to | 规则自身的细粒度生效窗(可选);为空=跟随活动窗。展示位场景一律留空(继承活动)。 |
enabled | 规则启用开关。 |
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 券绝不在联盟单返现。
展示位 = 一条 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_SPLASH | App 启动页 | 启动页 | 单张 | ✓ | 图/视频 | Flutter native |
枚举元数据(kind/multi/frequencyApplicable/media)是单一真相源,后台下拉、供数校验、前端常量都对齐它。HOME_NEW_USER_EXCLUSIVE 是 HOME_BRAND_BANNER 的旧名,后端供数保留旧→新 key 别名做零停机过渡(旧 App 仍取得到)。
| 字段 | 含义 |
|---|---|
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 对齐,端到端可追溯/埋点。
每次动作执行落一行 campaign_action_record:
idempotency_key 唯一键 → 同一(规则,用户,业务引用)重放不重复发。sum(amount_minor) by rule ≤ budget_amount_minor,超则跳过。count by rule+user ≤ max_issue_per_user。participation_scope=PER_IDENTITY):上面的「每人次数」绑 userId,会被「注销→重注册」绕过(新 userId)。规则可声明 participation_scope=PER_IDENTITY + participation_limit,把限次升维到身份锚点(手机号哈希):动作执行前查 campaign_participation_ledger、达上限即拦,参加后记账;账号注销时该账本是物理删除的唯一例外。新人券/首单礼/限领券都是它的取值,无需专属代码。详见 活动「每身份限参加 N 次」· 跨账号去重设计。| 步 | 配什么 | 后台字段 |
|---|---|---|
| ① 选业务场景 | 从后端事件目录选择真实可触发的场景 | trigger_event |
| ② 配活动与人群 | 名称 / 状态 / 时间 / 全部 USER 或指定人群 | campaign.* / audience_json |
| ③ 配触发条件 | 只显示该事件支持的平台、第 N 单、GMV、邀请码等条件 | campaign_rule 条件字段 |
| ④ 配执行动作 | 只显示该事件允许的发券、现金、加成、基金核销或 WA 通知 | action_type / action_config_json |
| ⑤ 体检并保存 | 确认业务摘要、预算、次数、动作配置和风险提示 | 规则体检 + 保存 |
运营全程不碰内部 code/id:活动码自动生成、展示位友好下拉、环境由全局 host 开关定(不入业务字段)。后台 = admin.beexofficial.com 的「活动列表 / 券模板 / 展示位」页面 + 创建期「体检」(动作配置校验 + 展示位占用/券复用提示)。
| 接口 | 用途 |
|---|---|
GET /api/v1/campaigns/placements?countryCode&placements&userId&role&appVersion | 按展示位拉内容(分组返回;人群/时间已在后端按所绑活动判定)。role 为兼容参数,当前只接受 USER,新调用可省略。 |
GET /api/v1/activity-campaigns/cards?countryCode | 活动卡片(奖励类规则的进度/已发)。 |
| 接口前缀 | 能力 |
|---|---|
/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(命中预览)。 |
app/constants/campaignSlots.ts 共享 SLOTS 常量(镜像后端枚举)+ 漂移告警;HomeTab 按常量拉取/渲染,banner 多张轮播,每位加 data-slot。SplashCampaignService(拉 APP_SPLASH → 下载素材到本地 → 缓存;启动读本地先显示、后台拉新配置下次启动生效)+ SplashScreenPage(图/视频 · 静音自动播 · 3s · 可跳过)+ SplashGate 接入启动时序。| 组件 | 位置 |
|---|---|
| 公开供数与事件执行 | beex-service:面向 App/H5 的查询、活动命中和业务事件执行。 |
| 配置与运营管理 | beex-admin-service:活动、规则、券模板、展示位、审计与发布管理;与业务服务独立部署。 |
| 配置后台前端 | beex-admin-page → OSS/CDN admin.beexofficial.com(云效 5052020 / 本地白名单脚本发布)。 |
| 建表/种子 | PrdSchemaInitializer:建 campaign/campaign_rule/campaign_action_record + 种子(新人返佣加倍、常驻位容器)+ 旧 key 改名迁移。 |
eventCatalog,再部署业务服务与管理服务;管理后台页面会自动显示,不需要重新开发或发布管理后台前端。只有新增全新的条件控件、动作类型或动作配置表单时,才需要同时修改并发布管理后台前端。本文随实现演进维护。配套:展示位设计 · 配置目录 · BeeX PRD v2.0。