Files
cursor/plans/转盘与agent分享归因_d2e94766.plan.md
ray zhou 2dd9f17da9 ok
2026-06-29 14:51:55 +08:00

8.6 KiB
Raw Permalink Blame History

name, overview, todos, isProject
name overview todos isProject
转盘与Agent分享归因 实现「转盘分享双计agent + 转盘、agent 分享仅计 agent」wheel 与 user_agent 各一条 share_url 短码MQ 的 share_origin 直接来自 invite_code 查表console 仅 share_origin=wheel 时发转盘助力。
id content status
console-origin slot_console: wheel 独立落库 origin=wheelLogic 仅 wheel 计助力invite-link/createShareUrl 走 wheel 短码 completed
id content status
user-mq slot_user: shouldNotifyAgentByInviteOrigin 含 wheelMQ share_origin 来自 share_url.origin completed
id content status
agent-filter slot_agent建议: console 回调粗筛 share_origin=wheel completed
id content status
tests-docs 单测/集成测 + 需求文档/YApi/deploy 对齐(撤销 wheel→user_agent 映射说明) completed
false

转盘分享 vs Agent 分享单向归因方案share_origin 双短码)

产品规则SSOT

分享入口 share_url.origin Agent 邀请 Lucky Rewards 助力
转盘分享(from=wheel / invite-link wheel
Agent 分享(from=user_agent user_agent 不算

方案选型(已确认)

方案 A两条短码wheeluser_agentshare_url 各存一行,同一邀请人可有 两个 short_code

  • MQ share_origin 由注册时 invite_codeshare_url.origin 得到,无需 landing_scene无需 FE 注册透传额外字段。
  • 撤销当前 ShareService::resolvePersistOrigin()wheel → user_agent 的映射。
sequenceDiagram
    participant Inviter
    participant Console as slot_console
    participant User as slot_user
    participant Agent as slot_agent

    alt WheelShare
        Inviter->>Console: createShareUrl from=wheel
        Console->>Console: share_url origin=wheel 短码W
        Note over Inviter: 分享短码W
        User->>User: register invite_code=W
        User->>Agent: MQ share_origin=wheel
        Agent->>Console: callback share_origin=wheel
        Console->>Console: success发Spin
    else AgentShare
        Inviter->>Console: createShareUrl from=user_agent
        Console->>Console: share_url origin=user_agent 短码A
        User->>User: register invite_code=A
        User->>Agent: MQ share_origin=user_agent
        Agent->>Console: callback share_origin=user_agent
        Console->>Console: skipped_not_wheel
        Note over Agent: agent关系照常
    end

为何之前不能「只改 MQ 不改落库」

当前实现把 from=wheel 映射成 user_agent 落库(复用一条短码)。此时代码查表得到的 origin 永远是 user_agentMQ 无法出现 share_origin=wheel,除非 FE 在注册时强行覆盖 —— 那与 landing_scene 同类,且语义与 DB 不一致。

双短码后:invite_code 本身即归因,链路最简。


实现步骤

1. slot_consolewheel 独立短码 + 助力判定

ShareService

  • 删除或停用 resolvePersistOrigin() 对 wheel 的 user_agent 映射;SHARE_FROM_WHEEL 直接作为 createUrl()$from / ShareUrlModel.origin
  • isAgentShareFrom() 保持 user_agent + wheelagent 文案接口仍适用)。
  • 更新/替换 ShareServiceWheelFromTest:断言 wheel 创建后 origin=wheel,且与 user_agent不同 short_code(同一 uid 两行)。

GiftController::createShareUrl()

  • from=wheelcreateUrl(ShareService::SHARE_FROM_WHEEL),不再经 resolvePersistOrigin

LuckyRewardInviteLogic::buildInviteLink()

  • 同上,直接 createUrl(SHARE_FROM_WHEEL)
  • PHPDoc 更新:不再写「落库复用 user_agent 短码」。

LuckyRewardInviteLogic::handleInviteBind()

  • 将现有「必须 share_origin=user_agent」改为 必须 share_origin=wheel
if ($callbackDto->shareOrigin !== ShareService::SHARE_FROM_WHEEL) {
    return $this->buildInviteBindResult(
        InviteBindResultEntity::STATUS_SKIPPED_NOT_WHEEL,
        'Invite code origin is not wheel'
    );
}

InviteBindResultEntity

  • 新增 STATUS_SKIPPED_NOT_WHEEL = 'skipped_not_wheel'(保留旧 skipped_not_user_agent 常量亦可,新逻辑用新 status
  • 不需要 landing_scene / skipped_no_landing(除非后续另有用途)。

InviteBindCallbackDTO

  • 已有 shareOrigin,无需新增 landingSceneagent/SDK 侧 landing_scene 字段可留空,不读)。

2. slot_user发 MQ + agent 资格

AbstractRegisterService::shouldNotifyAgentByInviteOrigin()

return in_array($origin, ['user_agent', 'wheel'], true);

notifyAgentInviteBind()

  • share_origin 继续写 $this->invite_share_origin(来自 share_url.originwheel 注册自然为 wheel
  • 无需新增 landing_scene 属性或 MQ 字段(与 agent 侧已有 landing_scene 字段兼容即可,留空)。

resolveInviteUidByInviteCode() — 已读 shareRow->origin,双短码下无需改逻辑。

3. slot_agentconsole 回调粗筛(建议)

LuckyRewardInviteCallbackGatewayService::canNotifyInviteBind() 增加:

  • share_origin === 'wheel' 时 HTTP 调 consoleagent 绑定、奖励、关系同步不受影响,仍处理全部 invite_bind MQ
  • user_agent 绑定不再打 console减少无效请求。

4. 前端 / 产品说明

  • 转盘页 Copy Link / 社媒分享:使用 invite-linkcreate-share-url from=wheel 返回的 codewheel 短码)。
  • Agent 中心分享:继续使用 from=user_agent 返回的 code(另一条短码)。
  • 不要混用:用 agent 短码进转盘页,只计 agent、不计转盘 —— 符合产品规则。

5. 测试

仓库 用例
slot_console ShareServiceWheelFromTest:同 uid 存在 wheel + user_agent 两行、短码不同
slot_console LuckyRewardInviteLogicUnitTestshare_origin=user_agentskipped_not_wheelwheel + 新注册 → success
slot_console LuckyRewardInviteBindIntegrationTestbuildValidInviteBindPayload()share_originwheel
slot_user shouldNotifyAgentByInviteOriginwheel / user_agent 为 true其它为 false

6. 文档与 YApi


判定优先级console 更新后)

  1. invalid_params
  2. skipped_self_invite
  3. skipped_old_user
  4. skipped_not_wheel(原 skipped_not_user_agent 逻辑替换)
  5. activity_closed
  6. already_processed
  7. success

风险与边界

  • 历史已发出的 wheel 链接:若当时用的是映射后的 user_agent 短码,升级后只计 agent、不计转盘新 wheel 链接需走 invite-link / from=wheel 拿新短码。可在发版说明中写清。
  • 同一用户两条码:运营/客服需知 wheel 与 agent 链接不可互换。
  • 手工绑码share_url.origin 决定 MQ share_origin;绑 agent 码不计转盘。
  • slot_sdk / agent landing_scene 字段保留兼容,本期不参与判定。

涉及仓库

  • 必改slot_consoleslot_user
  • 建议改slot_agentHTTP 粗筛 share_origin=wheel
  • 不改slot_sdk(已有 share_origin 转发)
  • FE:使用正确短码即可,无 register 额外字段