2780 lines
45 KiB
Markdown
2780 lines
45 KiB
Markdown
# 丹阳公益婚恋服务平台
|
||||
|
|
# V1.0 数据库详细设计与核心数据模型
|
|||
|
|
|
|||
|
|
版本:V1.0
|
|||
|
|
数据库建议:PostgreSQL
|
|||
|
|
适用范围:微信小程序用户端、公益红娘工作台、运营管理后台
|
|||
|
|
设计目标:结构清晰、敏感数据分层、状态可追溯、支持事务、便于后续扩展
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一章 数据库设计原则
|
|||
|
|
|
|||
|
|
V1.0数据库设计必须坚持:
|
|||
|
|
|
|||
|
|
- 账号数据与婚恋资料分离
|
|||
|
|
- 公共资料与敏感资料分离
|
|||
|
|
- 用户状态与关系状态分离
|
|||
|
|
- 审核数据可追溯
|
|||
|
|
- 风控数据独立
|
|||
|
|
- 聊天数据独立
|
|||
|
|
- 活动数据独立
|
|||
|
|
- 红娘服务独立
|
|||
|
|
- 权限与组织独立
|
|||
|
|
- 重要业务状态不通过删除实现
|
|||
|
|
- 核心业务使用数据库约束兜底
|
|||
|
|
- PostgreSQL作为业务真实数据源
|
|||
|
|
|
|||
|
|
不建议:
|
|||
|
|
|
|||
|
|
- 一个users表塞所有字段
|
|||
|
|
- 使用大量JSON替代清晰结构
|
|||
|
|
- 核心关系依赖Redis
|
|||
|
|
- 不做唯一约束
|
|||
|
|
- 只依赖前端校验
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第二章 核心数据域
|
|||
|
|
|
|||
|
|
V1.0数据库建议划分为:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
01 用户账号域
|
|||
|
|
02 实名认证域
|
|||
|
|
03 婚恋资料域
|
|||
|
|
04 人工审核域
|
|||
|
|
05 推荐与关系域
|
|||
|
|
06 聊天消息域
|
|||
|
|
07 公益活动域
|
|||
|
|
08 公益红娘域
|
|||
|
|
09 举报风控域
|
|||
|
|
10 系统通知域
|
|||
|
|
11 组织权限域
|
|||
|
|
12 审计日志域
|
|||
|
|
13 配置与统计域
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第三章 核心表总览
|
|||
|
|
|
|||
|
|
建议V1.0核心表:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
users
|
|||
|
|
user_identities
|
|||
|
|
user_profiles
|
|||
|
|
user_preferences
|
|||
|
|
user_interests
|
|||
|
|
interest_dictionary
|
|||
|
|
user_photos
|
|||
|
|
user_privacy_settings
|
|||
|
|
|
|||
|
|
review_tasks
|
|||
|
|
review_items
|
|||
|
|
review_reasons
|
|||
|
|
|
|||
|
|
recommendation_records
|
|||
|
|
user_relations
|
|||
|
|
matches
|
|||
|
|
relationship_success_requests
|
|||
|
|
|
|||
|
|
conversations
|
|||
|
|
conversation_members
|
|||
|
|
messages
|
|||
|
|
|
|||
|
|
activities
|
|||
|
|
activity_registrations
|
|||
|
|
activity_feedback
|
|||
|
|
|
|||
|
|
matchmaker_services
|
|||
|
|
matchmaker_recommendations
|
|||
|
|
matchmaker_followups
|
|||
|
|
|
|||
|
|
reports
|
|||
|
|
report_evidences
|
|||
|
|
user_risk_profiles
|
|||
|
|
risk_events
|
|||
|
|
risk_actions
|
|||
|
|
appeals
|
|||
|
|
|
|||
|
|
notifications
|
|||
|
|
|
|||
|
|
organizations
|
|||
|
|
operators
|
|||
|
|
roles
|
|||
|
|
permissions
|
|||
|
|
role_permissions
|
|||
|
|
operator_roles
|
|||
|
|
|
|||
|
|
audit_logs
|
|||
|
|
sensitive_access_logs
|
|||
|
|
|
|||
|
|
system_configs
|
|||
|
|
match_rule_configs
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第四章 通用字段规范
|
|||
|
|
|
|||
|
|
大部分业务表建议包含:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id
|
|||
|
|
created_at
|
|||
|
|
updated_at
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
需要软删除的表:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
deleted_at
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
业务状态不要用:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
is_deleted = 0/1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
优先采用:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
deleted_at IS NULL
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第五章 ID设计
|
|||
|
|
|
|||
|
|
推荐:
|
|||
|
|
|
|||
|
|
> UUID / UUIDv7
|
|||
|
|
|
|||
|
|
或:
|
|||
|
|
|
|||
|
|
> 应用生成的分布式唯一ID。
|
|||
|
|
|
|||
|
|
不要让外部接口直接暴露连续自增ID。
|
|||
|
|
|
|||
|
|
例如:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
user_id = 018f...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
或者:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
usr_xxxxxxxxx
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
如果数据库内部使用BIGINT,也建议API层映射公共ID。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第六章 users 用户账号表
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
> 只保存账号和平台级状态。
|
|||
|
|
|
|||
|
|
建议结构:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE users (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
wechat_openid VARCHAR(128) NOT NULL,
|
|||
|
|
wechat_unionid VARCHAR(128),
|
|||
|
|
phone VARCHAR(32),
|
|||
|
|
account_status VARCHAR(32) NOT NULL DEFAULT 'normal',
|
|||
|
|
relationship_status VARCHAR(32) NOT NULL DEFAULT 'searching',
|
|||
|
|
recommendation_enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
|||
|
|
last_login_at TIMESTAMPTZ,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
deleted_at TIMESTAMPTZ
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第七章 users约束
|
|||
|
|
|
|||
|
|
唯一约束:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE UNIQUE INDEX uk_users_openid
|
|||
|
|
ON users(wechat_openid)
|
|||
|
|
WHERE deleted_at IS NULL;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
手机号:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE UNIQUE INDEX uk_users_phone
|
|||
|
|
ON users(phone)
|
|||
|
|
WHERE phone IS NOT NULL
|
|||
|
|
AND deleted_at IS NULL;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
unionid:
|
|||
|
|
|
|||
|
|
如业务使用:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE UNIQUE INDEX uk_users_unionid
|
|||
|
|
ON users(wechat_unionid)
|
|||
|
|
WHERE wechat_unionid IS NOT NULL
|
|||
|
|
AND deleted_at IS NULL;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第八章 users状态约束
|
|||
|
|
|
|||
|
|
account_status:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
normal
|
|||
|
|
reviewing_risk
|
|||
|
|
limited
|
|||
|
|
suspended
|
|||
|
|
banned
|
|||
|
|
closed
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
relationship_status:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
searching
|
|||
|
|
getting_to_know
|
|||
|
|
paused
|
|||
|
|
matched_successfully
|
|||
|
|
service_exited
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
建议使用:
|
|||
|
|
|
|||
|
|
> VARCHAR + CHECK
|
|||
|
|
|
|||
|
|
而不是PostgreSQL ENUM。
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
后续状态扩展和数据库迁移更方便。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第九章 user_identities 实名认证表
|
|||
|
|
|
|||
|
|
高度敏感。
|
|||
|
|
|
|||
|
|
与users严格分离。
|
|||
|
|
|
|||
|
|
字段建议:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE user_identities (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
user_id UUID NOT NULL UNIQUE,
|
|||
|
|
real_name_enc TEXT NOT NULL,
|
|||
|
|
id_number_enc TEXT NOT NULL,
|
|||
|
|
id_number_hash VARCHAR(128) NOT NULL,
|
|||
|
|
gender VARCHAR(16),
|
|||
|
|
birth_date DATE,
|
|||
|
|
verification_status VARCHAR(32) NOT NULL,
|
|||
|
|
provider VARCHAR(64),
|
|||
|
|
provider_request_id VARCHAR(128),
|
|||
|
|
verified_at TIMESTAMPTZ,
|
|||
|
|
failed_reason_code VARCHAR(64),
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
CONSTRAINT fk_identity_user
|
|||
|
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第十章 实名敏感字段
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
real_name_enc
|
|||
|
|
id_number_enc
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
必须:
|
|||
|
|
|
|||
|
|
> 加密后存储。
|
|||
|
|
|
|||
|
|
同时建议存:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id_number_hash
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
用于:
|
|||
|
|
|
|||
|
|
- 防重复身份证注册
|
|||
|
|
- 查询重复身份
|
|||
|
|
|
|||
|
|
但不能通过Hash还原身份证。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第十一章 身份证重复约束
|
|||
|
|
|
|||
|
|
如果产品规则限制:
|
|||
|
|
|
|||
|
|
> 一个身份证只能一个有效账号
|
|||
|
|
|
|||
|
|
可建立:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE UNIQUE INDEX uk_identity_hash
|
|||
|
|
ON user_identities(id_number_hash)
|
|||
|
|
WHERE verification_status = 'verified';
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
具体注销后是否允许重新注册,应由后续业务规则决定。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第十二章 user_profiles 婚恋资料表
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
> 用户可以参与匹配的主要资料。
|
|||
|
|
|
|||
|
|
建议:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE user_profiles (
|
|||
|
|
user_id UUID PRIMARY KEY,
|
|||
|
|
|
|||
|
|
display_name VARCHAR(64),
|
|||
|
|
gender VARCHAR(16) NOT NULL,
|
|||
|
|
birth_date DATE NOT NULL,
|
|||
|
|
|
|||
|
|
height_cm SMALLINT,
|
|||
|
|
region_code VARCHAR(32),
|
|||
|
|
region_name VARCHAR(128),
|
|||
|
|
|
|||
|
|
marital_status VARCHAR(32),
|
|||
|
|
children_status VARCHAR(32),
|
|||
|
|
|
|||
|
|
education_code VARCHAR(32),
|
|||
|
|
occupation_code VARCHAR(32),
|
|||
|
|
work_region_code VARCHAR(32),
|
|||
|
|
|
|||
|
|
smoking_status VARCHAR(32),
|
|||
|
|
drinking_status VARCHAR(32),
|
|||
|
|
|
|||
|
|
long_term_danyang VARCHAR(32),
|
|||
|
|
future_danyang VARCHAR(32),
|
|||
|
|
|
|||
|
|
relationship_goal VARCHAR(64),
|
|||
|
|
marriage_plan VARCHAR(32),
|
|||
|
|
|
|||
|
|
self_intro TEXT,
|
|||
|
|
|
|||
|
|
profile_completion SMALLINT NOT NULL DEFAULT 0,
|
|||
|
|
profile_status VARCHAR(32) NOT NULL DEFAULT 'in_progress',
|
|||
|
|
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
CONSTRAINT fk_profile_user
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第十三章 用户年龄不要单独存
|
|||
|
|
|
|||
|
|
年龄随时间变化。
|
|||
|
|
|
|||
|
|
因此:
|
|||
|
|
|
|||
|
|
> 存birth_date,不存age作为业务真相。
|
|||
|
|
|
|||
|
|
展示时:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
age = 当前日期 - birth_date
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
如为了搜索性能需要,可建立表达式索引或预计算字段,但不要让前端修改age。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第十四章 profile_status
|
|||
|
|
|
|||
|
|
建议:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
in_progress
|
|||
|
|
completed
|
|||
|
|
pending_review
|
|||
|
|
approved
|
|||
|
|
need_edit
|
|||
|
|
rejected
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
但要注意:
|
|||
|
|
|
|||
|
|
> Profile状态主要用于快速业务查询。
|
|||
|
|
|
|||
|
|
完整审核历史仍以review_tasks为准。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第十五章 user_preferences 择偶条件表
|
|||
|
|
|
|||
|
|
一用户一条主配置。
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE user_preferences (
|
|||
|
|
user_id UUID PRIMARY KEY,
|
|||
|
|
|
|||
|
|
min_age SMALLINT,
|
|||
|
|
max_age SMALLINT,
|
|||
|
|
age_priority VARCHAR(16),
|
|||
|
|
|
|||
|
|
min_height_cm SMALLINT,
|
|||
|
|
max_height_cm SMALLINT,
|
|||
|
|
height_priority VARCHAR(16),
|
|||
|
|
|
|||
|
|
region_scope JSONB,
|
|||
|
|
region_priority VARCHAR(16),
|
|||
|
|
|
|||
|
|
marital_statuses JSONB,
|
|||
|
|
marital_priority VARCHAR(16),
|
|||
|
|
|
|||
|
|
min_education_code VARCHAR(32),
|
|||
|
|
education_priority VARCHAR(16),
|
|||
|
|
|
|||
|
|
children_acceptance VARCHAR(32),
|
|||
|
|
children_priority VARCHAR(16),
|
|||
|
|
|
|||
|
|
smoking_preference VARCHAR(32),
|
|||
|
|
drinking_preference VARCHAR(32),
|
|||
|
|
settlement_preference VARCHAR(32),
|
|||
|
|
marriage_plan_preference VARCHAR(32),
|
|||
|
|
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
CONSTRAINT fk_preference_user
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第十六章 为什么部分条件可以JSONB
|
|||
|
|
|
|||
|
|
适合JSONB:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
region_scope
|
|||
|
|
marital_statuses
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
因为本质是小型多选集合。
|
|||
|
|
|
|||
|
|
不建议把整个择偶条件全部放一个JSONB中。
|
|||
|
|
|
|||
|
|
核心匹配字段仍应独立列。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第十七章 Priority约束
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
required
|
|||
|
|
preferred
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
所有支持硬条件/软条件的字段统一使用。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第十八章 user_interests 兴趣关系表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE user_interests (
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
interest_code VARCHAR(32) NOT NULL,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
PRIMARY KEY(user_id, interest_code),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第十九章 interest_dictionary 兴趣字典
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE interest_dictionary (
|
|||
|
|
code VARCHAR(32) PRIMARY KEY,
|
|||
|
|
name VARCHAR(64) NOT NULL,
|
|||
|
|
sort_order INT NOT NULL DEFAULT 0,
|
|||
|
|
enabled BOOLEAN NOT NULL DEFAULT TRUE
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
例如:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
travel
|
|||
|
|
reading
|
|||
|
|
sports
|
|||
|
|
fitness
|
|||
|
|
photography
|
|||
|
|
movie
|
|||
|
|
music
|
|||
|
|
food
|
|||
|
|
cooking
|
|||
|
|
outdoor
|
|||
|
|
pets
|
|||
|
|
games
|
|||
|
|
culture
|
|||
|
|
charity
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第二十章 user_photos 用户照片表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE user_photos (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
file_key VARCHAR(512) NOT NULL,
|
|||
|
|
photo_type VARCHAR(32) NOT NULL,
|
|||
|
|
sort_order SMALLINT NOT NULL DEFAULT 0,
|
|||
|
|
review_status VARCHAR(32) NOT NULL DEFAULT 'pending',
|
|||
|
|
review_reason VARCHAR(256),
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
deleted_at TIMESTAMPTZ,
|
|||
|
|
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
photo_type:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
avatar
|
|||
|
|
lifestyle
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第二十一章 主头像约束
|
|||
|
|
|
|||
|
|
建议应用层保证:
|
|||
|
|
|
|||
|
|
> 一个用户只有一个有效avatar。
|
|||
|
|
|
|||
|
|
数据库可建立部分唯一索引:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE UNIQUE INDEX uk_user_avatar
|
|||
|
|
ON user_photos(user_id)
|
|||
|
|
WHERE photo_type = 'avatar'
|
|||
|
|
AND deleted_at IS NULL;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第二十二章 user_privacy_settings 隐私设置
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE user_privacy_settings (
|
|||
|
|
user_id UUID PRIMARY KEY,
|
|||
|
|
|
|||
|
|
visible_in_recommendations BOOLEAN NOT NULL DEFAULT TRUE,
|
|||
|
|
visible_in_search BOOLEAN NOT NULL DEFAULT TRUE,
|
|||
|
|
show_occupation BOOLEAN NOT NULL DEFAULT TRUE,
|
|||
|
|
show_lifestyle_photos BOOLEAN NOT NULL DEFAULT TRUE,
|
|||
|
|
receive_activity_recommendations BOOLEAN NOT NULL DEFAULT TRUE,
|
|||
|
|
accept_matchmaker_recommendations BOOLEAN NOT NULL DEFAULT TRUE,
|
|||
|
|
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第二十三章 review_tasks 审核任务
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE review_tasks (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
review_type VARCHAR(32) NOT NULL,
|
|||
|
|
status VARCHAR(32) NOT NULL DEFAULT 'pending',
|
|||
|
|
assigned_operator_id UUID,
|
|||
|
|
submitted_at TIMESTAMPTZ NOT NULL,
|
|||
|
|
started_at TIMESTAMPTZ,
|
|||
|
|
completed_at TIMESTAMPTZ,
|
|||
|
|
final_comment VARCHAR(1000),
|
|||
|
|
version INT NOT NULL DEFAULT 0,
|
|||
|
|
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第二十四章 审核任务索引
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE INDEX idx_review_tasks_status_time
|
|||
|
|
ON review_tasks(status, submitted_at);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
审核员:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE INDEX idx_review_tasks_operator
|
|||
|
|
ON review_tasks(assigned_operator_id, status);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第二十五章 review_items 审核明细
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE review_items (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
review_task_id UUID NOT NULL,
|
|||
|
|
item_type VARCHAR(32) NOT NULL,
|
|||
|
|
status VARCHAR(32) NOT NULL,
|
|||
|
|
reason_code VARCHAR(64),
|
|||
|
|
comment VARCHAR(500),
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(review_task_id)
|
|||
|
|
REFERENCES review_tasks(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
item_type:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
avatar
|
|||
|
|
lifestyle_photos
|
|||
|
|
basic_profile
|
|||
|
|
self_intro
|
|||
|
|
relationship_profile
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第二十六章 review_reasons 审核原因字典
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE review_reasons (
|
|||
|
|
code VARCHAR(64) PRIMARY KEY,
|
|||
|
|
name VARCHAR(128) NOT NULL,
|
|||
|
|
category VARCHAR(32),
|
|||
|
|
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
|||
|
|
sort_order INT NOT NULL DEFAULT 0
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
例如:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
AVATAR_NOT_CLEAR
|
|||
|
|
PHOTO_NOT_SELF
|
|||
|
|
CONTACT_INFO_INCLUDED
|
|||
|
|
AD_CONTENT
|
|||
|
|
PROFILE_CONFLICT
|
|||
|
|
INAPPROPRIATE_CONTENT
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第二十七章 recommendation_records 推荐记录
|
|||
|
|
|
|||
|
|
用于:
|
|||
|
|
|
|||
|
|
- 避免重复推荐
|
|||
|
|
- 计算冷却期
|
|||
|
|
- 统计曝光
|
|||
|
|
- 分析推荐效果
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE recommendation_records (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
target_user_id UUID NOT NULL,
|
|||
|
|
source VARCHAR(32) NOT NULL,
|
|||
|
|
score NUMERIC(5,2),
|
|||
|
|
level VARCHAR(16),
|
|||
|
|
reasons JSONB,
|
|||
|
|
shown_at TIMESTAMPTZ NOT NULL,
|
|||
|
|
action VARCHAR(32),
|
|||
|
|
action_at TIMESTAMPTZ,
|
|||
|
|
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id),
|
|||
|
|
FOREIGN KEY(target_user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第二十八章 推荐索引
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE INDEX idx_recommend_user_time
|
|||
|
|
ON recommendation_records(user_id, shown_at DESC);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
双方关系:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE INDEX idx_recommend_pair
|
|||
|
|
ON recommendation_records(user_id, target_user_id);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第二十九章 user_relations 用户单向关系
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE user_relations (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
target_user_id UUID NOT NULL,
|
|||
|
|
relation_type VARCHAR(32) NOT NULL,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id),
|
|||
|
|
FOREIGN KEY(target_user_id) REFERENCES users(id),
|
|||
|
|
|
|||
|
|
CONSTRAINT chk_not_self_relation
|
|||
|
|
CHECK (user_id <> target_user_id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第三十章 user_relations唯一约束
|
|||
|
|
|
|||
|
|
同方向同一关系类型:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE UNIQUE INDEX uk_user_relation
|
|||
|
|
ON user_relations(user_id, target_user_id, relation_type);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
relation_type:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
liked
|
|||
|
|
passed
|
|||
|
|
blocked
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第三十一章 blocked优先级
|
|||
|
|
|
|||
|
|
业务逻辑中:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
blocked > liked / passed
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
一旦拉黑:
|
|||
|
|
|
|||
|
|
- 推荐层排除
|
|||
|
|
- 聊天层禁止
|
|||
|
|
- 红娘层排除
|
|||
|
|
|
|||
|
|
是否物理删除旧liked,可不删除。
|
|||
|
|
|
|||
|
|
保持行为历史更利于审计。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第三十二章 matches 双向匹配表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE matches (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
user_a_id UUID NOT NULL,
|
|||
|
|
user_b_id UUID NOT NULL,
|
|||
|
|
status VARCHAR(32) NOT NULL DEFAULT 'active',
|
|||
|
|
source VARCHAR(32) NOT NULL DEFAULT 'user_like',
|
|||
|
|
matched_at TIMESTAMPTZ NOT NULL,
|
|||
|
|
unmatched_at TIMESTAMPTZ,
|
|||
|
|
successful_at TIMESTAMPTZ,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(user_a_id) REFERENCES users(id),
|
|||
|
|
FOREIGN KEY(user_b_id) REFERENCES users(id),
|
|||
|
|
|
|||
|
|
CONSTRAINT chk_match_users
|
|||
|
|
CHECK (user_a_id <> user_b_id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第三十三章 matches标准化顺序
|
|||
|
|
|
|||
|
|
应用层必须保证:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
user_a_id < user_b_id
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
或者基于UUID字符串排序。
|
|||
|
|
|
|||
|
|
并建立:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE UNIQUE INDEX uk_match_pair
|
|||
|
|
ON matches(user_a_id, user_b_id);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
如果未来允许同一双方历史多次重新匹配,可以改为:
|
|||
|
|
|
|||
|
|
> 活跃关系部分唯一索引。
|
|||
|
|
|
|||
|
|
V1建议一个pair一条match记录,通过状态保存历史。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第三十四章 match status
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
active
|
|||
|
|
getting_to_know
|
|||
|
|
unmatched
|
|||
|
|
successful
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第三十五章 relationship_success_requests
|
|||
|
|
|
|||
|
|
用于:
|
|||
|
|
|
|||
|
|
> 成功牵手必须双方确认。
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE relationship_success_requests (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
match_id UUID NOT NULL,
|
|||
|
|
initiated_by UUID NOT NULL,
|
|||
|
|
status VARCHAR(32) NOT NULL DEFAULT 'pending',
|
|||
|
|
confirmed_by UUID,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
resolved_at TIMESTAMPTZ,
|
|||
|
|
|
|||
|
|
FOREIGN KEY(match_id) REFERENCES matches(id),
|
|||
|
|
FOREIGN KEY(initiated_by) REFERENCES users(id),
|
|||
|
|
FOREIGN KEY(confirmed_by) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第三十六章 conversations 会话表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE conversations (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
match_id UUID NOT NULL UNIQUE,
|
|||
|
|
status VARCHAR(32) NOT NULL DEFAULT 'active',
|
|||
|
|
last_message_id UUID,
|
|||
|
|
last_message_at TIMESTAMPTZ,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(match_id) REFERENCES matches(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第三十七章 conversation_members
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE conversation_members (
|
|||
|
|
conversation_id UUID NOT NULL,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
last_read_message_id UUID,
|
|||
|
|
unread_count INT NOT NULL DEFAULT 0,
|
|||
|
|
can_send BOOLEAN NOT NULL DEFAULT TRUE,
|
|||
|
|
joined_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
PRIMARY KEY(conversation_id, user_id),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(conversation_id) REFERENCES conversations(id),
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第三十八章 messages 消息表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE messages (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
conversation_id UUID NOT NULL,
|
|||
|
|
sender_id UUID,
|
|||
|
|
client_message_id VARCHAR(128),
|
|||
|
|
message_type VARCHAR(32) NOT NULL,
|
|||
|
|
content TEXT,
|
|||
|
|
file_id UUID,
|
|||
|
|
status VARCHAR(32) NOT NULL DEFAULT 'sent',
|
|||
|
|
risk_level VARCHAR(16),
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(conversation_id) REFERENCES conversations(id),
|
|||
|
|
FOREIGN KEY(sender_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第三十九章 消息幂等唯一索引
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE UNIQUE INDEX uk_message_client_id
|
|||
|
|
ON messages(sender_id, client_message_id)
|
|||
|
|
WHERE client_message_id IS NOT NULL;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第四十章 消息查询索引
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE INDEX idx_messages_conversation_time
|
|||
|
|
ON messages(conversation_id, created_at DESC);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第四十一章 message_type
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
text
|
|||
|
|
image
|
|||
|
|
system
|
|||
|
|
risk_notice
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第四十二章 聊天内容是否加密
|
|||
|
|
|
|||
|
|
数据库层面建议至少:
|
|||
|
|
|
|||
|
|
> 磁盘/云数据库加密 + 严格访问权限。
|
|||
|
|
|
|||
|
|
如果后续提高安全等级,可对聊天正文做应用层加密。
|
|||
|
|
|
|||
|
|
但要注意:
|
|||
|
|
|
|||
|
|
- 风控检测
|
|||
|
|
- 举报取证
|
|||
|
|
- 消息搜索
|
|||
|
|
|
|||
|
|
会增加实现复杂度。
|
|||
|
|
|
|||
|
|
V1先以严格访问控制和审计为主。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第四十三章 activities 活动表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE activities (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
title VARCHAR(200) NOT NULL,
|
|||
|
|
cover_file_id UUID,
|
|||
|
|
description TEXT,
|
|||
|
|
|
|||
|
|
organizer_org_id UUID NOT NULL,
|
|||
|
|
coorganizer_text VARCHAR(500),
|
|||
|
|
|
|||
|
|
start_at TIMESTAMPTZ NOT NULL,
|
|||
|
|
end_at TIMESTAMPTZ NOT NULL,
|
|||
|
|
|
|||
|
|
location_name VARCHAR(200),
|
|||
|
|
location_address VARCHAR(500),
|
|||
|
|
|
|||
|
|
male_limit INT,
|
|||
|
|
female_limit INT,
|
|||
|
|
total_limit INT,
|
|||
|
|
|
|||
|
|
min_age SMALLINT,
|
|||
|
|
max_age SMALLINT,
|
|||
|
|
|
|||
|
|
registration_start_at TIMESTAMPTZ,
|
|||
|
|
registration_end_at TIMESTAMPTZ,
|
|||
|
|
|
|||
|
|
need_review BOOLEAN NOT NULL DEFAULT TRUE,
|
|||
|
|
|
|||
|
|
status VARCHAR(32) NOT NULL DEFAULT 'draft',
|
|||
|
|
|
|||
|
|
created_by UUID NOT NULL,
|
|||
|
|
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
deleted_at TIMESTAMPTZ,
|
|||
|
|
|
|||
|
|
FOREIGN KEY(organizer_org_id) REFERENCES organizations(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第四十四章 activity_registrations
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE activity_registrations (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
activity_id UUID NOT NULL,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
status VARCHAR(32) NOT NULL DEFAULT 'pending',
|
|||
|
|
|
|||
|
|
registered_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
reviewed_by UUID,
|
|||
|
|
reviewed_at TIMESTAMPTZ,
|
|||
|
|
reject_reason VARCHAR(500),
|
|||
|
|
|
|||
|
|
checkin_status VARCHAR(32) NOT NULL DEFAULT 'not_checked_in',
|
|||
|
|
checkin_at TIMESTAMPTZ,
|
|||
|
|
|
|||
|
|
emergency_contact_name VARCHAR(100),
|
|||
|
|
emergency_contact_phone_enc TEXT,
|
|||
|
|
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(activity_id) REFERENCES activities(id),
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id),
|
|||
|
|
|
|||
|
|
UNIQUE(activity_id, user_id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第四十五章 registration status
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
pending
|
|||
|
|
approved
|
|||
|
|
rejected
|
|||
|
|
cancelled
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
checkin_status:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
not_checked_in
|
|||
|
|
checked_in
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第四十六章 activity_feedback
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE activity_feedback (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
activity_id UUID NOT NULL,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
satisfaction SMALLINT,
|
|||
|
|
join_again VARCHAR(32),
|
|||
|
|
interested_user_id UUID,
|
|||
|
|
comment VARCHAR(1000),
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(activity_id) REFERENCES activities(id),
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id),
|
|||
|
|
FOREIGN KEY(interested_user_id) REFERENCES users(id),
|
|||
|
|
|
|||
|
|
UNIQUE(activity_id, user_id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第四十七章 活动意向隐私
|
|||
|
|
|
|||
|
|
interested_user_id:
|
|||
|
|
|
|||
|
|
> 不能直接向对方公开。
|
|||
|
|
|
|||
|
|
只有双方互选后:
|
|||
|
|
|
|||
|
|
> 触发匹配逻辑。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第四十八章 matchmaker_services 公益红娘服务
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE matchmaker_services (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
service_type VARCHAR(32) NOT NULL,
|
|||
|
|
description VARCHAR(1000),
|
|||
|
|
status VARCHAR(32) NOT NULL DEFAULT 'submitted',
|
|||
|
|
|
|||
|
|
organization_id UUID,
|
|||
|
|
assigned_operator_id UUID,
|
|||
|
|
|
|||
|
|
assigned_at TIMESTAMPTZ,
|
|||
|
|
completed_at TIMESTAMPTZ,
|
|||
|
|
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id),
|
|||
|
|
FOREIGN KEY(organization_id) REFERENCES organizations(id),
|
|||
|
|
FOREIGN KEY(assigned_operator_id) REFERENCES operators(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第四十九章 红娘服务索引
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE INDEX idx_matchmaker_status
|
|||
|
|
ON matchmaker_services(status, created_at);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
按红娘:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE INDEX idx_matchmaker_operator
|
|||
|
|
ON matchmaker_services(assigned_operator_id, status);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第五十章 matchmaker_recommendations
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE matchmaker_recommendations (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
service_id UUID NOT NULL,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
target_user_id UUID NOT NULL,
|
|||
|
|
operator_id UUID NOT NULL,
|
|||
|
|
reason VARCHAR(1000),
|
|||
|
|
status VARCHAR(32) NOT NULL DEFAULT 'pending_view',
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
viewed_at TIMESTAMPTZ,
|
|||
|
|
responded_at TIMESTAMPTZ,
|
|||
|
|
|
|||
|
|
FOREIGN KEY(service_id) REFERENCES matchmaker_services(id),
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id),
|
|||
|
|
FOREIGN KEY(target_user_id) REFERENCES users(id),
|
|||
|
|
FOREIGN KEY(operator_id) REFERENCES operators(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第五十一章 matchmaker_followups
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE matchmaker_followups (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
service_id UUID NOT NULL,
|
|||
|
|
operator_id UUID NOT NULL,
|
|||
|
|
followup_type VARCHAR(32),
|
|||
|
|
content VARCHAR(2000) NOT NULL,
|
|||
|
|
result_code VARCHAR(64),
|
|||
|
|
next_followup_at TIMESTAMPTZ,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(service_id) REFERENCES matchmaker_services(id),
|
|||
|
|
FOREIGN KEY(operator_id) REFERENCES operators(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第五十二章 reports 举报表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE reports (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
reporter_user_id UUID NOT NULL,
|
|||
|
|
target_user_id UUID NOT NULL,
|
|||
|
|
report_type VARCHAR(64) NOT NULL,
|
|||
|
|
description VARCHAR(2000),
|
|||
|
|
status VARCHAR(32) NOT NULL DEFAULT 'pending',
|
|||
|
|
risk_level VARCHAR(16) NOT NULL DEFAULT 'normal',
|
|||
|
|
|
|||
|
|
processed_by UUID,
|
|||
|
|
processed_at TIMESTAMPTZ,
|
|||
|
|
result_code VARCHAR(64),
|
|||
|
|
result_comment VARCHAR(2000),
|
|||
|
|
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(reporter_user_id) REFERENCES users(id),
|
|||
|
|
FOREIGN KEY(target_user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第五十三章 举报索引
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE INDEX idx_reports_status_risk
|
|||
|
|
ON reports(status, risk_level, created_at);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
按被举报用户:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE INDEX idx_reports_target
|
|||
|
|
ON reports(target_user_id, created_at DESC);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第五十四章 report_evidences
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE report_evidences (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
report_id UUID NOT NULL,
|
|||
|
|
file_key VARCHAR(512) NOT NULL,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(report_id) REFERENCES reports(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第五十五章 user_risk_profiles
|
|||
|
|
|
|||
|
|
一用户一条风险摘要。
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE user_risk_profiles (
|
|||
|
|
user_id UUID PRIMARY KEY,
|
|||
|
|
score INT NOT NULL DEFAULT 0,
|
|||
|
|
level VARCHAR(16) NOT NULL DEFAULT 'normal',
|
|||
|
|
report_count INT NOT NULL DEFAULT 0,
|
|||
|
|
block_count INT NOT NULL DEFAULT 0,
|
|||
|
|
last_event_at TIMESTAMPTZ,
|
|||
|
|
last_calculated_at TIMESTAMPTZ,
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第五十六章 risk_events
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE risk_events (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
event_type VARCHAR(64) NOT NULL,
|
|||
|
|
score_delta INT NOT NULL DEFAULT 0,
|
|||
|
|
source_type VARCHAR(32),
|
|||
|
|
source_id UUID,
|
|||
|
|
metadata JSONB,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第五十七章 risk_actions 风控处置
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE risk_actions (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
action_type VARCHAR(32) NOT NULL,
|
|||
|
|
reason VARCHAR(1000),
|
|||
|
|
operator_id UUID,
|
|||
|
|
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
expires_at TIMESTAMPTZ,
|
|||
|
|
revoked_at TIMESTAMPTZ,
|
|||
|
|
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id),
|
|||
|
|
FOREIGN KEY(operator_id) REFERENCES operators(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
action_type:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
warning
|
|||
|
|
feature_limit
|
|||
|
|
temporary_suspend
|
|||
|
|
ban
|
|||
|
|
manual_investigation
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第五十八章 appeals 申诉表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE appeals (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
related_action_id UUID,
|
|||
|
|
content VARCHAR(2000) NOT NULL,
|
|||
|
|
status VARCHAR(32) NOT NULL DEFAULT 'pending',
|
|||
|
|
processed_by UUID,
|
|||
|
|
processed_at TIMESTAMPTZ,
|
|||
|
|
result VARCHAR(1000),
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第五十九章 notifications 系统通知
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE notifications (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
type VARCHAR(32) NOT NULL,
|
|||
|
|
title VARCHAR(200) NOT NULL,
|
|||
|
|
content VARCHAR(2000),
|
|||
|
|
business_type VARCHAR(32),
|
|||
|
|
business_id UUID,
|
|||
|
|
read_status VARCHAR(16) NOT NULL DEFAULT 'unread',
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
read_at TIMESTAMPTZ,
|
|||
|
|
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第六十章 通知索引
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE INDEX idx_notifications_user
|
|||
|
|
ON notifications(user_id, read_status, created_at DESC);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第六十一章 organizations 组织表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE organizations (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
name VARCHAR(200) NOT NULL,
|
|||
|
|
type VARCHAR(32) NOT NULL,
|
|||
|
|
contact_name VARCHAR(100),
|
|||
|
|
contact_phone_enc TEXT,
|
|||
|
|
status VARCHAR(32) NOT NULL DEFAULT 'active',
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
type:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
women_federation
|
|||
|
|
trade_union
|
|||
|
|
charity_center
|
|||
|
|
volunteer_team
|
|||
|
|
civil_affairs_partner
|
|||
|
|
other
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第六十二章 operators 工作人员表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE operators (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
organization_id UUID,
|
|||
|
|
name VARCHAR(100) NOT NULL,
|
|||
|
|
phone_enc TEXT,
|
|||
|
|
phone_hash VARCHAR(128),
|
|||
|
|
username VARCHAR(100) NOT NULL,
|
|||
|
|
password_hash VARCHAR(255) NOT NULL,
|
|||
|
|
status VARCHAR(32) NOT NULL DEFAULT 'active',
|
|||
|
|
last_login_at TIMESTAMPTZ,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(organization_id) REFERENCES organizations(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第六十三章 工作人员唯一索引
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE UNIQUE INDEX uk_operator_username
|
|||
|
|
ON operators(username);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
手机号如果作为登录凭证,可对phone_hash建立唯一索引。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第六十四章 roles 角色表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE roles (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
code VARCHAR(64) NOT NULL UNIQUE,
|
|||
|
|
name VARCHAR(100) NOT NULL,
|
|||
|
|
description VARCHAR(500),
|
|||
|
|
system_role BOOLEAN NOT NULL DEFAULT FALSE,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第六十五章 默认角色
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
super_admin
|
|||
|
|
organization_admin
|
|||
|
|
reviewer
|
|||
|
|
matchmaker
|
|||
|
|
activity_manager
|
|||
|
|
risk_operator
|
|||
|
|
volunteer
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第六十六章 permissions 权限表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE permissions (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
code VARCHAR(128) NOT NULL UNIQUE,
|
|||
|
|
name VARCHAR(200) NOT NULL,
|
|||
|
|
module VARCHAR(64) NOT NULL,
|
|||
|
|
description VARCHAR(500)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第六十七章 role_permissions
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE role_permissions (
|
|||
|
|
role_id UUID NOT NULL,
|
|||
|
|
permission_id UUID NOT NULL,
|
|||
|
|
|
|||
|
|
PRIMARY KEY(role_id, permission_id),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(role_id) REFERENCES roles(id),
|
|||
|
|
FOREIGN KEY(permission_id) REFERENCES permissions(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第六十八章 operator_roles
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE operator_roles (
|
|||
|
|
operator_id UUID NOT NULL,
|
|||
|
|
role_id UUID NOT NULL,
|
|||
|
|
|
|||
|
|
PRIMARY KEY(operator_id, role_id),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(operator_id) REFERENCES operators(id),
|
|||
|
|
FOREIGN KEY(role_id) REFERENCES roles(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第六十九章 audit_logs 操作审计
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE audit_logs (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
operator_id UUID,
|
|||
|
|
organization_id UUID,
|
|||
|
|
|
|||
|
|
action VARCHAR(128) NOT NULL,
|
|||
|
|
resource_type VARCHAR(64) NOT NULL,
|
|||
|
|
resource_id VARCHAR(128),
|
|||
|
|
|
|||
|
|
before_data JSONB,
|
|||
|
|
after_data JSONB,
|
|||
|
|
|
|||
|
|
ip VARCHAR(64),
|
|||
|
|
user_agent VARCHAR(500),
|
|||
|
|
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第七十章 审计数据要求
|
|||
|
|
|
|||
|
|
before_data / after_data:
|
|||
|
|
|
|||
|
|
必须脱敏。
|
|||
|
|
|
|||
|
|
禁止写入:
|
|||
|
|
|
|||
|
|
- 完整身份证
|
|||
|
|
- 完整手机号
|
|||
|
|
- 密码
|
|||
|
|
- Token
|
|||
|
|
- 聊天正文
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第七十一章 sensitive_access_logs
|
|||
|
|
|
|||
|
|
专门记录敏感资料查看。
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE sensitive_access_logs (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
operator_id UUID NOT NULL,
|
|||
|
|
user_id UUID NOT NULL,
|
|||
|
|
data_type VARCHAR(64) NOT NULL,
|
|||
|
|
reason VARCHAR(500),
|
|||
|
|
ip VARCHAR(64),
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
|
|||
|
|
FOREIGN KEY(operator_id) REFERENCES operators(id),
|
|||
|
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第七十二章 system_configs
|
|||
|
|
|
|||
|
|
轻量系统配置。
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE system_configs (
|
|||
|
|
config_key VARCHAR(128) PRIMARY KEY,
|
|||
|
|
config_value JSONB NOT NULL,
|
|||
|
|
description VARCHAR(500),
|
|||
|
|
updated_by UUID,
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第七十三章 推荐配置示例
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
daily_recommendation_limit
|
|||
|
|
max_profile_photos
|
|||
|
|
max_interest_tags
|
|||
|
|
recommendation_cooldown_days
|
|||
|
|
activity_enabled
|
|||
|
|
matchmaker_enabled
|
|||
|
|
chat_image_enabled
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第七十四章 match_rule_configs
|
|||
|
|
|
|||
|
|
推荐独立结构:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE match_rule_configs (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
version INT NOT NULL,
|
|||
|
|
status VARCHAR(16) NOT NULL,
|
|||
|
|
|
|||
|
|
age_weight INT NOT NULL,
|
|||
|
|
region_weight INT NOT NULL,
|
|||
|
|
marital_weight INT NOT NULL,
|
|||
|
|
children_weight INT NOT NULL,
|
|||
|
|
education_weight INT NOT NULL,
|
|||
|
|
height_weight INT NOT NULL,
|
|||
|
|
marriage_plan_weight INT NOT NULL,
|
|||
|
|
settlement_weight INT NOT NULL,
|
|||
|
|
lifestyle_weight INT NOT NULL,
|
|||
|
|
interest_weight INT NOT NULL,
|
|||
|
|
|
|||
|
|
minimum_score INT NOT NULL DEFAULT 60,
|
|||
|
|
|
|||
|
|
created_by UUID,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
activated_at TIMESTAMPTZ
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第七十五章 匹配规则版本化
|
|||
|
|
|
|||
|
|
不要直接覆盖原权重。
|
|||
|
|
|
|||
|
|
建议:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
version 1
|
|||
|
|
version 2
|
|||
|
|
version 3
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
只有一条:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
status = active
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这样以后可以追溯:
|
|||
|
|
|
|||
|
|
> 某次推荐使用哪套规则。
|
|||
|
|
|
|||
|
|
recommendation_records可以增加:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
rule_version
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第七十六章 ER核心关系概览
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
users
|
|||
|
|
│
|
|||
|
|
├──1:1── user_identities
|
|||
|
|
├──1:1── user_profiles
|
|||
|
|
├──1:1── user_preferences
|
|||
|
|
├──1:1── user_privacy_settings
|
|||
|
|
│
|
|||
|
|
├──1:N── user_photos
|
|||
|
|
├──1:N── user_interests
|
|||
|
|
├──1:N── review_tasks
|
|||
|
|
├──1:N── recommendation_records
|
|||
|
|
├──1:N── user_relations
|
|||
|
|
├──N:N── matches
|
|||
|
|
├──N:N── conversations
|
|||
|
|
├──1:N── activity_registrations
|
|||
|
|
├──1:N── matchmaker_services
|
|||
|
|
├──1:N── reports
|
|||
|
|
├──1:1── user_risk_profiles
|
|||
|
|
└──1:N── notifications
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第七十七章 匹配关系ER
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
User A
|
|||
|
|
│
|
|||
|
|
├── liked ──────> User B
|
|||
|
|
│
|
|||
|
|
User B
|
|||
|
|
│
|
|||
|
|
└── liked ──────> User A
|
|||
|
|
│
|
|||
|
|
↓
|
|||
|
|
Match
|
|||
|
|
│
|
|||
|
|
↓
|
|||
|
|
Conversation
|
|||
|
|
│
|
|||
|
|
↓
|
|||
|
|
Messages
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第七十八章 红娘关系ER
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
User
|
|||
|
|
↓
|
|||
|
|
MatchmakerService
|
|||
|
|
↓
|
|||
|
|
Operator / Matchmaker
|
|||
|
|
↓
|
|||
|
|
MatchmakerRecommendation
|
|||
|
|
↓
|
|||
|
|
TargetUser
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
红娘推荐不会直接写入:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
user_relations.liked
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
必须由用户本人操作。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第七十九章 活动关系ER
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Activity
|
|||
|
|
│
|
|||
|
|
├── ActivityRegistration ── User
|
|||
|
|
│
|
|||
|
|
└── ActivityFeedback ───── User
|
|||
|
|
│
|
|||
|
|
└── interested_user_id
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第八十章 审核关系ER
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
User
|
|||
|
|
↓
|
|||
|
|
ReviewTask
|
|||
|
|
↓
|
|||
|
|
ReviewItem
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
一次资料修改:
|
|||
|
|
|
|||
|
|
> 新建新的ReviewTask。
|
|||
|
|
|
|||
|
|
不要覆盖历史审核任务。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第八十一章 数据保留原则
|
|||
|
|
|
|||
|
|
以下数据不能因为状态结束就删除:
|
|||
|
|
|
|||
|
|
- 匹配记录
|
|||
|
|
- 红娘服务记录
|
|||
|
|
- 审核记录
|
|||
|
|
- 举报记录
|
|||
|
|
- 风控处置
|
|||
|
|
- 活动报名
|
|||
|
|
- 操作日志
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
> 服务质量、纠纷处理、统计、审计都需要历史。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第八十二章 软删除建议
|
|||
|
|
|
|||
|
|
适合soft delete:
|
|||
|
|
|
|||
|
|
- 用户照片
|
|||
|
|
- 活动
|
|||
|
|
- 某些运营配置
|
|||
|
|
|
|||
|
|
不建议简单soft delete:
|
|||
|
|
|
|||
|
|
- messages
|
|||
|
|
- audit_logs
|
|||
|
|
- reports
|
|||
|
|
- review_tasks
|
|||
|
|
|
|||
|
|
这些属于业务记录。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第八十三章 用户注销后的数据策略
|
|||
|
|
|
|||
|
|
用户注销后:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
users.account_status = closed
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
同时:
|
|||
|
|
|
|||
|
|
- recommendation_enabled = false
|
|||
|
|
- search_visibility = false
|
|||
|
|
- 停止匹配
|
|||
|
|
- 停止新聊天
|
|||
|
|
|
|||
|
|
根据数据生命周期策略:
|
|||
|
|
|
|||
|
|
> 对公开资料匿名化或进入待清理流程。
|
|||
|
|
|
|||
|
|
具体删除周期需在隐私合规设计章节明确。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第八十四章 数据脱敏查询层
|
|||
|
|
|
|||
|
|
数据库Entity不直接返回前端。
|
|||
|
|
|
|||
|
|
必须经过DTO转换。
|
|||
|
|
|
|||
|
|
例如:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
PublicProfileDTO
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
不会包含:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
real_name_enc
|
|||
|
|
id_number_enc
|
|||
|
|
phone
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第八十五章 公共用户资料DTO
|
|||
|
|
|
|||
|
|
建议包含:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
userId
|
|||
|
|
displayName
|
|||
|
|
age
|
|||
|
|
height
|
|||
|
|
region
|
|||
|
|
education
|
|||
|
|
occupation
|
|||
|
|
maritalStatus
|
|||
|
|
childrenStatus
|
|||
|
|
interests
|
|||
|
|
photos
|
|||
|
|
relationshipGoal
|
|||
|
|
marriagePlan
|
|||
|
|
verified
|
|||
|
|
reviewed
|
|||
|
|
recommendReasons
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第八十六章 自己查看自己DTO
|
|||
|
|
|
|||
|
|
SelfProfileDTO可增加:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
phoneMasked
|
|||
|
|
reviewStatus
|
|||
|
|
profileCompletion
|
|||
|
|
privacySettings
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
仍然不要默认返回完整身份证。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第八十七章 红娘DTO
|
|||
|
|
|
|||
|
|
MatchmakerUserDTO:
|
|||
|
|
|
|||
|
|
可查看:
|
|||
|
|
|
|||
|
|
- 公开资料
|
|||
|
|
- 择偶条件
|
|||
|
|
- 服务状态
|
|||
|
|
- 推荐记录
|
|||
|
|
- 跟进记录
|
|||
|
|
|
|||
|
|
不可包含:
|
|||
|
|
|
|||
|
|
- 身份证
|
|||
|
|
- 完整聊天正文
|
|||
|
|
- 风控证据
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第八十八章 管理员DTO
|
|||
|
|
|
|||
|
|
AdminUserDTO根据权限动态裁剪。
|
|||
|
|
|
|||
|
|
敏感数据接口应独立:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
GET /admin/users/{id}/sensitive-identity
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
而不是:
|
|||
|
|
|
|||
|
|
> 用户详情接口默认带完整实名信息。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第八十九章 数据库索引重点
|
|||
|
|
|
|||
|
|
重点索引建议:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
users(account_status)
|
|||
|
|
users(relationship_status)
|
|||
|
|
|
|||
|
|
user_profiles(gender, region_code)
|
|||
|
|
user_profiles(birth_date)
|
|||
|
|
user_profiles(profile_status)
|
|||
|
|
|
|||
|
|
review_tasks(status, submitted_at)
|
|||
|
|
|
|||
|
|
user_relations(user_id, target_user_id)
|
|||
|
|
user_relations(target_user_id, relation_type)
|
|||
|
|
|
|||
|
|
matches(user_a_id, user_b_id)
|
|||
|
|
|
|||
|
|
messages(conversation_id, created_at)
|
|||
|
|
|
|||
|
|
activities(status, start_at)
|
|||
|
|
activity_registrations(activity_id, status)
|
|||
|
|
|
|||
|
|
matchmaker_services(status, assigned_operator_id)
|
|||
|
|
|
|||
|
|
reports(status, risk_level)
|
|||
|
|
reports(target_user_id)
|
|||
|
|
|
|||
|
|
notifications(user_id, read_status, created_at)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第九十章 匹配初筛查询建议
|
|||
|
|
|
|||
|
|
V1不要做全量暴力评分。
|
|||
|
|
|
|||
|
|
数据库先筛:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
性别
|
|||
|
|
审核通过
|
|||
|
|
账号正常
|
|||
|
|
婚恋状态正常
|
|||
|
|
隐私允许
|
|||
|
|
年龄粗范围
|
|||
|
|
地区
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
然后应用层继续:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
双方required条件
|
|||
|
|
preferred条件
|
|||
|
|
权重评分
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第九十一章 年龄查询建议
|
|||
|
|
|
|||
|
|
使用birth_date转换条件。
|
|||
|
|
|
|||
|
|
例如用户要求:
|
|||
|
|
|
|||
|
|
> 28~35岁。
|
|||
|
|
|
|||
|
|
换算成:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
birth_date BETWEEN 某两个日期
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这样比数据库逐条计算年龄更利于索引。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第九十二章 大字段控制
|
|||
|
|
|
|||
|
|
以下字段不要放主列表查询:
|
|||
|
|
|
|||
|
|
- self_intro
|
|||
|
|
- 活动description
|
|||
|
|
- 举报description
|
|||
|
|
- 红娘followup全文
|
|||
|
|
- 消息content
|
|||
|
|
|
|||
|
|
列表页只查询必要字段。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第九十三章 JSONB使用边界
|
|||
|
|
|
|||
|
|
适合:
|
|||
|
|
|
|||
|
|
- 推荐理由快照
|
|||
|
|
- 风险事件metadata
|
|||
|
|
- 审计before/after
|
|||
|
|
- 系统配置
|
|||
|
|
- 小型多选条件
|
|||
|
|
|
|||
|
|
不适合:
|
|||
|
|
|
|||
|
|
> 核心业务实体全部JSON化。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第九十四章 数据库事务场景一:双向喜欢
|
|||
|
|
|
|||
|
|
事务建议:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
BEGIN
|
|||
|
|
↓
|
|||
|
|
插入A→B liked
|
|||
|
|
↓
|
|||
|
|
检查B→A liked
|
|||
|
|
↓
|
|||
|
|
如果存在:
|
|||
|
|
创建match
|
|||
|
|
创建conversation
|
|||
|
|
创建2条conversation_member
|
|||
|
|
COMMIT
|
|||
|
|
↓
|
|||
|
|
事务后发送通知
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第九十五章 并发双向喜欢
|
|||
|
|
|
|||
|
|
A和B同时点击喜欢。
|
|||
|
|
|
|||
|
|
必须通过:
|
|||
|
|
|
|||
|
|
- unique relation约束
|
|||
|
|
- unique match pair约束
|
|||
|
|
- 捕获duplicate key后重新查询
|
|||
|
|
|
|||
|
|
保证最终:
|
|||
|
|
|
|||
|
|
> 只有一个Match。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第九十六章 数据库事务场景二:活动名额
|
|||
|
|
|
|||
|
|
审核通过报名时:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
BEGIN
|
|||
|
|
↓
|
|||
|
|
锁定活动/名额状态
|
|||
|
|
↓
|
|||
|
|
统计当前已通过人数
|
|||
|
|
↓
|
|||
|
|
判断性别名额
|
|||
|
|
↓
|
|||
|
|
更新registration
|
|||
|
|
COMMIT
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
避免超额。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第九十七章 更高效的活动名额方案
|
|||
|
|
|
|||
|
|
如果未来活动量增大:
|
|||
|
|
|
|||
|
|
可在activities增加:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
approved_male_count
|
|||
|
|
approved_female_count
|
|||
|
|
approved_total_count
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
使用原子更新。
|
|||
|
|
|
|||
|
|
V1可以先用事务统计。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第九十八章 数据库事务场景三:审核领取
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
UPDATE review_tasks
|
|||
|
|
SET status = 'processing',
|
|||
|
|
assigned_operator_id = :operatorId
|
|||
|
|
WHERE id = :id
|
|||
|
|
AND status = 'pending';
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
检查影响行数:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
1 → 领取成功
|
|||
|
|
0 → 已被其他审核员领取
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
不一定需要Redis锁。
|
|||
|
|
|
|||
|
|
数据库原子更新更简单。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第九十九章 数据库事务场景四:签到
|
|||
|
|
|
|||
|
|
唯一报名记录上更新:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
not_checked_in → checked_in
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
重复签到:
|
|||
|
|
|
|||
|
|
> 返回已签到,而不是插入第二条记录。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百章 数据归档策略
|
|||
|
|
|
|||
|
|
V1无需复杂冷热分层。
|
|||
|
|
|
|||
|
|
但应预留:
|
|||
|
|
|
|||
|
|
messages和audit_logs未来可能体量最大。
|
|||
|
|
|
|||
|
|
后续可按:
|
|||
|
|
|
|||
|
|
- 时间分区
|
|||
|
|
- 月度分区
|
|||
|
|
- 历史归档
|
|||
|
|
|
|||
|
|
扩展。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百零一章 messages未来分区建议
|
|||
|
|
|
|||
|
|
如果消息量明显增长:
|
|||
|
|
|
|||
|
|
可按:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
created_at
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
按月分区。
|
|||
|
|
|
|||
|
|
V1阶段无需提前复杂化。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百零二章 audit_logs未来分区
|
|||
|
|
|
|||
|
|
同样可按:
|
|||
|
|
|
|||
|
|
> 月份。
|
|||
|
|
|
|||
|
|
因为操作日志通常只追加。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百零三章 数据库迁移工具
|
|||
|
|
|
|||
|
|
必须使用迁移工具。
|
|||
|
|
|
|||
|
|
Java:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Flyway / Liquibase
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Node:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Prisma migrations / TypeORM migrations
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
不能生产环境:
|
|||
|
|
|
|||
|
|
> 手工改表。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百零四章 migration命名
|
|||
|
|
|
|||
|
|
例如:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
V001__init_users.sql
|
|||
|
|
V002__add_profiles.sql
|
|||
|
|
V003__add_review_tables.sql
|
|||
|
|
V004__add_match_tables.sql
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
每次变更可追溯。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百零五章 初始化字典数据
|
|||
|
|
|
|||
|
|
建议migration或seed初始化:
|
|||
|
|
|
|||
|
|
- 兴趣字典
|
|||
|
|
- 教育类型
|
|||
|
|
- 职业分类
|
|||
|
|
- 审核原因
|
|||
|
|
- 权限
|
|||
|
|
- 默认角色
|
|||
|
|
- 默认匹配规则
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百零六章 测试数据策略
|
|||
|
|
|
|||
|
|
开发环境可提供:
|
|||
|
|
|
|||
|
|
> seed脚本。
|
|||
|
|
|
|||
|
|
生成:
|
|||
|
|
|
|||
|
|
- 男用户
|
|||
|
|
- 女用户
|
|||
|
|
- 不同年龄
|
|||
|
|
- 不同婚姻状态
|
|||
|
|
- 不同择偶条件
|
|||
|
|
- 匹配/不匹配数据
|
|||
|
|
|
|||
|
|
方便测试匹配算法。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百零七章 生产数据严禁复制到开发环境
|
|||
|
|
|
|||
|
|
尤其不得直接复制:
|
|||
|
|
|
|||
|
|
- 实名信息
|
|||
|
|
- 聊天记录
|
|||
|
|
- 用户照片
|
|||
|
|
- 举报证据
|
|||
|
|
|
|||
|
|
如确需问题复现:
|
|||
|
|
|
|||
|
|
> 使用脱敏数据。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百零八章 备份对象
|
|||
|
|
|
|||
|
|
至少备份:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
PostgreSQL
|
|||
|
|
对象存储关键Bucket
|
|||
|
|
系统配置
|
|||
|
|
数据库迁移文件
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Redis:
|
|||
|
|
|
|||
|
|
原则上不需要作为业务恢复唯一依赖。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百零九章 数据恢复优先级
|
|||
|
|
|
|||
|
|
第一:
|
|||
|
|
|
|||
|
|
> 用户与业务数据库。
|
|||
|
|
|
|||
|
|
第二:
|
|||
|
|
|
|||
|
|
> 用户照片与证据。
|
|||
|
|
|
|||
|
|
第三:
|
|||
|
|
|
|||
|
|
> 配置。
|
|||
|
|
|
|||
|
|
Redis可以:
|
|||
|
|
|
|||
|
|
> 重建。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百一十章 敏感数据访问原则
|
|||
|
|
|
|||
|
|
实名数据库字段不能被:
|
|||
|
|
|
|||
|
|
- 推荐模块
|
|||
|
|
- 活动普通列表
|
|||
|
|
- 红娘候选列表
|
|||
|
|
- 统计模块
|
|||
|
|
|
|||
|
|
直接查询。
|
|||
|
|
|
|||
|
|
建议代码层也分Repository。
|
|||
|
|
|
|||
|
|
例如:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
IdentityRepository
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
只允许Verification/SensitiveAdmin服务使用。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百一十一章 数据库账号权限
|
|||
|
|
|
|||
|
|
生产环境至少拆:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
app_rw
|
|||
|
|
migration_admin
|
|||
|
|
backup_user
|
|||
|
|
readonly_reporting
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
后台运营人员绝不能直接拥有数据库账号。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百一十二章 数据最小化
|
|||
|
|
|
|||
|
|
没有业务必要就不采集。
|
|||
|
|
|
|||
|
|
例如V1不采集:
|
|||
|
|
|
|||
|
|
- 房产证
|
|||
|
|
- 车辆信息
|
|||
|
|
- 详细收入
|
|||
|
|
- 银行信息
|
|||
|
|
- 精确住宅地址
|
|||
|
|
|
|||
|
|
数据库也不要“先预留几十个字段以后可能用”。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百一十三章 业务唯一约束汇总
|
|||
|
|
|
|||
|
|
必须有:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
users.wechat_openid UNIQUE
|
|||
|
|
|
|||
|
|
users.phone UNIQUE(有效账号)
|
|||
|
|
|
|||
|
|
user_identities.user_id UNIQUE
|
|||
|
|
|
|||
|
|
user_profiles.user_id UNIQUE
|
|||
|
|
|
|||
|
|
user_preferences.user_id UNIQUE
|
|||
|
|
|
|||
|
|
user_privacy_settings.user_id UNIQUE
|
|||
|
|
|
|||
|
|
user_interests(user_id, interest_code) UNIQUE
|
|||
|
|
|
|||
|
|
user_relations(user_id,target_user_id,relation_type) UNIQUE
|
|||
|
|
|
|||
|
|
matches(user_a_id,user_b_id) UNIQUE
|
|||
|
|
|
|||
|
|
conversations.match_id UNIQUE
|
|||
|
|
|
|||
|
|
conversation_members(conversation_id,user_id) UNIQUE
|
|||
|
|
|
|||
|
|
messages(sender_id,client_message_id) UNIQUE
|
|||
|
|
|
|||
|
|
activity_registrations(activity_id,user_id) UNIQUE
|
|||
|
|
|
|||
|
|
activity_feedback(activity_id,user_id) UNIQUE
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百一十四章 外键策略
|
|||
|
|
|
|||
|
|
核心业务表建议使用外键。
|
|||
|
|
|
|||
|
|
好处:
|
|||
|
|
|
|||
|
|
> 防止孤儿数据。
|
|||
|
|
|
|||
|
|
但生产删除必须谨慎。
|
|||
|
|
|
|||
|
|
多数情况下:
|
|||
|
|
|
|||
|
|
> 不使用ON DELETE CASCADE。
|
|||
|
|
|
|||
|
|
因为婚恋业务需要历史审计。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百一十五章 不建议Cascade删除
|
|||
|
|
|
|||
|
|
例如删除User时绝不能自动删除:
|
|||
|
|
|
|||
|
|
- messages
|
|||
|
|
- reports
|
|||
|
|
- matches
|
|||
|
|
- review_tasks
|
|||
|
|
|
|||
|
|
因此:
|
|||
|
|
|
|||
|
|
> 账号关闭优先状态化,而不是删除。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百一十六章 统计数据来源
|
|||
|
|
|
|||
|
|
早期后台统计从业务表聚合。
|
|||
|
|
|
|||
|
|
例如:
|
|||
|
|
|
|||
|
|
成功牵手:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
matches.status = successful
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
审核通过:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
user_profiles.profile_status = approved
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
不要前端自己累加。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百一十七章 后续可增加每日汇总表
|
|||
|
|
|
|||
|
|
例如:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
daily_platform_metrics
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
字段:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
date
|
|||
|
|
new_users
|
|||
|
|
verified_users
|
|||
|
|
approved_users
|
|||
|
|
likes
|
|||
|
|
mutual_matches
|
|||
|
|
chat_started
|
|||
|
|
activity_registrations
|
|||
|
|
successful_matches
|
|||
|
|
reports
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
当实时统计性能不足时再启用。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百一十八章 推荐记录的数据价值
|
|||
|
|
|
|||
|
|
recommendation_records后续可以分析:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
曝光 → 查看
|
|||
|
|
查看 → 喜欢
|
|||
|
|
喜欢 → 双向
|
|||
|
|
双向 → 聊天
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这比一开始建设复杂AI推荐系统更重要。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百一十九章 未来AI匹配的数据基础
|
|||
|
|
|
|||
|
|
如果未来引入AI,现有表已经提供:
|
|||
|
|
|
|||
|
|
- 基础条件
|
|||
|
|
- 兴趣
|
|||
|
|
- 婚恋计划
|
|||
|
|
- 推荐曝光
|
|||
|
|
- 喜欢行为
|
|||
|
|
- 双向匹配
|
|||
|
|
- 解除匹配
|
|||
|
|
- 成功牵手
|
|||
|
|
|
|||
|
|
可以作为后续推荐优化基础。
|
|||
|
|
|
|||
|
|
因此V1不需要提前做向量数据库。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百二十章 数据库V1明确不建设
|
|||
|
|
|
|||
|
|
暂不需要:
|
|||
|
|
|
|||
|
|
- ElasticSearch
|
|||
|
|
- Neo4j
|
|||
|
|
- Milvus
|
|||
|
|
- ClickHouse
|
|||
|
|
- Kafka存储
|
|||
|
|
- 数据湖
|
|||
|
|
- 特征库
|
|||
|
|
- AI向量表
|
|||
|
|
- 推荐模型训练表
|
|||
|
|
- 支付订单表
|
|||
|
|
- VIP表
|
|||
|
|
- 礼物表
|
|||
|
|
- 直播表
|
|||
|
|
- 短视频表
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百二十一章 核心表开发优先级
|
|||
|
|
|
|||
|
|
## P0
|
|||
|
|
|
|||
|
|
第一批:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
users
|
|||
|
|
user_identities
|
|||
|
|
user_profiles
|
|||
|
|
user_preferences
|
|||
|
|
user_interests
|
|||
|
|
user_photos
|
|||
|
|
user_privacy_settings
|
|||
|
|
|
|||
|
|
review_tasks
|
|||
|
|
review_items
|
|||
|
|
|
|||
|
|
recommendation_records
|
|||
|
|
user_relations
|
|||
|
|
matches
|
|||
|
|
|
|||
|
|
conversations
|
|||
|
|
conversation_members
|
|||
|
|
messages
|
|||
|
|
|
|||
|
|
organizations
|
|||
|
|
operators
|
|||
|
|
roles
|
|||
|
|
permissions
|
|||
|
|
role_permissions
|
|||
|
|
operator_roles
|
|||
|
|
|
|||
|
|
audit_logs
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## P1
|
|||
|
|
|
|||
|
|
第二批:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
activities
|
|||
|
|
activity_registrations
|
|||
|
|
activity_feedback
|
|||
|
|
|
|||
|
|
matchmaker_services
|
|||
|
|
matchmaker_recommendations
|
|||
|
|
matchmaker_followups
|
|||
|
|
|
|||
|
|
notifications
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## P2
|
|||
|
|
|
|||
|
|
第三批:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
reports
|
|||
|
|
report_evidences
|
|||
|
|
user_risk_profiles
|
|||
|
|
risk_events
|
|||
|
|
risk_actions
|
|||
|
|
appeals
|
|||
|
|
|
|||
|
|
system_configs
|
|||
|
|
match_rule_configs
|
|||
|
|
sensitive_access_logs
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
风控功能本身仍是V1必做,这里的P2只是数据库实施排期顺序,不代表可以不上线。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百二十二章 数据库验收重点
|
|||
|
|
|
|||
|
|
必须验证:
|
|||
|
|
|
|||
|
|
### 用户
|
|||
|
|
|
|||
|
|
一个微信账号不能生成多个正常用户。
|
|||
|
|
|
|||
|
|
### 身份
|
|||
|
|
|
|||
|
|
一个认证身份证不能无限重复注册。
|
|||
|
|
|
|||
|
|
### 关系
|
|||
|
|
|
|||
|
|
不能自己喜欢自己。
|
|||
|
|
|
|||
|
|
### Match
|
|||
|
|
|
|||
|
|
一对用户不能生成重复Match。
|
|||
|
|
|
|||
|
|
### 消息
|
|||
|
|
|
|||
|
|
重复clientMessageId不能生成两条消息。
|
|||
|
|
|
|||
|
|
### 活动
|
|||
|
|
|
|||
|
|
同一用户不能重复报名同一活动。
|
|||
|
|
|
|||
|
|
### 审核
|
|||
|
|
|
|||
|
|
一个审核任务不能被多人同时完成。
|
|||
|
|
|
|||
|
|
### 权限
|
|||
|
|
|
|||
|
|
敏感信息不进入普通查询结果。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百二十三章 数据一致性验收
|
|||
|
|
|
|||
|
|
必须重点测试:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
喜欢成功但Match失败
|
|||
|
|
Match成功但Conversation失败
|
|||
|
|
活动报名成功但人数超限
|
|||
|
|
举报处理后User状态未同步
|
|||
|
|
用户拉黑后Conversation还能发送
|
|||
|
|
成功牵手后仍进入推荐池
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这些都必须通过事务和业务状态保证一致。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百二十四章 数据库ER文字总图
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
User
|
|||
|
|
│
|
|||
|
|
├─ Identity
|
|||
|
|
├─ Profile
|
|||
|
|
│ ├─ Photos
|
|||
|
|
│ ├─ Interests
|
|||
|
|
│ ├─ Preference
|
|||
|
|
│ └─ Privacy
|
|||
|
|
│
|
|||
|
|
├─ Reviews
|
|||
|
|
│ └─ ReviewItems
|
|||
|
|
│
|
|||
|
|
├─ Relations
|
|||
|
|
│ ↓
|
|||
|
|
│ Match
|
|||
|
|
│ ↓
|
|||
|
|
│ Conversation
|
|||
|
|
│ ↓
|
|||
|
|
│ Messages
|
|||
|
|
│
|
|||
|
|
├─ ActivityRegistrations
|
|||
|
|
│ ↓
|
|||
|
|
│ Activities
|
|||
|
|
│
|
|||
|
|
├─ MatchmakerServices
|
|||
|
|
│ ├─ Recommendations
|
|||
|
|
│ └─ Followups
|
|||
|
|
│
|
|||
|
|
├─ Reports
|
|||
|
|
│ └─ Evidences
|
|||
|
|
│
|
|||
|
|
├─ RiskProfile
|
|||
|
|
│ ├─ RiskEvents
|
|||
|
|
│ └─ RiskActions
|
|||
|
|
│
|
|||
|
|
└─ Notifications
|
|||
|
|
|
|||
|
|
Organization
|
|||
|
|
│
|
|||
|
|
└─ Operators
|
|||
|
|
├─ Roles
|
|||
|
|
│ └─ Permissions
|
|||
|
|
└─ AuditLogs
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 第一百二十五章 数据库设计最终原则
|
|||
|
|
|
|||
|
|
数据库层必须做到:
|
|||
|
|
|
|||
|
|
> **真实身份和公开婚恋资料物理分层。**
|
|||
|
|
|
|||
|
|
> **所有双向关系都有数据库唯一约束。**
|
|||
|
|
|
|||
|
|
> **所有重要状态变化都有历史可追溯。**
|
|||
|
|
|
|||
|
|
> **聊天、举报、审核、风控不能因为用户状态变化被随意删除。**
|
|||
|
|
|
|||
|
|
> **匹配数据能够支持未来持续优化,但V1不提前复杂化。**
|
|||
|
|
|
|||
|
|
> **敏感数据永远不通过普通User查询顺手返回。**
|
|||
|
|
|
|||
|
|
> **每个高风险业务都依赖数据库约束兜底,而不是只相信前端。**
|
|||
|
|
|
|||
|
|
最终数据库不是为了“表越多越专业”,而是为了保证:
|
|||
|
|
|
|||
|
|
> **用户、匹配、聊天、活动、红娘、审核和安全这几条核心业务链在任何异常、并发和后续扩展场景下,都能保持数据清晰、状态一致、责任可追溯。**
|