213 lines
11 KiB
Markdown
213 lines
11 KiB
Markdown
# Host, Agency And BD Implementation Sequence
|
||
|
||
本文定义主播、Agency、BD、BD Leader 功能的开发顺序。详细 App 架构见 [Host Agency BD App Architecture](./主播公会BD架构.md),后台工资和政策架构见 [Host Agency BD Admin Architecture](./主播公会BD后台架构.md)。
|
||
|
||
核心原则:先做关系事实,再做 App 主链路,最后做统计和工资。工资依赖 host、Agency、BD 关系快照和有效上麦/礼物统计;如果先做工资后台,会得到一套没有可靠输入的数据系统。
|
||
|
||
## Phase 1: User Service Host Domain Core
|
||
|
||
先建立 `user-service` 内 host domain 的核心事实模型。本文不拆独立 `host-service` 微服务;host、Agency、BD、coin_seller、申请邀请、关系快照、统计和工资后台都属于 user-services,代码落在当前仓库的 `services/user-service`。
|
||
|
||
交付:
|
||
|
||
- 在 `services/user-service` 内新增 host domain:domain、service、storage/mysql、gRPC handler 和必要配置。
|
||
- 新增 protobuf:host profile、Agency、BD profile、coin_seller profile、Agency membership、application、role invitation 的内部 gRPC 契约,由 `user-service` 实现。
|
||
- 在 user MySQL schema 新增表:`host_profiles`、`agencies`、`bd_profiles`、`coin_seller_profiles`、`agency_memberships`、`agency_applications`、`role_invitations`、`host_outbox`。
|
||
- 所有 host domain 表、命令幂等键、查询条件和 outbox 都必须带 `app_code`;首个种子 App 是 `com.org.laluparty -> lalu`。
|
||
- 审计 host domain 表的主键和唯一键:如果继续使用全局 `PRIMARY KEY(user_id)`、`PRIMARY KEY(command_id)` 或 `PRIMARY KEY(event_id)`,则 ID 生成和命令 ID 必须全局唯一;如果要支持同 ID 跨 App 复用,必须先迁移为 `(app_code, id)` 或 `(app_code, command_id)`。
|
||
- 实现 command id 幂等:申请、邀请、审核、踢出、接受邀请都不能因重试重复创建事实。
|
||
- 实现关系锁:涉及用户身份变化时锁 `host_profiles`、`agencies`、`bd_profiles` 和 active membership。
|
||
|
||
验收:
|
||
|
||
- 同一用户不能同时存在两个 active Agency membership。
|
||
- active host 不能接受成为 Agency 的邀请。
|
||
- Agency owner 自动拥有 host profile 和 owner membership。
|
||
- coin_seller 可以和 Agency、BD、BD Leader 身份并存。
|
||
- `go test ./services/user-service/...` 通过。
|
||
- 修改 protobuf 后必须 `make proto && go test ./...`。
|
||
- 多 App 写入前必须完成 keying 审计,不能出现文档按 `app_code` 幂等、数据库却用全局唯一键导致跨 App 冲突的灰区。
|
||
|
||
## Phase 2: Minimal Admin For Organization Seed
|
||
|
||
先做最小后台组织初始化能力,不做完整工资后台。App 需要有 Agency/BD 数据才能跑搜索、申请和邀请主链路。
|
||
|
||
交付:
|
||
|
||
- Admin 创建/停用 BD Leader。
|
||
- Admin 创建/停用 BD,并绑定 `parent_leader_user_id`。
|
||
- Admin 创建/关闭 Agency,并绑定 `parent_bd_user_id` 和 owner。
|
||
- Admin 设置 Agency `join_enabled`。
|
||
- Admin 展示 coin_seller 列表,能新增 coin_seller;列表展示币商 `COIN_SELLER_COIN` 余额。
|
||
- Admin 所有关系命令必须显式选择 `app_code`,并把该值写入 user-service host domain 请求和后台审计 detail。
|
||
- Admin 关系操作由 `hyapp-admin-server` 写 `hyapp_admin.admin_operation_logs`;`user-service` 只写关系事实、`command_id` 幂等结果和领域事件。
|
||
|
||
暂不做:
|
||
|
||
- 不做 salary policy。
|
||
- 不做 salary cycle。
|
||
- 不做工资单审批。
|
||
- 不做 wallet 入账。
|
||
|
||
验收:
|
||
|
||
- Admin 创建的 Agency 可以被同区域用户搜索到。
|
||
- 关闭或禁用加入的 Agency 不出现在 App 搜索结果。
|
||
- Admin 新增的 coin_seller 可以在币商列表看到,且可以同时是 Agency/BD/BD Leader。
|
||
- 所有 Admin 关系变更都有审计记录。
|
||
- 同一 `command_id` 重试不会重复创建 BD/Agency。
|
||
|
||
## Phase 3: App Main Flow
|
||
|
||
这个阶段跑通用户真实路径。完成后,主播身份和组织关系才成为可靠事实。
|
||
|
||
交付:
|
||
|
||
- 用户搜索同区域 active、joinable Agency。
|
||
- 用户申请加入 Agency。
|
||
- Agency owner 或授权管理者审核、拒绝申请。
|
||
- Agency 踢出 host:只结束 membership,不删除 host identity。
|
||
- Kicked host 可以重新申请其他 Agency。
|
||
- BD 邀请用户成为 Agency。
|
||
- BD 自己邀请自己成为 Agency:仅限 BD 当前不是 active host 且没有 active Agency。
|
||
- BD Leader 邀请用户成为 BD。
|
||
- BD Leader 直接邀请用户成为 Agency。
|
||
- active coin_seller 给同区域玩家转金币:扣币商 `COIN_SELLER_COIN`,给玩家增加普通 `COIN`,并按该区域充值政策记录充值美元金额。
|
||
- App 查询:`host/me`、`agency/me`、`agency/members`、`agency/applications`、`bd/me`、`bd/agencies`。
|
||
|
||
验收:
|
||
|
||
- 用户只能看到自己区域内的 Agency。
|
||
- 用户只能看到自己 `app_code` 内的 Agency;不同 App 即使同区域也不能互相搜索或申请。
|
||
- 申请通过后用户成为 host 且有 active membership。
|
||
- Agency 踢人后用户仍是 host,但 `current_agency_id` 为空。
|
||
- active host 接受 Agency 邀请被拒绝。
|
||
- BD 加入别的 Agency 成为 host 时,BD 身份仍然保留。
|
||
- BD Leader 邀请 BD 时,目标只得到 BD 身份,不自动成为 host。
|
||
- 非 active coin_seller 不能调用币商转账。
|
||
- 币商余额不足时转账失败,玩家 `COIN` 不增加。
|
||
- 币商和玩家不在同一区域时拒绝转账;缺少 active 充值政策时不产生账务分录。
|
||
|
||
## Phase 3.5: App Message Notifications
|
||
|
||
关系主链路跑通后接入 App `消息` tab。通知是用户体验能力,不是关系事实提交前置条件;任何通知失败都不能回滚 host/Agency/BD 事务。
|
||
|
||
交付:
|
||
|
||
- host outbox 事件接入 message inbox owner,具体接口和表见 [App Message Tab Architecture](./App消息Tab架构.md)。
|
||
- Agency 申请提交后通知 Agency owner 或授权审核者。
|
||
- 申请通过、拒绝、被踢出 Agency 时通知目标用户。
|
||
- BD/BD Leader 邀请 Agency 或 BD 时通知被邀请人。
|
||
- 邀请被接受后通知邀请人刷新团队列表。
|
||
- 后台创建 BD Leader、BD、Agency 后通知目标用户或 owner。
|
||
- 所有消息使用 `producer=user-service-host`、稳定 `producer_event_id`,重复消费不重复入箱。
|
||
|
||
验收:
|
||
|
||
- 同一 host outbox 事件重复消费,只生成一条 App system 消息。
|
||
- 消息只出现在当前 `app_code`、目标 `user_id` 的 `system` 分区。
|
||
- App 点击消息后仍通过 host/agency/bd 查询接口读取最新事实。
|
||
- message inbox 失败时 host 关系事实已提交,outbox 可重试。
|
||
|
||
## Phase 4: Stats And Attribution
|
||
|
||
关系主链路稳定后再消费房间和钱包事件。麦上在线时长先按所有用户统一沉淀,详见 [User Mic Online Time Architecture](./用户麦上在线时长架构.md)。host stats 是派生读模型;工资和团队统计必须使用派生时的关系快照,不能从当前 membership 反推历史归属。
|
||
|
||
交付:
|
||
|
||
- 消费或读取用户麦上时长基础事实,默认只累计 `publish_state=publishing` 的 `mic_online_ms`。
|
||
- 消费礼物/钱包事件,累计 host 收到的礼物积分或等价统计。
|
||
- 写入通用用户麦时长表,并从中派生 `host_daily_stats`;`host_daily_stats` 包含 `agency_id`、`bd_user_id`、`bd_leader_user_id` 和非空 `relation_scope_key`。
|
||
- 写入 `host_event_dedup`,按 `event_id` 幂等消费。
|
||
- 构建 App 读模型:`host_me_view`、`agency_member_view`、`bd_team_view`、`earning_summary_view` 的基础查询。
|
||
|
||
验收:
|
||
|
||
- `pending_publish` 不计有效工作时长。
|
||
- 用户成为 host 前累计的用户级麦上在线时长不会丢;是否用于 host 任务由任务政策决定。
|
||
- host 一天内换 Agency 时,stats 按 relation snapshot 拆行。
|
||
- 同一事件重复消费不会重复累计。
|
||
- 迟到事件可以修正未锁定 stats;已结算结果交给 Admin 调整单处理。
|
||
|
||
## Phase 5: Full Admin Salary
|
||
|
||
最后做完整工资后台。此时输入已经稳定:关系事实、事件统计和归属快照都可用。
|
||
|
||
交付:
|
||
|
||
- 配置 host、agency、bd 三类 salary policy。
|
||
- 配置 `daily`、`weekly`、`semi_monthly`、`monthly` cycle cadence。
|
||
- 生成 salary cycle 和 salary items。
|
||
- Host salary:基于有效上麦时长、礼物积分、有效天数。
|
||
- Agency salary:基于下属 host salary item 或明确配置的 agency 指标。
|
||
- BD/BD Leader salary:基于 downstream host salary sum,且按 source host salary item 去重。
|
||
- 后台审核工资周期。
|
||
- 调用 `wallet-service` 给 `USD_BALANCE` 入账,幂等键为 `salary:{salary_item_id}`。
|
||
- 支持调整单:迟到事件、人工修正、争议处理都走补差或冲正。
|
||
- Salary posted 和 adjustment posted 事件接入 App message inbox,通知接收人查看收益明细;通知失败不影响钱包入账事实。
|
||
|
||
验收:
|
||
|
||
- 同区域同 policy type 不能同时启用多个 active policy。
|
||
- 同一 cycle 重算不会重复生成工资项。
|
||
- BD Leader 直接管理 Agency 时,同一 host salary source 只算一次。
|
||
- Salary cycle 重复 post 不会重复给钱包入账。
|
||
- 已 posted item 不可原地修改,必须通过 adjustment 修正。
|
||
|
||
## Phase 6: Hardening And Operations
|
||
|
||
主链路和工资链路都跑通后,再补运维和风险能力。不要在前几阶段提前把这些能力做成阻塞项。
|
||
|
||
交付:
|
||
|
||
- Admin export:工资周期、工资项、Agency 成员、BD 团队。
|
||
- Rebuild job:按事实表重建 App read model。
|
||
- Compensation job:扫描 outbox 未投递、钱包 posting 失败、事件消费失败。
|
||
- Risk checks:异常高礼物积分、异常上麦时长、重复设备/账号关系。
|
||
- Dashboard:cycle 状态、posting 失败数、事件消费延迟、host stats watermark。
|
||
|
||
验收:
|
||
|
||
- outbox 消费失败可重放。
|
||
- read model 删除后可从事实表重建。
|
||
- wallet posting partial failure 可继续重试未 posted item。
|
||
- 关键后台动作都有 audit log。
|
||
|
||
## Recommended Milestones
|
||
|
||
| Milestone | Scope | Can Demo |
|
||
| --- | --- | --- |
|
||
| M1 | Phase 1 | 用 gRPC 创建基础关系事实,证明幂等和锁正确 |
|
||
| M2 | Phase 2 | 后台创建 BD/Agency,App 可以搜到 Agency |
|
||
| M3 | Phase 3 | 用户申请、审核、踢出、重新申请、邀请链路完整跑通 |
|
||
| M3.5 | Phase 3.5 | 申请、邀请、后台创建关系结果能进入 App 系统消息 |
|
||
| M4 | Phase 4 | 有效上麦和礼物统计按关系快照落库 |
|
||
| M5 | Phase 5 | 后台生成工资单,审批后入账 `USD_BALANCE` |
|
||
| M6 | Phase 6 | 失败补偿、导出、重建和监控可用 |
|
||
|
||
## Stop Conditions
|
||
|
||
- Phase 1 没有完成前,不做工资政策和工资周期。
|
||
- Phase 2 没有完成前,不做 App Agency 搜索上线,因为没有可信组织种子数据。
|
||
- Phase 3 没有完成前,不做工资发放,因为 host/Agency/BD 归属还不稳定。
|
||
- Phase 4 没有完成前,不做真实工资入账,因为缺少可审计统计输入。
|
||
- Phase 5 没有完成审批和幂等 posting 前,不允许写 `USD_BALANCE`。
|
||
|
||
## Verification Commands
|
||
|
||
文档落地到代码后,按改动范围验证:
|
||
|
||
```bash
|
||
make proto
|
||
go test ./...
|
||
docker compose config
|
||
```
|
||
|
||
涉及本地启动链路时再运行:
|
||
|
||
```bash
|
||
docker compose up -d
|
||
docker compose ps
|
||
docker compose down
|
||
```
|