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 |
|
zhangxianze
|
94b7c027be
|
fix(time): created_at 统一存北京时间,修面向用户展示慢 8h (#25)
savings/comparison/wallet(金币·现金流水)/report 写入显式 created_at=datetime.now(CN_TZ).replace(tzinfo=None),替代 SQLite 下返回 UTC 的 server_default=func.now()。后台统计 admin/ops 依赖 created_at 是 UTC,不动。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: xianze <ze@192.168.0.128>
Reviewed-on: #25
Co-authored-by: zhangxianze <zhangxianze@wonderable.ai>
Co-committed-by: zhangxianze <zhangxianze@wonderable.ai>
|
2026-06-08 16:23:26 +08:00 |
|
marco
|
97f0fb210f
|
fix(alembic): merge coupon_state + invite 双 head 为单一 head
coupon_state_tables 与 invite_code_and_relation 都挂在 11a1d08c6f55 下、是兄弟迁移,
合 main 后形成两个 head,alembic upgrade head 会报 Multiple head revisions 致部署失败。
本 merge 迁移(无 schema 变更)把两条链并起来,恢复单一 head。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-06-08 05:54:55 +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
|
f098ba3816
|
日志: app-server 增加 JSON 文件输出供阿里云 SLS 采集 (#19)
app/core/logging.py:
- 新增 RotatingFileHandler 落 logs/app-server.log (此前仅 stdout), 用 JsonFormatter 输出
单行 JSON (time/level/service/logger/func/line/message, 异常栈内嵌不换行)。
- 控制台保持文本 (stdout 行为不变, systemd/run.log 不受影响)。
- setup_logging 加幂等保护 + 清理预置 root handler 防重复输出。
- 支持环境变量 LOG_FILE/LOG_DIR/LOG_JSON_CONSOLE/LOG_SERVICE_NAME
(admin 子进程应设独立 LOG_FILE 避免与主进程争抢同一轮转文件)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: pure <pure@192.168.0.104>
Reviewed-on: #19
|
2026-06-07 02:26:45 +08:00 |
|
marco
|
b4780e256e
|
docs(database): 补全 19 表文档 + 新增 OVERVIEW 总览
- 重写 15 张已有表文档:每张补「用在 App 哪/增删改查时机/字段取值/join key 指向」
- 新建 4 张缺失表文档:wechat_transfer_authorization / ad_watch_log / price_report / app_config
- 新增 OVERVIEW.md:功能↔表映射 + 写入路径 + 表间关系(含语义 join key)+ ER + 资金模型
- README 索引补齐到 19 表 + 置顶 OVERVIEW + 通用约定补全
- 纠正过时:withdraw_order(reviewing/rejected/user_name)、savings_record(/order/report 真实写入)、coin_transaction(biz_type)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-06-07 00:25:57 +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 |
|
marco
|
e252277431
|
feat(tools): 美团 CPS API 调试 playground
浏览器填参数 → 本地签名代理打美团 → 卡片列表 + 可折叠 JSON 树。
模板按到店/到家分组 + 渠道标识(榜/搜/供),支持翻页、测试坐标、距离展示。
复用 integrations/meituan.py 的 _sign/_content_md5,AppSecret 只留后端,不碰生产代码。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-06-06 18:13:07 +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 |
|
marco
|
07c0b7502c
|
feat(welfare): 提现人工审核流程 + 看广告每日时长限流(防刷主闸) (#15)
提现人工审核(提现不再即时打款):
- models/wallet.py: WithdrawOrder 状态机改为
reviewing →(审核通过)→ pending → success/failed;reviewing →(驳回)→ rejected(已退款),
默认态 pending → reviewing(扣现金建单但不打款);新增 user_name 列(实名, 微信达额转账要求)
- admin/routers/withdraw.py + admin/schemas/wallet.py: 运营后台审核接口(通过触发微信转账 / 驳回退款)
- api/v1/wallet.py + repositories/wallet.py: 发起提现进 reviewing 态, 驳回退回现金并写 withdraw_refund
- schemas/welfare.py: 提现出参增 reviewing/rejected 状态 + fail_reason
看广告每日时长限流(防刷主闸 + 次数兜底):
- 新增 models/ad_watch_log.py: 按 (user_id, watch_date) 聚合当日观看秒数
- 新增 repositories/ad_watch.py: watched_seconds_today / add_watch_seconds(夹 [0, MAX_SINGLE_WATCH_SECONDS])
- api/v1/ad.py: 新增 POST /ad/watch-report(JWT 取 user, 落时长返当日累计);
/ad/reward-status 增 watched_seconds_today / limit / remaining
- schemas/ad.py: WatchReportIn/Out
- core/rewards.py: 新增 DAILY_AD_WATCH_SECONDS_LIMIT=50 分钟(主闸)+ MAX_SINGLE_WATCH_SECONDS=120;
DAILY_AD_REWARD_LIMIT 20→200 改作次数兜底(防前端少报时长绕过时长闸, 又不误伤看短广告的正常用户)
- repositories/ad_reward.py + models/__init__.py: 接入新表与时长闸
alembic: withdraw_review_and_ad_watch 迁移(withdraw_order.user_name 列 + ad_watch_log 表)
tests: 补 test_ad_reward / test_withdraw
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: pure <pure@192.168.0.104>
Reviewed-on: #15
|
2026-06-06 04:51:50 +08:00 |
|
marco
|
67a9a15775
|
feat(admin): app_config 运营配置后台(rewards 等常量可后台配置) (#14)
- 新增 app_config 表 + model/repository/config_schema + admin config 路由与 schema + 测试
- rewards.py 及 ad_reward/signin/task/wallet/comparison_milestone repositories 接入可配置项;ad.py / admin/main.py 配套
- alembic merge(ebb6af5c0b56)合并本地 app_config(cfg1a2b3c4d5)与 incoming price_report/best_deeplink(b7e2c1a9f4d3)两 head
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reviewed-on: #14
|
2026-06-06 04:13:08 +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 |
|
marco
|
b50495bebe
|
feat: 短信接入极光真实发送 + 新增运营 admin 后台子应用
短信(SMS_MOCK 切 mock/real):
- integrations/sms.py 重写: real 模式走极光短信 REST /v1/messages 自定义验证码(本服务 secrets
生成 6 位码 + 进程内存 + 本地校验一次性/防爆破), 鉴权复用极光一键登录 JG_APP_KEY/MASTER_SECRET
(同一极光应用, 上线只需 SMS_MOCK=false); mock 仍"任意6位通过"不动其余测试
- 防刷四层: 单号冷却 + 单号每日上限 + 单IP rate_limit(/sms/send 10/min、/sms/login 20/min)
+ 单码失败次数作废; SmsError 带 status_code 映射 429/503/400
- config 增 SMS_SEND_ENDPOINT/SIGN_ID/TEMPLATE_ID/CODE_LENGTH/DAILY_LIMIT/MAX_VERIFY_ATTEMPTS;
test_auth 加 real 模式单测; sms.md/后端技术实现/待办账本同步
admin 后台(app/admin/ 独立子应用, uvicorn app.admin.main:admin_app :8771):
- 复用主仓 models/repositories/integrations + 同库, 鉴权完全隔离(ADMIN_JWT_SECRET≠JWT_SECRET_KEY
+ payload typ=admin + bcrypt 密码 + 可选 IP 白名单); 主 app 不 import 本包, admin 崩不影响主进程
- 路由: 登录 / 账号管理(RBAC: super_admin·finance·operator) / 用户列表+360详情+封禁+手动调币 /
钱包流水 / 提现重试对账 / 反馈工单 / 数据大盘; 全写操作落 admin_audit_log(涉钱与业务写同事务)
- 涉钱逻辑(调微信/退款/对账)复用 app.repositories.wallet 不重写
- 新增 models/admin.py(AdminUser/AdminAuditLog) + admin_tables 迁移 + create_admin.py +
deploy/shaguabijia-admin.service; 依赖加 bcrypt
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-06-04 03:02:41 +08:00 |
|
ouzhou
|
90c0d65a16
|
chore(alembic): merge comparison_milestone 和 savings_report_fields 两个 head (#11)
Co-authored-by: OuYingJun1024 <1034284404@qq.com>
Reviewed-on: #11
Co-authored-by: ouzhou <ouzhou@wonderable.ai>
Co-committed-by: ouzhou <ouzhou@wonderable.ai>
|
2026-06-03 09:48:28 +08:00 |
|
OuYingJun1024
|
518f8c8b92
|
Merge branch 'main' of https://gitea.shaguabijia.com/WonderableAI/shaguabijia-app-server
|
2026-06-02 15:07:23 +08:00 |
|
marco
|
e4588303fb
|
feat(compare): 加 /api/v1/intent/step 透传到 pricebot(淘宝多帧意图识别)
配套 pricebot-backend 的 /api/intent/step(淘宝源 Phase 1 多帧意图识别: 展开 + 滚动
采集 → LLM 提取)。沿用 _passthrough 壳: 不鉴权、原样转发, 客户端循环调用直到 done
(done 帧顶层带 result + calibration)。目前仅淘宝源走这条, 其它源走单次 /intent/recognize。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-06-02 14:40:19 +08:00 |
|
OuYingJun1024
|
9521cd96ce
|
chore(alembic): merge comparison_milestone 和 savings_report_fields 两个 head
|
2026-06-02 09:53:25 +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 |
|
marco
|
a114a0f3f2
|
docs(integrations/wxpay): 删 code_to_openid 行,跟齐 9d1278c 死代码清理
9d1278c 已删 wxpay.py 的 code_to_openid 函数(能力被 code_to_userinfo 覆盖),
docs 函数表里这一行没跟着删,补齐。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-06-01 20:44:46 +08:00 |
|
marco
|
9d1278cb33
|
chore: 清理两处未使用代码
- app/db/base.py: 删 MappedAsDataclass 的 import (没人继承用)
- app/integrations/wxpay.py: 删 code_to_openid 函数 (code_to_userinfo 已覆盖能力, 18 行死代码)
|
2026-05-31 17:10:16 +08:00 |
|
marco
|
6c7eaa9734
|
docs: 跟齐 5 月 PR (#4 user/feedback / #5 ad-cooldown / #6 PG / abd8eab meituan 降级)
整轮 doc 跟齐 2026-05 落地但 doc 没补全/没更新的内容. 按 P0~P3 优先级处理.
P0 - 新 API doc + index 更新:
* docs/api/user-profile.md (新) PATCH /api/v1/user/profile 改昵称
* docs/api/user-avatar.md (新) POST /api/v1/user/avatar 上传头像(魔数嗅探/旧文件清理)
* docs/api/user-delete.md (新) DELETE /api/v1/user 注销账号(软删+匿名化)
* docs/api/feedback.md (新) POST /api/v1/feedback 提交反馈(含截图)
* docs/api/README.md 加 User/Feedback 组 + /media 静态服务段 +
修 UserOut "无接口可改恒为 null" 过时描述
P0 - 美团降级 / 现有 doc 校准:
* docs/api/meituan-coupons.md 加 "未配 MT_CPS 凭证降级返空" 说明
* docs/api/meituan-referral-link.md 同上 + 客户端兜底建议
* docs/api/meituan-feed.md 区分两种空结果路径(未配 vs 调用失败) +
/health.mt_cps_configured 排障入口
* docs/integrations/meituan.md "未配凭证降级" + "feed 静默吞错" 写进集成层
* ad-reward-status.md PR #5 commit 已自带 doc 更新, 复核无需再改
P1 - 主文档大改:
* docs/后端技术实现.md
- §1 能力表加 用户资料/外卖比价/钱包/福利/广告/反馈 (从 3 条扩到 9 条)
- §1 数据模型纠正 "仅 1 张 user 表" -> 现有 10 张 + alembic_version
- §2 DB 行 PG 主 / SQLite 兜底 + 加 psycopg3 行
- §3 目录树补 user.py / feedback.py / media.py / repositories/feedback.py /
scripts 子项 / docs/postgres-migration.md
- §7 数据模型重写: 10 张业务表速查表 + alembic 合并迁移 f01db5d77dac 始末
- §8 部署: 加 init_postgres.py 一句话流程 + checklist 加 "DATABASE_URL 切 PG"
+ "psycopg3 已装" + "MEDIA_ROOT 可写"
- §10 已知问题: 加 美团降级 / agent 不鉴权 / MEDIA_ROOT serve / init_postgres bug /
alembic 多 head 风险; 删过时 SQLite 行
- 接口计数 11 -> 38
* docs/待办与技术债.md
- 已解决追加: PG 切换 / 外卖比价透传 / 用户资料反馈接口 / 美团降级 /
看广告 4 态冷却
- 新增 "P2 DB 与 Alembic 治理" 段: alembic 多 head 团队规约 (含本次撞坑实录) +
init_postgres.py 已知 5 处小 bug + MEDIA_ROOT serve
P2 - PG 迁移文档互指 + 迁移链补完:
* docs/数据库迁移.md
- 顶部加 postgres-migration.md / 后端技术实现.md 互指
- §6 迁移链 9 条 -> 12 条 (含 feedback_table / convert_dishes_jsonb /
merge_pg_jsonb_and_feedback_heads)
- §7 踩坑里 "多 head" 一行扩成完整故事 + 修复命令 + 团队预防规约
* docs/postgres-migration.md
- 顶部加 数据库迁移.md / 后端技术实现.md §10 互指
P3 - 上线清单:
* docs/看广告赚金币上线清单.md
- 设计要点加 PR #5 4 态 CTA + 后端权威派生说明 +
VIDEO_ROUND_REQUIRED_COUNT/VIDEO_ROUND_COOLDOWN_SECONDS 常量
- §E 端到端验收加 本轮冷却 / 弹窗 limit note / 跨设备一致 三项
所有最后更新日期同步到 2026-05-31.
|
2026-05-31 11:05:10 +08:00 |
|
marco
|
c3c64fa06d
|
chore: alembic merge revision + PG 迁移指南文档 (#7)
PostgreSQL 迁移 (#6) 之后两个分支引入了独立 heads (ef96beb47b1e +
d1e2f3a4b5c6), 必须合并成单一 head 才能 alembic upgrade head 顺利跑通。
- alembic/versions/f01db5d77dac_merge_pg_jsonb_and_feedback_heads.py:
空 op 的 merge revision, 把两个 heads 收敛为 f01db5d77dac
- docs/postgres-migration.md: SQLite → PostgreSQL 迁移指南
(背景/动机/操作步骤/无真实用户数据假设, 上线前补 pgloader 演练等)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reviewed-on: #7
|
2026-05-30 18:13:11 +08:00 |
|
marco
|
e69e244de7
|
Merge pull request 'feat(ad-reward): reward-status 加本轮 3 次冷却字段 (round_count + cooldown_until)' (#5) from feat/welfare-video-round-cooldown into main
Reviewed-on: #5
|
2026-05-29 15:45:51 +08:00 |
|
marco
|
2ebde935f9
|
Merge pull request 'feat: SQLite → PostgreSQL 迁移代码改动' (#6) from feat/postgres-migration-and-bootstrap-script into main
Reviewed-on: #6
|
2026-05-29 15:44:40 +08:00 |
|
chenshuobo
|
b3d3fda744
|
feat: 新增 PG 初始化脚本 scripts/init_postgres.py
新机器一键拉起数据库, 替代手动跑 psql 建用户建库的 6 行命令.
脚本特性:
- 跨平台 Python (Windows/macOS/Linux 通吃, 不依赖 psql CLI 在 PATH 里)
- 直接用 psycopg 连 PG, 不 shell out
- 幂等: 用户已存在则重置密码, 库已存在则跳过, 重复跑不出错
- 业务密码自动 secrets.token_urlsafe(32) 强随机, 不让同事自己想
- 自动从 .env.example 复制出 .env 并写入 DATABASE_URL
- .env 里已有 DATABASE_URL 会询问是否覆盖 (不无脑覆盖)
- 跑完自动 alembic upgrade head, 一条命令到可用状态
- 全交互项支持环境变量提前指定 (PG_SUPER_PASS / APP_DB_PASS 等), CI 友好
同事新机器初始化流程从 6 步简化为 3 步:
pip install -e .
python scripts/init_postgres.py # 唯一手动输入项: postgres 超级用户密码
./run.sh
CREATE/ALTER USER 注意点: PG 不支持参数化密码绑定, 用 sql.Literal 内联,
psycopg 自带的转义会处理引号和注入.
docs/数据库迁移.md 拆出 PG / SQLite 两套初始化流程, PG 走脚本,
SQLite 保留旧步骤 (本地临时回退用).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-29 15:21:04 +08:00 |
|
chenshuobo
|
b76e5bd515
|
feat: SQLite → PostgreSQL 迁移代码改动
按 docs/数据库迁移.md 第 3 节扫雷清单落地代码层改动:
- pyproject.toml: 新增 psycopg[binary]>=3.1 依赖 (psycopg3, SQLAlchemy 2.0 时代默认, 不要再装 psycopg2)
- app/db/session.py: 非 SQLite 自动加连接池参数
- pool_size=10, max_overflow=20, pool_recycle=3600
- SQLite 单文件不池化, _is_sqlite 判断分支保留以便本地 dev 临时回退
- app/models/savings.py: dishes 列从 JSON 改为 JSONB
- PG 上能用 GIN 索引和 jsonb 操作符
- SQLite 上 JSON 实际是 TEXT, 切到 PG 后用 JSON 类型存的是 json 不是 jsonb
- alembic/versions/ef96beb47b1e_*.py: 新增迁移把 savings_record.dishes 从 json 转 jsonb
- 用 op.get_bind().dialect.name 判断 PG 才执行 ALTER COLUMN
- SQLite 上是 no-op (SQLite 没有 jsonb 类型)
- 旧的 savings_shop_dishes.py 迁移保持 sa.JSON() 不动 (按文档"不改老迁移"原则)
本地切 PG 验证: 10 张表全部建出, dishes 字段为 jsonb 类型,
登录/me/美团 feed 三个真接口全 200, user 数据正确写入 PG.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-29 15:20:22 +08:00 |
|
OuYingJun1024
|
56f4548654
|
feat(ad-reward): reward-status 加本轮 3 次冷却字段 (round_count + cooldown_until)
让客户端 4 态任务行 CTA (Normal/Loading/Capped/CoolingDown) 与 ExitReward
弹窗 limit note (本轮看完/今日看完 二选一) 都由后端权威派生, 跨设备 / 重装 /
杀进程都一致, 客户端不再依赖 in-memory 本地存储。
- core/rewards.py: 加 VIDEO_ROUND_REQUIRED_COUNT=3 / VIDEO_ROUND_COOLDOWN_SECONDS=600
- repositories/ad_reward.py: today_status 从 3-tuple 扩成 5-tuple,
从已有 created_at 字段按 ORDER BY DESC + OFFSET round_count 派生最近一个
已完成轮末尾时间; 零新字段零新表
- schemas/ad.py: AdRewardStatusOut + TestGrantOut 加 round_count + cooldown_until
- api/v1/ad.py: reward_status / test_grant 接 5-tuple
- tests: 加 4 个覆盖 (初始 / 未达一轮 / 刚达一轮进冷却 / 冷却已过)
- docs/api/ad-reward-status.md: 补字段说明 + 客户端 4 态 CTA 推导规则 +
"冷却仅 UX, 发奖不受影响" 注解
冷却是 UX 约束: pangle-callback 发奖只看 daily_limit, 冷却期间穿山甲
回调照常发奖, 不另设拒发分支。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-05-29 13:27:56 +08:00 |
|
marco
|
4d444b7c43
|
Merge pull request 'feat(user): 用户资料与反馈接口(昵称/头像/注销 + 帮助反馈)' (#4) from feat/user-profile-feedback-api into main
Reviewed-on: #4
|
2026-05-29 01:04:10 +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
|
abd8eabf9b
|
feat(meituan): 未配置 MT_CPS_APP_KEY 时接口降级返空,不再 502
之前未配美团 CPS 凭证时,/coupons 和 /referral-link 调用会抛 MeituanCpsError
被翻成 502,前端首页一进就拉 /feed → 看到错误(虽然 /feed 因 _fetch_topic
吞异常已经返空)。新开发机没填美团 key 时体验差。
本次让美团 3 个接口都在入口处早返空响应:
- Settings 新增 mt_cps_configured property(同 wxpay_configured 套路)
- /coupons / /feed / /referral-link 未配置时分别返空 list / 空 link
- 客户端首页 feed 看到空列表,其他业务(登录/领券/广告/提现)完全不受影响
副作用:/feed 返空现在同时表示"配置缺失"和"美团真无券"两种状态,排查时
看 settings.mt_cps_configured 区分。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-28 15:54:51 +08:00 |
|
marco
|
8d9bd3c72f
|
Merge pull request 'test(coupon-proxy): 修正已过时的 401 鉴权断言' (#3) from feature/coupon-claim-integration into main
Reviewed-on: #3
|
2026-05-28 10:53:58 +08:00 |
|
marco
|
ba946a9d9a
|
fix(docs): 移除 3ff95db merge commit 残留的冲突标记
3ff95db 那次 merge 时, IDE/editor 已经修改文件但 my Edit 被 file-freshness
guard 拒绝,后续 git add/commit/push 把仍带 <<<<<<< / =======/>>>>>>> 的
coupon-step.md 推上去了 —— 已部署文档破损。
按原合并方案 fix-forward:鉴权行用精确版「Bearer access_token(客户端契约;Server
MVP 阶段不强校验)」,⚠️ 段保留「前端已接通」详述 + 用「客户端契约 vs Server
实现」措辞写鉴权状态 + device_id 用途 + P1 链接。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-28 10:49:01 +08:00 |
|
marco
|
3ff95dba76
|
Merge origin/feature/coupon-claim-integration: 合并 coupon-step.md 鉴权措辞两边
冲突:本地 36f6465(MVP 不鉴权 + 前端已接通详述 + P1 指向)与远程 3d1bb78
(鉴权措辞精确化:Android 已带 Bearer 客户端契约 / Server MVP 不强校验)。
解法:综合两边——
- 鉴权行用远程精确版「Bearer access_token(客户端契约;Server MVP 阶段不强校验)」
- 说明段保留本地「前端已接通」路径详述(远程版没有)+ 用远程的「客户端契约 vs
Server 实现」措辞重写 ⚠️ 段 + 本地的 device_id 用途说明 + P1 链接。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-28 10:48:05 +08:00 |
|
no_gen_mu
|
3d1bb78afe
|
docs(api/coupon-step): 鉴权说法精确化 — Android 已带 Bearer / Server MVP 不强校验
P1 接通真机验证时 logcat 实证 Android 客户端通过 AuthInterceptor 自动带
Authorization: Bearer <access_token> 头(见 shaguabijia-app-android 仓
data/net/ApiClient.kt:36)。原 docs 只写「鉴权:Bearer access_token」描述
契约目标,但没说明 server 端 MVP 不强校验的实现现状,容易让对接方误以为
缺 token 就 401。
L3 + L18 修订后清晰描述「客户端契约 vs Server 端 MVP 实现」两端联合状态,
不动 server 代码(coupon.py 仍 MVP 不接 Depends, P1 后启用)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-28 10:44:19 +08:00 |
|
marco
|
36f646597d
|
docs: 同步领券去鉴权 + 前端已接通(收尾 stash 的预 WIP + merge 冲突解决)
应用本次会话开始时 stash 的两份文档 WIP(主题一致:领券去鉴权后的文档同步):
- docs/api/coupon-step.md: 鉴权 Bearer → 无(MVP);入参说明加 device_id;说明段去
"鉴权壳"措辞,加"前端已接通"链路 + MVP 不鉴权数据债说明(指向 P1)。
- docs/后端技术实现.md: 行 18 表格 / section 6 段 / 已知问题表三处 stash pop
已干净 apply;一句话总结(行 20)"鉴权 + 透传壳"→"透传壳"对齐;api/v1/ 文件树
冲突 — 采纳同事 8 行 router 清单(wallet/signin/tasks/savings/ad 新加),给
coupon.py 行末尾加"MVP 不鉴权",并补 compare.py 一行(本分支刚加的外卖比价
透传,同事 commit 那时还没有,补上保持文档跟代码一致)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-28 10:43:53 +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 |
|
marco
|
24faaf9d47
|
test(coupon-proxy): 修正已过时的 401 鉴权断言
coupon/step MVP 阶段已去鉴权(见「待办与技术债.md」已解决),但
test_coupon_step_requires_auth 仍断言"无 token → 401",baseline 实际走到上游
拿 502,这条用例长期红灯。改为 mock httpx 验证不带 token 也能正常透传,与新加的
compare 端点 no-auth 测试一致。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-28 10:29:20 +08:00 |
|
marco
|
6e99287c77
|
Merge pull request 'feat: 福利钱包+签到+省钱战绩+激励广告发奖+微信提现 后端' (#2) from feature/welfare-withdraw-ad into main
Reviewed-on: #2
|
2026-05-27 23:04:22 +08:00 |
|
OuYingJun1024
|
9a2599bc3a
|
docs: README 翻新到当前结构 + 上线清单改中文名 + 文档库导航补全
- README.md 翻新: 从 v0.1.0 登录模块版更新到当前(钱包/提现/签到/省钱/看广告/CPS);
目录结构按现状重写(integrations 含 pangle/wxpay、repositories 含全部数据访问、
core 含 ratelimit/rewards);API 改为按组速览 + 链 docs/api;建表步骤改为
alembic upgrade head(原步骤是过时的 autogenerate init);部署补微信支付证书同步
- docs/ad_reward_golive_checklist.md → docs/看广告赚金币上线清单.md(改中文名)
- docs/README.md 文档库导航补 integrations/ + 数据库迁移.md + 看广告上线清单
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-05-27 21:10:44 +08:00 |
|
OuYingJun1024
|
c61997b876
|
docs: 新增数据库迁移指南 + 迁移脚本,同步目录结构文档
- 新增 docs/数据库迁移.md: clone 后如何建表(alembic upgrade head)、日常升级、
新增迁移、迁移文件名 vs revision id 的关系与去前缀注意事项、当前 9 条迁移链
- 新增 scripts/migrate.sh: 只做迁移不启服务(部署/CI 用),run.sh 已自动包含
- 后端技术实现.md 目录树: crud 并入 repositories、alembic 文件名去 hex 说明、
补 docs/数据库迁移.md;接口层"调 repositories/integration"措辞同步
- README.md / docs/integrations 残留 crud 提法同步为 repositories
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-05-27 21:04:25 +08:00 |
|
OuYingJun1024
|
a4d214964a
|
refactor: crud 并入 repositories + alembic 迁移文件去 hex 前缀
- 数据访问层统一: app/crud/{ad_reward,savings,signin,task,wallet}.py 移入
app/repositories/(与 user.py 同目录),删除 crud/;更新 10 处 import
(api/v1/* + scripts/* + repositories 内部交叉引用 app.crud→app.repositories)
- alembic/versions 9 个迁移文件去掉 hex 前缀,改成可读文件名(如
welfare_tables_coin_account_coin_txn.py);**仅重命名文件**,文件内
revision/down_revision 不动 → 迁移链与已迁移库的 alembic_version 不受影响
(alembic heads/history 验证链完好,单一 head c8d9e0f1a2b3)
- 测试: 37 passed(1 个 coupon 代理失败为连不到 pricebot 上游的环境问题,与本次无关)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-05-27 21:04:03 +08:00 |
|
OuYingJun1024
|
3d1e8969e6
|
docs: 新建 docs/integrations 集成层文档 + api 文档变薄
- 新增 docs/integrations/(README + jiguang/sms/meituan/pangle/wxpay 各一篇):
记录各 SDK 集成的签名/验签/加解密/协议细节与踩坑(对齐 app/integrations 分层)
- docs/api 接口文档变薄: 受影响接口头部加「集成实现」链接,把验签/RSA/CPS 签名
等重逻辑描述移到集成文档;ad-pangle-callback 验签段精简为指针
- docs/api/README 补架构说明(api 薄 / 重逻辑在 integrations)
- 后端技术实现.md 目录树补全(福利/钱包/签到/省钱/发奖端点 + crud/integrations 现状),
pangle/wxpay 标注移入 integrations
- ad_reward_golive_checklist 路径同步 core→integrations
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-05-27 20:45:12 +08:00 |
|
OuYingJun1024
|
6f2731ee2d
|
refactor(integrations): 穿山甲验签改 GroMore SHA256 + pangle/wxpay 从 core 移入 integrations
- 验签: pangle.build_sign/verify_callback_sign 改为 GroMore 官方
sign=SHA256("{m-key}:{trans_id}")(普通 SHA256,只签 trans_id);
回调响应改成 GroMore 要求的 {is_verify, reason}
- 发奖: 按回调 reward_amount 发金币(rewards 带回退/夹紧),ad_reward 幂等 + 每日上限
- 分层: app/core/{pangle,wxpay}.py → app/integrations/(对齐 jiguang/meituan/sms);
更新 ad.py / crud/wallet.py / scripts/sim_pangle_callback.py / 测试的 import
(含 test_withdraw 的 monkeypatch 路径 app.core.wxpay→app.integrations.wxpay)
- 测试: test_ad_reward + test_withdraw 共 17 项通过
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-05-27 20:44:49 +08:00 |
|