Files
shaguabijia-app-server/docs/database/OVERVIEW.md
T
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

12 KiB
Raw Blame History

数据库总览 — 表 × 功能 × 关系

跨表视角。单表字段级细节看同目录 <表名>.md(索引见 README)。 本文专门回答三件「跨表」的事:① 每块 App 功能用到哪些表 ② 什么操作往哪张表写 ③ 表和表怎么连(join key,含没有外键约束、靠业务字段对齐的语义关联)范围:业务表全部在 shaguabijia-app-server(SQLAlchemy 2.0 + SQLite 开发 / PostgreSQL 生产)。pricebot-backend(比价/领券 Agent)是纯内存态、无任何表;Android 客户端只有 EncryptedSharedPreferences / SharedPreferences、无关系库。共 22 张业务表 + alembic_version(框架的迁移版本指针)。


一、按功能域看表(每张表用在 App 哪里)

比价(核心业务)

App 位置 / 动作 说明
比价/领券过程(看屏→决策→操作) (无) 在 pricebot-backend 内存态跑,过程不落库;只有结果回到 app-server 才落库
「我的比价记录」列表 / 详情 comparison_record 每次比价 done 后客户端带 JWT 上报一条完整明细
比价战绩里程碑(逐档领金币) comparison_milestone_claim 累计成功比价 N 次解锁;进度读 comparison_record 计数
profile「累计省了 / 省钱战绩 / 省钱明细」 savings_record 真实下单归因(source=compare)+ 无真实数据时 demo 兜底
「上报更低价」提交 / 列表 price_report 众包纠偏:用户举证某平台更便宜,人工审核发奖

钱包 / 福利(看广告赚钱闭环)

App 位置 / 动作 说明
资产卡 / 钱包余额 coin_account 一用户一行的金币+现金余额快照
金币明细 coin_transaction 每次金币变动一笔流水
现金明细 cash_transaction 每次现金变动一笔流水(分)
每日签到 signin_record + signin_boost_record 14 天循环发币;签到后看广告可膨胀一次
一次性任务(开消息提醒等) user_task 领一次发币
看激励视频赚金币 ad_reward_record + ad_watch_log + ad_ecpm_record 独立数据流:发奖 / 旧版观看时长 / 收益对账
信息流广告结算 ad_feed_reward_record 每展示满 10 秒累计一份奖励,完成后一次性入账
金币兑现金 coin_account + coin_transaction + cash_transaction exchange_out + exchange_in 两笔流水
提现到微信零钱 withdraw_order + wechat_transfer_authorization + cash_transaction 人工审核 + 微信商家转账
绑定微信(提现前置) user.wechat_* openid 唯一,一微信一账号

账号 / 反馈

App 位置 / 动作 说明
登录(极光/短信)/ 改资料 / 注销 user 登录主体,注册即登录
帮助与反馈 feedback 含截图,后台人工处理

运营后台 admin(独立子应用 app/admin/,端口 8771,独立鉴权)

后台模块 说明
管理员账号 / 登录 admin_user 与 C 端 user 完全隔离,独立 JWT + RBAC
操作审计 admin_audit_log 每个写操作落一条,只增不改不删
运营可配置项(改奖励常量) app_config 空表 = 用代码默认;后台改了即覆盖
用户/钱包/提现/反馈管理 跨读写上面的 C 端表 见下「写入路径」admin 段

二、写入路径(什么操作 → 写哪张表)

C=插入新行 · U=更新已有行 · 同一行内多张表表示同一事务原子写

C 端(App 用户触发)

触发(用户动作 / endpoint / 回调) 写入 操作
登录 POST /auth/jverify-login/auth/sms/login user C(首次=注册)/ U(last_login_at)
改昵称 PATCH /user/profile、传头像 POST /user/avatar user U
注销 DELETE /user user U(软删:phone→deleted_<id>status=deleted)
绑/解绑微信 POST /wallet/bind-wechat/unbind-wechat user.wechat_* U
签到 POST /signin/do signin_record(C) + coin_account(U) + coin_transaction(C signin) 同事务
签到膨胀 POST /signin/boost signin_boost_record(C) + coin_account(U) + coin_transaction(C signin_boost) 同事务;同日一次
领任务 POST /tasks/claim user_task(C) + coin_account(U) + coin_transaction(C task_<key>) 同事务
金币兑现金 POST /wallet/exchange coin_account(U) + coin_transaction(C exchange_out ) + cash_transaction(C exchange_in +) 同事务
发起提现 POST /wallet/withdraw withdraw_order(C reviewing) + coin_account(U 扣现金) + cash_transaction(C withdraw ) 同事务,不打款
查提现状态 / 用户取消 GET /wallet/withdraw/status withdraw_order(U) + 失败→cash_transaction(C withdraw_refund +)
穿山甲发奖 S2S 回调 POST /ad/pangle-callback ad_reward_record(C)+ granted→coin_account(U)+coin_transaction(C ad_reward) trans_id 幂等
看广告时长上报 POST /ad/watch-report ad_watch_log(C)
广告 eCPM 上报 POST /ad/ecpm-report ad_ecpm_record(C)
信息流广告结算 POST /ad/feed-reward ad_feed_reward_record(C)+ granted→coin_account(U)+coin_transaction(C feed_ad_reward) client_event_id 幂等
比价 done 上报 POST /compare/record comparison_record(C 或 U) (user_id, trace_id) 幂等覆盖
领里程碑 POST /compare/milestone/claim comparison_milestone_claim(C) 当前不发币(coin_awarded=0)
支付归因上报 POST /order/report savings_record(C source=compare) (user_id, client_event_id) 幂等
首次进 profile 省钱页且无真实记录 savings_record(C source=demo) 懒种子,ensure_seeded 按 user 幂等
上报更低价 POST /report price_report(C) comparison_record.best_price_cents 校验
提交反馈 POST /feedback feedback(C)

