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查询顺手返回。**
|
||
|
||
> **每个高风险业务都依赖数据库约束兜底,而不是只相信前端。**
|
||
|
||
最终数据库不是为了“表越多越专业”,而是为了保证:
|
||
|
||
> **用户、匹配、聊天、活动、红娘、审核和安全这几条核心业务链在任何异常、并发和后续扩展场景下,都能保持数据清晰、状态一致、责任可追溯。** |