26 Commits

Author SHA1 Message Date
guke 7b6756f936 feat(meituan-cps): 经纬度→城市离线反查 + rec/销量最高按城市过滤 (#116)
## 主要功能
新增离线「经纬度 → 美团 cityId」反查,让 `rec`(智能推荐)与 `top-sales`(销量最高)从离线库只返**同城券**(此前会混返异地券)。

- `app/utils/geo.py` + `app/utils/meituan_city.py`:坐标 → 美团 `city_id`(reverse_geocoder 离线反查,零网络)。
- `feed?tab=rec` / `/top-sales`:按 `city_id` 过滤;解析不出 / 老客户端不带坐标 → 降级返空。
- `top-sales` 与 `rec` 一致置空库内距离(相对城市默认点、对用户无意义)。

---------

Co-authored-by: guke <guke@autohome.com.cn>
Reviewed-on: #116
Co-authored-by: guke <guke@wonderable.ai>
Co-committed-by: guke <guke@wonderable.ai>
2026-07-05 09:31:53 +08:00
liujiahui 208112ff24 fix(dl): 落地页底图+logo 纳入 git → 修生产 /media 404 毛坯 (#97)
## 背景
用户反馈浏览器落地页仍是「毛坯」(裸黄底、缺优惠券卡/价格卡/logo)。

## 真因(实测线上)
`https://app-api.shaguabijia.com/media/dl.html` 的 **HTML 早已是完善版且已部署**,但它引用的两张静态图被 `.gitignore` 的 `data/media/*` 规则挡在库外、从未随部署进生产 `/media`:

| 资源 | 线上 | 本地/git |
|---|---|---|
| `/media/coupon-page-bg.png`(底图:优惠券卡+跨平台比价价格卡) | **404**(22B `{"detail":"Not Found"}`) | 之前被 gitignore |
| `/media/sb-brand.png`(logo) | **404** | 之前被 gitignore |
| `/media/shaguabijia.apk`(对照) | 200 ✓ | — |

→ 两图加载失败 → 页面回退裸黄底 = 毛坯。

## 改动
照 `dl.html` / `taobao_landing.jpg` 既有白名单写法,把这两张图加进 `.gitignore` 例外并入库。
- `.gitignore`:`!data/media/coupon-page-bg.png`、`!data/media/sb-brand.png`
- 入库两图,md5 与原型一致(coupon-page-bg `f2adf28a` / sb-brand `e5b6e004`)

**无代码/HTML 改动**(dl.html 本就对齐原型,见上一 commit `6d4cbc8`)。

## 部署后生效
合并并部署本分支后,生产 `/media/` 即含这两图,落地页恢复完整。对应 6-29 UI 对齐 #10。

---------

Co-authored-by: no_gen_mu <liujianhishen@gmail.com>
Reviewed-on: #97
Co-authored-by: liujiahui <liujiahui@wonderable.ai>
Co-committed-by: liujiahui <liujiahui@wonderable.ai>
2026-06-30 20:48:31 +08:00
guke b7b958ed58 perf(pricebot): 透传复用共享 httpx 单例,免每请求重建 SSL 上下文 + 绕过进程代理 (#87)
coupon/compare 透传原先每请求 async with httpx.AsyncClient(...) 新建:
每次重建 SSL 上下文(加载 certifi CA)实测 ~1s+,而 pricebot 是纯 HTTP
透传根本用不到 TLS;且 trust_env 默认 True 会把 http://localhost:8000
经进程代理(Clash)再绕几秒。

抽 app/core/pricebot_client.py 共享单例:trust_env=False 直连,lifespan
启动预热(SSL 一次性成本付在启动)、关停 aclose;timeout 下放到 .post()
保留 coupon 30s / compare 60s 差异。keep-alive 复用 TCP,每帧降到个位数 ms。

---------

Co-authored-by: guke <guke@autohome.com.cn>
Reviewed-on: #87
Co-authored-by: guke <guke@wonderable.ai>
Co-committed-by: guke <guke@wonderable.ai>
2026-06-28 09:36:31 +08:00
zhuzihao 667cda566f feat(analytics): 埋点事件接收接口 + admin 查询接口 + 埋点表 (#81)
新手引导埋点的服务端:
- 表 analytics_event(五维硬性列 + props JSON 扩展字段;event/device_id/user_id/session_id/created_at 带索引)
- POST /api/v1/analytics/events:客户端批量上报(不鉴权、body 读可选 user_id、补 client_ip + server_at)
- admin GET /admin/api/event-logs:列表 + 按 事件/设备/用户/会话/时间 筛选(offset 分页,照 list_feedbacks)
- alembic migration 建表(autogenerate 顺带检出的 ad/cps 历史索引漂移已手动剔除)

app 主后端 :8770 与 admin :8771 共用同一 SQLite,admin 同库直接查、无需跨库。
配套客户端五维上报 + admin 日志页(另两仓库 PR)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: zzhyyyyy <2685922758@qq.com>
Reviewed-on: #81
Co-authored-by: zhuzihao <zhuzihao@wonderable.ai>
Co-committed-by: zhuzihao <zhuzihao@wonderable.ai>
2026-06-26 23:33:31 +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
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 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 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 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 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
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 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
zhangxianze 4506677483 feat(report): 上报更低价后端——price_report 表 + 提交/列表接口 (#13)
Co-authored-by: xianze <ze@192.168.0.138>
Reviewed-on: #13
Co-authored-by: zhangxianze <zhangxianze@wonderable.ai>
Co-committed-by: zhangxianze <zhangxianze@wonderable.ai>
2026-06-06 00:42:39 +08:00
ouzhou da7ce69494 feat(ad): eCPM 上报接口 + 冷却策略解耦纯函数 + savings JSONB 跨库修复 (#8)
- 新增 POST /api/v1/ad/ecpm-report:激励视频展示后客户端上报本次 eCPM,落 ad_ecpm_record 做内部收益统计(model/repository/schema/alembic 迁移 + 接口文档)
- 看广告冷却策略抽到 app/core/ad_cooldown.py 纯函数;ad_reward.today_status 只取数据,换策略只改这一处
- savings.dishes 改 JSON().with_variant(JSONB,"postgresql"):SQLite 无 visit_JSONB 会让 create_all 编译崩,修复后测试套件恢复

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: OuYingJun1024 <1034284404@qq.com>
Reviewed-on: #8
Co-authored-by: ouzhou <ouzhou@wonderable.ai>
Co-committed-by: ouzhou <ouzhou@wonderable.ai>
2026-06-01 22:23:15 +08:00
zhangxianze 288766443a feat(记账): 比价省钱记账后端 M1(savings_record 唯一真相表 + /order/report + demo 兜底) (#10)
从最新 origin/main 重拉的干净分支,只含本人记账改动,不含 marco 的归因订单(order_record)——后者是另一条未合并分支 feat/user-order-records 的功能,此前被误用 git add -A 和记账混进了 feat/savings-accounting-m1。本分支不带它:savings_record 升级为唯一真相表(新增原价/比价价/支付渠道/源平台/幂等键等列,迁移 savings_report_fields 直接挂 f01db5d77dac、不经 order_record_table);/order/report 改写 savings_record(source='compare'),省额=源平台原价−实付;展示 /api/v1/savings/* 真实优先 demo 兜底。无 order_record 的 model/repo/迁移/路由。alembic 单一 head + pytest 54 passed。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: xianze <ze@192.168.0.138>
Reviewed-on: #10
Co-authored-by: zhangxianze <zhangxianze@wonderable.ai>
Co-committed-by: zhangxianze <zhangxianze@wonderable.ai>
2026-06-01 21:29:52 +08:00
陈世睿 49379fd045 feat(user): 用户资料与反馈接口(昵称/头像/注销 + 帮助反馈)
- /api/v1/user: PATCH 改昵称、POST 上传头像、DELETE 注销账号(软删除+匿名化)
- /api/v1/feedback: 提交反馈(内容/联系方式/截图入库)
- 新增 media 模块(图片落盘+魔数校验)+ /media 静态服务
- feedback 表 + Alembic 迁移(部署需 alembic upgrade head)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 22:27:36 +08:00
marco 16b78478c0 Merge remote-tracking branch 'origin/main' into feature/coupon-claim-integration
# Conflicts:
#	docs/api/README.md
2026-05-28 10:33:35 +08:00
marco aa34ad7d0b feat(compare): 外卖比价 2 端点透传到 pricebot-backend (food MVP)
仿 coupon_step 在 app/api/v1/compare.py 加纯 body 透传 2 端点(MVP 不鉴权,只读
device_id/trace_id/step 打日志,不做 schema 校验)。client /api/v1/{intent/recognize,
price/step} → backend 去掉 /v1 转发到 PRICEBOT_BASE_URL,接通外卖比价
client→server→pricebot-backend 链路。

- compare.py: _passthrough helper + intent/recognize + price/step
- config.py: PRICEBOT_COMPARE_TIMEOUT_SEC=60(意图识别大上下文 LLM、price/step
  每帧 LLM,比领券 30s 长;对齐客户端 agent ApiClient 的 60s 读超时)
- main.py: 注册 compare_router
- tests/test_compare_proxy.py: 2 端点参数化测试(透传/5xx→502/不可达→502/坏 JSON→400)
- docs/api/{compare-intent-recognize,compare-price-step}.md + 更新 README 索引
- 待办与技术债.md P2 外卖 2 端点标 (2026-05-27);电商 2 个待接(compare.py
  加两行即可)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 10:29:20 +08:00
OuYingJun1024 0722d7b0d5 feat: 福利钱包+签到+省钱战绩+激励广告发奖+微信提现 后端
- 福利钱包: 金币/现金余额、流水、兑换 (api/v1/wallet.py, crud/wallet.py, models/wallet.py, schemas/welfare.py)
- 每日签到: 连续天数 + 档位奖励 (api/v1/signin.py, crud/signin.py, models/signin.py)
- 任务系统: "打开消息提醒"等任务领奖 (api/v1/tasks.py, crud/task.py, models/task.py)
- 省钱战绩: 省钱汇总/战绩/店铺菜品 (api/v1/savings.py, crud/savings.py, models/savings.py)
- 激励广告发奖: 穿山甲服务端回调 + 发奖规则 + 限流 (api/v1/ad.py, core/pangle.py, core/rewards.py, core/ratelimit.py, crud/ad_reward.py, schemas/ad.py, docs/ad_reward_golive_checklist.md)
- 微信提现: 商家转账到零钱 V3 (core/wxpay.py); user 表加微信 openid/nickname/avatar
- DB 迁移: 8 个 alembic (welfare 表/cash_transaction/openid 唯一约束/savings 店铺菜品/savings_record/ad_reward/withdraw_order+openid/user 微信字段)
- 运维脚本: reconcile_withdraws(对账) + reset_signin/reset_welfare + sim_pangle_callback(模拟穿山甲回调)
- 测试: test_welfare / test_withdraw / test_ad_reward
- 配置: .env.example + config.py 新增福利/广告/微信支付项; main.py 挂 5 个新路由

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 17:38:08 +08:00
marco 391f3df1bb Merge branch 'main' into feature/coupon-claim-integration
把 main 的"美团 CPS 模块 + 后端分层重构(integrations/repositories)"合入领券分支。
解决 3 处冲突(均为两边各自新增, 保留双方):
- app/main.py: 同时注册 coupon_router 与 meituan_router
- app/core/config.py: 同时保留 PRICEBOT_* 与 MT_CPS_* 配置
- .env.example: 同上
coupon.py 本身无冲突(仅依赖 deps.CurrentUser 与 core.config, 重构未触及)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 11:26:11 +08:00
lowmaster-chen cc9d9f03f7 feat: 接入美团联盟 CPS 优惠券推荐模块
- 新增 app/core/meituan.py: 美团联盟 API 客户端 (S-Ca 签名, query_coupon, get_referral_link)
- 新增 app/api/v1/meituan.py: /api/v1/meituan/coupons 和 /feed 路由, 支持按经纬度推荐
- 新增 app/schemas/meituan.py: 请求/响应 Pydantic Schema
- app/main.py: 注册 meituan_router
- app/core/config.py: 新增 MT_CPS_* 配置项, .env 路径改为绝对路径避免 CWD 问题
- .env.example: 补充美团联盟 CPS 配置模板

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 20:29:31 +08:00
no_gen_mu 8fe58f4a42 feat(coupon): add /api/v1/coupon/step proxy to pricebot
- new POST /api/v1/coupon/step, JWT-authenticated, async httpx forwards body to pricebot
- new PRICEBOT_BASE_URL / PRICEBOT_REQUEST_TIMEOUT_SEC settings (default localhost:8000)
- error handling: pricebot unreachable / 5xx -> 502 with friendly message
- tests: auth, passthrough, 5xx, unreachable, invalid json (5 cases, all pass)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 19:46:14 +08:00
马润林 1aafc28621 feat: 正式 App 后端登录模块 v0.1.0
引入 JWT 认证、极光一键登录、短信 mock 登录与用户表,并补充技术实施文档与部署配置。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-23 17:37:18 +08:00