admin 端(管理员触发,均额外写一条 admin_audit_log)

后台操作 写入 操作
手动增减金币 coin_account(U)+coin_transaction(C admin_grant/admin_deduct)+admin_audit_log(C) 同事务
改用户状态(禁用/启用) user(U)+admin_audit_log(C) 同事务
审核通过提现 withdraw_order(U→pending/success/failed)+wechat_transfer_authorization(C/U)+失败时cash_transaction(refund)+admin_audit_log(C)
审核拒绝提现 withdraw_order(U→rejected)+cash_transaction(C withdraw_refund)+admin_audit_log(C)
处理反馈 feedback(U)+admin_audit_log(C) 同事务
改运营配置 app_config(C/U)+admin_audit_log(C) 同事务
任意写操作 admin_audit_log(C,永不 U/D)

没有任何表会被业务流程物理 DELETE。注销是软删(改 user 行),其余只 C/U。


三、表间关系 & Join Key

硬外键(数据库 FK 约束)

  • 17 张用户维度表 .user_iduser.id:coin_account(同时是 PK)、coin_transactioncash_transactionwithdraw_orderwechat_transfer_authorization(同时是 PK)、signin_recordsignin_boost_recorduser_taskcomparison_recordcomparison_milestone_claimsavings_recordad_reward_recordad_watch_logad_ecpm_recordad_feed_reward_recordprice_reportfeedback
  • admin_audit_log.admin_idadmin_user.id
  • price_report.comparison_record_idcomparison_record.id(可空:关联记录被删后仍留上报历史)。

语义 join key(无 FK 约束,靠业务字段对齐 —— 排障/对账必看)

  • coin_transaction.ref_id 指向随 biz_type:

    biz_type ref_id 指向 amount 符号
    signin 当天日期串(= signin_record.signin_date 的 ISO YYYY-MM-DD) +
    signin_boost 当天日期串(= signin_boost_record.signin_date 的 ISO YYYY-MM-DD) +
    task_<key> user_task.task_key +
    ad_reward ad_reward_record.trans_id +
    feed_ad_reward ad_feed_reward_record.client_event_id +
    exchange_out null(兑现金,无单据)
    admin_grant / admin_deduct null(原因记在 remark=admin:<reason>) + /
  • cash_transaction.ref_id:

    biz_type ref_id 指向 amount 符号
    withdraw / withdraw_refund withdraw_order.out_bill_no / +
    exchange_in null +
  • comparison_record.store_namesavings_record.shop_name:无 id 关联,按店名字符串相等给比价记录打「已下单」标记(瞬态,不写库)。两边店名同源 = 比价意图识别阶段的门店 query,语义=店级(同店比价多次会一并标已下单)。

  • 广告流互不关联:ad_reward_record / ad_watch_log / ad_ecpm_record / ad_feed_reward_record 之间无公共键,各自只按 (user_id, 日期串) 聚合。别试图 join 它们逐条对应。

  • 里程碑解锁进度不存库:comparison_milestone_claim 只记「哪几档已领」;进度 = comparison_recordstatus='success'count

ER 关系(文字版)

user ─1:1─ coin_account
user ─1:1─ wechat_transfer_authorization
user ─1:N─ { coin_transaction, cash_transaction, withdraw_order, signin_record,
            signin_boost_record, user_task, comparison_record, comparison_milestone_claim,
            savings_record, ad_reward_record, ad_watch_log, ad_ecpm_record, ad_feed_reward_record,
            price_report, feedback }
comparison_record ─1:N─ price_report        (comparison_record_id, 可空)
admin_user ─1:N─ admin_audit_log
app_config                                   (独立, 无外键, key 为主键)

四、资金模型(金币 / 现金 / 提现,三层)

  1. 余额快照 coin_account:coin_balance(金币个数)+ cash_balance_cents(现金分),一用户一行,读取展示用。
  2. 流水账本 coin_transaction / cash_transaction:每次变动写一笔,balance_after* 记变动后余额,可逐笔回溯对账。
  3. 唯一发金币入口 repositories/wallet.grant_coins:更新快照 + 写流水,不 commit,由调用方在同一事务里 commit(保证"记录"和"加币"原子化)。signin / signin_boost / task / ad_reward / feed_ad_reward / exchange / admin 都走它,靠 biz_type 区分来源。
  • 汇率:10000 金币 = 1 元 = 100 分(rewards.COIN_PER_YUAN);兑换额必须是整分倍数。
  • 提现状态机:reviewing(发起即原子扣现金、待人工审核、不打款)→ 审核通过 pending(微信转账在途)→ success / failed(失败自动退款);审核拒绝 rejected(退款)。扣款/退款都写 cash_transaction,out_bill_no 幂等,孤儿 pending 单由 reconcile_pending_withdraws 对账兜底。
  • 防超额:扣现金用带条件 UPDATE ... WHERE cash_balance_cents >= amount,并发/重试不会双扣。

五、通用约定

README → 通用约定:金额存整数(金币计数 / 现金存分)、业务「今天」按北京时间日期串等值聚合(不在 SQL 跨时区比 date)、JSON 列 PG 用 JSONB·SQLite 退化 JSON、改表必写 alembic 迁移并保持单 head + 同步更新本目录文档。