zzhyyyyy
3a60672f95
Merge remote-tracking branch 'origin/main' into feat/withdrawal-rewarded-ad
2026-06-24 22:18:53 +08:00
zzhyyyyy
9986a8c4f8
feat(ad): 提现看视频广告后端支持(withdrawal_ad 场景 + 开关下发)
...
- pangle-callback 新增 withdrawal_ad 场景:不发金币、只记一条幂等(coin=0),
避免提现看视频被穿山甲 S2S 回调误发金币
- ad_config 新增 withdrawal_ad_enabled 开关(默认 true),贯穿 admin schema 与
platform 下发接口,客户端拉取后用(关=直接放行提现)
- 提现广告 eCPM 复用 /ad/ecpm-report,以 ad_type=withdrawal_video 区分收益,无需 DB 迁移
2026-06-24 22:18:52 +08:00
guke
8008366abc
fix(wx-cps): 修复 微信cps分发时淘宝落地页授权刷新导致click_value 重复入库问题 0624 ( #73 )
...
通过authed=1判断当前请求是否是微信授权回填,如果是授权回填,不再insert cps_click
---------
Co-authored-by: guke <guke@autohome.com.cn >
Reviewed-on: #73
Co-authored-by: guke <guke@wonderable.ai >
Co-committed-by: guke <guke@wonderable.ai >
2026-06-24 18:15:44 +08:00
zhuzihao
d8c7a6d1ef
feat(auth): 测试账号免验证码登录 + 每次走引导 + 每日上限 ( #69 )
...
Co-authored-by: zzhyyyyy <2685922758@qq.com >
Reviewed-on: #69
Co-authored-by: zhuzihao <zhuzihao@wonderable.ai >
Co-committed-by: zhuzihao <zhuzihao@wonderable.ai >
2026-06-24 03:53:52 +08:00
chenshirui
a6f55a00b8
feat(device): 无障碍保护存活心跳检测 + 掉线后置检测(pull) ( #65 )
...
Co-authored-by: 陈世睿 <2839904623@qq.com >
Reviewed-on: #65
Co-authored-by: chenshirui <chenshirui@wonderable.ai >
Co-committed-by: chenshirui <chenshirui@wonderable.ai >
2026-06-23 17:33:38 +08:00
marco
a584e1f59f
feat(comparison): 比价记录累计 LLM token(入/出)并在 admin 展示
...
server 从 llm_calls[].usage 累加 prompt/completion_tokens 落库,admin 比价记录列表/详情据此展示 token 数与估算成本;配套迁移 comparison_token_cols。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-23 17:24:54 +08:00
chenshuobo
f868414966
feat(feedback): 补齐反馈历史审核发奖闭环 ( #66 )
...
- 新增反馈审核字段和迁移,支持 pending/adopted/rejected、未采纳原因和采纳金币
- 增加用户端反馈历史 records 接口和 admin 采纳/拒绝接口
- 采纳时同事务写状态、金币流水和审计日志,拦截重复审核
- 验证:pytest tests/test_feedback.py tests/test_admin_write.py tests/test_admin_read.py
---------
Co-authored-by: lowmaster-chen <1119780489@qq.com >
Reviewed-on: #66
Co-authored-by: chenshuobo <chenshuobo@wonderable.ai >
Co-committed-by: chenshuobo <chenshuobo@wonderable.ai >
2026-06-22 23:18:42 +08:00
zhuzihao
8a2f72d366
feat(user): 昵称上限放宽到 20 字(与客户端/原型一致) ( #63 )
...
Co-authored-by: zzhyyyyy <2685922758@qq.com >
Reviewed-on: #63
Co-authored-by: zhuzihao <zhuzihao@wonderable.ai >
Co-committed-by: zhuzihao <zhuzihao@wonderable.ai >
2026-06-21 00:16:40 +08:00
marco
f7a3ef2e0b
feat(internal): 启动确认窗 agent 兜底样本落盘(pricebot 回写)
...
- 新增内部端点 POST /internal/launch-confirm-sample(X-Internal-Secret 鉴权):
pricebot 对没见过文案的启动确认窗用 LLM 兜底放行后,把样本(host 包 / 弹窗树 /
LLM plan / 设备 locale 机型)回写落 launch_confirm_sample 表,供研发人工沉淀回
pricebot 规则 yaml
- 配套: model LaunchConfirmSample + schema + repo(都上报不去重) + alembic 迁移
launch_confirm_sample_table(down_revision=cps_wx_user) + main 注册 router +
models/__init__ 登记
- docs: 后端技术实现.md 加 §6.5 pricebot 回写内部端点说明
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-20 13:39:45 +08:00
marco
d8358a6816
fix(user): 注销账号前置校验资金余额 + 释放微信/邀请码唯一约束
...
- delete_account 端点: 有可提现现金余额 / 在审提现单(reviewing)时拒绝注销(409), 防余额锁死在 deleted 行无法退出; pending 提现已在途不拦(对账 worker 不依赖 user.status)
- soft_delete_account: 注销连带清 wechat_openid/nickname/avatar(释放微信绑定槽, 否则该微信永久无法再被任何账号绑定→提现通道锁死) + invite_code(释放邀请码唯一槽)
- wallet 新增 get_cash_balance_cents(只读, 不建账户) 供注销前置校验; 复用 has_reviewing_withdraw
- 新增 tests/test_delete_account.py
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-20 02:03:33 +08:00
marco
95a07f75b7
feat(ad): 穿山甲广告配置后台化(app_id/各位ID/验签密钥/各场景开关)
...
- app_config 存 ad_config(默认=客户端当前内置 ID,空库维持现状)
- GET /platform/ad-config 下发客户端(不含验签密钥 reward_mkey)
- admin GET/PATCH /admin/api/ad-config 读写(operator/finance + 审计,mkey 不记明文)
- pangle 回调验签 m-key 优先读后台配置、.env 兜底兼容
- 比价/领券信息流位拆分(compare/coupon_feed_code_id)
- 客户端需发版接入 /platform/ad-config 才生效;本次后端就绪、不影响现状
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-20 01:35:17 +08:00
marco
733a51260f
feat(cps): 微信网页授权加总开关 WX_MP_OAUTH_ENABLED(默认关)
...
服务号认证审核中,先关掉落地页授权(走原逻辑不跳授权/不拿 openid),整套微信代码保留。
审核通过后 .env 置 WX_MP_OAUTH_ENABLED=true + 重启即启用,无需改代码。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-19 12:03:58 +08:00
marco
7fd70a264d
feat(cps): 微信网页授权接入——落地页拿 openid/昵称头像,用户级群统计
...
- 服务号网页授权(WX_MP_APPID/SECRET,区别于 App 的 WECHAT_APP_ID):
落地页 base 静默拿 openid;点「领券」补 userinfo 拿昵称头像(交互触发避快照页)
- 新表 cps_wx_user + cps_click 加 openid + 迁移;integrations/wx_oauth
- /c/{code} 授权链路 + 回调 /wx/oauth/cb + cookie 免重复授权;click 带 openid
- admin 群详情加「群内微信用户」(领券画像)端点
- 下单归因到人需 user-level sid,本期只做身份+领券侧
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-19 11:44:11 +08:00
marco
4b98d405d7
feat: OTA 版本下发端点(检查更新)
...
- app_config 加 get/set_app_version(独立 key,复用表不进 CONFIG_DEFS)
- GET /api/v1/platform/app-version 公开读 + POST /internal/app-version 内部写(X-Internal-Secret)
- tests/test_app_version.py 5 端到端测试
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-19 08:31:31 +08:00
marco
42be0f828f
feat(cps): 加微信网页授权域名校验文件端点(MP_verify)
...
coupon.shaguabijia.com 全反代 app-server,微信请求该域名根目录 MP_verify_xxx.txt
验证域名归属(放根目录)。为微信网页授权(落地页拿 openid)接入做准备。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-19 05:53:45 +08:00
marco
3cab3b9055
fix(compare-record): admin 放行 cancelled 筛选 + llm_calls 拉取改后台任务
...
- admin 列表 status pattern 加 cancelled(客户端会上报用户终止比价)
- 上报端点拉 pricebot llm_calls 改 BackgroundTasks 异步回填, 不阻塞上报响应(独立 session)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-17 23:32:36 +08:00
marco
a2fd666203
feat(admin): 比价记录 debug 页后端——补全链路 + DB 迁移
...
model/schema 的 debug 字段已在 4ee6de2 起头,本次补完整条链路:
- repo upsert 存客户端环境/性能字段;端点同机拉 pricebot llm_calls 落库 + 算 llm次数/重试
- schema 加 platform_results 透传(admin「卡在哪一步」从 raw_payload 读)
- admin 比价记录查询接口(按 user_id/phone 列表分页 + 详情含 llm_calls)
- 迁移 comparison_debug_fields: 给 comparison_record 加环境/性能/llm_calls 列(全 nullable)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-17 22:33:33 +08:00
marco
d55f47fc59
feat(cps): 淘宝活动落地页图做活——每活动关联图,运营上传/选已有
...
- model: cps_activity.image_url + 迁移 cps_activity_image 回填存量淘宝活动为现有图
- admin: 新建淘宝活动必传图(上传 /upload-image 或选已有 /activity-images),存绝对 URL
- 落地页 cps_redirect: 按 link→activity 取图展示,缺图兜底默认图,img src 经 html.escape
- media: save_cps_image + to_abs_media_url(基于 CPS_REDIRECT_BASE,跨域 admin-web 可显示)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-17 21:32:10 +08:00
marco
7368a1ca8a
feat(cps): 淘宝落地页改用设计图主视觉 + 复制按钮上提至 75% 屏高
...
- banner/card 手画区域整体换成设计图 /media/taobao_landing.jpg(~240KB jpg)
- 复制淘口令按钮从底部固定上提到 top:75vh, 上方留白
- 图入库(data/media 白名单, 同 dl.html 先例), 同域 /media serve
- 淘口令注入 / 复制 / toast 逻辑不变
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-17 20:53:34 +08:00
marco
3a40f617bd
feat(cps): 后端接入淘宝/京东多平台(payload + 群多平台 + 复制统计 + 迁移)
...
- model: cps_group.platforms 多选 / cps_activity.payload(淘口令/京东链接)
/ cps_link.sid 可空 + 复制统计
- admin API: 群与活动平台多选、批量生成落地页短链 referral-links、对账字段可空
- 落地页 cps_redirect: 淘宝展示淘口令(记 copy 事件) / 京东 302 / 美团原逻辑
- 迁移 cps_v2_platforms: 加 platforms/payload/event_type 列, sid 放宽可空(含 downgrade)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-17 19:21:20 +08:00
marco
003fd9d986
feat(compare): 失败比价记录支持 trace 链接
...
compare.py 加 /trace/finalize 透传(按 trace_id 一致性 hash 落同一 pricebot 进程);compare_record.py list_records 加 include_trace,对本人记录在调试态(客户端 agent 调试模式)放行 trace_url。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-17 15:56:15 +08:00
ouzhou
04edb50acc
feat(admin/ad): 提现自动对账后台开关 + 客户端广告 flags 端点 + 穿山甲多 m-key 验签 ( #59 )
...
- 自动对账接入 app_config 运行时配置(新增 bool 配置类型):env 部署总闸 + DB 运营日常开关
双层;worker 每轮读 DB 即时生效,健康检查改报「env AND DB」实际生效态
- 新增 GET /api/v1/platform/flags(不鉴权)下发 comparing_ad_enabled 远程 kill-switch,
客户端拉取后缓存;空库回退默认 True
- 穿山甲发奖回调支持多激励位 m-key(三命名项 PANGLE_REWARD_SECRET_TEST/_DEDICATED/_PROD
+ 旧逗号分隔合并去重),verify_callback_sign_any 逐个验签任一通过即受理;向后兼容旧单 key
- 补 test_platform / bool config 用例;app_config 文档同步
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
---------
Co-authored-by: OuYingJun1024 <1034284404@qq.com >
Reviewed-on: #59
Co-authored-by: ouzhou <ouzhou@wonderable.ai >
Co-committed-by: ouzhou <ouzhou@wonderable.ai >
2026-06-17 10:37:54 +08:00
marco
277f9b16a2
feat(cps): 群发券分发与对账 + 短链点击追踪
...
群(sid)/活动池/转链(带sid)/美团 query_order 按 sid 对账/按群统计;
短链 /c/{code} 记点击(PV/UV)→302 跳美团,点击→下单漏斗。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-17 10:00:29 +08:00
marco
f15ca74a22
feat(store-mapping): JD 缓存 deeplink 失效标记(对标淘宝) ( #56 )
...
Reviewed-on: #56
2026-06-16 01:25:57 +08:00
ouzhou
f7d86011c1
feat(ad-revenue): admin 广告收益报表(按 用户/日期/类型/应用/代码位 聚合) ( #54 )
...
- 新增 GET /admin/api/ad-revenue-report:展示条数/收益 + 复用金币审计逐条复算做发奖对账
- ad_ecpm/ad_reward/ad_feed_reward 各加 app_env + our_code_id 两列(alembic 迁移)
- ecpm-report / feed-reward 接收并落库 app_env/our_code_id;激励发奖按 ad_session_id 回填
- ad_audit 抽出 audit_rows,报表与逐条审计复用同一复算口径
- 组级 matched 改「组内逐条全一致」,避免应发和==实发和的互相抵消掩盖错误
- list_feedbacks 改 offset 分页并返回 total(配合 admin 页码分页)
- 反馈正文上限 _CONTENT_MAX 2000→200
- 文档:新增 admin-ad-revenue-report,更新 ecpm/feed-reward/feedback 及对应 db docs
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
---------
Co-authored-by: OuYingJun1024 <1034284404@qq.com >
Reviewed-on: #54
Co-authored-by: ouzhou <ouzhou@wonderable.ai >
Co-committed-by: ouzhou <ouzhou@wonderable.ai >
2026-06-15 23:13:14 +08:00
marco
9ec9d2389d
feat(store_mapping): 淘宝缓存 deeplink 失效检测→标记→回退(app-server 侧) ( #53 )
...
加 taobao_deeplink_invalid_at 列(迁移+model);mark_taobao_deeplink_invalid 按 shopId 标记所有行;lookup_nearest 过滤失效淘宝候选;新增 POST /internal/store-mapping/invalidate。+ 7 单测。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Reviewed-on: #53
2026-06-15 18:07:32 +08:00
liujiahui
8fa55eec3e
fix(coupon): 领券弹窗频控按 App 独立 + debug 全重置补全 ( #52 )
...
bug: 弹窗 engagement 表只按 (device, 日) 全局记一条,美团弹过/领过就把整台设备当天
标记 engage,淘宝/京东被压住不弹。需求是美团/淘宝/京东各自独立、每日各弹一次。
改动:
- model: CouponPromptEngagement 加 package 列,唯一约束 (device,日) → (device,package,日)
- alembic: 新增迁移 coupon_engage_per_package(加列 + 改唯一约束, batch_alter_table)
- repository: has_engaged_today / mark_engagement 加 package 维度;新增 reset_today_completion
- api: should-show / dismiss 接收 package;coupon_step(step=0) 按 App 记 engagement;
补 /prompt/shown 接口(客户端一直在调但后端缺失, 原 404);
补 /completed-today/reset(开发设置全重置用, 解首页卡置灰)
验证: curl 端到端 —— 美团弹过后 should-show 美团=false 淘宝/京东=true;
shown/reset/completion-reset 端点全 ok。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
---------
Co-authored-by: no_gen_mu <liujianhishen@gmail.com >
Reviewed-on: #52
Co-authored-by: liujiahui <liujiahui@wonderable.ai >
Co-committed-by: liujiahui <liujiahui@wonderable.ai >
2026-06-14 23:41:54 +08:00
ouzhou
27f76918b2
feat(admin): 运营后台跟进——review 加固 + 反馈改版 + 列表页码分页 ( #51 )
...
本 PR 汇合三块运营后台改动(原 #50 仅含其中「加固」一块,已并入本 PR 并关闭)。
## 1. review 加固 (436b2a3 )
- 超管防自锁:降级/禁用最后一个 active super_admin 前校验,杜绝零超管死局
- 时间筛选统一 tz-aware(列为 timestamptz),比较绝对时刻、不依赖 DB 会话时区
- 上报审核 / 调余额(set·扣减)加行锁,防并发/连点重复发钱
- ad_audit 复算排序补 id 次级键;health-check 限 finance;调账/拒绝 reason 去空白校验
## 2. 反馈改版 (5a18dbb )
- contact 可选、截图≤6;admin 反馈列表筛选/排序;admin·wallet 接口调整 + docs
## 3. 列表页码分页 (1a7a624 )
- CursorPage 加 total;新增 offset_paginate(count 与分页同源)
- 上报/审计日志从 id 游标改 offset 分页(支持跳页)
- 用户 / 提现 / 上报 / 审计日志 四页接入页码分页
测试:admin 套件 47 passed。前端配套改动见 shaguabijia-admin-web。
---------
Co-authored-by: OuYingJun1024 <1034284404@qq.com >
Reviewed-on: #51
Co-authored-by: ouzhou <ouzhou@wonderable.ai >
Co-committed-by: ouzhou <ouzhou@wonderable.ai >
2026-06-14 22:54:07 +08:00
marco
8659a7ed2b
feat(store_mapping): 跨平台店铺映射表 + pricebot 内部上报端点 ( #48 )
...
新增「平台店铺表」资产层: 淘宝比价拿到 shopId 后, pricebot server→server 把跨平台
店铺身份(各平台 id/名 + 地理 + 来源)落库, 作为未来"我见过这家店→跳过重搜/匹配"的源头。
与 price_observation(价格事实)平行、独立。
- models/store_mapping.py: store_mapping 表 22 列 —— 跨平台身份(id/name_taobao/meituan/jd)
+ 地理(city/geohash/lng/lat/taobao_address) + 溯源(source_platform/trace_id/device/user)
+ 淘宝原料(share_url/resolved_url/deeplink) + attrs(JSONB) + created_at。
- schemas/store_mapping.py + repositories/store_mapping.py: append-only, trace_id 幂等
(pricebot 重试/replay 不重复写; 并发 IntegrityError 兜底返已存在行), 跨方言安全。
- api/internal/store.py: POST /internal/store-mapping(复用 price.py 共享密钥 X-Internal-Secret 校验)。
- 注册 model(__init__) + router(main.py); 迁移 store_mapping_table 接现 head coin_txn_task_ref_uq。
验证: alembic 单 head + 零模型/迁移漂移; TestClient 全链(无密钥401/有密钥inserted=1/幂等inserted=0/错密钥401)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Reviewed-on: #48
2026-06-14 01:24:29 +08:00
ouzhou
8d7b91219a
feat(wallet): 解绑微信前对待审核提现二次确认 ( #46 )
...
## 改动
解绑微信前若有**待审核(reviewing)**提现单,首次解绑被拦下返回二次确认,用户确认后带 `force=true` 才真解绑。
- `schemas`: `UnbindWechatRequest{force}` + `UnbindWechatResultOut{needs_confirm, message}`
- `repositories`: `has_reviewing_withdraw`(只看 reviewing)
- `api`: `unbind-wechat` 接受可选 body(兼容旧无 body 客户端);`bound` 返回真实绑定态
- `docs/api`: 同步协议
## 为什么只拦 reviewing
reviewing 单解绑后审核打款会回读空 openid → 自动退回现金(钱不丢、只为让用户知情);pending 转账已在途、解绑影响不到,不拦。
配套客户端见 shaguabijia-app-android 同名分支。
🤖 Generated with [Claude Code](https://claude.com/claude-code )
---------
Co-authored-by: OuYingJun1024 <1034284404@qq.com >
Reviewed-on: #46
Co-authored-by: ouzhou <ouzhou@wonderable.ai >
Co-committed-by: ouzhou <ouzhou@wonderable.ai >
2026-06-13 03:53:43 +08:00
marco
e8bd12cc1f
feat(onboarding): force_onboarding 改设备维度 + admin 设备管理 + status 查询
...
废弃 force_onboarding(运营按用户强制引导,客户端不认——被 onboarding_completed 压过),
改用 onboarding_completion(设备+账号 维度),admin 直接增删该表记录控制重走。
- 删 force_onboarding: User 列 + auth/admin schema + admin 接口 + mutations + repo
clear + /onboarding/complete 调用 + 3 测试;新增 alembic 迁移删列
- admin 设备管理: 列设备(按 device 聚合) / 重置单设备 / 全部重置(清 onboarding_completion)
- 新增 GET /api/v1/user/onboarding/status: 客户端已登录启动查"本设备是否要重走引导"
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-12 00:51:47 +08:00
zhuzihao
3d07461ef5
feat(force-onboarding): 运营一键开启新手引导 — User.force_onboarding + admin 接口 + /me 带出 + 走完自动清 ( #43 )
...
- User 新增 force_onboarding 列(仿 debug_trace_enabled)+ 迁移 user_force_onboarding。
- POST /admin/api/users/{id}/force-onboarding(operator 角色 + 审计 user.force_onboarding.set)。
- UserOut(/me 与登录响应)带出该字段;/api/v1/user/onboarding/complete 走完即自动清回 false,只触发一次。
- 测试:admin 设置+审计+角色守卫、走完引导自动清标记。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
---------
Co-authored-by: zzhyyyyy <2685922758@qq.com >
Reviewed-on: #43
Co-authored-by: zhuzihao <zhuzihao@wonderable.ai >
Co-committed-by: zhuzihao <zhuzihao@wonderable.ai >
2026-06-10 22:27:06 +08:00
marco
a753843804
美团 feed 改用离线库 + 三 tab 降级兜底(替换 main 的实时版 feed) ( #40 )
...
把 main 的实时 feed 换成离线库版本 + status 降级兜底:
- rec 智能推荐:改走离线库 meituan_coupon 筛佣金≥3%(SQL 去重+排序+分页),不再实时撞限流
- distance 距离最近:改实时搜索翻页(sortField=6),按用户真实位置由近及远排
- top_sales 销量最高:改 SQL DISTINCT ON 分页,修原全表拉取+全量解析的翻页卡顿
- 四路加 status(ok/empty/degraded):空库/上游失败均返 200 不再 5xx;/coupons 502 软化为降级
- FeedResponse/CouponListResponse 加 status 字段(默认 ok,向后兼容)
注意:替换 main #18 的实时 feed 实现,需 review 行为变更;依赖的离线库由 ETL 灌(见 meituan-etl PR)
---------
Co-authored-by: chenshuobo <1119780489@qq.com >
Reviewed-on: #40
2026-06-10 20:05:50 +08:00
zhangxianze
bf82c68408
feat(compare): 美团比价前用券透传端点 /intent/precoupon/step ( #41 )
...
## 背景
客户端在美团源比价的**意图识别前**先循环调本端点用券。app-server 只做透传壳(决策在 pricebot-backend)。
## 改动
- 新增 `POST /api/v1/intent/precoupon/step` → 透传到 pricebot-backend `/api/intent/precoupon/step`
- 同 `/intent/step` 透传壳: 不鉴权、不做 schema 校验, device_id 透传区分设备
## 测试
- 链路自测(:8770 → :8000) + 真机实测用券成功
## 关联(跨三仓库, 同名分支 `feat/meituan-precoupon`)
- WonderableAI/pricebot-backend
- WonderableAI/shaguabijia-app-server
- WonderableAI/shaguabijia-app-android
**改协议字段需三仓库一起改。**
🤖 Generated with [Claude Code](https://claude.com/claude-code )
---------
Co-authored-by: xianze <ze@192.168 .0.128>
Reviewed-on: #41
Co-authored-by: zhangxianze <zhangxianze@wonderable.ai >
Co-committed-by: zhangxianze <zhangxianze@wonderable.ai >
2026-06-10 19:35:58 +08:00
zzhyyyyy
dacb37e3e1
feat(onboarding): 新手引导完成按 设备+账号 去重(表/模型/仓储/端点/迁移/测试)
...
- onboarding_completion 表(user_id+device_id 唯一约束)+ model + repository
- POST /api/v1/user/onboarding/complete 标记完成;登录响应 TokenWithUser.onboarding_completed
(按登录请求带的 device_id 判定是否已走过引导,跨卸载重装稳定)
- alembic 迁移 onboarding_completion(rebase 到最新 main 后已链在 coupon_daily_completion 之后,单 head)
- docs/database 文档 + tests/test_onboarding.py + run.bat(本地启动脚本)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-10 18:32:51 +08:00
liujiahui
0890e693d7
feat(coupon): 今日跑完整轮领券后端记录 + 查询(首页置灰源) ( #34 )
...
新增 coupon_daily_completion 表:按 (device_id, 自然日) 记"今天是否已跑完
整轮领券(到 done 帧)"。客户端据此把首页「去领取」卡置灰、不可点。
口径(用户决策 A 方案):到 done 即算,不管单券成败 —— 失败/跳过常是无障碍/
环境问题,重复点也补不回来。判断维度 device_id,与 engagement/claim 一致。
- model CouponDailyCompletion(uq device+complete_date,仿 CouponPromptEngagement)
- repo has_completed_today / mark_completed_today(幂等 upsert + IntegrityError 兜底)
- schema CouponCompletedTodayOut(completed: bool)
- coupon_step 透传链路在 action.command=="done" 那帧 best-effort 写完成记录
(pricebot 只在整轮全跑完才保留 command=="done",故无需再判 continue)
- GET /api/v1/coupon/completed-today?device_id= 供首页查询
- alembic 迁移 coupon_daily_completion(down_revision=0cf18d590b1d 当前 head)
合并后需 alembic upgrade head,否则 /completed-today 500。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
---------
Co-authored-by: no_gen_mu <liujianhishen@gmail.com >
Reviewed-on: #34
Co-authored-by: liujiahui <liujiahui@wonderable.ai >
Co-committed-by: liujiahui <liujiahui@wonderable.ai >
2026-06-10 16:07:33 +08:00
ouzhou
0bddce516f
feat(ad): eCPM 单位统一为分 + 新增看广告金币审计接口 ( #32 )
...
- eCPM 口径修正:getEcpm 原值是分/千次,新增 parse_ecpm_fen;parse_ecpm_yuan
改为 ÷100 转元,因子1 阈值按元判档(100/200/400),收益换算用元
- test-grant 用客户端按 ad_session_id 上报的真实 eCPM 发奖(取不到/≤0 兜底 200)
- 新增 GET /admin/api/ad-coin-audit 只读复算对账(router/repo/schema),复用发奖公式
- 同步更新 docs/api、docs/database 的分/元口径
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
---------
Co-authored-by: OuYingJun1024 <1034284404@qq.com >
Reviewed-on: #32
Co-authored-by: ouzhou <ouzhou@wonderable.ai >
Co-committed-by: ouzhou <ouzhou@wonderable.ai >
2026-06-10 15:53:52 +08:00
marco
953a05a5e6
feat(debug-trace): 调试链接权限 + trace_url 落库与按权限下发 ( #35 )
...
- user 加 debug_trace_enabled、comparison_record 加 trace_url
- 迁移 f8d3b1e60a27:加两列,down_revision 用 tuple 顺带合并既存双 head(invite_fingerprint_table + 044dce6e9b1f)
- UserOut 加 debug_trace_enabled → /me 与登录响应带出
- ComparisonRecordIn/Out 加 trace_url;upsert 落库
- /compare/records 列表与详情按 user.debug_trace_enabled 下发;详情连 raw_payload 里那份一并抹掉,防权限绕过
- admin 加 POST /users/{id}/debug-trace(operator + 审计),列表带该字段
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
Reviewed-on: #35
2026-06-10 15:35:08 +08:00
xiebing
b2f5a53dd8
feat(invite): 被邀请人列表接口 + 指纹归因(任务3) ( #31 )
...
- GET /invitees: 分页 + 名字降级兜底(昵称→微信昵称→脱敏手机号)
- 指纹归因: 落地页采集 + (IP,设备型号)反查撞库 + 时间窗口闸
- test_invite: +5 个列表测试(脱敏/倒序/昵称优先/分页/空), 修指纹测试跨用例串味
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Reviewed-on: #31
Co-authored-by: xiebing <xiebing@wonderable.ai >
Co-committed-by: xiebing <xiebing@wonderable.ai >
2026-06-09 21:48:48 +08:00
marco
25b2b6850b
feat(coupon): 领券弹窗频控加重置端点 + reset_today_engagement ( #29 )
...
- 加 POST /api/v1/coupon/prompt/reset:删该设备今日 engagement → has_engaged_today 变 false、
今天又能弹。开发设置「重置今日领券弹窗状态」按钮调它(客户端改纯后台频控后前台清缓存已失效)
- coupon_state 加 reset_today_engagement(按 device_id + 今天删);should-show 文档改为"纯后台判据"
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Reviewed-on: #29
2026-06-09 11:18:07 +08:00
ouzhou
d7c29c0883
feat(coin): 金币数值体系二期——看广告按 eCPM 发奖 + ad_session_id 幂等 + 签到膨胀固定金币 ( #28 )
...
- rewards: 激励视频实发改按 calculate_ad_reward_coin(eCPM, 当日第N次) 公式;AD_REWARD_COIN/MAX_AD_REWARD_COIN 降为历史兼容口径;新增 SIGNIN_BOOST_COIN=2000
- 签到膨胀: Day1-13 看完激励视频额外发固定金币、Day14 不允许 (signin.py / signin-boost)
- ad_session_id 幂等: ad_ecpm/ad_reward/ad_feed_reward 记录加 ad_session_id 列 + 唯一索引(新迁移 coin_reward_phase2 / ad_feed_reward_session)
- ad.py + schemas + repositories: ecpm-report / feed-reward / reward-status / test-grant 改造;config_schema 增 signin_boost_coin;admin stats overview 补充
- 同步 docs/api + docs/database + docs/integrations/pangle 及 tests(test_ad_reward / test_welfare)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
---------
Co-authored-by: OuYingJun1024 <1034284404@qq.com >
Reviewed-on: #28
Co-authored-by: ouzhou <ouzhou@wonderable.ai >
Co-committed-by: ouzhou <ouzhou@wonderable.ai >
2026-06-09 01:56:47 +08:00
ouzhou
6432497af1
feat: 后端接入微信提现人工审核与资金安全校验 ( #27 )
...
提现申请改为先扣款并进入待审核,审核通过后才发起微信打款,审核拒绝或微信失败时自动退款。
新增运营后台提现列表的关键词搜索、日期筛选、快捷筛选和排序参数,并支持批量通过、批量拒绝、批量刷新查单。
新增微信支付配置健康检查、现金账本校验、自动对账 worker 和单实例保护。
新增数据库唯一索引,约束同一用户未完成提现和同一提现单重复退款,提升并发安全性。
---------
Co-authored-by: OuYingJun1024 <1034284404@qq.com >
Reviewed-on: #27
Co-authored-by: ouzhou <ouzhou@wonderable.ai >
Co-committed-by: ouzhou <ouzhou@wonderable.ai >
2026-06-09 01:56:37 +08:00
marco
4d392f44f5
feat(invite): 好友邀请后端(注册即生效,邀请人+被邀请人各发1万金币) ( #24 )
...
- user.invite_code 列 + invite_relation 表(invitee_user_id 唯一 = 幂等防重复发奖)
- GET /api/v1/invite/me(我的码+分享链接+战绩)、POST /api/v1/invite/bind
- 复用 wallet.grant_coins 同事务发币;自邀屏蔽 / 无效码 / 新用户闸(注册72h内才发)
- alembic 迁移(11a1d08c6f55 -> invite_code_and_relation)+ 8 个测试(钱路/幂等/并发兜底全覆盖)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
Reviewed-on: #24
2026-06-08 04:57:55 +08:00
marco
357ba27499
feat(coupon): 领券今日状态后端(弹窗频控 + 领券记录) ( #23 )
...
- 两张表 + Alembic 迁移:coupon_prompt_engagement(device×日,弹窗频控源)/ coupon_claim_record(device×券×日,领券记录·资产)
- coupon/step 透传顺手写库:step0 写 engagement(claim_started);响应解析 last_coupon_result/coupon_results 幂等写 claim record(按 coupon_id 去重,避免 done 帧 last 与 coupon_results 重复在 autoflush=False 下撞唯一约束回滚整批)
- 新增 GET /coupon/prompt/should-show(弹窗判据)+ POST /coupon/prompt/dismiss(拒绝通知,透传链路看不到拒绝)
- 判断按 device_id(券发到设备登录的外卖账号,比 user 更贴近登录环境);user_id 仅资产留痕、可空
- MVP 先不去重(队列照旧全发);pricebot 未改
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
Reviewed-on: #23
2026-06-08 03:20:51 +08:00
marco
ece41086cd
新增美团 CPS 券定时抓取入库(北京试点),作为"销量/佣金排序"的本地数据源 ( #18 )
...
背景:美团搜索/供给对销量排序支持差(实测乱序)、且有 402 限流和单次召回上限,不适合
每次实时打接口排序。改为定时把券抓进本地 meituan_coupon 表,查询时从库里捞、自己按
销量/佣金排。
本次内容:
- app/models/meituan_coupon.py:新表模型。字段尽量全(售价/原价/销量档/佣金率/佣金额/
门店/距离/品牌/图 等),raw 列存整条原始返回避免漏字段;(source, product_view_sign) 唯一。
- alembic/versions/meituan_coupon_table.py:建表迁移(挂在 withdraw_review_ad_watch 之后)。
- scripts/pull_meituan_coupons.py:ETL,抓 3 路并按 (source, product_view_sign) upsert:
1) 外卖·搜"外卖"(platform=1)翻到尽头
2) 外卖·搜"美食"(platform=1)翻到尽头
3) 到店·多业务线供给(到餐+到综+酒店+门票)翻到尽头
支持 --once(单轮,给 cron;线上每 1h)/ --loop --interval(本地循环,默认 10min)
+ 运行锁防重叠 + --prune-hours 清理陈旧券(默认 24h)。
- app/models/__init__.py:注册新模型。
实测:北京一轮约 2.5 分钟、入库约 2700 条;销量/佣金可直接从库里排序。
给接手同事:
- 仅北京(city_id 固定);v2 再加 per商圈 union 突破全城单次召回上限。
- 销量仅粗档位且约 51% 的券才有,查询需 WHERE sale_volume_num IS NOT NULL
(PG 的 DESC 默认把 NULL 排最前);佣金、价格 100% 有值。
- productViewSign/skuViewId 跨渠道会变,不能当全局 id;跨源去重用 dedup_key=md5(品牌|名|价)。
- 待做:查询接口(从库捞 + dedup_key 去重 + 按销量/佣金排,返回前端)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
---------
Co-authored-by: chenshuobo <1119780489@qq.com >
Reviewed-on: #18
2026-06-08 00:16:25 +08:00
ouzhou
766666601e
feat(platform): 首页门面三统计 + 运营后台展示模式配置 ( #22 )
...
Co-authored-by: OuYingJun1024 <1034284404@qq.com >
Reviewed-on: #22
Reviewed-by: marco <marco@wonderable.ai >
Co-authored-by: ouzhou <ouzhou@wonderable.ai >
Co-committed-by: ouzhou <ouzhou@wonderable.ai >
2026-06-07 23:17:27 +08:00
marco
f5d1a1a20d
feat(price-observation): 价格观测资产表 + pricebot 内部上报端点 ( #21 )
...
比价沉淀的价格事实(平台/门店/菜篮/到手价/时间/来源)无条件落库,server 侧存储、
与登录无关,独立于用户视角的 comparison_record。是未来"别人查过同店→秒回价格"
价格大数据的源头(先存数据,用法后续)。
- models/price_observation.py: 新增 price_observation 表。结构化列(平台/门店/价格/
红包/地理/来源)+ dishes/attrs 两个 JSONB 兜底列;(trace_id,platform,scope) 幂等
唯一约束;observed_at/store_name/geohash/source_device_id/source_user_id 等索引
- alembic/versions/price_observation_table.py: 建表迁移,down_revision=wx_transfer_auth
(已核为当前唯一 head,无多 head 风险)
- schemas/ + repositories/price_observation.py: 批量收发模型 + 跨方言(PG/SQLite)幂等
批量插入(先查 trace 已有 (platform,scope) 只插新的,并发撞唯一约束则回滚跳过)
- api/internal/price.py: 新增 POST /internal/price-observation,X-Internal-Secret 头校验
(常量时间比较,未配密钥→503),server→server 专用,不走用户 JWT
- core/config.py + main.py: 新增 INTERNAL_API_SECRET 配置 + 注册内部路由
- .env.example: INTERNAL_API_SECRET(须与 pricebot 侧同值,留空=内部写端点关闭)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
---------
Co-authored-by: pure <pure@192.168 .0.104>
Reviewed-on: #21
2026-06-07 03:31:35 +08:00
marco
7126fb3ba3
feat(concurrency): trace 一致性 hash 亲和 + 透传 stream 优化 ( #20 )
...
配合 pricebot 单机多进程:透传层按 trace_id 把同一次比价/领券的所有帧
亲和到同一 pricebot 实例,使进程内内存维护 state、无需 Redis。本仓改动:
- 一致性 hash: 新增 app/core/pricebot_router.py(ketama 环,1000 虚拟节点)
+ pick_pricebot(trace_id),md5 纯函数、跨 worker 一致;实测负载偏差 4%、
6→7 扩容只重映射 ~13%(取模会 ~85%)。
- 实例列表: app/core/config.py 加 PRICEBOT_INSTANCES(逗号分隔)+
pricebot_instances property;留空 fallback 单实例,向后兼容。
- 透传亲和 + stream: api/v1/compare.py + coupon.py 改为读原始字节、只
loads 一次拿 trace_id 选实例、转发原始 bytes 不重序列化(省 ~半透传 CPU,
单 worker 即可扛高并发,避开多 worker 破坏短信内存表的坑);覆盖
intent/recognize、intent/step、price/step、coupon/step 四端点。
- .env.example 加 PRICEBOT_INSTANCES + PRICEBOT_COMPARE_TIMEOUT_SEC。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
---------
Co-authored-by: pure <pure@192.168 .0.104>
Reviewed-on: #20
2026-06-07 02:33:50 +08:00
marco
b59dc3ac19
feat(wallet): 微信商家转账「用户授权免确认收款」(免确认到账) ( #16 )
...
提现从「每次跳微信确认」升级为免确认模式:首次授权一次,之后审核通过直接到账,用户零跳转。
方式一(首单转账顺带授权 pre-transfer-with-authorization)+ 方式二(显式开启 user-confirm-authorization)。
- 新增 wechat_transfer_authorization 表(user 1:1,out_authorization_no/authorization_id/state) + 迁移
- wxpay.py 新增 apply/query/close_transfer_authorization + pre_transfer_with_authorization + transfer_with_authorization
- repositories/wallet.py 授权 CRUD + sync/_refresh_active_auth + execute_withdraw_transfer 三分叉
(active->免确认转账 / 无授权且配了回调->方式一 / 未配->退化原确认模式);失效回查授权权威判定,绝不盲退
- /wallet/transfer-auth(开启)/status/close 路由 + withdraw-info 增 transfer_auth_enabled
- 授权结果回调 stub /api/v1/wxpay/transfer-auth-notify(一期仅应答不验签,真值靠 query 轮询)
- config 增 WXPAY_AUTH_NOTIFY_URL
一期无回调验签;二期补 V3 平台证书验签 + AEAD 解密。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
Reviewed-on: #16
2026-06-06 18:52:42 +08:00
ouzhou
0e42e96ddb
docs(admin): 补充管理后台 API 与数据库文档 ( #12 )
...
新增 admin 模块接口文档(auth login/me、admins CRUD、audit-logs、feedback 处理、stats 概览、user coins/detail/status、wallet 流水、withdraw 对账/刷新/列表) + admin_user/admin_audit_log 两张表文档,更新 api/database README 索引。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
---------
Co-authored-by: OuYingJun1024 <1034284404@qq.com >
Reviewed-on: #12
Co-authored-by: ouzhou <ouzhou@wonderable.ai >
Co-committed-by: ouzhou <ouzhou@wonderable.ai >
2026-06-06 15:58:23 +08:00