提示信息
# 同伴 App 数据库设计规范
> 本文档由系统根据 `database/schema/*.sql` 自动生成。请勿手动修改本项目文件。
## 表结构概览
| 数据表 | 中文说明 |
| :--- | :--- |
| [`users`](#表users) | 用户核心信息 |
| [`user_devices`](#表user_devices) | 用户设备绑定 |
| [`user_blocks`](#表user_blocks) | 黑名单 |
| [`user_login_logs`](#表user_login_logs) | 登录流水 |
| [`user_risk_logs`](#表user_risk_logs) | 风控/风险日志 |
| [`user_forbidden`](#表user_forbidden) | 封禁记录 |
| [`user_sign_stats`](#表user_sign_stats) | 用户签到统计 |
| [`user_sign_logs`](#表user_sign_logs) | 用户签到流水 |
| [`user_module_cursors`](#表user_module_cursors) | 用户模块游标 |
| [`user_verifications`](#表user_verifications) | 用户实人认证流水 |
| [`user_cancellations`](#表user_cancellations) | 用户注销申请 |
| [`reports`](#表reports) | 举报 |
| [`signals`](#表signals) | 信号 |
| [`signal_receives`](#表signal_receives) | 信号收取记录 |
| [`signal_replies`](#表signal_replies) | 信号回复 |
| [`signal_low_quality_feedbacks`](#表signal_low_quality_feedbacks) | 信号低质量反馈 |
| [`im_stranger_limit`](#表im_stranger_limit) | IM陌生人聊天限制 |
| [`im_daily_greet`](#表im_daily_greet) | IM每日打招呼记录 |
| [`im_day_stats`](#表im_day_stats) | IM每日统计 |
| [`user_upload_logs`](#表user_upload_logs) | 用户上传日志 |
| [`im_violation_logs`](#表im_violation_logs) | IM违规拦截日志 |
| [`user_conversation_settings`](#表user_conversation_settings) | 用户私聊会话设置 |
| [`app_versions`](#表app_versions) | 版本检查与更新配置表 |
| [`orders`](#表orders) | 交易订单与充值流水表 |
| [`sms_logs`](#表sms_logs) | |
| [`app_documents`](#表app_documents) | 法律文档 |
| [`system_notifications`](#表system_notifications) | 系统通知广播 |
| [`user_system_notification_reads`](#表user_system_notification_reads) | extra 字段规范(基于最新的统跳 URI Scheme): {"url":"tongban://profile/membership"} → 会员中心 {"url":"tongban://webview?url=https%3A%2F%2F..."} → 使用端内 WebView 打开外部网页 {"url":"tongban://profile/user?uid=123"} → 用户主页 {"url":"tongban://message/chat?uid=123"} → 指定用户单聊 {"url":"tongban://signal/inbox"} → 信号收件箱 (Tab栏首个会重置导航栈进入) {"url":"tongban://signal/publish"} → 发布信号页 {"url":"tongban://message/notifications"} → 通知中心 {"url":"tongban://profile/feedback"} → 意见反馈 {"url":"tongban://profile/verification"} → 实名认证 {"url":"tongban://profile/privacySettings"} → 隐私设置 {"url":"tongban://profile/accountSecurity"} → 账号与安全 {"url":"tongban://system/logout"} → 强制退出登录 {"url":"tongban://profile/editProfile"} → 编辑资料 {"url":"tongban://profile/cacheManagement"} → 存储与清理 {"url":"tongban://profile/about"} → 关于我们 {"url":"tongban://profile/youthMode"} → 青少年模式 {"url":"tongban://profile/blockList"} → 黑名单管理 {"url":"tongban://message/customerService"} → 联系人工客服 null 或省略 → 仅展示通知,不跳转 用户已读记录 |
| [`user_vip_records`](#表user_vip_records) | 用户 VIP 开通明细 |
| [`user_profile_audits`](#表user_profile_audits) | 用户资料审核记录 |
| [`sensitive_words`](#表sensitive_words) | 敏感词库:每条规则属于且只属于一个场景(scope),同一词可在不同场景建不同规则。 scope: nickname | bio | signal | signal_reply | chat action: block = 命中直接拒绝;review = 放行进人工审核(私聊场景 block/review 均只记日志) ⚠️ 词表匹配规则(决定能放什么词): 1. 纯子串匹配(str_contains),无正则、无组合逻辑。只放「单独出现即违规、且作为子串极少误伤正常文本」的高精度词。 2. 联系方式 / 引流(手机号·QQ号·微信号·URL·"平台词+动词"·裸长数字)由 app/Services/TextModerationService.php 的 detectContact() 硬编码分级处理,不进词表。 3. normalize() 会在匹配前改写文本:微信/vx→wechat、扣扣→qq、圈号数字→阿拉伯、去分隔符。 词表里不放会被改写的形态(如"微信"),否则匹配不上。 词源:线上昵称/签名重置历史样本 + 大陆社交平台常见违规词。 |
| [`app_routes`](#表app_routes) | |
| [`user_page_views`](#表user_page_views) | 用户访问路径埋点 |
| [`admin_roles`](#表admin_roles) | 后台管理基础 |
| [`admin_users`](#表admin_users) | |
| [`admin_permissions`](#表admin_permissions) | |
| [`admin_role_permissions`](#表admin_role_permissions) | |
| [`admin_audit_logs`](#表admin_audit_logs) | |
| [`admin_login_logs`](#表admin_login_logs) | |
| [`admin_feature_dictionaries`](#表admin_feature_dictionaries) | |
| [`products`](#表products) | 商城商品 |
| [`im_photo_swap`](#表im_photo_swap) | 换照(Photo Swap)记录 |
| [`im_emoji`](#表im_emoji) | 表情主表 |
| [`im_emoji_favorite`](#表im_emoji_favorite) | 个人表情收藏表 |
| [`friend_requests`](#表friend_requests) | 好友申请 |
| [`user_friends`](#表user_friends) | 好友关系 |
| [`user_remarks`](#表user_remarks) | 用户备注 |
| [`qrcode_invite_logs`](#表qrcode_invite_logs) | 扫码加好友埋点:记录「谁通过谁的个人二维码加了好友」。 第一版仅统计累计人数(/user/qrcode/stats),为二期「拉新达标赠会员」铺路,暂不发放奖励。 写入时机:好友以 source=3(扫码)建立关系时,见 FriendService::acceptRequest。 |
| [`user_visits`](#表user_visits) | 主页访客(足迹) |
| [`banned_login_attempts`](#表banned_login_attempts) | 封禁用户登录尝试记录 触发时机:验证码通过 → 封禁检查命中,此时 device_info 完整可用 用途:① 7天内该手机号发验证码直接返回封禁信息 ② 设备防控数据源 |
| [`fraud_samples`](#表fraud_samples) | 反诈样本 |
| [`splash_ads`](#表splash_ads) | ============================================================================= 开屏广告(自建广告位) 设计文档:iOS 仓库 Tongban/Docs/splash_ad_plan.md V1:官方运营位(owner_uid 预留给 V4 用户付费投放) ============================================================================= |
| [`splash_ad_events`](#表splash_ad_events) | 事件流水:曝光/点击/跳过/完播(量 = DAU × 启动次数级别;V4 结算前按月归档即可) |
| [`app_configs`](#表app_configs) | ============================================================================= 动态配置中心:DB 覆盖 config/business.php,带版本快照与一键回滚 设计文档:docs/信号曝光与流量分发体系规划方案.md §九 读取链路:BusinessConfig::limit() → Redis hash biz_config(全量缓存+版本号,TTL 300s) → miss 读 app_configs 灌入 → DB 无该 key → fallback config/business.php ============================================================================= |
| [`app_config_versions`](#表app_config_versions) | 配置版本快照:每次后台保存写入全量快照,可一键回滚 |
| [`hobbies`](#表hobbies) | 兴趣标签字典:由旧库 xl_hobby 迁移,供 app/config 下发与 users.hobby_ids 校验 |
| [`user_traffic_profiles`](#表user_traffic_profiles) | 用户流量画像(跑批读写、后台展示,不参与分发查询) |
| [`signal_traffic_daily_stats`](#表signal_traffic_daily_stats) | 信号流量日统计(后台展示 / 质量分跑批输入 / Redis 丢失回补) |
| [`signal_traffic_events`](#表signal_traffic_events) | 漏斗事件明细(看板用,明细只留 30~90 天,定期清理) |
| [`user_active_days`](#表user_active_days) | ============================================================================= 用户按天活跃事实 |
| [`user_experience_logs`](#表user_experience_logs) | ============================================================================= 用户经验流水 |
| [`admin_roles`](#表admin_roles) | ───────────────────────────────────────────────────────────────────────── admin_roles:角色。super_admin 为特殊角色代码,代码层直接短路放行全部权限, 不依赖 admin_role_permissions,且不可删除/不可编辑权限。 ───────────────────────────────────────────────────────────────────────── |
| [`admin_users`](#表admin_users) | ───────────────────────────────────────────────────────────────────────── admin_users:管理员账号,手机号 + 密码登录。 phone 同时用作 App 端"我的页"管理入口可见性判定依据(与 users.phone 匹配)。 uid 可空:纯后台账号无需关联 App 账号;关联后可在后台展示该管理员对应的 App 身份。 ───────────────────────────────────────────────────────────────────────── |
| [`admin_permissions`](#表admin_permissions) | ───────────────────────────────────────────────────────────────────────── admin_permissions:权限点目录。code 形如 {module}.view / {module}.manage, module 与 admin/src/config/adminMenu.ts 的 AdminPageKey 一一对应, 新增后台菜单时同步在此补充一对权限即可。 ───────────────────────────────────────────────────────────────────────── |
| [`admin_role_permissions`](#表admin_role_permissions) | ───────────────────────────────────────────────────────────────────────── admin_role_permissions:角色 ↔ 权限多对多。super_admin 不写入任何行(代码层短路全权限)。 ───────────────────────────────────────────────────────────────────────── |
| [`im_callback_events`](#表im_callback_events) | OpenIM 回调事件幂等记录表 回调快速落库后返回;后续处理(风控/推送/统计)失败可重试;死信可在 Admin 查看/重放 |
| [`app_events`](#表app_events) | 核心漏斗事件表 事件事实源以后端落库为准;不保存聊天正文、精确位置、身份证等非必要敏感内容 |
| [`credit_violation_events`](#表credit_violation_events) | 内容信用治理:四场景违规事件、能力限制与举报处理扩展。 |
| [`user_credit_restrictions`](#表user_credit_restrictions) | |
| [`coin_transactions`](#表coin_transactions) | 虚拟币流水(钱包明细):充值入账 / 消费出账 / 退款 / 后台调整 余额本体在 users.coin_balance,本表只记每一笔变动,供「我的钱包-明细」展示与对账 |
| [`moments`](#表moments) | 动态主表 |
| [`moment_likes`](#表moment_likes) | 动态点赞表 |
| [`moment_comments`](#表moment_comments) | 动态评论表(最多两层:一级评论 + 二级回复) |
| [`moment_comment_likes`](#表moment_comment_likes) | 评论点赞表 |
| [`moment_views`](#表moment_views) | 动态浏览/曝光上报表(前端批量上报) |
| [`moment_mentions`](#表moment_mentions) | 动态 @ 用户表(@通知 / 提到我的) |
| [`topics`](#表topics) | 话题表 |
| [`moment_topics`](#表moment_topics) | 动态-话题关联表 |
| [`topic_follows`](#表topic_follows) | 话题关注表 |
| [`topic_daily_stats`](#表topic_daily_stats) | 话题每日统计表(热门话题榜数据源,定时聚合写入) |
| [`moment_reports`](#表moment_reports) | 动态举报表 |
| [`moment_comment_reports`](#表moment_comment_reports) | 评论举报表 |
| [`user_bonds`](#表user_bonds) | 亲密关系绑定主表 bond_type: 1=恋人(每人限 1 段活跃)2=基友/哥们 3=闺蜜/姐妹(不限数量) status: 0=待确认 1=生效 2=已拒绝 3=已解绑 4=suspended(封禁时系统置入) |
| [`user_bond_cards`](#表user_bond_cards) | 关系卡库存:每人每种卡一行,quantity 累加 card_type: 1=恋人卡 2=基友卡 3=闺蜜卡 4=通用卡(自定义绑定用) |
## 详细字段设计
<a name="表users"></a>
### 表:`users`
> **说明**:用户核心信息表:存储账号、资料、统计数据及隐私设置
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 用户唯一标识 |
| `nickname` | `VARCHAR(255)` | 昵称 |
| `bio` | `VARCHAR(500)` | 个人简介 |
| `phone` | `VARCHAR(30)` | 手机号 |
| `password_hash` | `VARCHAR(255)` | 密码哈希 |
| `avatar` | `TEXT` | 头像地址 |
| `gender` | `SMALLINT` | 性别 ([`Gender`](/docs/dictionary#Gender)) |
| `orientation` | `SMALLINT` | 性取向 |
| `attribute` | `SMALLINT` | 属性 |
| `birth_date` | `DATE` | 出生日期 |
| `residence` | `JSONB` | 常住地 (结构化数据: 省/市/区) |
| `hobby_ids` | `JSONB` | 兴趣标签 ID 列表(最多 8 个,来自 hobbies.id) |
| `mbti` | `VARCHAR(10)` | MBTI 人格类型 |
| `profile_version` | `INTEGER` | 资料版本号 (每次提交审核 +1,用于审核侧乐观锁) |
| `is_verified` | `BOOLEAN` | 是否通过认证 |
| `is_vip` | `BOOLEAN` | 是否是 VIP(缓存字段,以 vip_expired_at > NOW() 为准) |
| `vip_expired_at` | `TIMESTAMPTZ` | VIP 到期时间,NULL=从未开通 |
| `force_auth` | `BOOLEAN` | 是否强制认证 |
| `forbidden_type` | `SMALLINT` | 当前封禁原因 ([`ForbiddenType`](/docs/dictionary#ForbiddenType)),null=正常 |
| `canceled_at` | `TIMESTAMPTZ` | 注销时间 |
| `rating_updated_at` | `TIMESTAMPTZ` | 评级/分值更新时间 |
| `trust_level` | `SMALLINT` | 信任等级 (TrustLevel: -2垃圾 -1低质 0普通 1实名 2优质),内部使用不展示 |
| `trust_score` | `INT` | 信任分(0~100),跑批重算映射到 trust_level |
| `trust_level_locked` | `BOOLEAN` | admin 锁定后跑批不再覆盖 trust_level |
| `content_rating` | `SMALLINT` | 创作者内容尺度画像(0~3),分发生效尺度跟人走,影响其全部信号的尺度过滤 |
| `content_rating_locked` | `BOOLEAN` | admin 锁定后跑批不再覆盖 content_rating |
| `nsfw_pref` | `SMALLINT` | 接收尺度偏好 (NsfwPref: -1纯净/0标准(默认)/1开放/2无限制);v3.3:1/2档由行为推断达标,不再要求实名 |
| `nsfw_pref_before_pure` | `SMALLINT` | v3.3:手动纯净模式冻结标志兼恢复目标。NULL=非纯净态(跑批接管 nsfw_pref);非NULL=用户开了纯净(nsfw_pref=-1冻结),存开纯净前档位,关纯净即写回(§2.5) |
| `location` | `POINT` | 经纬度位置 |
| `accepted_privacy_version` | `SMALLINT` | 已同意的隐私政策版本 |
| `is_profile_hidden` | `BOOLEAN` | 是否隐藏资料页 |
| `is_visit_hidden` | `BOOLEAN` | 是否隐藏访问记录 |
| `is_read_status_hidden` | `BOOLEAN` | 是否隐藏消息已读状态 |
| `is_active_hidden` | `BOOLEAN` | 是否隐藏活跃时间 |
| `is_vip_hidden` | `BOOLEAN` | 是否隐藏 VIP 标志 |
| `is_personalized` | `BOOLEAN` | 是否开启个性化推荐 |
| `friend_apply_mode` | `SMALLINT` | 好友申请接收范围:0=所有人 1=仅认证用户 2=不接收(主页隐藏/锁定加好友入口;已是好友不影响) |
| `push_enabled` | `BOOLEAN` | 推送总开关(关=服务端一律不推离线通知) |
| `push_show_detail` | `BOOLEAN` | 推送是否显示详情(默认关=脱敏:标题"同伴"/正文"收到一条新消息";开=标题显示昵称、正文显示内容) |
| `young_pass` | `VARCHAR(100)` | 青少年模式密码 (空表示未开启) |
| `device_id` | `VARCHAR(255)` | 注册时的设备 ID |
| `last_ip` | `INET` | 最后访问 IP 地址 |
| `experience` | `INTEGER` | 经验余额(>=0,补签时扣减,不足则补签失败) |
| `coin_balance` | `BIGINT` | 虚拟币余额(>=0) |
| `last_active_at` | `TIMESTAMPTZ` | 最后活跃时间 |
| `profile_reset_at` | `TIMESTAMPTZ` | 管理后台最近一次资料重置时间 |
| `created_at` | `TIMESTAMPTZ` | 注册时间 |
---
<a name="表user_devices"></a>
### 表:`user_devices`
> **说明**:用户设备绑定表:记录用户登录过的设备信息及封禁状态
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 主键 |
| `user_id` | `BIGINT` | 用户 ID |
| `device_id` | `TEXT` | 设备唯一标识 (UUID/IDFA等) |
| `model` | `TEXT` | 设备型号 (例: iPhone 16 Pro) |
| `platform` | `TEXT` | 平台 (ios/android) |
| `os_version` | `TEXT` | 操作系统版本 |
| `app_version` | `TEXT` | App 版本 |
| `is_banned` | `BOOLEAN` | 该设备是否被封禁 |
| `ban_reason` | `TEXT` | 封禁原因 |
| `risk_flags` | `TEXT[]` | 设备风险标志数组,来自 IOSSecuritySuite (例: ["safe"] / ["jailbreak","hook"]) |
| `risk_updated_at` | `TIMESTAMPTZ` | 风险标志最后更新时间 |
| `first_seen_at` | `TIMESTAMPTZ` | 首次在该设备登录时间 |
| `last_seen_at` | `TIMESTAMPTZ` | 最后在该设备登录时间 |
---
<a name="表user_blocks"></a>
### 表:`user_blocks`
> **说明**:黑名单表:记录用户屏蔽关系
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 主键 |
| `user_id` | `BIGINT` | 发起屏蔽的用户 ID |
| `target_user_id` | `BIGINT` | 被屏蔽的用户 ID |
| `created_at` | `TIMESTAMPTZ` | 屏蔽时间 |
| `deleted_at` | `TIMESTAMPTZ` | 解除屏蔽时间 (逻辑删除) |
---
<a name="表user_login_logs"></a>
### 表:`user_login_logs`
> **说明**:登录流水表:记录用户所有登录尝试及环境信息
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 主键 |
| `user_id` | `BIGINT` | 用户 ID |
| `device_id` | `TEXT` | 设备 ID |
| `model` | `TEXT` | 设备型号 |
| `platform` | `TEXT` | 平台 (ios/android) |
| `os_version` | `TEXT` | 系统版本 |
| `app_version` | `TEXT` | App 版本 |
| `ip` | `INET` | 登录 IP 地址 |
| `ip_country` | `TEXT` | 国家 (由 ip2region 解析) |
| `ip_city` | `TEXT` | 城市 (由 ip2region 解析) |
| `user_agent` | `TEXT` | 浏览器/客户端 UA |
| `client_type` | `TEXT` | 客户端类型 (app/web) |
| `network_type` | `TEXT` | 网络类型 (wifi/5g等) |
| `locale` | `TEXT` | 语言/时区设置 |
| `login_type` | `SMALLINT` | 登录方式 ([`LoginType`](/docs/dictionary#LoginType)) |
| `is_success` | `BOOLEAN` | 是否成功 |
| `fail_reason` | `TEXT` | 失败原因 |
| `extra_info` | `JSONB` | 扩展信息 (风控、埋点等) |
| `request_id` | `TEXT` | 请求追踪 ID |
| `is_emulator` | `BOOLEAN` | 是否模拟器 |
| `is_root` | `BOOLEAN` | 是否 Root/越狱 |
| `is_debugger` | `BOOLEAN` | 是否开启调试 |
| `is_hook` | `BOOLEAN` | 是否有 Hook 框架 |
| `created_at` | `TIMESTAMPTZ` | 记录时间 |
---
<a name="表user_risk_logs"></a>
### 表:`user_risk_logs`
> **说明**:风控/风险日志表:记录系统检测到的疑似异常或风险行为
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 主键 |
| `user_id` | `BIGINT` | 用户 ID |
| `device_id` | `TEXT` | 触发风险的设备 ID |
| `risk_type` | `SMALLINT` | 风险类型 (1-异地登录 2-模拟器 3-Root 4-Hook 5-调试 6-多账号 7-频繁失败 8-录屏 9-VPN 10-Token异常) |
| `risk_level` | `SMALLINT` | 风险等级 (1-低 2-中 3-高) |
| `detail` | `JSONB` | 详细风险上下文 |
| `ip` | `INET` | 触发风险的 IP |
| `created_at` | `TIMESTAMPTZ` | 记录时间 |
---
<a name="表user_forbidden"></a>
### 表:`user_forbidden`
> **说明**:封禁记录表:记录用户或设备的处罚详情及期限
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 主键 |
| `user_id` | `BIGINT` | 被封禁的用户 ID |
| `device_id` | `TEXT` | 被封禁的设备 ID (可选) |
| `forbidden_type` | `SMALLINT` | 封禁类型 ([`ForbiddenType`](/docs/dictionary#ForbiddenType)) |
| `reason` | `TEXT` | 封禁原因 |
| `start_at` | `TIMESTAMPTZ` | 封禁开始时间 |
| `end_at` | `TIMESTAMPTZ` | 封禁结束时间 (NULL 表示永久) |
| `operator_user_id` | `BIGINT` | 操作员 ID (NULL 表示系统自动执行) |
| `is_active` | `BOOLEAN` | 是否当前生效 |
| `created_at` | `TIMESTAMPTZ` | 记录创建时间 |
---
<a name="表user_sign_stats"></a>
### 表:`user_sign_stats`
> **说明**:用户签到统计表:维护用户的连续签到与累计签到数据(1 用户 1 行)
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `user_id` | `BIGINT` | 用户 ID |
| `continuous_days` | `INTEGER` | 以 last_sign_date 为链尾的连续签到天数(读取时若 last_sign_date < 昨天则展示 0) |
| `total_days` | `INTEGER` | 累计签到总天数(含补签) |
| `last_sign_date` | `DATE` | 最近一次"签到所属自然日"(补签历史日期不会改它,除非补的就是最新日) |
| `last_sign_at` | `TIMESTAMPTZ` | 最近一次签到"动作"发生的时间戳 |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表user_sign_logs"></a>
### 表:`user_sign_logs`
> **说明**:用户签到流水表:记录每一天的具体签到(正常签 / 补签)
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | 用户 ID |
| `sign_date` | `DATE` | 签到所属日期 |
| `sign_type` | `SMALLINT` | 1=正常签到 2=补签 |
| `experience_reward` | `INTEGER` | 该次签到获得的经验(补签固定 0) |
| `experience_cost` | `INTEGER` | 补签消耗的经验(正常签到固定 0) |
| `free_repair` | `BOOLEAN` | 是否因当日有活跃而免费补签 |
| `reward_week_day` | `SMALLINT` | 本次正常签命中的 7 日梯度档位(1~7,补签为 0) |
| `created_at` | `TIMESTAMPTZ` | 签到动作的具体时间 |
---
<a name="表user_module_cursors"></a>
### 表:`user_module_cursors`
> **说明**:用户模块游标表:记录用户在三个入口(系统通知/好友申请/访客)的最后查看时间,用于消息 tab 角标 未读计数逻辑:各模块列表查询时先返回数据再更新对应 last_*_view_at, 下次进入该模块时用此时间戳与最新数据比较得到未读数
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `user_id` | `BIGINT` | 用户 ID |
| `last_notify_view_at` | `TIMESTAMPTZ` | 最后查看系统通知列表时间(NULL=从未查看) |
| `last_friend_request_view_at` | `TIMESTAMPTZ` | 最后查看好友申请列表时间(NULL=从未查看) |
| `last_visitors_view_at` | `TIMESTAMPTZ` | 最后查看访客列表时间(NULL=从未查看) |
| `updated_at` | `TIMESTAMPTZ` | 记录更新时间 |
---
<a name="表user_verifications"></a>
### 表:`user_verifications`
> **说明**:用户实人认证流水表:对接三方服务(如阿里云、腾讯云)进行的三要素认证以及人工认证
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 主键 |
| `user_id` | `BIGINT` | 用户 ID |
| `outer_order_no` | `VARCHAR(64)` | 业务流水号 |
| `verify_type` | `VARCHAR(32)` | 认证类型 (three_elements-三要素, manual-人工) |
| `real_name` | `VARCHAR(255)` | 真实姓名 (加密存储) |
| `id_card` | `VARCHAR(255)` | 身份证号 (加密存储) |
| `mobile` | `VARCHAR(32)` | 认证手机号 |
| `photo_url` | `TEXT` | 人工认证照片URL(JSON数组) |
| `request_payload` | `JSONB` | 原始请求信息(可选) |
| `provider_response` | `JSONB` | 三方接口的原始完整响应 |
| `fail_reason` | `VARCHAR(255)` | 认证失败的原因说明 |
| `status` | `SMALLINT` | 认证状态: 0=pending, 1=approved, 2=rejected, 3=cancelled |
| `created_at` | `TIMESTAMPTZ` | 创建时间 |
| `updated_at` | `TIMESTAMPTZ` | 更新时间 |
| `deleted_at` | `TIMESTAMPTZ` | 软删除时间:账号注销自动释放或用户主动删除认证资料后置位,置位后该身份信息可被其他账号重新认证 |
---
<a name="表user_cancellations"></a>
### 表:`user_cancellations`
> **说明**:用户注销申请表:管理注销冷静期生命周期,并追踪受限账户重注册
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | |
| `phone` | `VARCHAR(30)` | 申请时的手机号(注销执行后 users.phone 会被清空) |
| `ip` | `VARCHAR(50)` | |
| `platform` | `VARCHAR(50)` | ios / android / web |
| `model` | `VARCHAR(100)` | 设备型号 |
| `os_version` | `VARCHAR(100)` | 系统版本 |
| `app_version` | `VARCHAR(50)` | App 版本 |
| `reason` | `VARCHAR(500)` | |
| `status` | `SMALLINT` | 0=取消申请 1=申请中 |
| `is_end` | `SMALLINT` | 0=未执行 1=已执行 |
| `scheduled_at` | `TIMESTAMPTZ` | 预定执行时间(申请时间 + 7 天) |
| `executed_at` | `TIMESTAMPTZ` | 实际执行时间 |
| `forbidden_type` | `SMALLINT` | 申请时账号封禁类型,非 NULL 表示受限账户,用于重注册限制 |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表reports"></a>
### 表:`reports`
> **说明**:举报表:记录用户对其他用户资料、信号内容或聊天行为的举报 v2(2026-06):按举报对象(target)组织理由,语义化 reason_code; 新增聊天授权、服务端快照、自动风控记录与 AI 审核占位字段。
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 主键 |
| `reporter_uid` | `BIGINT` | 举报人 ID |
| `target` | `VARCHAR(16)` | 举报对象:profile=资料 signal=信号内容 chat=聊天行为 |
| `relation_id` | `VARCHAR(255)` | target_id:用户ID/信号ID/会话ID |
| `reported_uid` | `BIGINT` | 被举报的用户 ID |
| `reason_code` | `VARCHAR(64)` | 理由 code(语义化,如 fraud_romance;旧数据为 int 字符串如 '1001') |
| `message` | `VARCHAR(1000)` | 补充说明 |
| `images` | `JSONB` | 证据图片 JSON 数组(含客户端自动截图) |
| `chat_authorized` | `BOOLEAN` | 举报人是否授权查看双方聊天记录(target=chat 必为 true) |
| `extra` | `JSONB` | 服务端快照等:{snapshot:{nickname,avatar,bio}|{signal...}} |
| `status` | `SMALLINT` | 0=待处理 1=违规成立 2=举报无效 |
| `handle_result` | `SMALLINT` | 处理措施:1=封禁账号 2=警告提醒 3=仅记录违规 NULL(status=2时)=举报无效 |
| `handle_note` | `VARCHAR(500)` | 处理备注,内部可见 |
| `handled_at` | `TIMESTAMPTZ` | 管理员处理时间 |
| `dismiss_reason` | `VARCHAR(50)` | 驳回原因:incomplete=举报材料不完整 no_violation=未发现任何违规 |
| `reporter_violated` | `BOOLEAN` | 举报人是否同时存在违规行为(恶意诬告等) |
| `auto_action` | `JSONB` | 提交时触发的自动风控(如 {"action":"verify_lock"}),dismiss 回滚依据 |
| `ai_review_status` | `SMALLINT` | AI 审核状态(占位):0未审核 1审核中 2完成 3失败 |
| `ai_review_result` | `JSONB` | AI 审核结果(占位) |
| `created_at` | `TIMESTAMPTZ` | 举报创建时间 |
| `updated_at` | `TIMESTAMPTZ` | 状态最后流转时间 |
---
<a name="表signals"></a>
### 表:`signals`
> **说明**:信号表:存储用户发布的信号(匹配请求)
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 信号唯一 ID |
| `uid` | `BIGINT` | 发布者用户 ID |
| `category` | `SMALLINT` | 信号分类 ([`SignalCategory`](/docs/dictionary#SignalCategory)) |
| `content` | `TEXT` | 信号文本内容 |
| `type` | `VARCHAR(20)` | 信号内容类型 ([`SignalType`](/docs/dictionary#SignalType): text/image/multiImage/voice/flashImage/photoSwap/sticker,与客户端聊天消息类型镜像) |
| `attachment` | `JSONB` | 附件信息 {object_key, width, height, duration} |
| `is_archived` | `BOOLEAN` | 是否归档(表示暂停曝光,作者还可见) |
| `status` | `SMALLINT` | 信号状态 ([`SignalStatus`](/docs/dictionary#SignalStatus)) |
| `reply_count` | `INT` | 累计被回复次数 |
| `collect_count` | `INT` | 累计被收取的次数 |
| `block_reason_code` | `VARCHAR(32)` | 违规原因 code ([`ContentViolationReason`](/docs/dictionary#ContentViolationReason)),action=block 时写入 |
| `content_rating` | `SMALLINT` | 内容尺度评级 (0~3),影响尺度过滤 |
| `is_featured` | `BOOLEAN` | 是否精选(运营加权插队,端上不露出) |
| `featured_until` | `TIMESTAMPTZ` | 精选有效期,NULL=长期 |
| `featured_by` | `BIGINT` | 操作管理员 uid |
| `featured_source` | `VARCHAR(20)` | 精选来源: admin/purchase(付费置顶预留) |
| `is_seed` | `BOOLEAN` | 是否为冷启动种子信号 |
| `created_at` | `TIMESTAMPTZ` | 创建时间 |
| `updated_at` | `TIMESTAMPTZ` | 最后热度或内容更新时间 |
| `deleted_at` | `TIMESTAMPTZ` | 删除时间 |
---
<a name="表signal_receives"></a>
### 表:`signal_receives`
> **说明**:信号收取记录表:记录用户收取了哪些信号或回复
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 收取记录唯一 ID |
| `uid` | `BIGINT` | 收取者用户 ID |
| `type` | `SMALLINT` | 收取类型 ([`SignalReceiveType`](/docs/dictionary#SignalReceiveType)) |
| `source_id` | `BIGINT` | 来源 ID (对应 signals.id 或 signal_replies.id) |
| `source_uid` | `BIGINT` | 发送者用户 ID |
| `status` | `SMALLINT` | 互动状态 ([`SignalReceiveStatus`](/docs/dictionary#SignalReceiveStatus)) |
| `is_read` | `BOOLEAN` | 是否已读 |
| `created_at` | `TIMESTAMPTZ` | 收取时间 |
| `deleted_at` | `TIMESTAMPTZ` | 删除时间 |
---
<a name="表signal_replies"></a>
### 表:`signal_replies`
> **说明**:信号回复表:存储用户针对某个信号的回复内容
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 回复唯一 ID |
| `signal_id` | `BIGINT` | 所属信号 ID |
| `from_uid` | `BIGINT` | 回复者(收取了信号的人) |
| `to_uid` | `BIGINT` | 被回复者(信号发布者) |
| `content` | `TEXT` | 回复文本内容(非文字类型可为空) |
| `type` | `VARCHAR(20)` | 回复内容类型 ([`SignalType`](/docs/dictionary#SignalType),与 signals.type 镜像;当前仅支持 text) |
| `attachment` | `JSONB` | 回复附件 {object_key, mime, duration, width, height, size},未来换照/闪图等类型使用 |
| `received_at` | `TIMESTAMPTZ` | 被收取时间 (NULL 表示信号主尚未收取此回复) |
| `status` | `SMALLINT` | 审核状态 0=正常 1=待审(涉诈/引流命中且未被收取) 2=确认违规 3=误判放行 |
| `violation_reason` | `VARCHAR(32)` | 确认违规时的原因 code ([`ContentViolationReason`](/docs/dictionary#ContentViolationReason)) |
| `is_im_opened` | `BOOLEAN` | 是否已直接开启 IM 对话 |
| `created_at` | `TIMESTAMPTZ` | 回复时间 |
| `deleted_at` | `TIMESTAMPTZ` | 删除时间 |
---
<a name="表signal_low_quality_feedbacks"></a>
### 表:`signal_low_quality_feedbacks`
> **说明**:信号低质量反馈表:记录用户对信号或回复的低质量反馈
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 主键 |
| `reporter_uid` | `BIGINT` | 反馈人 ID |
| `reported_uid` | `BIGINT` | 被反馈的用户 ID |
| `target_type` | `SMALLINT` | 反馈对象类型 (1:信号 2:回复) |
| `target_id` | `BIGINT` | 目标 ID (信号 ID 或回复 ID) |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表im_stranger_limit"></a>
### 表:`im_stranger_limit`
> **说明**:IM陌生人聊天限制表:记录陌生人之间的消息发送次数及解锁状态
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `sender_user_id` | `BIGINT` | 发送者用户 ID |
| `receiver_user_id` | `BIGINT` | 接收者用户 ID |
| `msg_count` | `SMALLINT` | 已发送条数 |
| `is_unlocked` | `BOOLEAN` | 是否已解锁 |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表im_daily_greet"></a>
### 表:`im_daily_greet`
> **说明**:IM每日打招呼记录表:记录用户每天向哪些人发送了打招呼,用于限频控制
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | 打招呼的用户 ID |
| `greet_date` | `DATE` | 统计日期 |
| `target_user_id` | `BIGINT` | 被打招呼的用户 ID |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表im_day_stats"></a>
### 表:`im_day_stats`
> **说明**:IM每日统计表:按天汇总 IM 消息量、活跃用户等核心运营指标
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `stat_date` | `DATE` | 统计日期 |
| `active_users` | `INTEGER` | 活跃人数 |
| `new_registrations` | `INTEGER` | 新增注册 |
| `msg_text_count` | `INTEGER` | 文本消息数 |
| `msg_pic_count` | `INTEGER` | 图片消息数 |
| `msg_voice_count` | `INTEGER` | 语音消息数 |
| `msg_video_count` | `INTEGER` | 视频消息数 |
| `msg_total_count` | `INTEGER` | 总消息数 |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表user_upload_logs"></a>
### 表:`user_upload_logs`
> **说明**:用户上传日志表:记录所有上传文件的信息及内容安全审核结果 scene 取值: avatar / chat_image / chat_flash / chat_multi / chat_audio / signal_audio audit_status: 0=未审核 1=正常 2=违规 3=待人工审核
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | |
| `scene` | `VARCHAR(32)` | |
| `file_type` | `VARCHAR(16)` | image / audio / video |
| `file_path` | `VARCHAR(255)` | |
| `file_md5` | `CHAR(32)` | 文件内容 MD5,用于跨天审核结果去重 |
| `file_phash` | `BIGINT` | 图片感知哈希(dHash 64bit),用于涉诈图「换皮」识别 |
| `audit_status` | `SMALLINT` | |
| `audit_raw` | `JSONB` | 阿里云原始审核结果 |
| `upload_ip` | `INET` | 上传时客户端 IP(风控用) |
| `is_deleted` | `BOOLEAN` | 消息撤回 / 闪图已查看 |
| `deleted_at` | `TIMESTAMPTZ` | |
| `is_fraud` | `BOOLEAN` | 涉诈标记:上传者被以"涉嫌诈骗"封禁时批量标识其资源,便于风控查询 |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表im_violation_logs"></a>
### 表:`im_violation_logs`
> **说明**:IM违规拦截日志表:记录被内容安全系统拦截的消息及人工审核状态
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `sender_user_id` | `BIGINT` | 发送者用户 ID |
| `receiver_user_id` | `BIGINT` | 接收者用户 ID |
| `content_type` | `SMALLINT` | 1:文本 2:图片 3:语音 4:视频 |
| `content` | `TEXT` | 违规内容(文本或文件 URL) |
| `risk_type` | `TEXT` | 违规类型(涉黄/广告/政治,多标签逗号分隔) |
| `risk_score` | `INTEGER` | 机器评分(0-100) |
| `status` | `SMALLINT` | 0:拦截待审 1:确认违规 2:误判放行 |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表user_conversation_settings"></a>
### 表:`user_conversation_settings`
> **说明**:用户私聊会话设置表:记录每个用户对某私聊会话的免打扰和背景设置
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | 设置所属用户 |
| `conversation_id` | `VARCHAR(128)` | OpenIM 会话 ID,如 si_xxx_yyy |
| `target_uid` | `BIGINT` | 私聊对方 UID(推送前快速过滤用) |
| `is_muted` | `BOOLEAN` | 是否开启免打扰 |
| `chat_background` | `VARCHAR(512)` | 聊天背景(URL / objectKey / 预设 ID) |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表app_versions"></a>
### 表:`app_versions`
> **说明**:版本检查与更新配置表
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `platform` | `TEXT` | 平台 (ios / android) |
| `version_code` | `INTEGER` | 版本号(整型,用于比较大小) |
| `version_name` | `VARCHAR(20)` | 版本名 (例: 1.0.1) |
| `is_force` | `BOOLEAN` | 是否强制更新 |
| `min_version_code` | `INTEGER` | 强制升级临界点:当前版本 < 此值时必强更 |
| `update_content` | `TEXT` | 更新日志内容 |
| `download_url` | `TEXT` | 下载地址 (Android APK 直链或 H5 下载页) |
| `status` | `SMALLINT` | 状态: 1=正常 0=下线 |
| `created_at` | `TIMESTAMPTZ` | 创建时间 |
---
<a name="表orders"></a>
### 表:`orders`
> **说明**:交易订单与充值流水表
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 订单唯一标识 |
| `user_id` | `BIGINT` | 用户ID (关联 users.id) |
| `trade_no` | `VARCHAR(64)` | 内部订单号 (年+月+日+雪花算法流水号) |
| `transaction_id` | `VARCHAR(128)` | 第三方通道真实交易流水号 (Apple IAP / 微信 / 支付宝) |
| `pay_platform` | `SMALLINT` | 支付渠道 (1:微信, 2:支付宝, 3:Apple原生) |
| `relation_type` | `SMALLINT` | 关联类型 (1:VIP, 2:SVIP, 3:派币/虚拟币, 9:购买商品) |
| `relation_id` | `INTEGER` | 关联套餐ID 或 商品ID |
| `product_name` | `VARCHAR(128)` | 商品名称 (快照) |
| `currency` | `VARCHAR(16)` | 币种 (CNY, USD等) |
| `pay_amount` | `NUMERIC(11,2)` | 实付金额 |
| `status` | `SMALLINT` | 交易状态 (0:待支付, 1:支付成功, 2:支付失败/关闭, 3:已退款) |
| `refund_status` | `SMALLINT` | 退款状态 (0:无, 1:已退款) |
| `benefit_status` | `SMALLINT` | 权益发放状态 (0:待发放, 1:发放中, 2:已发放, 3:失败) |
| `benefit_attempts` | `SMALLINT` | 已尝试发放次数 |
| `benefit_last_error` | `TEXT` | 最后一次发放失败原因 |
| `benefit_fulfilled_at` | `TIMESTAMPTZ` | 权益发放成功时间 |
| `source` | `VARCHAR(64)` | 购买来源/渠道归因 (譬如 visitor_list, daily_limit) |
| `refund_time` | `TIMESTAMPTZ` | 退款时间 |
| `pay_time` | `TIMESTAMPTZ` | 付款成功时间 |
| `created_at` | `TIMESTAMPTZ` | 订单创建时间 |
| `updated_at` | `TIMESTAMPTZ` | 最后修改时间(benefit_compensate 用于检测卡死的处理中订单) |
---
<a name="表sms_logs"></a>
### 表:`sms_logs`
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
---
<a name="表app_documents"></a>
### 表:`app_documents`
> **说明**:法律文档表:存储隐私政策、用户协议、个人信息收集清单、第三方共享清单 支持版本管理,is_current=true 表示当前生效版本
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `type` | `VARCHAR(50)` | privacy / terms / info_collection / third_party |
| `version_code` | `SMALLINT` | 数字版本号,与 users.accepted_privacy_version 对应 |
| `version` | `VARCHAR(20)` | 展示版本号,如 2025-03-28 或 1.0 |
| `title` | `VARCHAR(200)` | 文档标题 |
| `content` | `TEXT` | HTML 正文(仅 <body> 内容片段) |
| `is_current` | `BOOLEAN` | 是否为当前生效版本 |
| `published_at` | `TIMESTAMPTZ` | 生效时间 |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表system_notifications"></a>
### 表:`system_notifications`
> **说明**:系统通知广播表:管理员创建,面向全体用户展示
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `title` | `TEXT` | 通知标题 |
| `body` | `TEXT` | 通知正文 |
| `extra` | `JSONB` | 跳转动作,格式见下方注释 |
| `push_platform` | `TEXT` | 推送平台:ios / android / all |
| `push_sent` | `BOOLEAN` | 是否已触发群推 |
| `created_by` | `BIGINT` | 操作管理员 uid |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表user_system_notification_reads"></a>
### 表:`user_system_notification_reads`
> **说明**:extra 字段规范(基于最新的统跳 URI Scheme): {"url":"tongban://profile/membership"} → 会员中心 {"url":"tongban://webview?url=https%3A%2F%2F..."} → 使用端内 WebView 打开外部网页 {"url":"tongban://profile/user?uid=123"} → 用户主页 {"url":"tongban://message/chat?uid=123"} → 指定用户单聊 {"url":"tongban://signal/inbox"} → 信号收件箱 (Tab栏首个会重置导航栈进入) {"url":"tongban://signal/publish"} → 发布信号页 {"url":"tongban://message/notifications"} → 通知中心 {"url":"tongban://profile/feedback"} → 意见反馈 {"url":"tongban://profile/verification"} → 实名认证 {"url":"tongban://profile/privacySettings"} → 隐私设置 {"url":"tongban://profile/accountSecurity"} → 账号与安全 {"url":"tongban://system/logout"} → 强制退出登录 {"url":"tongban://profile/editProfile"} → 编辑资料 {"url":"tongban://profile/cacheManagement"} → 存储与清理 {"url":"tongban://profile/about"} → 关于我们 {"url":"tongban://profile/youthMode"} → 青少年模式 {"url":"tongban://profile/blockList"} → 黑名单管理 {"url":"tongban://message/customerService"} → 联系人工客服 null 或省略 → 仅展示通知,不跳转 用户已读记录表:记录哪些用户已读了哪条系统通知
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `uid` | `BIGINT` | |
| `notification_id` | `BIGINT` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表user_vip_records"></a>
### 表:`user_vip_records`
> **说明**:用户 VIP 开通明细表:记录每次开通/续费的起止时间
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | 关联 users.id |
| `order_id` | `BIGINT` | 关联 orders.id,后台赠送时为 NULL |
| `days` | `INTEGER` | 本次开通天数 |
| `free_type` | `SMALLINT` | 0=付费开通 1=应用商店评价 2=签到 3=匹配活动 4=邀请好友 5=系统补偿 |
| `started_at` | `TIMESTAMPTZ` | 本段有效期起点(叠加后) |
| `expired_at` | `TIMESTAMPTZ` | 本段有效期截止 |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表user_profile_audits"></a>
### 表:`user_profile_audits`
> **说明**:用户资料审核记录表:存储头像、昵称、签名的审核记录
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | 用户ID |
| `field_type` | `VARCHAR(20)` | 字段类型: avatar, nickname, bio |
| `old_value` | `TEXT` | 旧值 |
| `new_value` | `TEXT` | 新值 |
| `status` | `SMALLINT` | 审核状态: 0=待审核, 1=已通过, 2=已驳回, 3=已废弃(被新提交覆盖) |
| `reject_code` | `VARCHAR(32)` | 驳回原因编码 (ProfileRejectReason) |
| `reject_detail` | `VARCHAR(255)` | 驳回补充说明(选填) |
| `reject_reason` | `VARCHAR(255)` | 驳回原因(兼容字段,面向用户的展示文案) |
| `operator_uid` | `BIGINT` | 人工审核的管理员 UID;NULL=无人工介入(pending 或系统自动),与 status 配合区分 |
| `handled_at` | `TIMESTAMPTZ` | 审核处理时间 |
| `profile_version` | `INTEGER` | 提交时的 users.profile_version,审核时作乐观锁校验 |
| `archive_key` | `TEXT` | 违规归档对象 key(头像驳回时存模糊缩略图,路径如 avatar_archive/.../xxx.jpg) |
| `is_deleted` | `SMALLINT` | 软删: 0=正常, 1=用户主动删除, 2=系统/管理员归档(后台默认不展示) |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表sensitive_words"></a>
### 表:`sensitive_words`
> **说明**:敏感词库:每条规则属于且只属于一个场景(scope),同一词可在不同场景建不同规则。 scope: nickname | bio | signal | signal_reply | chat action: block = 命中直接拒绝;review = 放行进人工审核(私聊场景 block/review 均只记日志) ⚠️ 词表匹配规则(决定能放什么词): 1. 纯子串匹配(str_contains),无正则、无组合逻辑。只放「单独出现即违规、且作为子串极少误伤正常文本」的高精度词。 2. 联系方式 / 引流(手机号·QQ号·微信号·URL·"平台词+动词"·裸长数字)由 app/Services/TextModerationService.php 的 detectContact() 硬编码分级处理,不进词表。 3. normalize() 会在匹配前改写文本:微信/vx→wechat、扣扣→qq、圈号数字→阿拉伯、去分隔符。 词表里不放会被改写的形态(如"微信"),否则匹配不上。 词源:线上昵称/签名重置历史样本 + 大陆社交平台常见违规词。
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `word` | `VARCHAR(64)` | |
| `scope` | `VARCHAR(20)` | |
| `category` | `VARCHAR(20)` | |
| `action` | `VARCHAR(10)` | |
| `score` | `INTEGER` | |
| `enabled` | `BOOLEAN` | |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表app_routes"></a>
### 表:`app_routes`
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `name` | `VARCHAR(100)` | 路由名称,如 "用户主页" |
| `module_name` | `VARCHAR(50)` | 模块名称,分类用 |
| `uri_scheme` | `VARCHAR(255)` | 路由协议核心路径,如 "tongban://profile/user" |
| `params_desc` | `JSONB` | 参数描述,前端根据此动态生成输入框,如 [{"key": "uid", "name": "用户ID", "required": true}] |
| `status` | `SMALLINT` | 状态: 1=正常 0=禁用 |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表user_page_views"></a>
### 表:`user_page_views`
> **说明**:用户访问路径埋点表:自建 pageView 序列,按 session_id + client_ts 串联可还原访问路径与漏斗 不依赖第三方分析 SDK,数据自有不出境,合规友好。 典型查询 ——「进会员页前一页」漏斗: SELECT from_page, COUNT(*) FROM user_page_views WHERE page = 'membership' GROUP BY from_page ORDER BY 2 DESC;
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | 登录前为空(OptionalAuth) |
| `device_id` | `VARCHAR(64)` | |
| `session_id` | `VARCHAR(64)` | 冷启动 / 久置后台回前台生成 |
| `page` | `VARCHAR(64)` | 路由 key(双端对齐) |
| `from_page` | `VARCHAR(64)` | 上一页(进会员页漏斗靠它) |
| `source` | `VARCHAR(64)` | 来源渠道(可空) |
| `platform` | `VARCHAR(16)` | ios / android |
| `app_version` | `INTEGER` | |
| `extra` | `JSONB` | |
| `client_ts` | `TIMESTAMPTZ` | 客户端事件时间(排序依据) |
| `created_at` | `TIMESTAMPTZ` | 服务端落库时间 |
---
<a name="表admin_roles"></a>
### 表:`admin_roles`
> **说明**:后台管理基础表:管理员、角色、权限、操作日志、登录日志、功能字典
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `code` | `VARCHAR(64)` | |
| `name` | `VARCHAR(100)` | |
| `description` | `TEXT` | |
| `status` | `SMALLINT` | 1=启用 0=禁用 |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
| `deleted_at` | `TIMESTAMPTZ` | |
---
<a name="表admin_users"></a>
### 表:`admin_users`
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `uid` | `BIGINT` | 关联 App 用户 UID;口令后台过渡期可为空 |
| `username` | `VARCHAR(64)` | |
| `nickname` | `VARCHAR(100)` | |
| `role_id` | `BIGINT` | |
| `status` | `SMALLINT` | 1=启用 0=禁用 |
| `last_login_at` | `TIMESTAMPTZ` | |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
| `deleted_at` | `TIMESTAMPTZ` | |
---
<a name="表admin_permissions"></a>
### 表:`admin_permissions`
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `code` | `VARCHAR(100)` | 如 users.view / users.ban / refunds.approve |
| `name` | `VARCHAR(100)` | |
| `module` | `VARCHAR(64)` | |
| `type` | `VARCHAR(20)` | |
| `description` | `TEXT` | |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表admin_role_permissions"></a>
### 表:`admin_role_permissions`
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `role_id` | `BIGINT` | |
| `permission_id` | `BIGINT` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表admin_audit_logs"></a>
### 表:`admin_audit_logs`
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `admin_uid` | `BIGINT` | |
| `admin_user_id` | `BIGINT` | |
| `action` | `VARCHAR(100)` | profile_audit.approve / user.ban / refund.reject |
| `target_type` | `VARCHAR(64)` | |
| `target_id` | `BIGINT` | |
| `target_uid` | `BIGINT` | |
| `request_data` | `JSONB` | |
| `before_data` | `JSONB` | |
| `after_data` | `JSONB` | |
| `result` | `SMALLINT` | 1=成功 0=失败 |
| `error_message` | `TEXT` | |
| `ip` | `INET` | |
| `user_agent` | `TEXT` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表admin_login_logs"></a>
### 表:`admin_login_logs`
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `admin_uid` | `BIGINT` | |
| `admin_user_id` | `BIGINT` | |
| `login_type` | `VARCHAR(30)` | password / sso / token_exchange |
| `success` | `BOOLEAN` | |
| `fail_reason` | `TEXT` | |
| `ip` | `INET` | |
| `user_agent` | `TEXT` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表admin_feature_dictionaries"></a>
### 表:`admin_feature_dictionaries`
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `feature` | `VARCHAR(64)` | profile_audit / signal_audit / report / ban / refund / system_message |
| `dict_type` | `VARCHAR(64)` | reject_reason / status / action / template / duration |
| `code` | `VARCHAR(100)` | |
| `label` | `VARCHAR(100)` | |
| `value` | `JSONB` | |
| `sort_order` | `INTEGER` | |
| `enabled` | `BOOLEAN` | |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
| `deleted_at` | `TIMESTAMPTZ` | |
---
<a name="表products"></a>
### 表:`products`
> **说明**:商城商品表:替代 config/shop.php 中的模拟商品数据,支持后台后续维护
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `title` | `VARCHAR(128)` | |
| `thumb` | `TEXT` | |
| `price` | `NUMERIC(11,2)` | |
| `currency` | `VARCHAR(16)` | |
| `type_tag` | `VARCHAR(32)` | |
| `category_name` | `VARCHAR(64)` | |
| `number` | `VARCHAR(64)` | |
| `description` | `TEXT` | |
| `status` | `SMALLINT` | |
| `sort` | `INTEGER` | |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表im_photo_swap"></a>
### 表:`im_photo_swap`
> **说明**:换照(Photo Swap)记录表:一次换照会话的配对与解锁状态 作为签名门控(/upload/oss/sign)与撤回校验(/chat/message/revoke)的权威来源
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `swap_id` | `VARCHAR(64)` | 换照会话唯一 ID(客户端生成 uuid) |
| `conversation_id` | `VARCHAR(128)` | 会话 ID(si_{lowerUID}_{higherUID}) |
| `initiator_uid` | `BIGINT` | 发起方 |
| `initiator_object_key` | `VARCHAR(255)` | 发起方照片 objectKey(chat_swap/...) |
| `initiator_client_msg_id` | `VARCHAR(64)` | 发起方消息 clientMsgID |
| `responder_uid` | `BIGINT` | 回拍方(回拍前为空) |
| `responder_object_key` | `VARCHAR(255)` | 回拍方照片 objectKey |
| `responder_client_msg_id` | `VARCHAR(64)` | 回拍方消息 clientMsgID |
| `state` | `VARCHAR(16)` | locked / unlocked |
| `created_at` | `TIMESTAMPTZ` | |
| `unlocked_at` | `TIMESTAMPTZ` | |
---
<a name="表im_emoji"></a>
### 表:`im_emoji`
> **说明**:表情主表
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `md5` | `VARCHAR(64)` | 图片内容 md5,去重命门 |
| `object_key` | `VARCHAR(255)` | OSS objectKey(emoji/...,头像 Bucket) |
| `url` | `VARCHAR(512)` | 公开访问地址(冗余,免每次拼) |
| `pack` | `VARCHAR(32)` | 来源:fav=自定义 / official_x=系统包 / effect=动效 |
| `sticker_id` | `VARCHAR(128)` | 表情唯一标识(自定义=objectKey;系统=包内 id) |
| `effect` | `VARCHAR(128)` | 非空=动效表情,值为动效资源标识 |
| `w` | `INT` | |
| `h` | `INT` | |
| `mime` | `VARCHAR(64)` | |
| `creator_uid` | `BIGINT` | 自定义上传者;系统包为 NULL |
| `favorite_count` | `INT` | 被收藏人数(去重后) |
| `send_count` | `INT` | 被发送总次数 |
| `disabled` | `SMALLINT` | 0=正常 1=管理员下架 |
| `file_phash` | `BIGINT` | 感知哈希(dHash 64bit),用于删除后拦截换皮重传 |
| `delete_reason` | `SMALLINT` | 违规原因:0=正常 1=色情低俗 2=暴力血腥 3=涉政敏感 4=违法违规 5=辱骂仇恨 6=广告引流 7=版权/肖像投诉 8=其他 |
| `sort` | `INT` | 排序权重(system_gif 靠前展示用) |
| `created_at` | `TIMESTAMPTZ` | |
| `deleted_at` | `TIMESTAMPTZ` | 软删除时间戳;非 NULL = 已删除(OSS 文件已物理删除) |
---
<a name="表im_emoji_favorite"></a>
### 表:`im_emoji_favorite`
> **说明**:个人表情收藏表
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `uid` | `BIGINT` | 收藏者 |
| `emoji_id` | `BIGINT` | → im_emoji.id |
| `sort` | `INT` | 排序权重(越大越靠前) |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表friend_requests"></a>
### 表:`friend_requests`
> **说明**:好友申请表:记录"App 内申请添加好友"的申请与处理状态 关系为对称好友(互为好友);申请通过后在 user_friends 建立双行关系。
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 主键 |
| `from_uid` | `BIGINT` | 申请发起方 |
| `to_uid` | `BIGINT` | 被申请方 |
| `message` | `VARCHAR(100)` | 申请留言(可空) |
| `source` | `SMALLINT` | 来源 1主页 2会话(预留扫码/搜索/附近的人) |
| `status` | `SMALLINT` | 0待处理 1已同意 2已拒绝 3已过期 |
| `reject_reason` | `VARCHAR(100)` | 拒绝原因;非空=允许对方重新申请,空=婉拒不可再申请 |
| `is_read` | `SMALLINT` | 被申请方是否已读(角标用) |
| `expire_at` | `TIMESTAMPTZ` | 过期时间(创建 + business.friend.request_expire_days) |
| `handled_at` | `TIMESTAMPTZ` | 处理(同意/拒绝)时间 |
| `created_at` | `TIMESTAMPTZ` | 申请时间(重新申请会 bump 至最新,用于置顶) |
| `updated_at` | `TIMESTAMPTZ` | |
| `deleted_at` | `TIMESTAMPTZ` | 软删除(行级,预留;覆盖式更新不使用) |
| `from_deleted_at` | `TIMESTAMPTZ` | 申请方在「我发出的」列表中删除该记录(仅隐藏自己一侧) |
| `to_deleted_at` | `TIMESTAMPTZ` | 被申请方在「收到的」列表中删除该记录(仅隐藏自己一侧) |
---
<a name="表user_friends"></a>
### 表:`user_friends`
> **说明**:好友关系表:对称好友关系,双行存储(A→B、B→A 各一行) 删除好友为单方面操作,软删双行;仅解除关系,不影响会话/聊天记录。
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 主键 |
| `user_id` | `BIGINT` | 关系拥有者 |
| `friend_uid` | `BIGINT` | 好友 |
| `is_starred` | `BOOLEAN` | 星标好友(按 owner 维度,A 星标 B 不影响 B 星标 A;好友很多时置顶) |
| `source_request_id` | `BIGINT` | 来源申请 id,便于追溯 |
| `created_at` | `TIMESTAMPTZ` | 成为好友时间 |
| `deleted_at` | `TIMESTAMPTZ` | 解除关系时间(软删除) |
---
<a name="表user_remarks"></a>
### 表:`user_remarks`
> **说明**:用户备注表:当前用户对「任意用户」设置的备注名(不限好友,陌生人/会话对象均可) 单一事实源;备注不替换任何展示昵称,仅在备注编辑入口与用户资料处展示。 取代旧的 user_friends.remark(该列已移除),好友列表的 remark 改从本表读取。
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 主键 |
| `user_id` | `BIGINT` | 备注设置者 |
| `target_uid` | `BIGINT` | 被备注的用户 |
| `remark` | `VARCHAR(255)` | 备注内容(≤255 字;清空备注时删除整行) |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表qrcode_invite_logs"></a>
### 表:`qrcode_invite_logs`
> **说明**:扫码加好友埋点:记录「谁通过谁的个人二维码加了好友」。 第一版仅统计累计人数(/user/qrcode/stats),为二期「拉新达标赠会员」铺路,暂不发放奖励。 写入时机:好友以 source=3(扫码)建立关系时,见 FriendService::acceptRequest。
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 主键 |
| `owner_uid` | `BIGINT` | 二维码主人(被扫者 = 好友请求 to_uid) |
| `friend_uid` | `BIGINT` | 扫码并加好友的人(from_uid) |
| `created_at` | `TIMESTAMPTZ` | 建立时间 |
---
<a name="表user_visits"></a>
### 表:`user_visits`
> **说明**:主页访客(足迹)表:记录"谁访问了谁的用户主页"。 同一访客对同一主页每天最多一行(按 visit_date 去重,命中当天行仅刷新 updated_at)。 隐身访问:写入时取访问者 users.is_visit_hidden;隐身行对被访问者不可见,仅访问者自己可见。 删除足迹:访问者软删 visitor_deleted_at,双向消失(我列表 + 对方列表都不再出现)。
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | 主键 |
| `visitor_uid` | `BIGINT` | 访问者(看别人主页的人) |
| `visited_uid` | `BIGINT` | 被访问者(主页所有者) |
| `visit_date` | `DATE` | 访问日期(按天去重) |
| `is_stealth` | `BOOLEAN` | 是否隐身访问(对被访问者不可见) |
| `last_source` | `SMALLINT` | 最近一次访问来源:1其他 2会话 3扫码 4信号列表 5信号详情 6好友申请 7好友列表 8通知中心 9访客-访问我的 10搜索 11附近 12访客-我访问的 |
| `created_at` | `TIMESTAMPTZ` | 首次访问时间 |
| `updated_at` | `TIMESTAMPTZ` | 当天最近一次访问时间 |
| `visitor_deleted_at` | `TIMESTAMPTZ` | 访问者删除自己足迹(软删,双向生效) |
---
<a name="表banned_login_attempts"></a>
### 表:`banned_login_attempts`
> **说明**:封禁用户登录尝试记录 触发时机:验证码通过 → 封禁检查命中,此时 device_info 完整可用 用途:① 7天内该手机号发验证码直接返回封禁信息 ② 设备防控数据源
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | |
| `phone` | `VARCHAR(20)` | |
| `device_id` | `TEXT` | 设备唯一标识 |
| `platform` | `TEXT` | ios / android |
| `device_model` | `TEXT` | 设备型号 |
| `os_version` | `TEXT` | 系统版本 |
| `app_version` | `TEXT` | App 版本 |
| `is_root` | `BOOLEAN` | 是否 Root/越狱 |
| `is_emulator` | `BOOLEAN` | 是否模拟器 |
| `is_debugger` | `BOOLEAN` | 是否调试模式 |
| `is_vpn` | `BOOLEAN` | 是否挂 VPN |
| `is_hook` | `BOOLEAN` | 是否 Hook 框架 |
| `client_risk_flags` | `TEXT[]` | 客户端上报的风险标签 |
| `ip` | `INET` | |
| `forbidden_type` | `SMALLINT` | |
| `is_fraud` | `BOOLEAN` | |
| `sms_blocked_until` | `TIMESTAMPTZ` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表fraud_samples"></a>
### 表:`fraud_samples`
> **说明**:反诈样本表:人工在后台确认「涉诈 / 误判」时落一条,为 V2 涉诈识别模型攒训练料。 V1 不接模型,本表只写不读;V2 训练时直接 SELECT 导出。
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `text` | `TEXT` | 原始文本(信号/回复/聊天/留言内容) |
| `label` | `SMALLINT` | 1=涉诈正样本 0=误判负样本(人工裁定) |
| `source` | `TEXT` | 来源入口:signal / reply / chat / friend |
| `biz_id` | `BIGINT` | 关联业务记录 ID(如 signal_replies.id、im_violation_logs.id) |
| `user_id` | `BIGINT` | 发文用户(仅留痕,可为空) |
| `hit_rules` | `JSONB` | 命中规则快照(涉诈词/联系方式/批量重复) |
| `operator_id` | `BIGINT` | 处理的后台管理员 ID |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表splash_ads"></a>
### 表:`splash_ads`
> **说明**:============================================================================= 开屏广告(自建广告位) 设计文档:iOS 仓库 Tongban/Docs/splash_ad_plan.md V1:官方运营位(owner_uid 预留给 V4 用户付费投放) =============================================================================
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `version` | `INT` | 素材/配置变更时 +1,客户端据此重新下载 |
| `type` | `VARCHAR(16)` | 素材类型: image(V2+: video / lottie) |
| `title` | `VARCHAR(64)` | 运营备注 + 模板可选标题文案 |
| `subtitle` | `VARCHAR(128)` | 模板可选副文案 |
| `material_object` | `VARCHAR(255)` | 素材 OSS object key(私有桶,下发时实时签名) |
| `material_md5` | `CHAR(32)` | 下载完整性校验 |
| `material_size` | `INT` | 字节数(蜂窝网下载策略判断) |
| `material_width` | `INT` | |
| `material_height` | `INT` | |
| `duration` | `SMALLINT` | 展示秒数(3~5) |
| `skippable_after` | `SMALLINT` | N 秒后才可跳过;V1 强制 0(合规) |
| `full_screen` | `BOOLEAN` | false=底部保留品牌安全区 |
| `show_ad_label` | `BOOLEAN` | 是否显示"广告"角标 |
| `jump_url` | `VARCHAR(512)` | 点击跳转:tongban://(app_routes 注册表)或 https://;NULL=纯展示 |
| `start_at` | `TIMESTAMPTZ` | 档期开始 |
| `end_at` | `TIMESTAMPTZ` | 档期结束 |
| `daily_limit` | `INT` | 每设备每日展示上限(0=不限) |
| `total_limit` | `INT` | 每设备累计展示上限(0=不限) |
| `min_interval_sec` | `INT` | 单条两次展示最小间隔秒(0=不限) |
| `weight` | `INT` | 轮播排序权重(高者排前) |
| `channel` | `VARCHAR(32)` | NULL=全渠道 |
| `platform` | `VARCHAR(16)` | NULL=双端, ios|android |
| `status` | `SMALLINT` | 0=草稿 1=上线 2=下线(3=待审核,V4 预留) |
| `owner_uid` | `BIGINT` | V4 预留:付费购买者;NULL=官方 |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表splash_ad_events"></a>
### 表:`splash_ad_events`
> **说明**:事件流水:曝光/点击/跳过/完播(量 = DAU × 启动次数级别;V4 结算前按月归档即可)
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `ad_id` | `BIGINT` | |
| `uid` | `BIGINT` | 上报时已登录则带上 |
| `device_id` | `VARCHAR(64)` | |
| `event` | `VARCHAR(16)` | impression|click|skip|finish |
| `event_uuid` | `CHAR(36)` | 客户端去重 ID(防重放,V4 结算对账基础) |
| `client_ts` | `BIGINT` | 客户端事件时间戳(秒) |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表app_configs"></a>
### 表:`app_configs`
> **说明**:============================================================================= 动态配置中心:DB 覆盖 config/business.php,带版本快照与一键回滚 设计文档:docs/信号曝光与流量分发体系规划方案.md §九 读取链路:BusinessConfig::limit() → Redis hash biz_config(全量缓存+版本号,TTL 300s) → miss 读 app_configs 灌入 → DB 无该 key → fallback config/business.php =============================================================================
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `group_key` | `VARCHAR(64)` | 分组(后台分类展示用): traffic / moderation / trust ... |
| `config_key` | `VARCHAR(128)` | 与 business.php dotted path 对齐,如 traffic.quota_matrix |
| `value` | `JSONB` | 配置值 |
| `description` | `TEXT` | |
| `updated_by` | `BIGINT` | 操作管理员 uid |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表app_config_versions"></a>
### 表:`app_config_versions`
> **说明**:配置版本快照:每次后台保存写入全量快照,可一键回滚
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `version` | `INT` | |
| `snapshot` | `JSONB` | 全量 app_configs 快照 {config_key: value} |
| `operator_id` | `BIGINT` | |
| `note` | `TEXT` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表hobbies"></a>
### 表:`hobbies`
> **说明**:兴趣标签字典:由旧库 xl_hobby 迁移,供 app/config 下发与 users.hobby_ids 校验
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `name` | `VARCHAR(64)` | |
| `icon` | `VARCHAR(64)` | |
| `category_id` | `SMALLINT` | |
| `category_name` | `VARCHAR(32)` | |
| `sort_order` | `INTEGER` | |
| `deleted_at` | `TIMESTAMPTZ` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表user_traffic_profiles"></a>
### 表:`user_traffic_profiles`
> **说明**:用户流量画像(跑批读写、后台展示,不参与分发查询)
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `user_id` | `BIGINT` | |
| `reply_rate` | `NUMERIC(6,4)` | 信号被回复率 |
| `chat_open_rate` | `NUMERIC(6,4)` | 回复→开聊转化率 |
| `avg_reply_secs` | `INT` | 平均响应时长(响应度权重输入) |
| `complaint_rate` | `NUMERIC(6,4)` | 举报/低质反馈率 |
| `nsfw_affinity` | `NUMERIC(5,4)` | 接收端对擦边内容(rating>=1)的隐式亲和度(0~1),钩子探测输入 |
| `score_breakdown` | `JSONB` | trust_score / content_rating_score 构成明细 |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表signal_traffic_daily_stats"></a>
### 表:`signal_traffic_daily_stats`
> **说明**:信号流量日统计(后台展示 / 质量分跑批输入 / Redis 丢失回补)
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `stat_date` | `DATE` | |
| `user_id` | `BIGINT` | |
| `publish_count` | `INT` | |
| `receive_count` | `INT` | |
| `exposure_count` | `INT` | 本人信号被收取数 |
| `reply_count` | `INT` | 发出的回复 |
| `im_open_count` | `INT` | |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表signal_traffic_events"></a>
### 表:`signal_traffic_events`
> **说明**:漏斗事件明细(看板用,明细只留 30~90 天,定期清理)
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `event_type` | `VARCHAR(24)` | candidate/collected/replied/im_opened/quota_blocked/shadow_blocked/risk_blocked |
| `signal_id` | `BIGINT` | 相关信号 |
| `author_uid` | `BIGINT` | 信号作者 |
| `receiver_uid` | `BIGINT` | 收取者/被拦截者 |
| `reason` | `VARCHAR(32)` | 拦截/分类原因(quota_exhausted/shadow_garbage 等) |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表user_active_days"></a>
### 表:`user_active_days`
> **说明**:============================================================================= 用户按天活跃事实表:补签免费判定的核心依据 说明:users.last_active_at 只保留最近一次,无法回答"某历史日是否活跃过"。 该表由 UserActivityMiddleware 在成功请求后按天 upsert(Redis 当天去重)。 =============================================================================
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | 用户 ID |
| `active_date` | `DATE` | 活跃所属自然日 |
| `source` | `VARCHAR(20)` | 写入来源:request / heartbeat |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表user_experience_logs"></a>
### 表:`user_experience_logs`
> **说明**:============================================================================= 用户经验流水表:经验余额 users.experience 的加减审计 余额字段:users.experience(见 01_users.sql) 第一版仅签到产出 / 补签消耗在用;后续等级、商城再拆资产表也不迟。 =============================================================================
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | 用户 ID |
| `change_amount` | `INTEGER` | 本次变动(正=增加,负=扣减) |
| `balance_after` | `INTEGER` | 变动后余额 |
| `biz_type` | `VARCHAR(32)` | sign_reward / sign_repair_consume / admin_grant / system_compensate |
| `biz_id` | `BIGINT` | 关联业务 ID(如 user_sign_logs.id) |
| `extra` | `JSONB` | 附加信息(如补签日期、命中档位) |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表admin_roles"></a>
### 表:`admin_roles`
> **说明**:───────────────────────────────────────────────────────────────────────── admin_roles:角色。super_admin 为特殊角色代码,代码层直接短路放行全部权限, 不依赖 admin_role_permissions,且不可删除/不可编辑权限。 ─────────────────────────────────────────────────────────────────────────
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `code` | `VARCHAR(64)` | |
| `name` | `VARCHAR(100)` | |
| `description` | `TEXT` | |
| `status` | `SMALLINT` | 1=启用 0=禁用 |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
| `deleted_at` | `TIMESTAMPTZ` | |
---
<a name="表admin_users"></a>
### 表:`admin_users`
> **说明**:───────────────────────────────────────────────────────────────────────── admin_users:管理员账号,手机号 + 密码登录。 phone 同时用作 App 端"我的页"管理入口可见性判定依据(与 users.phone 匹配)。 uid 可空:纯后台账号无需关联 App 账号;关联后可在后台展示该管理员对应的 App 身份。 ─────────────────────────────────────────────────────────────────────────
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `phone` | `VARCHAR(20)` | |
| `password_hash` | `VARCHAR(255)` | |
| `uid` | `BIGINT` | |
| `nickname` | `VARCHAR(100)` | |
| `role_id` | `BIGINT` | |
| `status` | `SMALLINT` | 1=启用 0=禁用 |
| `last_login_at` | `TIMESTAMPTZ` | |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
| `deleted_at` | `TIMESTAMPTZ` | |
---
<a name="表admin_permissions"></a>
### 表:`admin_permissions`
> **说明**:───────────────────────────────────────────────────────────────────────── admin_permissions:权限点目录。code 形如 {module}.view / {module}.manage, module 与 admin/src/config/adminMenu.ts 的 AdminPageKey 一一对应, 新增后台菜单时同步在此补充一对权限即可。 ─────────────────────────────────────────────────────────────────────────
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `code` | `VARCHAR(100)` | |
| `name` | `VARCHAR(100)` | |
| `module` | `VARCHAR(64)` | |
| `type` | `VARCHAR(20)` | |
| `description` | `TEXT` | |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表admin_role_permissions"></a>
### 表:`admin_role_permissions`
> **说明**:───────────────────────────────────────────────────────────────────────── admin_role_permissions:角色 ↔ 权限多对多。super_admin 不写入任何行(代码层短路全权限)。 ─────────────────────────────────────────────────────────────────────────
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `role_id` | `BIGINT` | |
| `permission_id` | `BIGINT` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表im_callback_events"></a>
### 表:`im_callback_events`
> **说明**:OpenIM 回调事件幂等记录表 回调快速落库后返回;后续处理(风控/推送/统计)失败可重试;死信可在 Admin 查看/重放
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `operation_id` | `VARCHAR(128)` | |
| `callback_command` | `VARCHAR(64)` | |
| `sender_uid` | `BIGINT` | |
| `receiver_uid` | `BIGINT` | |
| `content_type` | `SMALLINT` | |
| `server_msg_id` | `VARCHAR(128)` | |
| `client_msg_id` | `VARCHAR(128)` | |
| `payload` | `JSONB` | |
| `status` | `VARCHAR(16)` | |
| `attempts` | `SMALLINT` | |
| `last_error` | `TEXT` | |
| `created_at` | `TIMESTAMPTZ` | |
| `processed_at` | `TIMESTAMPTZ` | |
---
<a name="表app_events"></a>
### 表:`app_events`
> **说明**:核心漏斗事件表 事件事实源以后端落库为准;不保存聊天正文、精确位置、身份证等非必要敏感内容
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `event` | `VARCHAR(64)` | |
| `uid` | `BIGINT` | |
| `platform` | `VARCHAR(16)` | |
| `channel` | `VARCHAR(64)` | |
| `city_code` | `VARCHAR(32)` | |
| `properties` | `JSONB` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表credit_violation_events"></a>
### 表:`credit_violation_events`
> **说明**:内容信用治理:四场景违规事件、能力限制与举报处理扩展。
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | |
| `scene` | `VARCHAR(24)` | |
| `category` | `VARCHAR(64)` | |
| `severity` | `SMALLINT` | |
| `base_deduction` | `NUMERIC(8,2)` | |
| `source` | `VARCHAR(16)` | |
| `source_type` | `VARCHAR(32)` | |
| `source_id` | `BIGINT` | |
| `target_type` | `VARCHAR(32)` | |
| `target_id` | `VARCHAR(255)` | |
| `punish` | `BOOLEAN` | |
| `punishment_scene` | `VARCHAR(24)` | |
| `evidence` | `JSONB` | |
| `note` | `VARCHAR(500)` | |
| `operator_uid` | `BIGINT` | |
| `occurred_at` | `TIMESTAMPTZ` | |
| `confirmed_at` | `TIMESTAMPTZ` | |
| `revoked_at` | `TIMESTAMPTZ` | |
| `revoke_reason` | `VARCHAR(255)` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表user_credit_restrictions"></a>
### 表:`user_credit_restrictions`
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | |
| `capability` | `VARCHAR(24)` | |
| `reason_code` | `VARCHAR(64)` | |
| `source_event_id` | `BIGINT` | |
| `start_at` | `TIMESTAMPTZ` | |
| `end_at` | `TIMESTAMPTZ` | |
| `is_active` | `BOOLEAN` | |
| `operator_uid` | `BIGINT` | |
| `note` | `VARCHAR(500)` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表coin_transactions"></a>
### 表:`coin_transactions`
> **说明**:虚拟币流水(钱包明细):充值入账 / 消费出账 / 退款 / 后台调整 余额本体在 users.coin_balance,本表只记每一笔变动,供「我的钱包-明细」展示与对账
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `user_id` | `BIGINT` | 用户ID (关联 users.id) |
| `change_amount` | `BIGINT` | 变动数量:正=入账 负=出账 |
| `balance_after` | `BIGINT` | 变动后余额(快照,明细直接展示,免聚合) |
| `biz_type` | `SMALLINT` | 业务类型 (1:充值 2:消费 3:退款 9:后台调整) |
| `ref_no` | `VARCHAR(64)` | 关联单号:充值=orders.trade_no,消费=业务单号 |
| `remark` | `VARCHAR(128)` | 备注(展示文案) |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表moments"></a>
### 表:`moments`
> **说明**:动态主表
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `uid` | `BIGINT` | |
| `content` | `TEXT` | |
| `type` | `VARCHAR(20)` | MomentType: text/image/multiImage/voice/video |
| `attachment` | `JSONB` | 图片/语音/视频附件 |
| `entities` | `JSONB` | 富文本实体: @用户/话题/表情 |
| `thumb` | `TEXT` | 首图/视频封面/语音封面 |
| `visibility` | `SMALLINT` | MomentVisibility: 0公开 1仅自己 |
| `comment_mode` | `SMALLINT` | MomentCommentMode: 0公开 1好友 2私密 3关闭 |
| `source_type` | `SMALLINT` | 0原创 1来源于网络 |
| `source_url` | `TEXT` | |
| `exposure_score` | `INT` | |
| `is_featured` | `BOOLEAN` | |
| `featured_until` | `TIMESTAMPTZ` | |
| `featured_by` | `BIGINT` | |
| `featured_source` | `VARCHAR(20)` | admin/purchase/system |
| `is_home_pinned` | `BOOLEAN` | |
| `home_pinned_at` | `TIMESTAMPTZ` | |
| `like_count` | `INT` | |
| `comment_count` | `INT` | |
| `view_count` | `INT` | = base_view_count + real_view_count |
| `real_view_count` | `INT` | |
| `base_view_count` | `INT` | |
| `impression_count` | `INT` | |
| `share_count` | `INT` | |
| `last_comment_at` | `TIMESTAMPTZ` | |
| `status` | `SMALLINT` | MomentStatus: 0审核中 1正常 2拒绝 3系统屏蔽 |
| `block_reason_code` | `VARCHAR(32)` | |
| `content_rating` | `SMALLINT` | 0普通 1轻微 2擦边 3高风险 |
| `reviewed_by` | `BIGINT` | |
| `reviewed_at` | `TIMESTAMPTZ` | |
| `publish_ip` | `INET` | |
| `ip_region_code` | `BIGINT` | |
| `ip_region_text` | `VARCHAR(100)` | |
| `address` | `VARCHAR(255)` | |
| `location` | `POINT` | |
| `published_at` | `TIMESTAMPTZ` | |
| `edited_at` | `TIMESTAMPTZ` | |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
| `deleted_at` | `TIMESTAMPTZ` | |
---
<a name="表moment_likes"></a>
### 表:`moment_likes`
> **说明**:动态点赞表
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `moment_id` | `BIGINT` | |
| `uid` | `BIGINT` | |
| `moment_uid` | `BIGINT` | 动态作者,减少通知连表 |
| `reaction_type` | `SMALLINT` | 1普通点赞(预留表情点赞) |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
| `deleted_at` | `TIMESTAMPTZ` | |
---
<a name="表moment_comments"></a>
### 表:`moment_comments`
> **说明**:动态评论表(最多两层:一级评论 + 二级回复)
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `moment_id` | `BIGINT` | |
| `uid` | `BIGINT` | |
| `moment_uid` | `BIGINT` | 动态作者 |
| `parent_id` | `BIGINT` | 0=一级评论,否则为一级评论 id |
| `reply_to_uid` | `BIGINT` | |
| `content` | `TEXT` | |
| `entities` | `JSONB` | |
| `like_count` | `INT` | |
| `is_author_liked` | `BOOLEAN` | 动态作者是否赞过此评论 |
| `is_private` | `BOOLEAN` | 私密评论(仅作者/评论者/被回复者可见) |
| `status` | `SMALLINT` | MomentStatus: 0审核中 1正常 2拒绝 3屏蔽 |
| `block_reason_code` | `VARCHAR(32)` | |
| `content_rating` | `SMALLINT` | |
| `publish_ip` | `INET` | |
| `ip_region_code` | `BIGINT` | |
| `ip_region_text` | `VARCHAR(100)` | |
| `reviewed_by` | `BIGINT` | |
| `reviewed_at` | `TIMESTAMPTZ` | |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
| `deleted_at` | `TIMESTAMPTZ` | |
---
<a name="表moment_comment_likes"></a>
### 表:`moment_comment_likes`
> **说明**:评论点赞表
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `comment_id` | `BIGINT` | |
| `moment_id` | `BIGINT` | |
| `uid` | `BIGINT` | |
| `comment_uid` | `BIGINT` | |
| `reaction_type` | `SMALLINT` | |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
| `deleted_at` | `TIMESTAMPTZ` | |
---
<a name="表moment_views"></a>
### 表:`moment_views`
> **说明**:动态浏览/曝光上报表(前端批量上报)
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `moment_id` | `BIGINT` | |
| `uid` | `BIGINT` | 未登录时为 0 |
| `scene` | `VARCHAR(50)` | recommend_feed/user_home/topic/detail |
| `visible_ms` | `INT` | 可见时长(毫秒) |
| `visible_ratio` | `NUMERIC(4,2)` | 可见比例 |
| `is_valid_view` | `BOOLEAN` | 满足 50% + 1s 停留则有效 |
| `device_id` | `VARCHAR(255)` | |
| `ip` | `INET` | |
| `view_date` | `DATE` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表moment_mentions"></a>
### 表:`moment_mentions`
> **说明**:动态 @ 用户表(@通知 / 提到我的)
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `moment_id` | `BIGINT` | |
| `uid` | `BIGINT` | 被 @ 的用户 |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表topics"></a>
### 表:`topics`
> **说明**:话题表
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `title` | `VARCHAR(64)` | |
| `description` | `TEXT` | |
| `pic` | `TEXT` | |
| `uid` | `BIGINT` | 创建者/运营账号 |
| `focus_count` | `INT` | |
| `moment_count` | `INT` | |
| `view_count` | `INT` | |
| `heat_score` | `INT` | |
| `status` | `SMALLINT` | TopicStatus: 0建设中 1正常 2隐藏 |
| `show_desc` | `BOOLEAN` | |
| `show_thumb` | `BOOLEAN` | |
| `is_hot` | `BOOLEAN` | |
| `is_recommend` | `BOOLEAN` | 是否推荐(首页/搜索展示,对齐旧库 index_show) |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
| `deleted_at` | `TIMESTAMPTZ` | |
---
<a name="表moment_topics"></a>
### 表:`moment_topics`
> **说明**:动态-话题关联表
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `moment_id` | `BIGINT` | |
| `topic_id` | `BIGINT` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表topic_follows"></a>
### 表:`topic_follows`
> **说明**:话题关注表
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `topic_id` | `BIGINT` | |
| `uid` | `BIGINT` | |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
| `deleted_at` | `TIMESTAMPTZ` | |
---
<a name="表topic_daily_stats"></a>
### 表:`topic_daily_stats`
> **说明**:话题每日统计表(热门话题榜数据源,定时聚合写入)
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `topic_id` | `BIGINT` | |
| `stat_date` | `DATE` | |
| `new_moment_count` | `INT` | |
| `view_count` | `INT` | |
| `like_count` | `INT` | |
| `comment_count` | `INT` | |
| `follow_count` | `INT` | |
| `heat_score` | `INT` | |
| `created_at` | `TIMESTAMPTZ` | |
| `updated_at` | `TIMESTAMPTZ` | |
---
<a name="表moment_reports"></a>
### 表:`moment_reports`
> **说明**:动态举报表
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `moment_id` | `BIGINT` | |
| `uid` | `BIGINT` | |
| `moment_uid` | `BIGINT` | |
| `reason_code` | `VARCHAR(32)` | |
| `content` | `TEXT` | |
| `status` | `SMALLINT` | 0待处理 1有效 2无效 |
| `reviewed_by` | `BIGINT` | |
| `reviewed_at` | `TIMESTAMPTZ` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表moment_comment_reports"></a>
### 表:`moment_comment_reports`
> **说明**:评论举报表
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `comment_id` | `BIGINT` | |
| `moment_id` | `BIGINT` | |
| `uid` | `BIGINT` | |
| `comment_uid` | `BIGINT` | |
| `reason_code` | `VARCHAR(32)` | |
| `content` | `TEXT` | |
| `status` | `SMALLINT` | |
| `reviewed_by` | `BIGINT` | |
| `reviewed_at` | `TIMESTAMPTZ` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表user_bonds"></a>
### 表:`user_bonds`
> **说明**:亲密关系绑定主表 bond_type: 1=恋人(每人限 1 段活跃)2=基友/哥们 3=闺蜜/姐妹(不限数量) status: 0=待确认 1=生效 2=已拒绝 3=已解绑 4=suspended(封禁时系统置入)
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `id` | `BIGINT` | |
| `initiator_uid` | `BIGINT` | |
| `receiver_uid` | `BIGINT` | |
| `bond_type` | `SMALLINT` | |
| `status` | `SMALLINT` | |
| `rejected_at` | `TIMESTAMPTZ` | |
| `accepted_at` | `TIMESTAMPTZ` | |
| `unbound_at` | `TIMESTAMPTZ` | |
| `unbound_by` | `BIGINT` | |
| `created_at` | `TIMESTAMPTZ` | |
---
<a name="表user_bond_cards"></a>
### 表:`user_bond_cards`
> **说明**:关系卡库存:每人每种卡一行,quantity 累加 card_type: 1=恋人卡 2=基友卡 3=闺蜜卡 4=通用卡(自定义绑定用)
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `uid` | `BIGINT` | |
| `card_type` | `SMALLINT` | |
| `quantity` | `INT` | |
---