From b223cc5f81e59783287cd47095adb8c88806f920 Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Sun, 12 Jul 2026 23:10:20 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E9=82=80=E8=AF=B7=E5=A5=96=E5=8A=B1=20?= =?UTF-8?q?+=20=E5=A5=96=E5=8A=B1=E4=BB=BB=E5=8A=A1(=E5=8A=A0=E5=85=A5=20T?= =?UTF-8?q?G=20=E9=A2=91=E9=81=93)=E8=AE=BE=E8=AE=A1=E6=96=87=E6=A1=A3(Spe?= =?UTF-8?q?c=20=E2=91=A1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 两条并行得分途径共用发天数原语(applySubscription source=invite/task): - 邀请两段式双方都得:注册各 +3、被邀请人首充双方再各 +7(每转化 +10/+10) - 奖励任务首个「加入 TG 频道」+3,Bot getChatMember 真校验 (token 绑号 → /tg/webhook → 查频道成员 → 发) 防刷:自邀请拦截 + invitee 唯一 + dp_uuid 设备去重 + 注册段月度封顶(首充不封) + telegram_id 全局唯一领 数据:users +invite_code/first_paid_at、referrals、通用 reward_claims 含 TG 验证时序 SVG 图;登记 docs/index.html。边界:不做现金/多级/退群回收, 通知集成留接缝待 Spec③。 Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/index.html | 5 + docs/invite-task-rewards-design.html | 247 +++++++++++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 docs/invite-task-rewards-design.html diff --git a/docs/index.html b/docs/index.html index e9b82b4..5955fc3 100644 --- a/docs/index.html +++ b/docs/index.html @@ -44,6 +44,11 @@

设计方案 / Specs

+ +
邀请奖励 + 奖励任务(加入 TG 频道)(Spec ②)HTML
+
用「送 Pro 会员天数」驱动增长,两条并行途径共用发天数原语(applySubscription source=invite/task)。① 邀请两段式双方都得:注册各 +3、被邀请人首充双方再各 +7(每转化 +10/+10)。② 奖励任务首个「加入 Telegram 频道」+3,经 Bot getChatMember 真校验(token 绑号→/tg/webhook→查成员→发)。防刷:自邀请拦截 + invitee 唯一 + dp_uuid 设备去重 + 注册段月度封顶(首充不封)+ telegram_id 全局唯一领。数据:users +invite_code/first_paid_at、referrals、通用 reward_claims。不做现金/多级/退群回收;通知集成留接缝待 Spec③。
+
docs/invite-task-rewards-design.html
+
账户 / 设置 / 联系 信息架构重构(Spec ①/3)HTML
去重 + 归位:App 自足、Web 退居次要;每功能一个家。桌面提 Account 为一级侧栏项,移动 Account tab 含设置/联系下钻。收敛联系渠道(×3→1)/语言主题(×2→1)/购买入口(散3→Account)。为「🔔 通知」(顶栏铃铛)+「邀请好友」(账户入口)预留落点。决策:奖励双方都得、兑换码保留、Web 链接保留。后续 ②推广激励 ③系统通知 另立 spec。
diff --git a/docs/invite-task-rewards-design.html b/docs/invite-task-rewards-design.html new file mode 100644 index 0000000..337dc13 --- /dev/null +++ b/docs/invite-task-rewards-design.html @@ -0,0 +1,247 @@ + + + + + +邀请奖励 + 奖励任务(加入 TG 频道) — 设计 + + + +
+← 文档索引 +

邀请奖励 + 奖励任务

+

设计文档 · 2026-07-12 · Spec ②(推广激励)· 状态 待评审

+ +
+目标:用「送 Pro 会员天数」驱动增长。两条并行的得分途径,共用同一条发天数链路:
+① 邀请好友 —— 两段式,双方都得(注册各 +3 天,被邀请人首充双方再各 +7 天)。
+② 奖励任务 —— 首个任务「加入 Telegram 频道」+3 天,经 Bot getChatMember 真校验。框架可扩展(后续「关注推特 / App 评分」复用)。
+发天数原语:复用现有 subscriptions 延时逻辑(applySubscription(..., source) = max(到期,now)+days),与付费 / 兑换码同一条,不造新轮子。 +
+ +

1 · 邀请奖励模型(两段式,双方都得)

+ + + + +
阶段触发邀请人被邀请人封顶
注册被邀请人用邀请码注册成功+3 天 Pro+3 天 Pro邀请人 N 次/月(默认 10)
首充被邀请人首次成功付费(任何档,含 ¥6 优惠)+7 天 Pro+7 天 Pro不封顶
+

每转化一个付费用户:邀请人累计 +10 天、被邀请人累计 +10 天。注册段是唯一「免费面」故设月度封顶;首充段真金白银自带成本,不封顶。

+ +

邀请码 / 链接 / 绑定

+ + +

2 · 防刷

+ + +

3 · 数据模型

+

users 加一列(SQLite / MySQL 两套迁移):

+ + + + +
类型说明
invite_codevarchar(16) UNIQUE本用户的永久邀请码;注册/首次访问邀请页时惰性生成。
first_paid_atdatetime NULL首次成功付费时刻;判「首充」+ 幂等首充奖励。
+ +

referrals —— 邀请关系(关系型,一对一绑定):

+ + + + + + + + + + +
类型说明
idPK
inviter_idbigint邀请人 user id(索引)。
invitee_idbigint UNIQUE被邀请人 user id;唯一 = 一人只被绑一次。
device_uuidvarchar被邀请人注册设备 dp_uuid(设备去重取证)。
statusvarcharboundreg_rewardedpaid_rewarded,或 rejected(防刷命中)。
reg_rewarded_atdatetime NULL注册段奖励发放时刻(幂等)。
paid_rewarded_atdatetime NULL首充段奖励发放时刻(幂等)。
created_atdatetime
+ +

reward_claims —— 通用一次性任务领取(TG 及后续任务复用):

+ + + + + + + + + +
类型说明
idPK
user_idbigint领取人。
task_keyvarchar任务标识,如 telegram_join
external_refvarchar外部去重键;TG 用 telegram_id
granted_daysint本次发放天数。
granted_atdatetime
约束:UNIQUE(user_id, task_key)(每账户每任务一次)+ UNIQUE(task_key, external_ref)(同一 telegram_id 只领一次)。
+

奖励发放本身落现有 subscriptions(source='invite' / 'task')+ sub_events 审计,不新增奖励台账表。

+ +

4 · 后端 API + 钩子

+ + + + + + + +
端点 / 钩子动作
Register(..., inviteCode)注册流程加 inviteCode 参:建号成功后解析码 → 邀请人 → 建 referrals(bound) → 过防刷闸(自邀请 / 设备去重 / 月度封顶)→ 发注册段双方 +3(reg_rewarded)。
pay webhook.settle()首充钩子:在 GrantPaidSubscriptionTx 之后,若 users.first_paid_at 本次由空转非空(=首充)且该用户是被邀请人(referrals 命中)→ 发首充段双方 +7(paid_rewarded,幂等)。
GET /v1/invite我的邀请码 / 链接 + 战绩:已邀请数、已转化(首充)数、累计获赠天数、明细列表;附奖励任务清单(TG 完成态)。
GET /v1/tasks/telegram/start签发绑定 token(10 分钟有效、绑当前账户),返回 bot 深链 t.me/<reward_bot>?start=<token>
POST /tg/webhookTelegram Bot 更新回调(secret 校验,与 pay webhook 同款外部回调):收 /start <token> → 校验成员 → 发 TG 任务 +3。详见 §5。
+ +

5 · TG 任务验证流程(Bot getChatMember)

+
+ + + + + + + + + + App(客户端) + + pangolin-server + + Telegram(Bot/API) + + + + + + + + + ① GET /v1/tasks/telegram/start + + ② 返回 t.me/<bot>?start=<token> + + ③ 拉起 bot,用户按 Start(/start token) + + ④ POST /tg/webhook(update:token + telegram_id) + + ⑤ getChatMember(频道, telegram_id) + + ⑥ status = member / administrator + + + ⑦ 发 +3 天(reward_claims) + + ⑧ sendMessage「✅ 已到账 +3 天」 + + ⑨ App 回前台 GET /v1/invite → 任务已完成 + + + 非成员 → bot 回「请先加入频道再验证」,不发 + +
+
    +
  1. token 短时有效(10 分钟)、一次性,绑当前账户 —— 防止链接被转发后他人领取。
  2. +
  3. webhook 安全:设置 Telegram secret_token,服务端校验 X-Telegram-Bot-Api-Secret-Token 头;路径也可带 secret 段。控制面经 Cloudflare Tunnel 已是公网 HTTPS,Telegram 可达,无需开入站端口
  4. +
  5. 成员判定:getChatMember 返回 member / administrator / creator 视为已加入;left / kicked / 查询失败视为未加入。
  6. +
  7. 不追溯退群:一次性发放,发后不因退群回收(回收体验差、收益低)。
  8. +
+ +

6 · 新基建(上线前置,需在 Telegram 侧配一次)

+ + +

7 · 客户端 UI

+

邀请页(占位屏已在)升级为「邀请 + 任务」两区,数据来自 GET /v1/invite:

+
+

邀请区(上)

+
    +
  • 真实邀请码 + 邀请链接,复制 / 系统分享。
  • +
  • 规则说明:注册双方各 +3、首充双方各 +7。
  • +
  • 战绩台账:已邀请 / 已转化 / 累计获赠天数 + 明细列表。
  • +
+

任务区(下)「更多得会员」

+
    +
  • 首张卡:加入 Telegram 频道 +3 天。
  • +
  • 未完成 → 「加入频道」+「验证领取」两步按钮。
  • +
  • 已完成 → 「已领 +3 天」置灰。
  • +
  • 未配 bot → 整卡不显示。
  • +
+
+

注册页:加「邀请码(选填)」输入框;deep link …/i/<code> 打开 App 自动预填并锁定。l10n 六语。

+ +

8 · 边界(YAGNI,本期不做)

+ + +

9 · 测试要点

+ + +

10 · 涉及文件(实现锚点)

+
# 后端
+server/internal/auth/service.go        # Register 加 inviteCode + 建 referrals + 注册段发奖
+server/internal/reward/                 # 新包:邀请/任务发奖 + 防刷闸 + getChatMember
+server/internal/pay/webhook.go          # settle() 首充钩子接首充段发奖
+server/internal/httpapi/                 # GET /v1/invite、/v1/tasks/telegram/start、POST /tg/webhook
+server/migrations/{mysql,sqlite}/        # users +2 列、referrals、reward_claims
+# 客户端
+client/lib/screens/invite_page.dart      # 占位 → 真实(邀请区 + 任务区)
+client/lib/widgets/auth_screen.dart      # 注册页加邀请码输入 + deep link 预填
+client/lib/services/ + state/            # invite api + provider(auth_api.Register 加 inviteCode)
+client/lib/l10n/                          # 六语文案
+ +

下一步:定稿后进 writing-plans 出逐任务实现计划(docs/superpowers/plans/2026-07-12-invite-task-rewards.md),Subagent 驱动执行。TG 新基建(bot / 频道管理员 / webhook)在实现前由你在 Telegram 侧配好。

+ +
+ +