Appearance
00 · 架构总纲
0. 文档说明
| 项 | 内容 |
|---|---|
| 版本 | V1.0 |
本篇是全部系统设计的地基与总目录。任何单系统文档的疑问,先回到本篇的三层模型与通用约定。
一、定位与职责
BetCorgi 是一套多商户链游包网平台(multi-tenant white-label):平台方提供一份核心能力引擎与全套运营能力,支撑几十至上百套独立运营的子平台(租户/商户)。领域为链游/娱乐场——三方游戏聚合、优惠、返水、VIP、充提;不引入其他业态假设。
本篇定义:
- 全平台的分层架构(三层模型)与两个平面(用户端 App / 运营后台);
- 各业务系统之间的关系(系统全景,00–17);
- 全部系统必须共同遵守的通用设计约定(配置驱动、币种无关、状态机、幂等、审计、事件、命名、数据隔离、降级)。
不做什么:本篇不展开任一具体系统的字段与规则,那是 01–17 各分册的事。
二、多商户三层模型(核心)
┌───────────────────────────────────────────┐
③ 展示层 │ 用户端 App(H5) 运营后台(→15) │
Presentation │ 纯渲染:读「租户配置 + 引擎数据」出界面 │
│ 换皮、换布局、换文案 → 不碰引擎 │
└───────────────▲───────────────────────────┘
│ 读配置 + 数据
┌───────────────┴───────────────────────────┐
② 租户配置层 │ Tenant Config(每租户一份,继承+覆盖) │
Tenant Config │ 功能开关 / 币种 / 活动 / 等级门槛 / 费率 │
│ 主题 / 布局 / 文案 / 合规区域 / 灰度 │
└───────────────▲───────────────────────────┘
│ 配置注入(引擎读租户配置执行)
┌───────────────┴───────────────────────────┐
① 核心能力引擎 │ Capability Engine(全租户共享) │
Capability Engine │ 规则 + 状态机 + 数据模型 │
│ 与租户/币种/主题无关,只认「配置 + 事件」 │
└───────────────────────────────────────────┘2.1 三层各自的铁律
| 层 | 允许 | 禁止 |
|---|---|---|
| ① 引擎 | 定义规则、状态机、数据模型;读租户配置参数执行 | ❌ 硬编码任何租户专属数值/文案/币种/费率;❌ 感知主题与布局 |
| ② 配置 | 声明「这个子平台开什么、值多少、长什么样」 | ❌ 写业务逻辑;❌ 直接操作数据 |
| ③ 展示 | 渲染、交互、动效;按配置切皮换布局 | ❌ 前端写死业务规则/汇率/费率;❌ 绕过引擎改数据 |
判断一段逻辑该放哪层:换一个子平台会不会变?会变 → 配置层。所有子平台都一样的算法 → 引擎层。只影响长相 → 展示层。
2.2 为什么这样分
- 开新站近乎零开发:新子平台 = 复制默认配置模板 + 改差异项,不 fork 代码。
- 引擎一处升级、全站受益:返水算法优化一次,上百个子平台同时生效。
- 展示随便换皮不伤筋骨:UI/主题/布局是配置 + 设计系统的产物,不回灌业务。
2.3 两个平面(同一引擎的两类客户端)
| 平面 | 使用者 | 形态 | 职责 |
|---|---|---|---|
| 用户端 App | 玩家 | 移动 H5(原型 global.html) | 玩、充提、领奖 |
| 运营后台 | 平台方 / 商户运营者 | 桌面 Web(→ 15 运营后台) | 平台控制台:建站、模板/预设、跨租户管理;商户控制台:本站配置、活动、财务审核、报表 |
两个平面共用同一引擎与配置层,后台也是展示层的一种客户端——它多出的能力是「写配置、审工单」,同样不内嵌业务规则。运营后台在本项目范围内,详设归 15。
现有 global.html 原型即「Global 租户 · CNY 站(本位币 = CNY)」的一次用户端渲染。参见 01-多商户与租户配置。
三、系统全景(00–17)
┌─────────────────────────────┐
│ 01 多商户与租户配置(地基) │ ← 所有系统读它
└──────────────┬──────────────┘
┌──────────────┬────────────────┼────────────────┬──────────────┐
▼ ▼ ▼ ▼ ▼
┌─────────────┐ ┌───────────┐ ┌───────────────┐ ┌───────────┐ ┌─────────────┐
│05 账户/认证 │ │02 货币/钱包│ │12 游戏聚合 │ │06 等级 │ │09 优惠活动 │
└──────┬──────┘ └─────┬─────┘ └───────┬───────┘ └─────┬─────┘ └──────┬──────┘
│ │ │ │ │
│ ┌─────┴─────┐ │ ┌──────┴──────┐ │
│ ▼ ▼ │ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ │ ┌──────────┐ ┌──────────┐ │
│ │03 充值 │ │04 提现 │ │ │07 VIP俸禄│ │08 实时返水│ │
│ └──────────┘ └──────────┘ │ └──────────┘ └──────────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ │
└─────────────────►│10 任务 │ │11 返佣 │◄─────────────────┘
└──────────┘ └──────────┘
│ │
▼ ▼
┌───────────────────────────┐
│ 13 记录与账变(账本底座) │ ← 所有资金/权益动作留痕
└───────────────────────────┘
────────────────────────── 横切平面 ──────────────────────────
14 风控与反作弊 —— 卡在一切「领取/派发/提现」路径上的前置校验
15 运营后台 —— 全系统的管理面(平台控制台 + 商户控制台)
16 消息通知 —— 订阅领域事件,站内信/推送
17 数据看板 —— 聚合 13 流水,商户报表 + 平台经营视图依赖关系速查
- 02 货币/钱包是资金底座:03/04/07/08/09/10/11/12 的任何金额进出都经它记账。
- 06 等级是权益底座:07 俸禄、08 返水、09 部分活动的档位都读用户等级。
- 12 游戏聚合产出投注/输赢流水 → 驱动 08 返水、10 打码进度(06 成长值由充值驱动,→ 06 升级)。
- 13 记录与账变是账本:一切余额变化写不可变流水,对账与展示都读它。
- 14 风控是闸门:领取、派发、提现在入账前必须过风控前置校验。
- 15 后台读写 01 配置、驱动 04 提现审核与 02 人工调整,一切操作留审计。
- 17 看板只读:聚合 13 的流水与各系统快照,不产生业务写操作。
四、通用设计约定(全系统强制)
4.1 配置驱动(Config over Code)
任何「不同子平台可能不一样」的量都必须来自租户配置,禁止散落在引擎/前端。包括但不限于:金额、费率、比例、门槛、开关、文案、图标、精度、时区、合规限制。配置项命名以系统命名空间为前缀,如 wallet.currencies、vipSalary.levels[].dailyAmount。
4.2 币种无关(Currency-agnostic)+ 单币种站型
引擎内部一律以 { amount, currency } 表达金额,禁止裸数字、禁止隐含币种、禁止前端/引擎写死汇率。
- 一租户 = 一「本位币站」:站内全链路单币种、单账户(本位币 baseCurrency,取 CNY 站 / USDT 站),站内无换算、无第二币种符号、一人一钱包;等级/俸禄/任务/统计一律本位币单口径。
- 换算只发生在两个「钱包边界」,均锁价 + 快照 + 审计:充值(通道币种可 ≠ 本位币,下单时点锁价折入)、提现(本位币按提现时点锁价折出到通道币种);站内不提供币币兑换。
- 展示铁律:已发生金额永远带「出生币种」,不重标、不换算;禁止「数字不变只换符号」的渲染。
- 平台跨站层面是多币种(不同站不同本位币),平台看板/跨租户对账「按币种分列」(→ 17);单站内部为单币种口径。 详见 02-货币与钱包系统。
4.3 状态机优先(State machine)
凡有生命周期的实体(租户、活动、领取、充值、提现、任务、彩金、工单)必须显式定义状态枚举 + 允许的流转 + 触发条件,不用零散布尔位拼状态。每篇分册用状态图表达。
4.4 幂等与一致性(Idempotency)
一切资金/权益写操作(领取、派发、入账、扣款)必须幂等:携带业务唯一键(如 claimId),重复请求不重复入账。领取类动作先扣「可领资格」再入账,失败可重放。数据库层以 (tenant_id, op_code, biz_key) 唯一约束兜底。
4.5 审计留痕(Auditability)
余额或权益的每次变化写 13 账变流水(谁、何时、因何事件、变动前后值),不可变、可对账。后台侧一切配置变更与人工操作写 15 审计日志(谁改了哪个租户的哪项、前后值)。
4.6 事件驱动解耦(Event-driven)+ 事件登记表
系统间用领域事件通信,不直接互调内部逻辑。新事件必须先在本表登记再使用;载荷一律含 eventId / tenantId / occurredAt。
| 事件 | 生产者 | 主要消费者 | 载荷关键字段 | 幂等键 |
|---|---|---|---|---|
UserRegistered | 05 | 09(新手活动)、11(绑定上级)、16 | userId, channel, ref(短链 slug 归因,无邀请码) | userId |
DepositSucceeded | 03 | 02(入账)、06(成长值)、09(充值活动)、11、16 | orderId, currency, amount, isFirstOverall(该租户首笔), isFirstOfKind(法币/加密各自首笔) | orderId |
WithdrawCompleted | 04 | 16、17 | withdrawId, currency, amount | withdrawId |
BetSettled | 12 | 08(返水)、10(打码)、17(报表) | betId, gameType, vendor, currency, validTurnover, winLoss | betId |
BetCancelled | 12 | 08(冲正)、10(冲正)、17(修正) | betId, reason | betId+cancelSeq |
LevelChanged | 06 | 07(俸禄档位)、08(返水率)、16 | userId, fromLevel, toLevel, reason(UP/DOWN/ADJUST) | userId+changeSeq |
RewardClaimed | 07/08/09/10/11 | 02(入账)、13、14(事后画像)、16 | claimId, source, currency, amount, target(available/bonus) | claimId |
BonusUnlocked | 10(打码引擎) | 02(转可用)、16 | grantId, currency, amount | grantId |
RiskFlagged | 14 | 相关系统(拦截/冻结)、15(工单) | flagId, userId, ruleId, action | flagId |
登记表口径锁定(全库唯一源,各分册对齐本表):
BonusUnlocked生产者 = 10 打码引擎:10 判定打码达标 → 调用 02 执行BONUS_UNLOCK入账(bonus→available)→ 由 10 发BonusUnlocked(幂等键grantId),02 §2.4 状态机的「发BonusUnlocked」即指此步由 10 触发(打码进度权威 = 10 wagering_obligations,02 bonus_grants 的wagering_progress为冗余展示,以grantId关联)。LevelChanged.reason枚举 = {UP, DOWN, ADJUST}(无KEEP——保级维持不发事件;ADJUST= 人工调级,→ 06/16)。DepositSucceeded载荷含isFirstOverall(该租户首笔)+isFirstOfKind(法币/加密各自首笔) 两布尔(不用单一isFirst,供 09 区分首存/钱包首入/虚拟币首入,→ 03/09)。BetCancelled幂等键 =betId+cancelSeq(同注单可多次/部分取消,08/10/12 消费方均以此为准)。
4.7 展示契约(Presentation Contract)
每篇分册末列出「驱动 UI 的字段」及其到原型 DOM/JS 的映射,前端据此对接,以字段为准而非截图。
4.8 命名与单位约定
- 金额:存储用高精度定点小数
DECIMAL(32,8);API 传输一律字符串(如"888.88"),禁止 float;展示精度由本位币wallet.decimals决定,内部精度高于展示精度。逐笔金额恒带「出生币种」(→ §4.2 展示铁律)。 - 比例/费率:统一用小数(
0.006表示 0.6%),展示时格式化。 - 时间:存储 UTC,展示按
tenant.timezone。 - 标识:业务唯一键统一
xxxId;枚举用大写下划线常量;表字段蛇形命名。
4.9 数据隔离与租户上下文
- 默认:共享库表 + 行级隔离 —— 所有业务表强制
tenant_id列;业务唯一键一律做成(tenant_id, …)复合唯一;数据访问层(DAL/中间件)强制注入租户过滤,不依赖开发者手写WHERE。 - 请求链路:入口按域名解析出
tenantId(→ 01 §2.4),写入请求上下文,贯穿到存储层。 - 逃生口:超大租户或强合规区域可整租户拆库(同 schema、独立实例),对引擎透明。
- 用户、钱包、KYC、流水等一切数据按租户强隔离;同一自然人在不同子平台默认是两套独立账户。
4.10 错误与降级
- 配置缺键:合并链保证任何键都有默认模板兜底值(→ 01 §四),引擎不因缺键崩溃。
- 引擎/下游异常:展示层展示兜底态(如「暂时无法领取,请稍后再试」),禁止前端自行估算金额或跳过校验。
- 三方游戏厂商故障:该厂商标记维护中,不影响其他厂商与平台功能(→ 12)。
五、租户配置解析链路(引擎如何拿到「这个站的值」)
默认模板配置(平台级基线)
│ 继承
▼
区域/行业预设 Preset(可选)
│ 继承
▼
租户覆盖配置(该子平台的差异项)
│ 继承
▼
灰度 / A-B / 站点覆盖(可选)
│ 合并(深合并,后者覆盖前者;合规层只收紧不放开)
▼
有效配置 EffectiveConfig(引擎与前端实际读到的)合并规则、域名→租户解析、bootstrap 契约、版本灰度回滚详见 01-多商户与租户配置。
六、端到端示例:领取 VIP 俸禄(一次走通三层)
① 展示层(App) 用户在「奖励中心·VIP俸禄」点【领取日俸禄】
POST /rewards/vip-salary/claim { claimId: "cs-20260713-u1001-daily" }
② 引擎·校验 读 EffectiveConfig:vipSalary.enabled?
用户等级 V18 → vipSalary.levels[18].daily = 888(本位币口径,本站 = CNY 站)
读状态:今日未领?保级打码达标?(规则归 06/07)
③ 风控前置(14) 领取频次 / 设备指纹 / 黑名单 检查 → 放行
④ 记账(02+13) REWARD_CREDIT(available, +888 CNY, 幂等键=claimId) → 写账变流水
⑤ 事件(§4.6) 发 RewardClaimed{claimId, source: VIP_SALARY, currency: CNY, amount: "888"}
→ 16 到账通知 · 17 看板计数 · 14 事后画像
⑥ 展示层回显 余额胶囊 +888 · 按钮转「明日可领」倒计时 · 奖励 tab 红点按新状态刷新- 用户重复点击(同
claimId)→ ④ 幂等返回首次结果,不重复入账。 - 改这条链路的方式:改各级俸禄额 → 只改②的租户配置;改风控阈值 → 只改 14 的规则;改按钮文案样式 → 只动展示层。三层互不惊动——这就是分层的意义。
七、术语表
| 术语 | 含义 |
|---|---|
| 包网 | 平台方提供整套技术与运营能力,商户「租用开站」独立运营的模式 |
| 租户 / 商户 / 子平台 | 一套独立运营的站点实例,拥有独立配置、用户、账本、域名 |
| 平台控制台 / 商户控制台 | 运营后台的两侧:平台方管全局;商户运营者管自己站(→ 15) |
| 引擎 / 能力 | 全租户共享的业务逻辑与数据模型 |
| 有效配置 EffectiveConfig | 默认模板 + 预设 + 租户覆盖 + 灰度合并后的最终配置 |
| 本位币 baseCurrency | 站的唯一记账与展示币种;站内全链路单币种 |
| 站型 | CNY 站 / USDT 站(= 本位币取值),一租户一站型,建站锁定 |
| 通道币种 channelCurrency | 充值/提现通道对外收付的币种,可 ≠ 本位币,边界锁价 |
| 链路 route | 场馆向厂商申报币种的选择:原生 / CNY 映射(→ 12) |
| 映射 mapping | CNY 映射链路下 1:1 标签替换(非换算、无小数、进出等值可逆) |
| 锁价 lockedRate | 边界事件发生时点快照的汇率,存单据、可审计 |
| 钱包 Wallet | 用户在本站本位币下的资金账户(可用 + 彩金 + 冻结);单币种站一人一钱包 |
| 打码 / 流水 | 有效投注额,用于解锁彩金、保级、返水计算 |
| 幂等键 | 资金/权益写操作的业务唯一键,重复请求不重复生效 |
| 工单 | 后台侧需审批的操作(资金调整、提现审核等),有自己的状态机(→ 15) |
| 展示契约 | 分册末定义的「字段 → UI」映射,前端对接依据 |
八、扩展点与开放问题
- 区域合规:不同地区对活动/币种/KYC 有强监管差异,配置层已留「合规强制层」,细则待 05 展开。
- 多语言:文案入配置层 + i18n 字典;以配置层文案键为准。
- 事件基础设施:事件的投递保证(至少一次 + 消费端幂等)与重放机制,属技术选型,文档只约束语义。
- 展示层金额渲染:各分册「展示契约」定义前端对接标准;资金面禁止「数字不变只换符号」的重刷(只格式化本位币,不做符号替换,→ 02 展示铁律)。