chore: establish V1.1 recovery baseline

This commit is contained in:
2026-09-09 22:05:00 +08:00
commit b46b48eb33
947 changed files with 155471 additions and 0 deletions
@@ -0,0 +1,94 @@
server:
port: 8080
servlet:
context-path: /api/v1
spring:
application:
name: danyang-match-platform
profiles:
active: dev
datasource:
url: jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:danyang_match}
username: ${DB_USER:postgres}
password: ${DB_PASSWORD:postgres}
driver-class-name: org.postgresql.Driver
hikari:
maximum-pool-size: 20
minimum-idle: 5
idle-timeout: 30000
max-lifetime: 1800000
connection-timeout: 30000
jackson:
default-property-inclusion: non_null
serialization:
write-dates-as-timestamps: false
deserialization:
fail-on-unknown-properties: false
flyway:
enabled: true
locations: classpath:db/migration
baseline-on-migrate: true
baseline-version: 0
out-of-order: false
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD:}
timeout: 5000ms
main:
allow-bean-definition-overriding: false
# MyBatis-Plus
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
type-handlers-package: com.danyang.match.platform.shared.typehandler
global-config:
db-config:
id-type: assign_uuid
# Logging
logging:
level:
root: INFO
com.danyang.match.platform: DEBUG
org.springframework.security: INFO
org.mybatis: DEBUG
pattern:
console: '%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] %-5level %logger{36} - %msg%n'
# Actuator
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: when_authorized
show-components: always
health:
db:
enabled: true
redis:
enabled: true
# Spring Security (default disable for dev, will be configured in security module)
spring.security:
user:
name: admin
password: admin
# Rate limiting
rate-limit:
max-requests-per-window: 20
window-seconds: 60
+7
View File
@@ -0,0 +1,7 @@
# App metadata
info:
app:
name: danyang-match-platform
version: 0.0.1-SNAPSHOT
description: 丹阳公益婚恋服务平台 V1.0
encodedName: 丹��公益婚恋服务平台
@@ -0,0 +1,482 @@
-- ============================================================
-- 丹阳公益婚恋服务平台 — Demo Seed 最终版(单次事务,纯 SQL)
-- ============================================================
BEGIN;
SET session_replication_role = 'replica';
-- 1. 组织
INSERT INTO organizations (name, type, contact_name, status) VALUES
('丹阳市妇女联合会', 'women_federation', '张丽华', 'active'),
('丹阳市总工会', 'trade_union', '李明远', 'active'),
('丹阳市慈善基金会', 'charity_center', '王秀英', 'active');
-- 2. 工作人员(V1.0原有 + V1.1新增)
INSERT INTO operators (organization_id, name, username, password_hash, status)
SELECT id, '陈主任', 'admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'
FROM organizations WHERE type='women_federation' LIMIT 1
UNION ALL
SELECT id, '红娘小王', 'wanghongniang', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'
FROM organizations WHERE type='women_federation' LIMIT 1
UNION ALL
SELECT id, '审核员小张', 'reviewer01', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'
FROM organizations WHERE type='charity_center' LIMIT 1
UNION ALL
SELECT id, '活动管理员赵', 'activitymgr','$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'
FROM organizations WHERE type='trade_union' LIMIT 1
-- V1.1 新增演示操作员
UNION ALL
SELECT id, '服务站小李', 'stationop', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'
FROM organizations WHERE type='women_federation' LIMIT 1
UNION ALL
SELECT id, '咨询师小周', 'counselor', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'
FROM organizations WHERE type='charity_center' LIMIT 1
UNION ALL
SELECT id, '内容编辑小吴', 'contenteditor','$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'
FROM organizations WHERE type='women_federation' LIMIT 1;
-- 操作员角色绑定(V1.0原有 + V1.1新增)
INSERT INTO operator_roles (operator_id, role_id)
-- V1.0: admin = super_admin + platform_admin
SELECT o.id, '00000000-0000-0000-0000-000000000001' FROM operators WHERE username='admin'
UNION ALL SELECT o.id, '00000000-0000-0000-0000-000000000002' FROM operators WHERE username='admin'
-- V1.0: wanghongniang = matchmaker + activity_manager
SELECT o.id, '00000000-0000-0000-0000-000000000005' FROM operators WHERE username='wanghongniang'
UNION ALL SELECT o.id, '00000000-0000-0000-0000-000000000006' FROM operators WHERE username='wanghongniang'
-- V1.0: reviewer01 = reviewer + risk_operator
SELECT o.id, '00000000-0000-0000-0000-000000000004' FROM operators WHERE username='reviewer01'
UNION ALL SELECT o.id, '00000000-0000-0000-0000-000000000007' FROM operators WHERE username='reviewer01'
-- V1.0: activitymgr = activity_manager + volunteer
SELECT o.id, '00000000-0000-0000-0000-000000000006' FROM operators WHERE username='activitymgr'
UNION ALL SELECT o.id, '00000000-0000-0000-0000-000000000008' FROM operators WHERE username='activitymgr'
-- V1.1: stationop = service_station_operator
SELECT o.id, '00000000-0000-0000-0000-000000000010' FROM operators WHERE username='stationop'
-- V1.1: counselor = counselor
SELECT o.id, '00000000-0000-0000-0000-000000000011' FROM operators WHERE username='counselor'
-- V1.1: contenteditor = content_editor
SELECT o.id, '00000000-0000-0000-0000-000000000013' FROM operators WHERE username='contenteditor';
-- 3. 用户 + 资料 + 偏好 + 实名 + 兴趣 + 隐私 + 照片(一次性生成UUID并关联)
WITH demo_users AS (
INSERT INTO users (wechat_openid, account_status, relationship_status, recommendation_enabled, created_at)
VALUES
('demo_openid_f01','normal','searching',true,'2026-03-15T10:00:00Z'),
('demo_openid_f02','normal','searching',true,'2026-03-20T14:30:00Z'),
('demo_openid_f03','normal','searching',true,'2026-04-01T09:15:00Z'),
('demo_openid_f04','normal','paused',true,'2026-04-10T16:00:00Z'),
('demo_openid_f05','normal','searching',true,'2026-05-01T11:20:00Z'),
('demo_openid_f06','normal','searching',true,'2026-05-15T08:45:00Z'),
('demo_openid_m01','normal','searching',true,'2026-03-10T09:00:00Z'),
('demo_openid_m02','normal','getting_to_know',true,'2026-03-25T13:00:00Z'),
('demo_openid_m03','normal','searching',true,'2026-04-05T15:30:00Z'),
('demo_openid_m04','normal','searching',true,'2026-04-20T10:00:00Z'),
('demo_openid_m05','normal','matched_successfully',true,'2026-05-01T14:00:00Z'),
('demo_openid_m06','normal','searching',true,'2026-05-10T16:30:00Z')
RETURNING id, wechat_openid
), user_map AS (
SELECT id, wechat_openid,
CASE wechat_openid
WHEN 'demo_openid_f01' THEN 'f01' WHEN 'demo_openid_f02' THEN 'f02'
WHEN 'demo_openid_f03' THEN 'f03' WHEN 'demo_openid_f04' THEN 'f04'
WHEN 'demo_openid_f05' THEN 'f05' WHEN 'demo_openid_f06' THEN 'f06'
WHEN 'demo_openid_m01' THEN 'm01' WHEN 'demo_openid_m02' THEN 'm02'
WHEN 'demo_openid_m03' THEN 'm03' WHEN 'demo_openid_m04' THEN 'm04'
WHEN 'demo_openid_m05' THEN 'm05' WHEN 'demo_openid_m06' THEN 'm06'
END as alias
FROM demo_users
),
user_data AS (
SELECT id, wechat_openid, alias,
CASE alias WHEN 'f01' THEN '小芳' WHEN 'f02' THEN '晓燕' WHEN 'f03' THEN '婷婷'
WHEN 'f04' THEN '美玲' WHEN 'f05' THEN '慧琴' WHEN 'f06' THEN '秀英'
WHEN 'm01' THEN '张伟' WHEN 'm02' THEN '李强' WHEN 'm03' THEN '王磊'
WHEN 'm04' THEN '赵明' WHEN 'm05' THEN '孙浩' WHEN 'm06' THEN '周洋' END as display_name,
CASE WHEN alias LIKE 'f%' THEN 'female' ELSE 'male' END as gender,
CASE alias
WHEN 'f01' THEN '1995-06-15' WHEN 'f02' THEN '1993-09-20' WHEN 'f03' THEN '1998-02-10'
WHEN 'f04' THEN '1990-11-05' WHEN 'f05' THEN '1996-07-22' WHEN 'f06' THEN '1992-04-18'
WHEN 'm01' THEN '1992-01-10' WHEN 'm02' THEN '1990-08-25' WHEN 'm03' THEN '1997-12-03'
WHEN 'm04' THEN '1988-05-30' WHEN 'm05' THEN '1994-03-14' WHEN 'm06' THEN '1999-08-08'
END as birth_date,
CASE alias
WHEN 'f01' THEN 162 WHEN 'f02' THEN 165 WHEN 'f03' THEN 158
WHEN 'f04' THEN 160 WHEN 'f05' THEN 163 WHEN 'f06' THEN 157
WHEN 'm01' THEN 175 WHEN 'm02' THEN 178 WHEN 'm03' THEN 180
WHEN 'm04' THEN 172 WHEN 'm05' THEN 182 WHEN 'm06' THEN 176
END as height_cm,
CASE WHEN alias IN ('f01','f02','f04','f05','m01','m02','m04','m05') THEN '321181'
WHEN alias IN ('f03','m03') THEN '321100' WHEN alias='m06' THEN '320500' END as region_code,
CASE WHEN alias IN ('f01','f02','f04','f05','m01','m02','m04','m05') THEN '丹阳'
WHEN alias IN ('f03','m03') THEN '镇江' WHEN alias='m06' THEN '苏州' END as region_name,
CASE alias WHEN 'f02' THEN 'divorced' WHEN 'f06' THEN 'widowed' ELSE 'never_married' END as marital_status,
CASE alias
WHEN 'f01' THEN 'bachelor' WHEN 'f02' THEN 'college' WHEN 'f03' THEN 'master'
WHEN 'f04' THEN 'senior_high' WHEN 'f05' THEN 'bachelor' WHEN 'f06' THEN 'junior_high'
WHEN 'm01' THEN 'bachelor' WHEN 'm02' THEN 'master' WHEN 'm03' THEN 'college'
WHEN 'm04' THEN 'senior_high' WHEN 'm05' THEN 'bachelor' WHEN 'm06' THEN 'master'
END as education_code,
CASE alias
WHEN 'f01' THEN 'clerical' WHEN 'f02' THEN 'teacher' WHEN 'f03' THEN 'designer'
WHEN 'f04' THEN 'factory' WHEN 'f05' THEN 'nurse' WHEN 'f06' THEN 'farmer'
WHEN 'm01' THEN 'engineer' WHEN 'm02' THEN 'manager' WHEN 'm03' THEN 'programmer'
WHEN 'm04' THEN 'sales' WHEN 'm05' THEN 'doctor' WHEN 'm06' THEN 'researcher'
END as occupation_code,
CASE alias WHEN 'f03' THEN 'sometimes' WHEN 'f06' THEN 'often' WHEN 'm02' THEN 'sometimes'
WHEN 'm04' THEN 'often' WHEN 'm05' THEN 'sometimes' ELSE 'never' END as smoking,
CASE alias WHEN 'f03' THEN 'often' WHEN 'f06' THEN 'often' WHEN 'm02' THEN 'often'
WHEN 'm04' THEN 'often' ELSE 'sometimes' END as drinking,
CASE WHEN alias IN ('f03','m06') THEN '否' ELSE '是' END as long_term,
CASE WHEN alias IN ('f03','m06') THEN '否' ELSE '是' END as future,
CASE WHEN alias IN ('f03','m06') THEN '恋爱' ELSE '结婚' END as goal,
CASE alias
WHEN 'f01' THEN 90 WHEN 'f02' THEN 95 WHEN 'f03' THEN 85 WHEN 'f04' THEN 70
WHEN 'f05' THEN 92 WHEN 'f06' THEN 60 WHEN 'm01' THEN 88 WHEN 'm02' THEN 95
WHEN 'm03' THEN 82 WHEN 'm04' THEN 75 WHEN 'm05' THEN 97 WHEN 'm06' THEN 80
END as completion
FROM user_map
)
INSERT INTO user_profiles (user_id, display_name, gender, birth_date, height_cm,
region_code, region_name, marital_status, children_status,
education_code, occupation_code, smoking_status, drinking_status,
long_term_danyang, future_danyang, relationship_goal, profile_completion, profile_status)
SELECT id, display_name, gender, birth_date::date, height_cm,
region_code, region_name, marital_status, 'none',
education_code, occupation_code, smoking, drinking,
long_term, future, goal, completion, 'approved'
FROM user_data;
-- 偏好
INSERT INTO user_preferences (user_id, min_age, max_age, age_priority, min_height_cm, max_height_cm, height_priority, region_scope, region_priority, marital_statuses, marital_priority, min_education_code, education_priority)
SELECT id,
CASE WHEN alias LIKE 'f%' THEN 28 WHEN alias LIKE 'm%' THEN 22 ELSE 25 END,
CASE WHEN alias LIKE 'f%' THEN 40 WHEN alias LIKE 'm%' THEN 38 ELSE 35 END,
'required',
CASE WHEN alias LIKE 'f%' THEN 155 WHEN alias LIKE 'm%' THEN 170 ELSE 158 END,
CASE WHEN alias LIKE 'f%' THEN 172 WHEN alias LIKE 'm%' THEN 188 ELSE 185 END,
'preferred',
'[\"321181\",\"321100\"]', 'required', '[\"never_married\"]', 'required',
CASE alias WHEN 'f02' THEN 'college' WHEN 'm02' THEN 'college' WHEN 'f01' THEN 'bachelor'
WHEN 'm01' THEN 'bachelor' WHEN 'm05' THEN 'bachelor' ELSE NULL END,
'preferred'
FROM user_data;
-- 实名认证
INSERT INTO user_identities (id, user_id, real_name_enc, id_number_enc, id_number_hash, gender, birth_date, verification_status, provider, verified_at)
SELECT gen_random_uuid(), id, encode(('demo_enc_'||alias)::bytea,'escape'), encode(('demo_id_'||alias)::bytea,'escape'), 'demo_sha256_'||alias, gender, birth_date::date, 'verified', 'mock', NOW()-INTERVAL '1 day')
FROM user_data;
-- 兴趣
WITH interests AS (
SELECT ud.id as user_id, ic.code
FROM user_data ud
CROSS JOIN (VALUES ('reading'),('cooking'),('travel'),('sports'),('music'),('outdoor'),
('photography'),('dance'),('movie'),('pets'),('fitness'),('charity'),('gardening'),
('gaming'),('hiking'),('coding'),('cars'),('running'),('research')) ic(code)
WHERE (ud.alias='f01' AND ic.code IN ('reading','cooking','travel'))
OR (ud.alias='f02' AND ic.code IN ('sports','music','outdoor'))
OR (ud.alias='f03' AND ic.code IN ('photography','dance','movie'))
OR (ud.alias='f04' AND ic.code IN ('pets','cooking'))
OR (ud.alias='f05' AND ic.code IN ('reading','fitness','charity'))
OR (ud.alias='f06' AND ic.code IN ('gardening','cooking'))
OR (ud.alias='m01' AND ic.code IN ('sports','gaming','travel'))
OR (ud.alias='m02' AND ic.code IN ('reading','investment','hiking'))
OR (ud.alias='m03' AND ic.code IN ('gaming','music','coding'))
OR (ud.alias='m04' AND ic.code IN ('cars','cooking'))
OR (ud.alias='m05' AND ic.code IN ('running','reading','charity'))
OR (ud.alias='m06' AND ic.code IN ('research','travel','photography'))
)
INSERT INTO user_interests (user_id, interest_code) SELECT user_id, code FROM interests;
-- 隐私设置
INSERT INTO user_privacy_settings (user_id, visible_in_recommendations, visible_in_search, show_occupation, show_lifestyle_photos, receive_activity_recommendations, accept_matchmaker_recommendations)
SELECT id, true,
CASE WHEN alias IN ('f03','f06','m04') THEN false ELSE true END,
CASE WHEN alias IN ('f02','f04','m02','m03') THEN false ELSE true END,
CASE WHEN alias IN ('f02','m02','m03') THEN false ELSE true END,
CASE WHEN alias IN ('f05','m03') THEN false ELSE true END,
CASE WHEN alias='f03' THEN false ELSE true END
FROM user_data;
-- 照片
WITH photo_source AS (
SELECT id, alias FROM user_data
)
INSERT INTO user_photos (id, user_id, file_key, photo_type, sort_order, review_status)
SELECT gen_random_uuid(), id, 'photos/demo/'||alias||'/avatar.jpg', 'avatar', 0, 'approved' FROM photo_source
UNION ALL
SELECT gen_random_uuid(), id, 'photos/demo/'||alias||'/lifestyle1.jpg', 'lifestyle', 1, 'approved' FROM photo_source;
-- ============================================================
-- 4. 审核任务
-- ============================================================
INSERT INTO review_tasks (id, user_id, review_type, status, assigned_operator_id, submitted_at, started_at, completed_at, final_comment, version)
SELECT gen_random_uuid(), ud.id, 'initial_profile', 'approved',
(SELECT id FROM operators WHERE username='reviewer01'),
NOW()-INTERVAL '60 days', NOW()-INTERVAL '59 days', NOW()-INTERVAL '58 days', '资料完整', 1
FROM user_data ud WHERE ud.alias IN ('f01','f02','f03','m01','m02','m03','m05');
-- ============================================================
-- 5. 用户关系
-- ============================================================
WITH f01 AS (SELECT id FROM user_data WHERE alias='f01'),
f02 AS (SELECT id FROM user_data WHERE alias='f02'),
f03 AS (SELECT id FROM user_data WHERE alias='f03'),
f04 AS (SELECT id FROM user_data WHERE alias='f04'),
f05 AS (SELECT id FROM user_data WHERE alias='f05'),
f06 AS (SELECT id FROM user_data WHERE alias='f06'),
m01 AS (SELECT id FROM user_data WHERE alias='m01'),
m02 AS (SELECT id FROM user_data WHERE alias='m02'),
m03 AS (SELECT id FROM user_data WHERE alias='m03'),
m04 AS (SELECT id FROM user_data WHERE alias='m04'),
m05 AS (SELECT id FROM user_data WHERE alias='m05'),
m06 AS (SELECT id FROM user_data WHERE alias='m06')
INSERT INTO user_relations (id, user_id, target_user_id, relation_type, created_at)
VALUES
(gen_random_uuid(), (SELECT id FROM f01), (SELECT id FROM m01), 'liked', '2026-06-01T10:00:00Z'),
(gen_random_uuid(), (SELECT id FROM m01), (SELECT id FROM f01), 'liked', '2026-06-01T10:05:00Z'),
(gen_random_uuid(), (SELECT id FROM f02), (SELECT id FROM m02), 'liked', '2026-06-02T14:00:00Z'),
(gen_random_uuid(), (SELECT id FROM f03), (SELECT id FROM m03), 'liked', '2026-06-03T09:00:00Z'),
(gen_random_uuid(), (SELECT id FROM m03), (SELECT id FROM f03), 'liked', '2026-06-03T09:30:00Z'),
(gen_random_uuid(), (SELECT id FROM m04), (SELECT id FROM f02), 'liked', '2026-06-04T11:00:00Z'),
(gen_random_uuid(), (SELECT id FROM f04), (SELECT id FROM m04), 'passed', '2026-06-04T12:00:00Z'),
(gen_random_uuid(), (SELECT id FROM f05), (SELECT id FROM m05), 'liked', '2026-06-05T10:00:00Z'),
(gen_random_uuid(), (SELECT id FROM m05), (SELECT id FROM f05), 'liked', '2026-06-05T10:05:00Z'),
(gen_random_uuid(), (SELECT id FROM m06), (SELECT id FROM f01), 'liked', '2026-06-06T14:00:00Z'),
(gen_random_uuid(), (SELECT id FROM f04), (SELECT id FROM m06), 'passed', '2026-06-06T15:00:00Z'),
(gen_random_uuid(), (SELECT id FROM f06), (SELECT id FROM m04), 'blocked', '2026-06-07T09:00:00Z'),
(gen_random_uuid(), (SELECT id FROM m02), (SELECT id FROM f03), 'passed', '2026-06-07T10:00:00Z');
-- ============================================================
-- 6. Match
-- ====================================================
WITH f01 AS (SELECT id FROM user_data WHERE alias='f01'),
f03 AS (SELECT id FROM user_data WHERE alias='f03'),
f05 AS (SELECT id FROM user_data WHERE alias='f05'),
m01 AS (SELECT id FROM user_data WHERE alias='m01'),
m03 AS (SELECT id FROM user_data WHERE alias='m03'),
m05 AS (SELECT id FROM user_data WHERE alias='m05')
INSERT INTO matches (id, user_a_id, user_b_id, status, source, matched_at)
VALUES
(gen_random_uuid(), (SELECT id FROM f01), (SELECT id FROM m01), 'active', 'user_like', '2026-06-01T10:05:00Z'),
(gen_random_uuid(), (SELECT id FROM f03), (SELECT id FROM m03), 'active', 'user_like', '2026-06-03T09:30:00Z'),
(gen_random_uuid(), (SELECT id FROM f05), (SELECT id FROM m05), 'successful', 'user_like', '2026-06-05T10:05:00Z');
-- ============================================================
-- 7. 成功牵手请求
-- ====================================================
WITH match_success AS (SELECT id FROM matches WHERE status='successful' LIMIT 1),
match_active AS (SELECT id FROM matches WHERE status='active' ORDER BY created_at LIMIT 1),
f01 AS (SELECT id FROM user_data WHERE alias='f01'),
m05 AS (SELECT id FROM user_data WHERE alias='m05'),
f05 AS (SELECT id FROM user_data WHERE alias='f05')
INSERT INTO relationship_success_requests (id, match_id, initiated_by, status, confirmed_by, created_at, resolved_at)
VALUES
(gen_random_uuid(), (SELECT id FROM match_success), (SELECT id FROM f05), 'confirmed', (SELECT id FROM m05), '2026-07-01T10:00:00Z', '2026-07-01T10:30:00Z'),
(gen_random_uuid(), (SELECT id FROM match_active), (SELECT id FROM f01), 'pending', NULL, '2026-07-15T14:00:00Z', NULL);
-- ============================================================
-- 8. Conversations & Messages
-- ====================================================
WITH conv_ids AS (
SELECT gen_random_uuid() as id, match_id FROM matches WHERE status='active' ORDER BY created_at
)
INSERT INTO conversations (id, match_id, status, last_message_at)
SELECT id, match_id, 'active', NOW()-INTERVAL '5 days' FROM conv_ids
RETURNING id, match_id INTO TEMP TABLE _conv_result (id, match_id);
-- members
WITH _match_pairs AS (
SELECT m.user_a_id, m.user_b_id FROM matches m JOIN _conv_result c ON c.match_id=m.id
)
INSERT INTO conversation_members (conversation_id, user_id, unread_count, can_send, joined_at)
SELECT (SELECT id FROM _conv_result WHERE match_id=(SELECT match_id FROM _match_pairs WHERE user_a_id=up.user_a_id LIMIT 1)), up.user_a_id, 0, true, NOW() FROM _match_pairs up
UNION ALL
SELECT (SELECT id FROM _conv_result WHERE match_id=(SELECT match_id FROM _match_pairs WHERE user_b_id=up.user_b_id LIMIT 1)), up.user_b_id, 0, true, NOW() FROM _match_pairs up;
-- messages
INSERT INTO messages (id, conversation_id, sender_id, message_type, content, status, risk_level, created_at)
VALUES
(gen_random_uuid(), (SELECT id FROM conversations ORDER BY created_at LIMIT 1), (SELECT id FROM user_data WHERE alias='f01'), 'text', '你好!看到你的资料觉得挺合适的~', 'sent', 'normal', '2026-06-15T14:00:00Z'),
(gen_random_uuid(), (SELECT id FROM conversations ORDER BY created_at LIMIT 1), (SELECT id FROM user_data WHERE alias='m01'), 'text', '你好!谢谢你的喜欢,我也觉得挺有缘的', 'sent', 'normal', '2026-06-15T14:05:00Z'),
(gen_random_uuid(), (SELECT id FROM conversations ORDER BY created_at LIMIT 1), (SELECT id FROM user_data WHERE alias='f01'), 'text', '你也在丹阳工作吗?平时喜欢做些什么?', 'sent', 'normal', '2026-06-15T14:10:00Z'),
(gen_random_uuid(), (SELECT id FROM conversations ORDER BY created_at OFFSET 1 LIMIT 1), (SELECT id FROM user_data WHERE alias='m03'), 'text', '嗨,你好!很高兴认识你', 'sent', 'normal', '2026-07-05T19:30:00Z'),
(gen_random_uuid(), (SELECT id FROM conversations ORDER BY created_at OFFSET 1 LIMIT 1), (SELECT id FROM user_data WHERE alias='f03'), 'text', '你好呀!我平时喜欢拍照和跳舞,你呢?', 'sent', 'normal', '2026-07-05T19:35:00Z'),
(gen_random_uuid(), (SELECT id FROM conversations ORDER BY created_at OFFSET 2 LIMIT 1), (SELECT id FROM user_data WHERE alias='m05'), 'text', '你好,很高兴认识你!', 'sent', 'normal', '2026-06-10T10:00:00Z');
-- update last_message_at
UPDATE conversations SET last_message_at = (SELECT MAX(created_at) FROM messages WHERE messages.conversation_id = conversations.id);
-- ============================================================
-- 9. 推荐记录
-- ====================================================
WITH f01 AS (SELECT id FROM user_data WHERE alias='f01'), f03 AS (SELECT id FROM user_data WHERE alias='f03'),
f05 AS (SELECT id FROM user_data WHERE alias='f05'),
m01 AS (SELECT id FROM user_data WHERE alias='m01'), m03 AS (SELECT id FROM user_data WHERE alias='m03'),
m05 AS (SELECT id FROM user_data WHERE alias='m05'), m06 AS (SELECT id FROM user_data WHERE alias='m06')
INSERT INTO recommendation_records (id, user_id, target_user_id, source, score, level, shown_at, action, action_at, rule_version)
VALUES
(gen_random_uuid(), (SELECT id FROM f01), (SELECT id FROM m01), 'daily', 82.50, 'high', '2026-05-28T10:00:00Z', 'liked', '2026-06-01T10:00:00Z', 1),
(gen_random_uuid(), (SELECT id FROM f01), (SELECT id FROM m03), 'daily', 70.00, 'medium', '2026-05-28T10:00:00Z', 'passed','2026-05-28T10:01:00Z', 1),
(gen_random_uuid(), (SELECT id FROM m01), (SELECT id FROM f01), 'daily', 85.00, 'high', '2026-05-28T11:00:00Z', 'liked', '2026-06-01T10:05:00Z', 1),
(gen_random_uuid(), (SELECT id FROM f03), (SELECT id FROM m03), 'daily', 78.00, 'high', '2026-06-01T09:00:00Z', 'liked', '2026-06-03T09:30:00Z', 1),
(gen_random_uuid(), (SELECT id FROM m03), (SELECT id FROM f03), 'daily', 75.00, 'high', '2026-06-01T09:30:00Z', 'liked', '2026-06-03T09:30:00Z', 1),
(gen_random_uuid(), (SELECT id FROM f05), (SELECT id FROM m05), 'daily', 88.00, 'high', '2026-06-01T10:00:00Z', 'liked', '2026-06-05T10:00:00Z', 1),
(gen_random_uuid(), (SELECT id FROM m05), (SELECT id FROM f05), 'daily', 86.00, 'high', '2026-06-01T10:30:00Z', 'liked', '2026-06-05T10:05:00Z', 1),
(gen_random_uuid(), (SELECT id FROM m06), (SELECT id FROM f01), 'daily', 62.00, 'medium','2026-06-06T14:00:00Z', 'liked', '2026-06-06T14:00:00Z', 1);
-- ============================================================
-- 10. 相亲活动
-- ====================================================
WITH women_org AS (SELECT id FROM organizations WHERE type='women_federation' LIMIT 1),
trade_org AS (SELECT id FROM organizations WHERE type='trade_union' LIMIT 1),
mgr AS (SELECT id FROM operators WHERE username='activitymgr' LIMIT 1)
INSERT INTO activities (id, title, description, organizer_org_id, coorganizer_text,
start_at, end_at, location_name, location_address,
male_limit, female_limit, total_limit, min_age, max_age,
registration_start_at, registration_end_at, need_review, status, created_by)
VALUES
(gen_random_uuid(), '丹阳公益单身联谊会(夏季场)',
'面向丹阳市区及周边乡镇的单身青年,由妇联、工会联合主办。',
(SELECT id FROM women_org), '丹阳市总工会、丹阳市慈善基金会',
'2026-08-15T14:00:00Z', '2026-08-15T17:30:00Z', '丹阳市文化馆多功能厅', '丹阳市丹北路168号',
15, 15, 30, 22, 40, '2026-07-01T00:00:00Z', '2026-08-10T23:59:59Z', true, 'registration_open', (SELECT id FROM mgr)),
(gen_random_uuid(), '七夕特别活动·丹阳缘来是你',
'七夕节特别策划,浪漫主题相亲活动。',
(SELECT id FROM trade_org), '丹阳市新时代文明实践中心',
'2026-08-29T15:00:00Z', '2026-08-29T18:00:00Z', '丹阳大剧院报告厅', '丹阳市书院路28号',
20, 20, 40, 25, 45, '2026-08-01T00:00:00Z', '2026-08-25T23:59:59Z', true, 'draft', (SELECT id FROM mgr));
-- ============================================================
-- 11. 活动报名
-- ====================================================
WITH act1 AS (SELECT id FROM activities WHERE title LIKE '夏季%' LIMIT 1),
mgr2 AS (SELECT id FROM operators WHERE username='activitymgr' LIMIT 1)
INSERT INTO activity_registrations (id, activity_id, user_id, status, registered_at, reviewed_by, reviewed_at, checkin_status)
SELECT gen_random_uuid(), (SELECT id FROM act1), ud.id,
CASE ud.alias WHEN 'f01' THEN 'approved' WHEN 'f02' THEN 'pending' WHEN 'f03' THEN 'approved'
WHEN 'f04' THEN 'rejected' WHEN 'f05' THEN 'approved' WHEN 'm01' THEN 'approved'
WHEN 'm02' THEN 'approved' WHEN 'm03' THEN 'approved' WHEN 'm05' THEN 'approved' END,
NOW()-INTERVAL '30 days',
CASE WHEN ud.alias='f02' THEN NULL ELSE (SELECT id FROM mgr2) END,
CASE WHEN ud.alias='f02' THEN NULL ELSE NOW()-INTERVAL '29 days' END,
'not_checked_in'
FROM user_data ud WHERE ud.alias IN ('f01','f02','f03','f04','f05','m01','m02','m03','m05');
-- ============================================================
-- 12. 活动互选意向
-- ====================================================
WITH act1 AS (SELECT id FROM activities WHERE title LIKE '夏季%' LIMIT 1)
INSERT INTO activity_interests (id, source_user_id, target_user_id, activity_id, status, confirmed_at, created_at)
SELECT gen_random_uuid(),
(SELECT id FROM user_data WHERE alias='f01'), (SELECT id FROM user_data WHERE alias='m01'), (SELECT id FROM act1), 'mutual', '2026-08-15T17:00:00Z', '2026-08-15T17:00:00Z'
UNION ALL SELECT gen_random_uuid(),
(SELECT id FROM user_data WHERE alias='f03'), (SELECT id FROM user_data WHERE alias='m03'), (SELECT id FROM act1), 'mutual', '2026-08-15T17:05:00Z', '2026-08-15T17:05:00Z'
UNION ALL SELECT gen_random_uuid(),
(SELECT id FROM user_data WHERE alias='f05'), (SELECT id FROM user_data WHERE alias='m05'), (SELECT id FROM act1), 'expressed','2026-08-15T17:10:00Z', '2026-08-15T17:10:00Z';
-- ============================================================
-- 13. 红娘服务
-- ====================================================
WITH mh_op AS (SELECT id FROM operators WHERE username='wanghongniang' LIMIT 1),
women_org AS (SELECT id FROM organizations WHERE type='women_federation' LIMIT 1),
charity_org AS (SELECT id FROM organizations WHERE type='charity_center' LIMIT 1)
INSERT INTO matchmaker_services (id, user_id, service_type, description, status, organization_id, assigned_operator_id, assigned_at, completed_at)
VALUES
(gen_random_uuid(), (SELECT id FROM user_data WHERE alias='f02'), 'recommend_partner', '离异用户希望找到合适的伴侣', 'in_service', (SELECT id FROM women_org), (SELECT id FROM mh_op), '2026-06-20T10:00:00Z', NULL),
(gen_random_uuid(), (SELECT id FROM user_data WHERE alias='f06'), 'no_match_help', '丧偶用户希望重新融入社交', 'waiting_user', (SELECT id FROM charity_org), (SELECT id FROM mh_op), '2026-06-25T14:00:00Z', NULL),
(gen_random_uuid(), (SELECT id FROM user_data WHERE alias='f04'), 'review_preference', '用户希望调整择偶条件', 'completed', (SELECT id FROM women_org), (SELECT id FROM mh_op), '2026-06-15T09:00:00Z', '2026-06-20T11:00:00Z');
-- 红娘推荐
WITH ms_f02 AS (SELECT id FROM matchmaker_services WHERE user_id=(SELECT id FROM user_data WHERE alias='f02') LIMIT 1),
mh_op2 AS (SELECT id FROM operators WHERE username='wanghongniang' LIMIT 1)
INSERT INTO matchmaker_recommendations (id, service_id, user_id, target_user_id, operator_id, reason, status, created_at, viewed_at, responded_at)
VALUES (gen_random_uuid(), (SELECT id FROM ms_f02), (SELECT id FROM user_data WHERE alias='f02'), (SELECT id FROM user_data WHERE alias='m02'), (SELECT id FROM mh_op2),
'两人同在丹阳工作,年龄相仿,都离过婚有共同语言', 'viewed', '2026-06-21T10:00:00Z', '2026-06-22T09:00:00Z', NULL);
-- 红娘跟进
WITH ms_f02_2 AS (SELECT id FROM matchmaker_services WHERE user_id=(SELECT id FROM user_data WHERE alias='f02') LIMIT 1),
ms_f04 AS (SELECT id FROM matchmaker_services WHERE user_id=(SELECT id FROM user_data WHERE alias='f04') LIMIT 1),
mh_op3 AS (SELECT id FROM operators WHERE username='wanghongniang' LIMIT 1)
INSERT INTO matchmaker_followups (id, service_id, operator_id, followup_type, content, result_code, next_followup_at, created_at)
VALUES
(gen_random_uuid(), (SELECT id FROM ms_f02_2), (SELECT id FROM mh_op3), 'phone_call', '电话沟通用户情况,了解离异原因及择偶期望', '正常', '2026-07-01T10:00:00Z', '2026-06-22T10:00:00Z'),
(gen_random_uuid(), (SELECT id FROM ms_f04), (SELECT id FROM mh_op3), 'face_to_face','面对面交流,帮助用户调整身高要求', '已调整', NULL, '2026-06-18T15:00:00Z');
-- ============================================================
-- 14. 系统通知
-- ====================================================
INSERT INTO notifications (id, user_id, type, title, content, business_type, read_status, created_at)
SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='f01'), 'match', '你们互相喜欢!', '张伟也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-01T10:05:00Z'
UNION ALL SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='m01'), 'match', '你们互相喜欢!', '小芳也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-01T10:05:00Z'
UNION ALL SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='f03'), 'match', '你们互相喜欢!', '王磊也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-03T09:30:00Z'
UNION ALL SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='m03'), 'match', '你们互相喜欢!', '婷婷也喜欢了你,可以开始聊天啦~', 'match', 'unread','2026-06-03T09:30:00Z'
UNION ALL SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='f05'), 'match', '你们互相喜欢!', '孙浩也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-05T10:05:00Z'
UNION ALL SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='m05'), 'match', '你们互相喜欢!', '慧琴也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-05T10:05:00Z'
UNION ALL SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='f05'), 'system', '恭喜牵手成功!', '您与孙浩已成功牵手,祝你们幸福!', 'match', 'read', '2026-07-01T10:30:00Z'
UNION ALL SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='m05'), 'system', '恭喜牵手成功!', '您与慧琴已成功牵手,祝你们幸福!', 'match', 'read', '2026-07-01T10:30:00Z'
UNION ALL SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='f01'), 'activity', '活动报名已确认', '您已成功报名「丹阳公益单身联谊会」', 'activity', 'read', '2026-07-05T10:30:00Z'
UNION ALL SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='f05'), 'activity', '活动报名已确认', '您已成功报名「丹阳公益单身联谊会」', 'activity', 'unread','2026-07-07T09:20:00Z'
UNION ALL SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='f02'), 'matchmaker', '红娘已为您服务', '您的红娘服务申请已被分配,红娘小王将在24小时内与您联系', 'matchmaker', 'read', '2026-06-20T10:30:00Z';
-- ============================================================
-- 15. 同意记录
-- ====================================================
INSERT INTO consent_records (id, user_id, type, version, agreed_at, ip_address, user_agent)
SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='f01'), 'terms_of_service', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'
UNION ALL SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='f01'), 'privacy_policy', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'
UNION ALL SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='m01'), 'terms_of_service', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0'
UNION ALL SELECT gen_random_uuid(), (SELECT id FROM user_data WHERE alias='m01'), 'privacy_policy', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0';
-- ============================================================
-- 16. 审核原因字典
-- ====================================================
INSERT INTO review_reasons (code, name, category, enabled, sort_order)
VALUES
('profile_incomplete', '资料不完整', 'quality', true, 1),
('photo_unclear', '照片不清晰', 'quality', true, 2),
('fake_info', '信息疑似虚假', 'trust', true, 3),
('inappropriate_photo', '照片内容不当', 'safety', true, 4),
('duplicate_identity', '重复注册', 'duplicate', true, 5),
('suspicious_behavior', '行为异常', 'risk', true, 6),
('manual_review_needed', '需人工复核', 'quality', true, 7)
ON CONFLICT (code) DO NOTHING;
SET session_replication_role = 'origin';
DROP TABLE IF EXISTS _conv_result;
-- ============================================================
-- V1.1 Feature Flag 初始化
-- ============================================================
INSERT INTO system_configs (config_key, config_value, description) VALUES
('livenessVerification.enabled', 'false', '人脸核验功能开关(V1.1预留,默认关闭)'),
('localEligibility.evidencePolicy', 'need_based', '本地资格佐证策略:need_based=按需触发 / mandatory=全部强制'),
('counseling.enabled', 'true', '婚恋咨询功能开关'),
('premarital.enabled', 'true', '婚前辅导功能开关'),
('serviceLocation.enabled', 'true', '善缘服务站功能开关'),
('content.enabled', 'true', '内容中心功能开关'),
('localEligibility.enabled', 'true', '本地资格功能开关'),
('banner.maxActiveCount', '5', 'Banner最大活跃数量')
ON CONFLICT (config_key) DO NOTHING;
-- ============================================================
-- 验证
-- ====================================================
DO $$
DECLARE
u_cnt INTEGER; op_cnt INTEGER; m_cnt INTEGER; a_cnt INTEGER; r_cnt INTEGER; n_cnt INTEGER; p_cnt INTEGER;
BEGIN
SELECT COUNT(*) INTO u_cnt FROM users WHERE deleted_at IS NULL;
SELECT COUNT(*) INTO op_cnt FROM operators;
SELECT COUNT(*) INTO m_cnt FROM matches;
SELECT COUNT(*) INTO a_cnt FROM activities WHERE deleted_at IS NULL;
SELECT COUNT(*) INTO r_cnt FROM user_relations;
SELECT COUNT(*) INTO n_cnt FROM notifications;
SELECT COUNT(*) INTO p_cnt FROM user_profiles;
RAISE NOTICE '========================================';
RAISE NOTICE '✅ Demo 数据填充完成!';
RAISE NOTICE '========================================';
RAISE NOTICE ' 用户: %人 | 资料: %条 | 操作员: %人', u_cnt, p_cnt, op_cnt;
RAISE NOTICE ' Match: %对 | 关系: %条 | 活动: %个 | 通知: %条', m_cnt, r_cnt, a_cnt, n_cnt;
RAISE NOTICE '========================================';
END $$;
COMMIT;
@@ -0,0 +1,463 @@
-- ============================================================
-- 丹阳公益婚恋服务平台 — Demo Seed 数据脚本 v2
-- 版本: 1.0.0-RC.2
-- 说明: 所有 id 使用真实 UUID 格式(36字符含连字符)
-- 执行: psql -U postgres -d danyang_match -f demo-seed-v2.sql
-- ============================================================
SET session_replication_role = 'replica';
-- ============================================================
-- 1. 组织
-- ============================================================
INSERT INTO organizations (id, name, type, contact_name, status) VALUES
(gen_random_uuid(), '丹阳市妇女联合会', 'women_federation', '张丽华', 'active'),
(gen_random_uuid(), '丹阳市总工会', 'trade_union', '李明远', 'active'),
(gen_random_uuid(), '丹阳市慈善基金会', 'charity_center', '王秀英', 'active');
-- 取回生成的 org id
WITH org_ids AS (
SELECT id FROM organizations ORDER BY created_at LIMIT 1
),
org2 AS (
SELECT id FROM organizations WHERE id NOT IN (SELECT id FROM org_ids) ORDER BY created_at LIMIT 1
),
org3 AS (
SELECT id FROM organizations WHERE id NOT IN (SELECT id FROM org_ids, org2) ORDER BY created_at LIMIT 1
)
SELECT 'org-women' as org1_placeholder, 'org-trade' as org2_placeholder, 'org-charity' as org3_placeholder
INTO TEMP TABLE _org_placeholders;
-- ============================================================
-- 2. 工作人员(BCrypt hash of "demo123")
-- ============================================================
INSERT INTO operators (id, organization_id, name, username, password_hash, status) VALUES
(gen_random_uuid(), (SELECT id FROM organizations WHERE type='women_federation' LIMIT 1), '陈主任', 'admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'),
(gen_random_uuid(), (SELECT id FROM organizations WHERE type='women_federation' LIMIT 1), '红娘小王', 'wanghongniang','$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'),
(gen_random_uuid(), (SELECT id FROM organizations WHERE type='charity_center' LIMIT 1), '审核员小张', 'reviewer01', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'),
(gen_random_uuid(), (SELECT id FROM organizations WHERE type='trade_union' LIMIT 1), '活动管理员赵', 'activitymgr','$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active');
INSERT INTO operator_roles (operator_id, role_id) VALUES
((SELECT id FROM operators WHERE username='admin'), '00000000-0000-0000-0000-000000000001'),
((SELECT id FROM operators WHERE username='admin'), '00000000-0000-0000-0000-000000000002'),
((SELECT id FROM operators WHERE username='wanghongniang'), '00000000-0000-0000-0000-000000000005'),
((SELECT id FROM operators WHERE username='wanghongniang'), '00000000-0000-0000-0000-000000000006'),
((SELECT id FROM operators WHERE username='reviewer01'), '00000000-0000-0000-0000-000000000004'),
((SELECT id FROM operators WHERE username='reviewer01'), '00000000-0000-0000-0000-000000000007'),
((SELECT id FROM operators WHERE username='activitymgr'), '00000000-0000-0000-0000-000000000006'),
((SELECT id FROM operators WHERE username='activitymgr'), '00000000-0000-0000-0000-000000000008');
-- ============================================================
-- 3. Demo 用户 — 12人(6女6男),ID 使用字符串但不含连字符(VARCHAR(36)兼容)
-- ============================================================
-- 注意:users.id 是 VARCHAR(36),我们使用短UUID格式(32位hex无连字符)
INSERT INTO users (id, wechat_openid, phone, account_status, relationship_status, recommendation_enabled, created_at) VALUES
('f01a2b3c4d5e6f70000000000000001', 'demo_openid_f01', NULL, 'normal', 'searching', true, '2026-03-15T10:00:00Z'),
('f02a2b3c4d5e6f70000000000000002', 'demo_openid_f02', NULL, 'normal', 'searching', true, '2026-03-20T14:30:00Z'),
('f03a2b3c4d5e6f70000000000000003', 'demo_openid_f03', NULL, 'normal', 'searching', true, '2026-04-01T09:15:00Z'),
('f04a2b3c4d5e6f70000000000000004', 'demo_openid_f04', NULL, 'normal', 'paused', true, '2026-04-10T16:00:00Z'),
('f05a2b3c4d5e6f70000000000000005', 'demo_openid_f05', NULL, 'normal', 'searching', true, '2026-05-01T11:20:00Z'),
('f06a2b3c4d5e6f70000000000000006', 'demo_openid_f06', NULL, 'normal', 'searching', true, '2026-05-15T08:45:00Z'),
('m01a2b3c4d5e6f70000000000000001', 'demo_openid_m01', NULL, 'normal', 'searching', true, '2026-03-10T09:00:00Z'),
('m02a2b3c4d5e6f70000000000000002', 'demo_openid_m02', NULL, 'normal', 'getting_to_know', true, '2026-03-25T13:00:00Z'),
('m03a2b3c4d5e6f70000000000000003', 'demo_openid_m03', NULL, 'normal', 'searching', true, '2026-04-05T15:30:00Z'),
('m04a2b3c4d5e6f70000000000000004', 'demo_openid_m04', NULL, 'normal', 'searching', true, '2026-04-20T10:00:00Z'),
('m05a2b3c4d5e6f70000000000000005', 'demo_openid_m05', NULL, 'normal', 'matched_successfully', true, '2026-05-01T14:00:00Z'),
('m06a2b3c4d5e6f70000000000000006', 'demo_openid_m06', NULL, 'normal', 'searching', true, '2026-05-10T16:30:00Z');
-- ============================================================
-- 4. 用户资料
-- ============================================================
INSERT INTO user_profiles (
user_id, display_name, gender, birth_date, height_cm,
region_code, region_name, marital_status, children_status,
education_code, occupation_code, smoking_status, drinking_status,
long_term_danyang, future_danyang, relationship_goal, profile_completion, profile_status
) VALUES
('f01a2b3c4d5e6f70000000000000001', '小芳', 'female', '1995-06-15', 162, '321181', '丹阳', 'never_married', 'none', 'bachelor', 'clerical', 'never', 'sometimes', '是', '是', '结婚', 90, 'approved'),
('f02a2b3c4d5e6f70000000000000002', '晓燕', 'female', '1993-09-20', 165, '321181', '丹阳', 'divorced', 'none', 'college', 'teacher', 'never', 'never', '是', '是', '结婚', 95, 'approved'),
('f03a2b3c4d5e6f70000000000000003', '婷婷', 'female', '1998-02-10', 158, '321100', '镇江', 'never_married', 'none', 'master', 'designer', 'sometimes', 'often', '是', '否', '恋爱', 85, 'approved'),
('f04a2b3c4d5e6f70000000000000004', '美玲', 'female', '1990-11-05', 160, '321181', '丹阳', 'never_married', 'none', 'senior_high', 'factory', 'never', 'never', '是', '是', '结婚', 70, 'approved'),
('f05a2b3c4d5e6f70000000000000005', '慧琴', 'female', '1996-07-22', 163, '321181', '丹阳', 'never_married', 'none', 'bachelor', 'nurse', 'never', 'sometimes','是', '是', '结婚', 92, 'approved'),
('f06a2b3c4d5e6f70000000000000006', '秀英', 'female', '1992-04-18', 157, '321181', '丹阳', 'widowed', 'none', 'junior_high','farmer', 'often', 'often', '是', '是', '结婚', 60, 'approved'),
('m01a2b3c4d5e6f70000000000000001', '张伟', 'male', '1992-01-10', 175, '321181', '丹阳', 'never_married', 'none', 'bachelor', 'engineer', 'never', 'sometimes','是', '是', '结婚', 88, 'approved'),
('m02a2b3c4d5e6f70000000000000002', '李强', 'male', '1990-08-25', 178, '321181', '丹阳', 'divorced', 'none', 'master', 'manager', 'sometimes', 'often', '是', '是', '结婚', 95, 'approved'),
('m03a2b3c4d5e6f70000000000000003', '王磊', 'male', '1997-12-03', 180, '321100', '镇江', 'never_married', 'none', 'college', 'programmer', 'never', 'never', '是', '是', '恋爱', 82, 'approved'),
('m04a2b3c4d5e6f70000000000000004', '赵明', 'male', '1988-05-30', 172, '321181', '丹阳', 'never_married', 'none', 'senior_high','sales', 'often', 'often', '否', '是', '结婚', 75, 'approved'),
('m05a2b3c4d5e6f70000000000000005', '孙浩', 'male', '1994-03-14', 182, '321181', '丹阳', 'never_married', 'none', 'bachelor', 'doctor', 'never', 'sometimes','是', '是', '结婚', 97, 'approved'),
('m06a2b3c4d5e6f70000000000000006', '周洋', 'male', '1999-08-08', 176, '320500', '苏州', 'never_married', 'none', 'master', 'researcher', 'never', 'never', '是', '否', '恋爱', 80, 'approved');
-- ============================================================
-- 5. 用户择偶偏好
-- ============================================================
INSERT INTO user_preferences (
user_id, min_age, max_age, age_priority,
min_height_cm, max_height_cm, height_priority,
region_scope, region_priority,
marital_statuses, marital_priority,
min_education_code, education_priority
) VALUES
('f01a2b3c4d5e6f70000000000000001', 28, 38, 'required', 170, 185, 'required',
'["321181","321100"]', 'required', '["never_married"]', 'required', 'bachelor', 'preferred'),
('f02a2b3c4d5e6f70000000000000002', 28, 40, 'required', 170, 188, 'required',
'["321181"]', 'required', '["never_married","divorced"]', 'preferred', 'college', 'preferred'),
('f03a2b3c4d5e6f70000000000000003', 25, 35, 'preferred', 172, 185, 'preferred',
'["321181","321100","320500"]', 'preferred', '["never_married"]', 'required', NULL, NULL),
('f04a2b3c4d5e6f70000000000000004', 30, 45, 'required', 168, 185, 'required',
'["321181"]', 'required', '["never_married","divorced"]', 'preferred', 'senior_high', 'preferred'),
('f05a2b3c4d5e6f70000000000000005', 27, 36, 'required', 172, 186, 'required',
'["321181","321100"]', 'preferred', '["never_married"]', 'required', 'bachelor', 'preferred'),
('f06a2b3c4d5e6f70000000000000006', 30, 50, 'required', 165, 185, 'required',
'["321181"]', 'required', '["never_married","divorced","widowed"]', 'preferred', NULL, NULL),
('m01a2b3c4d5e6f70000000000000001', 22, 32, 'required', 155, 170, 'preferred',
'["321181","321100"]', 'required', '["never_married"]', 'required', 'junior_high', 'preferred'),
('m02a2b3c4d5e6f70000000000000002', 25, 38, 'preferred', 158, 172, 'preferred',
'["321181"]', 'preferred', '["never_married","divorced"]', 'preferred', 'college', 'preferred'),
('m03a2b3c4d5e6f70000000000000003', 22, 30, 'preferred', 155, 168, 'preferred',
'["321181","321100","320500"]', 'preferred', '["never_married"]', 'required', 'college', 'preferred'),
('m04a2b3c4d5e6f70000000000000004', 25, 40, 'preferred', 155, 170, 'preferred',
'["321181"]', 'required', '["never_married","divorced"]', 'preferred', NULL, NULL),
('m05a2b3c4d5e6f70000000000000005', 23, 33, 'required', 158, 170, 'preferred',
'["321181","321100"]', 'preferred', '["never_married"]', 'required', 'bachelor', 'preferred'),
('m06a2b3c4d5e6f70000000000000006', 22, 32, 'preferred', 155, 170, 'preferred',
'["321181","321100","320500"]', 'preferred', '["never_married"]', 'required', 'master', 'preferred');
-- ============================================================
-- 6. 实名认证(user_identities)— mock
-- ============================================================
INSERT INTO user_identities (
id, user_id, real_name_enc, id_number_enc, id_number_hash,
gender, birth_date, verification_status, provider, verified_at
) VALUES
(gen_random_uuid(), 'f01a2b3c4d5e6f70000000000000001', E'\\xenc_f01', E'\\xenc_id_f01', 'sha256_f01_demo_hash', 'female', '1995-06-15', 'verified', 'mock', '2026-03-16T10:00:00Z'),
(gen_random_uuid(), 'f02a2b3c4d5e6f70000000000000002', E'\\xenc_f02', E'\\xenc_id_f02', 'sha256_f02_demo_hash', 'female', '1993-09-20', 'verified', 'mock', '2026-03-21T14:30:00Z'),
(gen_random_uuid(), 'f03a2b3c4d5e6f70000000000000003', E'\\xenc_f03', E'\\xenc_id_f03', 'sha256_f03_demo_hash', 'female', '1998-02-10', 'verified', 'mock', '2026-04-02T09:15:00Z'),
(gen_random_uuid(), 'f04a2b3c4d5e6f70000000000000004', E'\\xenc_f04', E'\\xenc_id_f04', 'sha256_f04_demo_hash', 'female', '1990-11-05', 'verified', 'mock', '2026-04-11T16:00:00Z'),
(gen_random_uuid(), 'f05a2b3c4d5e6f70000000000000005', E'\\xenc_f05', E'\\xenc_id_f05', 'sha256_f05_demo_hash', 'female', '1996-07-22', 'verified', 'mock', '2026-05-02T11:20:00Z'),
(gen_random_uuid(), 'f06a2b3c4d5e6f70000000000000006', E'\\xenc_f06', E'\\xenc_id_f06', 'sha256_f06_demo_hash', 'female', '1992-04-18', 'verified', 'mock', '2026-05-16T08:45:00Z'),
(gen_random_uuid(), 'm01a2b3c4d5e6f70000000000000001', E'\\xenc_m01', E'\\xenc_id_m01', 'sha256_m01_demo_hash', 'male', '1992-01-10', 'verified', 'mock', '2026-03-11T09:00:00Z'),
(gen_random_uuid(), 'm02a2b3c4d5e6f70000000000000002', E'\\xenc_m02', E'\\xenc_id_m02', 'sha256_m02_demo_hash', 'male', '1990-08-25', 'verified', 'mock', '2026-03-26T13:00:00Z'),
(gen_random_uuid(), 'm03a2b3c4d5e6f70000000000000003', E'\\xenc_m03', E'\\xenc_id_m03', 'sha256_m03_demo_hash', 'male', '1997-12-03', 'verified', 'mock', '2026-04-06T15:30:00Z'),
(gen_random_uuid(), 'm04a2b3c4d5e6f70000000000000004', E'\\xenc_m04', E'\\xenc_id_m04', 'sha256_m04_demo_hash', 'male', '1988-05-30', 'verified', 'mock', '2026-04-21T10:00:00Z'),
(gen_random_uuid(), 'm05a2b3c4d5e6f70000000000000005', E'\\xenc_m05', E'\\xenc_id_m05', 'sha256_m05_demo_hash', 'male', '1994-03-14', 'verified', 'mock', '2026-05-02T14:00:00Z'),
(gen_random_uuid(), 'm06a2b3c4d5e6f70000000000000006', E'\\xenc_m06', E'\\xenc_id_m06', 'sha256_m06_demo_hash', 'male', '1999-08-08', 'verified', 'mock', '2026-05-11T16:30:00Z');
-- ============================================================
-- 7. 兴趣标签
-- ============================================================
INSERT INTO user_interests (user_id, interest_code) VALUES
('f01a2b3c4d5e6f70000000000000001', 'reading'), ('f01a2b3c4d5e6f70000000000000001', 'cooking'), ('f01a2b3c4d5e6f70000000000000001', 'travel'),
('f02a2b3c4d5e6f70000000000000002', 'sports'), ('f02a2b3c4d5e6f70000000000000002', 'music'), ('f02a2b3c4d5e6f70000000000000002', 'outdoor'),
('f03a2b3c4d5e6f70000000000000003', 'photography'), ('f03a2b3c4d5e6f70000000000000003', 'dance'), ('f03a2b3c4d5e6f70000000000000003', 'movie'),
('f04a2b3c4d5e6f70000000000000004', 'pets'), ('f04a2b3c4d5e6f70000000000000004', 'cooking'),
('f05a2b3c4d5e6f70000000000000005', 'reading'), ('f05a2b3c4d5e6f70000000000000005', 'fitness'), ('f05a2b3c4d5e6f70000000000000005', 'charity'),
('f06a2b3c4d5e6f70000000000000006', 'gardening'), ('f06a2b3c4d5e6f70000000000000006', 'cooking'),
('m01a2b3c4d5e6f70000000000000001', 'sports'), ('m01a2b3c4d5e6f70000000000000001', 'gaming'), ('m01a2b3c4d5e6f70000000000000001', 'travel'),
('m02a2b3c4d5e6f70000000000000002', 'reading'), ('m02a2b3c4d5e6f70000000000000002', 'investment'), ('m02a2b3c4d5e6f70000000000000002', 'hiking'),
('m03a2b3c4d5e6f70000000000000003', 'gaming'), ('m03a2b3c4d5e6f70000000000000003', 'music'), ('m03a2b3c4d5e6f70000000000000003', 'coding'),
('m04a2b3c4d5e6f70000000000000004', 'cars'), ('m04a2b3c4d5e6f70000000000000004', 'cooking'),
('m05a2b3c4d5e6f70000000000000005', 'running'), ('m05a2b3c4d5e6f70000000000000005', 'reading'), ('m05a2b3c4d5e6f70000000000000005', 'charity'),
('m06a2b3c4d5e6f70000000000000006', 'research'), ('m06a2b3c4d5e6f70000000000000006', 'travel'), ('m06a2b3c4d5e6f70000000000000006', 'photography');
-- ============================================================
-- 8. 隐私设置
-- ============================================================
INSERT INTO user_privacy_settings (user_id, visible_in_recommendations, visible_in_search, show_occupation, show_lifestyle_photos, receive_activity_recommendations, accept_matchmaker_recommendations) VALUES
('f01a2b3c4d5e6f70000000000000001', true, true, true, true, true, true),
('f02a2b3c4d5e6f70000000000000002', true, true, true, false, true, true),
('f03a2b3c4d5e6f70000000000000003', true, false, true, true, true, false),
('f04a2b3c4d5e6f70000000000000004', true, true, false, true, true, true),
('f05a2b3c4d5e6f70000000000000005', true, true, true, true, false, true),
('f06a2b3c4d5e6f70000000000000006', true, false, true, true, true, true),
('m01a2b3c4d5e6f70000000000000001', true, true, true, true, true, true),
('m02a2b3c4d5e6f70000000000000002', true, true, true, false, true, true),
('m03a2b3c4d5e6f70000000000000003', true, true, true, true, true, false),
('m04a2b3c4d5e6f70000000000000004', true, false, true, true, true, true),
('m05a2b3c4d5e6f70000000000000005', true, true, true, true, true, true),
('m06a2b3c4d5e6f70000000000000006', true, true, true, true, true, true);
-- ============================================================
-- 9. 照片(user_photos)
-- ============================================================
INSERT INTO user_photos (id, user_id, file_key, photo_type, sort_order, review_status) VALUES
(gen_random_uuid(), 'f01a2b3c4d5e6f70000000000000001', 'photos/demo/f01/avatar.jpg', 'avatar', 0, 'approved'),
(gen_random_uuid(), 'f01a2b3c4d5e6f70000000000000001', 'photos/demo/f01/lifestyle1.jpg','lifestyle',1, 'approved'),
(gen_random_uuid(), 'f01a2b3c4d5e6f70000000000000001', 'photos/demo/f01/lifestyle2.jpg','lifestyle',2, 'approved'),
(gen_random_uuid(), 'f02a2b3c4d5e6f70000000000000002', 'photos/demo/f02/avatar.jpg', 'avatar', 0, 'approved'),
(gen_random_uuid(), 'f02a2b3c4d5e6f70000000000000002', 'photos/demo/f02/lifestyle1.jpg','lifestyle',1, 'approved'),
(gen_random_uuid(), 'f03a2b3c4d5e6f70000000000000003', 'photos/demo/f03/avatar.jpg', 'avatar', 0, 'approved'),
(gen_random_uuid(), 'f03a2b3c4d5e6f70000000000000003', 'photos/demo/f03/lifestyle1.jpg','lifestyle',1, 'approved'),
(gen_random_uuid(), 'f03a2b3c4d5e6f70000000000000003', 'photos/demo/f03/lifestyle2.jpg','lifestyle',2, 'approved'),
(gen_random_uuid(), 'f04a2b3c4d5e6f70000000000000004', 'photos/demo/f04/avatar.jpg', 'avatar', 0, 'approved'),
(gen_random_uuid(), 'f05a2b3c4d5e6f70000000000000005', 'photos/demo/f05/avatar.jpg', 'avatar', 0, 'approved'),
(gen_random_uuid(), 'f05a2b3c4d5e6f70000000000000005', 'photos/demo/f05/lifestyle1.jpg','lifestyle',1, 'approved'),
(gen_random_uuid(), 'f06a2b3c4d5e6f70000000000000006', 'photos/demo/f06/avatar.jpg', 'avatar', 0, 'approved'),
(gen_random_uuid(), 'm01a2b3c4d5e6f70000000000000001', 'photos/demo/m01/avatar.jpg', 'avatar', 0, 'approved'),
(gen_random_uuid(), 'm01a2b3c4d5e6f70000000000000001', 'photos/demo/m01/lifestyle1.jpg','lifestyle',1, 'approved'),
(gen_random_uuid(), 'm01a2b3c4d5e6f70000000000000001', 'photos/demo/m01/lifestyle2.jpg','lifestyle',2, 'approved'),
(gen_random_uuid(), 'm02a2b3c4d5e6f70000000000000002', 'photos/demo/m02/avatar.jpg', 'avatar', 0, 'approved'),
(gen_random_uuid(), 'm02a2b3c4d5e6f70000000000000002', 'photos/demo/m02/lifestyle1.jpg','lifestyle',1, 'approved'),
(gen_random_uuid(), 'm03a2b3c4d5e6f70000000000000003', 'photos/demo/m03/avatar.jpg', 'avatar', 0, 'approved'),
(gen_random_uuid(), 'm03a2b3c4d5e6f70000000000000003', 'photos/demo/m03/lifestyle1.jpg','lifestyle',1, 'approved'),
(gen_random_uuid(), 'm04a2b3c4d5e6f70000000000000004', 'photos/demo/m04/avatar.jpg', 'avatar', 0, 'approved'),
(gen_random_uuid(), 'm05a2b3c4d5e6f70000000000000005', 'photos/demo/m05/avatar.jpg', 'avatar', 0, 'approved'),
(gen_random_uuid(), 'm05a2b3c4d5e6f70000000000000005', 'photos/demo/m05/lifestyle1.jpg','lifestyle',1, 'approved'),
(gen_random_uuid(), 'm05a2b3c4d5e6f70000000000000005', 'photos/demo/m05/lifestyle2.jpg','lifestyle',2, 'approved'),
(gen_random_uuid(), 'm06a2b3c4d5e6f70000000000000006', 'photos/demo/m06/avatar.jpg', 'avatar', 0, 'approved');
-- ============================================================
-- 10. 审核任务
-- ============================================================
INSERT INTO review_tasks (id, user_id, review_type, status, assigned_operator_id, submitted_at, started_at, completed_at, final_comment, version) VALUES
(gen_random_uuid(), 'f01a2b3c4d5e6f70000000000000001', 'initial_profile', 'approved', (SELECT id FROM operators WHERE username='reviewer01'), '2026-03-15T11:00:00Z', '2026-03-15T11:30:00Z', '2026-03-15T12:00:00Z', '资料完整,信息真实', 1),
(gen_random_uuid(), 'f02a2b3c4d5e6f70000000000000002', 'initial_profile', 'approved', (SELECT id FROM operators WHERE username='reviewer01'), '2026-03-20T15:00:00Z', '2026-03-20T15:30:00Z', '2026-03-20T16:00:00Z', '资料完整', 1),
(gen_random_uuid(), 'f03a2b3c4d5e6f70000000000000003', 'initial_profile', 'approved', (SELECT id FROM operators WHERE username='reviewer01'), '2026-04-01T10:00:00Z', '2026-04-01T10:30:00Z', '2026-04-01T11:00:00Z', '资料完整', 1),
(gen_random_uuid(), 'm01a2b3c4d5e6f70000000000000001', 'initial_profile', 'approved', (SELECT id FROM operators WHERE username='reviewer01'), '2026-03-10T10:00:00Z', '2026-03-10T10:30:00Z', '2026-03-10T11:00:00Z', '资料完整', 1),
(gen_random_uuid(), 'm02a2b3c4d5e6f70000000000000002', 'initial_profile', 'approved', (SELECT id FROM operators WHERE username='reviewer01'), '2026-03-25T14:00:00Z', '2026-03-25T14:30:00Z', '2026-03-25T15:00:00Z', '资料完整', 1),
(gen_random_uuid(), 'm03a2b3c4d5e6f70000000000000003', 'initial_profile', 'approved', (SELECT id FROM operators WHERE username='reviewer01'), '2026-04-05T16:00:00Z', '2026-04-05T16:30:00Z', '2026-04-05T17:00:00Z', '资料完整', 1),
(gen_random_uuid(), 'm05a2b3c4d5e6f70000000000000005', 'initial_profile', 'approved', (SELECT id FROM operators WHERE username='reviewer01'), '2026-05-01T15:00:00Z', '2026-05-01T15:30:00Z', '2026-05-01T16:00:00Z', '资料完整', 1);
-- ============================================================
-- 11. 用户关系
-- ============================================================
INSERT INTO user_relations (id, user_id, target_user_id, relation_type, created_at) VALUES
(gen_random_uuid(), 'f01a2b3c4d5e6f70000000000000001', 'm01a2b3c4d5e6f70000000000000001', 'liked', '2026-06-01T10:00:00Z'),
(gen_random_uuid(), 'm01a2b3c4d5e6f70000000000000001', 'f01a2b3c4d5e6f70000000000000001', 'liked', '2026-06-01T10:05:00Z'),
(gen_random_uuid(), 'f02a2b3c4d5e6f70000000000000002', 'm02a2b3c4d5e6f70000000000000002', 'liked', '2026-06-02T14:00:00Z'),
(gen_random_uuid(), 'f03a2b3c4d5e6f70000000000000003', 'm03a2b3c4d5e6f70000000000000003', 'liked', '2026-06-03T09:00:00Z'),
(gen_random_uuid(), 'm03a2b3c4d5e6f70000000000000003', 'f03a2b3c4d5e6f70000000000000003', 'liked', '2026-06-03T09:30:00Z'),
(gen_random_uuid(), 'm04a2b3c4d5e6f70000000000000004', 'f02a2b3c4d5e6f70000000000000002', 'liked', '2026-06-04T11:00:00Z'),
(gen_random_uuid(), 'f04a2b3c4d5e6f70000000000000004', 'm04a2b3c4d5e6f70000000000000004', 'passed', '2026-06-04T12:00:00Z'),
(gen_random_uuid(), 'f05a2b3c4d5e6f70000000000000005', 'm05a2b3c4d5e6f70000000000000005', 'liked', '2026-06-05T10:00:00Z'),
(gen_random_uuid(), 'm05a2b3c4d5e6f70000000000000005', 'f05a2b3c4d5e6f70000000000000005', 'liked', '2026-06-05T10:05:00Z'),
(gen_random_uuid(), 'm06a2b3c4d5e6f70000000000000006', 'f01a2b3c4d5e6f70000000000000001', 'liked', '2026-06-06T14:00:00Z'),
(gen_random_uuid(), 'f04a2b3c4d5e6f70000000000000004', 'm06a2b3c4d5e6f70000000000000006', 'passed', '2026-06-06T15:00:00Z'),
(gen_random_uuid(), 'f06a2b3c4d5e6f70000000000000006', 'm04a2b3c4d5e6f70000000000000004', 'blocked', '2026-06-07T09:00:00Z'),
(gen_random_uuid(), 'm02a2b3c4d5e6f70000000000000002', 'f03a2b3c4d5e6f70000000000000003', 'passed', '2026-06-07T10:00:00Z');
-- ============================================================
-- 12. Match
-- ============================================================
INSERT INTO matches (id, user_a_id, user_b_id, status, source, matched_at) VALUES
(gen_random_uuid(), 'f01a2b3c4d5e6f70000000000000001', 'm01a2b3c4d5e6f70000000000000001', 'active', 'user_like', '2026-06-01T10:05:00Z'),
(gen_random_uuid(), 'f03a2b3c4d5e6f70000000000000003', 'm03a2b3c4d5e6f70000000000000003', 'active', 'user_like', '2026-06-03T09:30:00Z'),
(gen_random_uuid(), 'f05a2b3c4d5e6f70000000000000005', 'm05a2b3c4d5e6f70000000000000005', 'successful', 'user_like', '2026-06-05T10:05:00Z');
-- ============================================================
-- 13. 成功牵手请求
-- ============================================================
INSERT INTO relationship_success_requests (id, match_id, initiated_by, status, confirmed_by, created_at, resolved_at) VALUES
(gen_random_uuid(), (SELECT id FROM matches WHERE user_a_id='f05a2b3c4d5e6f70000000000000005'), 'f05a2b3c4d5e6f70000000000000005', 'confirmed', 'm05a2b3c4d5e6f70000000000000005', '2026-07-01T10:00:00Z', '2026-07-01T10:30:00Z'),
(gen_random_uuid(), (SELECT id FROM matches WHERE user_a_id='f01a2b3c4d5e6f70000000000000001'), 'f01a2b3c4d5e6f70000000000000001', 'pending', NULL, '2026-07-15T14:00:00Z', NULL);
-- ============================================================
-- 14. Conversations & Messages
-- ============================================================
INSERT INTO conversations (id, match_id, status, last_message_id, last_message_at) VALUES
(gen_random_uuid(), (SELECT id FROM matches WHERE user_a_id='f01a2b3c4d5e6f70000000000000001'), 'active', NULL, '2026-07-10T16:00:00Z'),
(gen_random_uuid(), (SELECT id FROM matches WHERE user_a_id='f03a2b3c4d5e6f70000000000000003'), 'active', NULL, '2026-07-08T20:00:00Z'),
(gen_random_uuid(), (SELECT id FROM matches WHERE user_a_id='f05a2b3c4d5e6f70000000000000005'), 'active', NULL, '2026-07-01T18:00:00Z');
-- 取回 conversation ids
WITH conv_ids AS (
SELECT id, match_id FROM conversations ORDER BY created_at
)
INSERT INTO conversation_members (conversation_id, user_id, last_read_message_id, unread_count, can_send, joined_at)
SELECT c.id, CASE WHEN m.user_a_id='f01a2b3c4d5e6f70000000000000001' OR m.user_a_id='f03a2b3c4d5e6f70000000000000003' OR m.user_a_id='f05a2b3c4d5e6f70000000000000005' THEN u else NULL end, NULL, 0, true, NOW()
FROM conv_ids c
JOIN matches m ON m.id = c.match_id
JOIN LATERAL (SELECT 'f01a2b3c4d5e6f70000000000000001' as uid UNION ALL SELECT 'm01a2b3c4d5e6f70000000000000001' UNION ALL SELECT 'f03a2b3c4d5e6f70000000000000003' UNION ALL SELECT 'm03a2b3c4d5e6f70000000000000003' UNION ALL SELECT 'f05a2b3c4d5e6f70000000000000005' UNION ALL SELECT 'm05a2b3c4d5e6f70000000000000005') u ON TRUE
WHERE (m.user_a_id='f01a2b3c4d5e6f70000000000000001' AND u.uid IN ('f01a2b3c4d5e6f70000000000000001','m01a2b3c4d5e6f70000000000000001'))
OR (m.user_a_id='f03a2b3c4d5e6f70000000000000003' AND u.uid IN ('f03a2b3c4d5e6f70000000000000003','m03a2b3c4d5e6f70000000000000003'))
OR (m.user_a_id='f05a2b3c4d5e6f70000000000000005' AND u.uid IN ('f05a2b3c4d5e6f70000000000000005','m05a2b3c4d5e6f70000000000000005'));
-- 简化的 conversation_members 插入
DELETE FROM conversation_members;
WITH conv AS (
SELECT id, match_id FROM conversations
), match_users AS (
SELECT c.id as conv_id, m.user_a_id, m.user_b_id
FROM conv c JOIN matches m ON m.id = c.match_id
)
INSERT INTO conversation_members (conversation_id, user_id, last_read_message_id, unread_count, can_send, joined_at)
SELECT mu.conv_id, mu.user_a_id, NULL, 0, true, NOW() FROM match_users mu
UNION ALL
SELECT mu.conv_id, mu.user_b_id, NULL, 0, true, NOW() FROM match_users mu;
INSERT INTO messages (id, conversation_id, sender_id, message_type, content, status, risk_level, created_at) VALUES
(gen_random_uuid(), (SELECT id FROM conversations ORDER BY created_at LIMIT 1), 'f01a2b3c4d5e6f70000000000000001', 'text', '你好!看到你的资料觉得挺合适的~', 'sent', 'normal', '2026-06-15T14:00:00Z'),
(gen_random_uuid(), (SELECT id FROM conversations ORDER BY created_at LIMIT 1), 'm01a2b3c4d5e6f70000000000000001', 'text', '你好!谢谢你的喜欢,我也觉得挺有缘的', 'sent', 'normal', '2026-06-15T14:05:00Z'),
(gen_random_uuid(), (SELECT id FROM conversations ORDER BY created_at LIMIT 1), 'f01a2b3c4d5e6f70000000000000001', 'text', '你也在丹阳工作吗?平时喜欢做些什么?', 'sent', 'normal', '2026-06-15T14:10:00Z'),
(gen_random_uuid(), (SELECT id FROM conversations ORDER BY created_at OFFSET 1 LIMIT 1), 'm03a2b3c4d5e6f70000000000000003', 'text', '嗨,你好!很高兴认识你', 'sent', 'normal', '2026-07-05T19:30:00Z'),
(gen_random_uuid(), (SELECT id FROM conversations ORDER BY created_at OFFSET 1 LIMIT 1), 'f03a2b3c4d5e6f70000000000000003', 'text', '你好呀!我平时喜欢拍照和跳舞,你呢?', 'sent', 'normal', '2026-07-05T19:35:00Z'),
(gen_random_uuid(), (SELECT id FROM conversations ORDER BY created_at OFFSET 2 LIMIT 1), 'm05a2b3c4d5e6f70000000000000005', 'text', '你好,很高兴认识你!', 'sent', 'normal', '2026-06-10T10:00:00Z');
-- 更新 conversations.last_message_id
UPDATE conversations SET last_message_id = (SELECT id FROM messages WHERE conversation_id = conversations.id ORDER BY created_at DESC LIMIT 1);
-- ============================================================
-- 15. 推荐记录
-- ============================================================
INSERT INTO recommendation_records (id, user_id, target_user_id, source, score, level, shown_at, action, action_at, rule_version) VALUES
(gen_random_uuid(), 'f01a2b3c4d5e6f70000000000000001', 'm01a2b3c4d5e6f70000000000000001', 'daily', 82.50, 'high', '2026-05-28T10:00:00Z', 'liked', '2026-06-01T10:00:00Z', 1),
(gen_random_uuid(), 'f01a2b3c4d5e6f70000000000000001', 'm03a2b3c4d5e6f70000000000000003', 'daily', 70.00, 'medium', '2026-05-28T10:00:00Z', 'passed','2026-05-28T10:01:00Z', 1),
(gen_random_uuid(), 'm01a2b3c4d5e6f70000000000000001', 'f01a2b3c4d5e6f70000000000000001', 'daily', 85.00, 'high', '2026-05-28T11:00:00Z', 'liked', '2026-06-01T10:05:00Z', 1),
(gen_random_uuid(), 'f03a2b3c4d5e6f70000000000000003', 'm03a2b3c4d5e6f70000000000000003', 'daily', 78.00, 'high', '2026-06-01T09:00:00Z', 'liked', '2026-06-03T09:30:00Z', 1),
(gen_random_uuid(), 'm03a2b3c4d5e6f70000000000000003', 'f03a2b3c4d5e6f70000000000000003', 'daily', 75.00, 'high', '2026-06-01T09:30:00Z', 'liked', '2026-06-03T09:30:00Z', 1),
(gen_random_uuid(), 'f05a2b3c4d5e6f70000000000000005', 'm05a2b3c4d5e6f70000000000000005', 'daily', 88.00, 'high', '2026-06-01T10:00:00Z', 'liked', '2026-06-05T10:00:00Z', 1),
(gen_random_uuid(), 'm05a2b3c4d5e6f70000000000000005', 'f05a2b3c4d5e6f70000000000000005', 'daily', 86.00, 'high', '2026-06-01T10:30:00Z', 'liked', '2026-06-05T10:05:00Z', 1),
(gen_random_uuid(), 'm06a2b3c4d5e6f70000000000000006', 'f01a2b3c4d5e6f70000000000000001', 'daily', 62.00, 'medium','2026-06-06T14:00:00Z', 'liked', '2026-06-06T14:00:00Z', 1);
-- ============================================================
-- 16. 相亲活动
-- ============================================================
WITH act_org AS (
SELECT id FROM organizations WHERE type='women_federation' LIMIT 1
), act_mgr AS (
SELECT id FROM operators WHERE username='activitymgr' LIMIT 1
)
INSERT INTO activities (id, title, description, organizer_org_id, coorganizer_text,
start_at, end_at, location_name, location_address,
male_limit, female_limit, total_limit, min_age, max_age,
registration_start_at, registration_end_at, need_review, status, created_by)
VALUES
((SELECT id FROM act_org),
'丹阳公益单身联谊会(夏季场)',
'面向丹阳市区及周边乡镇的单身青年,由妇联、工会联合主办,提供安全、真实的交友平台。现场设有互动游戏、自由交流环节,红娘全程辅助。',
(SELECT id FROM act_org),
'丹阳市总工会、丹阳市慈善基金会',
'2026-08-15T14:00:00Z', '2026-08-15T17:30:00Z',
'丹阳市文化馆多功能厅', '丹阳市丹北路168号',
15, 15, 30, 22, 40,
'2026-07-01T00:00:00Z', '2026-08-10T23:59:59Z',
true, 'registration_open', (SELECT id FROM act_mgr)),
((SELECT id FROM organizations WHERE type='trade_union' LIMIT 1),
'七夕特别活动·丹阳缘来是你',
'七夕节特别策划,浪漫主题相亲活动。适合寻找认真关系的单身人士。',
(SELECT id FROM organizations WHERE type='trade_union' LIMIT 1),
'丹阳市新时代文明实践中心',
'2026-08-29T15:00:00Z', '2026-08-29T18:00:00Z',
'丹阳大剧院报告厅', '丹阳市书院路28号',
20, 20, 40, 25, 45,
'2026-08-01T00:00:00Z', '2026-08-25T23:59:59Z',
true, 'draft', (SELECT id FROM operators WHERE username='activitymgr' LIMIT 1));
-- ============================================================
-- 17. 活动报名
-- ============================================================
WITH act1 AS (SELECT id FROM activities WHERE title LIKE '夏季%' LIMIT 1),
mgr AS (SELECT id FROM operators WHERE username='activitymgr' LIMIT 1)
INSERT INTO activity_registrations (id, activity_id, user_id, status, registered_at, reviewed_by, reviewed_at, checkin_status) VALUES
(gen_random_uuid(), (SELECT id FROM act1), 'f01a2b3c4d5e6f70000000000000001', 'approved', '2026-07-05T10:00:00Z', (SELECT id FROM mgr), '2026-07-05T10:30:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), 'f03a2b3c4d5e6f70000000000000003', 'approved', '2026-07-06T14:00:00Z', (SELECT id FROM mgr), '2026-07-06T14:15:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), 'f05a2b3c4d5e6f70000000000000005', 'approved', '2026-07-07T09:00:00Z', (SELECT id FROM mgr), '2026-07-07T09:20:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), 'm01a2b3c4d5e6f70000000000000001', 'approved', '2026-07-08T11:00:00Z', (SELECT id FROM mgr), '2026-07-08T11:10:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), 'm03a2b3c4d5e6f70000000000000003', 'approved', '2026-07-09T15:00:00Z', (SELECT id FROM mgr), '2026-07-09T15:20:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), 'm05a2b3c4d5e6f70000000000000005', 'approved', '2026-07-10T08:30:00Z', (SELECT id FROM mgr), '2026-07-10T08:45:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), 'f02a2b3c4d5e6f70000000000000002', 'pending', '2026-07-12T10:00:00Z', NULL, NULL, 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), 'm02a2b3c4d5e6f70000000000000002', 'approved', '2026-07-11T16:00:00Z', (SELECT id FROM mgr), '2026-07-11T16:30:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), 'f04a2b3c4d5e6f70000000000000004', 'rejected', '2026-07-13T09:00:00Z', (SELECT id FROM mgr), '2026-07-13T09:15:00Z', 'not_checked_in');
-- ============================================================
-- 18. 活动互选意向
-- ============================================================
WITH act1 AS (SELECT id FROM activities WHERE title LIKE '夏季%' LIMIT 1)
INSERT INTO activity_interests (id, source_user_id, target_user_id, activity_id, status, confirmed_at, created_at) VALUES
(gen_random_uuid(), 'f01a2b3c4d5e6f70000000000000001', 'm01a2b3c4d5e6f70000000000000001', (SELECT id FROM act1), 'mutual', '2026-08-15T17:00:00Z', '2026-08-15T17:00:00Z'),
(gen_random_uuid(), 'f03a2b3c4d5e6f70000000000000003', 'm03a2b3c4d5e6f70000000000000003', (SELECT id FROM act1), 'mutual', '2026-08-15T17:05:00Z', '2026-08-15T17:05:00Z'),
(gen_random_uuid(), 'f05a2b3c4d5e6f70000000000000005', 'm05a2b3c4d5e6f70000000000000005', (SELECT id FROM act1), 'expressed','2026-08-15T17:10:00Z', '2026-08-15T17:10:00Z');
-- ============================================================
-- 19. 红娘服务
-- ============================================================
WITH mh_op AS (SELECT id FROM operators WHERE username='wanghongniang' LIMIT 1),
women_org AS (SELECT id FROM organizations WHERE type='women_federation' LIMIT 1),
charity_org AS (SELECT id FROM organizations WHERE type='charity_center' LIMIT 1)
INSERT INTO matchmaker_services (id, user_id, service_type, description, status, organization_id, assigned_operator_id, assigned_at, completed_at) VALUES
(gen_random_uuid(), 'f02a2b3c4d5e6f70000000000000002', 'recommend_partner', '离异用户希望找到合适的伴侣,需要红娘协助筛选',
'in_service', (SELECT id FROM women_org), (SELECT id FROM mh_op), '2026-06-20T10:00:00Z', NULL),
(gen_random_uuid(), 'f06a2b3c4d5e6f70000000000000006', 'no_match_help', '丧偶用户希望重新融入社交,找到新伴侣',
'waiting_user', (SELECT id FROM charity_org), (SELECT id FROM mh_op), '2026-06-25T14:00:00Z', NULL),
(gen_random_uuid(), 'f04a2b3c4d5e6f70000000000000004', 'review_preference', '用户希望调整择偶条件,请红娘帮助评估',
'completed', (SELECT id FROM women_org), (SELECT id FROM mh_op), '2026-06-15T09:00:00Z', '2026-06-20T11:00:00Z');
-- 红娘推荐
WITH ms_f02 AS (SELECT id FROM matchmaker_services WHERE user_id='f02a2b3c4d5e6f70000000000000002' LIMIT 1),
mh_op2 AS (SELECT id FROM operators WHERE username='wanghongniang' LIMIT 1)
INSERT INTO matchmaker_recommendations (id, service_id, user_id, target_user_id, operator_id, reason, status, created_at, viewed_at, responded_at)
VALUES (gen_random_uuid(), (SELECT id FROM ms_f02), 'f02a2b3c4d5e6f70000000000000002', 'm02a2b3c4d5e6f70000000000000002', (SELECT id FROM mh_op2),
'两人同在丹阳工作,年龄相仿,都离过婚有共同语言', 'viewed', '2026-06-21T10:00:00Z', '2026-06-22T09:00:00Z', NULL);
-- 红娘跟进
WITH ms_f02_2 AS (SELECT id FROM matchmaker_services WHERE user_id='f02a2b3c4d5e6f70000000000000002' LIMIT 1),
ms_f04 AS (SELECT id FROM matchmaker_services WHERE user_id='f04a2b3c4d5e6f70000000000000004' LIMIT 1),
mh_op3 AS (SELECT id FROM operators WHERE username='wanghongniang' LIMIT 1)
INSERT INTO matchmaker_followups (id, service_id, operator_id, followup_type, content, result_code, next_followup_at, created_at) VALUES
(gen_random_uuid(), (SELECT id FROM ms_f02_2), (SELECT id FROM mh_op3), 'phone_call', '电话沟通用户情况,了解离异原因及择偶期望', '正常', '2026-07-01T10:00:00Z', '2026-06-22T10:00:00Z'),
(gen_random_uuid(), (SELECT id FROM ms_f04), (SELECT id FROM mh_op3), 'face_to_face', '面对面交流,帮助用户调整身高要求从170改为168', '已调整', NULL, '2026-06-18T15:00:00Z');
-- ============================================================
-- 20. 系统通知
-- ============================================================
WITH notif_users AS (
SELECT 'f01a2b3c4d5e6f70000000000000001' as uid, 'f03a2b3c4d5e6f70000000000000003' as u2, 'f05a2b3c4d5e6f70000000000000005' as u3,
'm01a2b3c4d5e6f70000000000000001' as mu1, 'm03a2b3c4d5e6f70000000000000003' as mu2, 'm05a2b3c4d5e6f70000000000000005' as mu3,
'f02a2b3c4d5e6f70000000000000002' as mf2
)
INSERT INTO notifications (id, user_id, type, title, content, business_type, business_id, read_status, created_at)
SELECT gen_random_uuid(), uid, type, title, content, business_type, NULL::uuid, read_status, created_at FROM (
VALUES
('match','f01a2b3c4d5e6f70000000000000001','match','你们互相喜欢!','张伟也喜欢了你,可以开始聊天啦~','match','read','2026-06-01T10:05:00Z'),
('match','m01a2b3c4d5e6f70000000000000001','match','你们互相喜欢!','小芳也喜欢了你,可以开始聊天啦~','match','read','2026-06-01T10:05:00Z'),
('match','f03a2b3c4d5e6f70000000000000003','match','你们互相喜欢!','王磊也喜欢了你,可以开始聊天啦~','match','read','2026-06-03T09:30:00Z'),
('match','m03a2b3c4d5e6f70000000000000003','match','你们互相喜欢!','婷婷也喜欢了你,可以开始聊天啦~','match','unread','2026-06-03T09:30:00Z'),
('match','f05a2b3c4d5e6f70000000000000005','match','你们互相喜欢!','孙浩也喜欢了你,可以开始聊天啦~','match','read','2026-06-05T10:05:00Z'),
('match','m05a2b3c4d5e6f70000000000000005','match','你们互相喜欢!','慧琴也喜欢了你,可以开始聊天啦~','match','read','2026-06-05T10:05:00Z'),
('system','f05a2b3c4d5e6f70000000000000005','system','恭喜牵手成功!','您与孙浩已成功牵手,祝你们幸福!','match','read','2026-07-01T10:30:00Z'),
('system','m05a2b3c4d5e6f70000000000000005','system','恭喜牵手成功!','您与慧琴已成功牵手,祝你们幸福!','match','read','2026-07-01T10:30:00Z'),
('activity','f01a2b3c4d5e6f70000000000000001','activity','活动报名已确认','您已成功报名「丹阳公益单身联谊会」','activity','read','2026-07-05T10:30:00Z'),
('activity','f05a2b3c4d5e6f70000000000000005','activity','活动报名已确认','您已成功报名「丹阳公益单身联谊会」','activity','unread','2026-07-07T09:20:00Z'),
('matchmaker','f02a2b3c4d5e6f70000000000000002','matchmaker','红娘已为您服务','您的红娘服务申请已被分配,红娘小王将在24小时内与您联系','matchmaker','read','2026-06-20T10:30:00Z')
) AS t(type, user_id, ntype, title, content, business_type, read_status, created_at);
-- ============================================================
-- 21. 同意记录
-- ============================================================
INSERT INTO consent_records (id, user_id, type, version, agreed_at, ip_address, user_agent) VALUES
(gen_random_uuid(), 'f01a2b3c4d5e6f70000000000000001', 'terms_of_service', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'),
(gen_random_uuid(), 'f01a2b3c4d5e6f70000000000000001', 'privacy_policy', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'),
(gen_random_uuid(), 'm01a2b3c4d5e6f70000000000000001', 'terms_of_service', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0'),
(gen_random_uuid(), 'm01a2b3c4d5e6f70000000000000001', 'privacy_policy', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0');
-- ============================================================
-- 22. 审核原因字典
-- ============================================================
INSERT INTO review_reasons (code, name, category, enabled, sort_order) VALUES
('profile_incomplete', '资料不完整', 'quality', true, 1),
('photo_unclear', '照片不清晰', 'quality', true, 2),
('fake_info', '信息疑似虚假', 'trust', true, 3),
('inappropriate_photo', '照片内容不当', 'safety', true, 4),
('duplicate_identity', '重复注册', 'duplicate', true, 5),
('suspicious_behavior', '行为异常', 'risk', true, 6),
('manual_review_needed', '需人工复核', 'quality', true, 7);
SET session_replication_role = 'origin';
-- ============================================================
-- 验证数据量
-- ============================================================
DO $$
DECLARE
u_cnt INTEGER; op_cnt INTEGER; m_cnt INTEGER; a_cnt INTEGER; r_cnt INTEGER; n_cnt INTEGER;
BEGIN
SELECT COUNT(*) INTO u_cnt FROM users WHERE deleted_at IS NULL;
SELECT COUNT(*) INTO op_cnt FROM operators;
SELECT COUNT(*) INTO m_cnt FROM matches;
SELECT COUNT(*) INTO a_cnt FROM activities WHERE deleted_at IS NULL;
SELECT COUNT(*) INTO r_cnt FROM user_relations;
SELECT COUNT(*) INTO n_cnt FROM notifications;
RAISE NOTICE '✅ Demo 数据填充完成:';
RAISE NOTICE ' 用户: %人 | 操作员: %人 | Match: %对', u_cnt, op_cnt, m_cnt;
RAISE NOTICE ' 关系: %条 | 活动: %个 | 通知: %条', r_cnt, a_cnt, n_cnt;
END $$;
@@ -0,0 +1,565 @@
-- ============================================================
-- 丹阳公益婚恋服务平台 — Demo Seed 数据脚本 v3(纯 UUID)
-- 所有 ID 使用 gen_random_uuid() 生成,完全兼容 PostgreSQL UUID 类型
-- ============================================================
SET session_replication_role = 'replica';
-- ============================================================
-- 1. 组织
-- ============================================================
INSERT INTO organizations (name, type, contact_name, status) VALUES
('丹阳市妇女联合会', 'women_federation', '张丽华', 'active'),
('丹阳市总工会', 'trade_union', '李明远', 'active'),
('丹阳市慈善基金会', 'charity_center', '王秀英', 'active');
-- ============================================================
-- 2. 工作人员
-- ============================================================
INSERT INTO operators (organization_id, name, username, password_hash, status) VALUES
((SELECT id FROM organizations WHERE type='women_federation' LIMIT 1), '陈主任', 'admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'),
((SELECT id FROM organizations WHERE type='women_federation' LIMIT 1), '红娘小王', 'wanghongniang','$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'),
((SELECT id FROM organizations WHERE type='charity_center' LIMIT 1), '审核员小张', 'reviewer01', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'),
((SELECT id FROM organizations WHERE type='trade_union' LIMIT 1), '活动管理员赵', 'activitymgr', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active');
-- 操作员角色绑定
INSERT INTO operator_roles (operator_id, role_id) SELECT id, '00000000-0000-0000-0000-000000000001' FROM operators WHERE username='admin';
INSERT INTO operator_roles (operator_id, role_id) SELECT id, '00000000-0000-0000-0000-000000000002' FROM operators WHERE username='admin';
INSERT INTO operator_roles (operator_id, role_id) SELECT id, '00000000-0000-0000-0000-000000000005' FROM operators WHERE username='wanghongniang';
INSERT INTO operator_roles (operator_id, role_id) SELECT id, '00000000-0000-0000-0000-000000000006' FROM operators WHERE username='wanghongniang';
INSERT INTO operator_roles (operator_id, role_id) SELECT id, '00000000-0000-0000-0000-000000000004' FROM operators WHERE username='reviewer01';
INSERT INTO operator_roles (operator_id, role_id) SELECT id, '00000000-0000-0000-0000-000000000007' FROM operators WHERE username='reviewer01';
INSERT INTO operator_roles (operator_id, role_id) SELECT id, '00000000-0000-0000-0000-000000000006' FROM operators WHERE username='activitymgr';
INSERT INTO operator_roles (operator_id, role_id) SELECT id, '00000000-0000-0000-0000-000000000008' FROM operators WHERE username='activitymgr';
-- ============================================================
-- 3. Demo 用户 12人(UUID 格式)
-- ============================================================
WITH demo_users AS (
INSERT INTO users (wechat_openid, account_status, relationship_status, recommendation_enabled, created_at)
VALUES
('demo_openid_f01', 'normal', 'searching', true, '2026-03-15T10:00:00Z'),
('demo_openid_f02', 'normal', 'searching', true, '2026-03-20T14:30:00Z'),
('demo_openid_f03', 'normal', 'searching', true, '2026-04-01T09:15:00Z'),
('demo_openid_f04', 'normal', 'paused', true, '2026-04-10T16:00:00Z'),
('demo_openid_f05', 'normal', 'searching', true, '2026-05-01T11:20:00Z'),
('demo_openid_f06', 'normal', 'searching', true, '2026-05-15T08:45:00Z'),
('demo_openid_m01', 'normal', 'searching', true, '2026-03-10T09:00:00Z'),
('demo_openid_m02', 'normal', 'getting_to_know', true, '2026-03-25T13:00:00Z'),
('demo_openid_m03', 'normal', 'searching', true, '2026-04-05T15:30:00Z'),
('demo_openid_m04', 'normal', 'searching', true, '2026-04-20T10:00:00Z'),
('demo_openid_m05', 'normal', 'matched_successfully', true, '2026-05-01T14:00:00Z'),
('demo_openid_m06', 'normal', 'searching', true, '2026-05-10T16:30:00Z')
RETURNING id, wechat_openid
)
SELECT * FROM demo_users;
-- 将生成的用户ID放入临时表供后续引用
CREATE TEMP TABLE demo_user_ids ON COMMIT DROP AS
SELECT id, wechat_openid FROM users WHERE wechat_openid LIKE 'demo_openid_%';
-- 建立映射别名
CREATE TEMP TABLE demo_user_map ON COMMIT DROP AS
SELECT
id,
wechat_openid,
CASE wechat_openid
WHEN 'demo_openid_f01' THEN 'f01'
WHEN 'demo_openid_f02' THEN 'f02'
WHEN 'demo_openid_f03' THEN 'f03'
WHEN 'demo_openid_f04' THEN 'f04'
WHEN 'demo_openid_f05' THEN 'f05'
WHEN 'demo_openid_f06' THEN 'f06'
WHEN 'demo_openid_m01' THEN 'm01'
WHEN 'demo_openid_m02' THEN 'm02'
WHEN 'demo_openid_m03' THEN 'm03'
WHEN 'demo_openid_m04' THEN 'm04'
WHEN 'demo_openid_m05' THEN 'm05'
WHEN 'demo_openid_m06' THEN 'm06'
END as alias
FROM demo_user_ids;
SELECT 'users inserted' as step, COUNT(*) as cnt FROM demo_user_map;
-- ============================================================
-- 4. 用户资料
-- ============================================================
INSERT INTO user_profiles (
user_id, display_name, gender, birth_date, height_cm,
region_code, region_name, marital_status, children_status,
education_code, occupation_code, smoking_status, drinking_status,
long_term_danyang, future_danyang, relationship_goal, profile_completion, profile_status
)
SELECT
m.id,
CASE m.alias WHEN 'f01' THEN '小芳' WHEN 'f02' THEN '晓燕' WHEN 'f03' THEN '婷婷'
WHEN 'f04' THEN '美玲' WHEN 'f05' THEN '慧琴' WHEN 'f06' THEN '秀英'
WHEN 'm01' THEN '张伟' WHEN 'm02' THEN '李强' WHEN 'm03' THEN '王磊'
WHEN 'm04' THEN '赵明' WHEN 'm05' THEN '孙浩' WHEN 'm06' THEN '周洋' END,
CASE WHEN m.alias LIKE 'f%' THEN 'female' ELSE 'male' END,
CASE m.alias
WHEN 'f01' THEN '1995-06-15' WHEN 'f02' THEN '1993-09-20' WHEN 'f03' THEN '1998-02-10'
WHEN 'f04' THEN '1990-11-05' WHEN 'f05' THEN '1996-07-22' WHEN 'f06' THEN '1992-04-18'
WHEN 'm01' THEN '1992-01-10' WHEN 'm02' THEN '1990-08-25' WHEN 'm03' THEN '1997-12-03'
WHEN 'm04' THEN '1988-05-30' WHEN 'm05' THEN '1994-03-14' WHEN 'm06' THEN '1999-08-08'
END,
CASE m.alias
WHEN 'f01' THEN 162 WHEN 'f02' THEN 165 WHEN 'f03' THEN 158
WHEN 'f04' THEN 160 WHEN 'f05' THEN 163 WHEN 'f06' THEN 157
WHEN 'm01' THEN 175 WHEN 'm02' THEN 178 WHEN 'm03' THEN 180
WHEN 'm04' THEN 172 WHEN 'm05' THEN 182 WHEN 'm06' THEN 176
END,
CASE WHEN m.alias IN ('f01','f02','f04','f05','m01','m02','m04','m05') THEN '321181'
WHEN m.alias IN ('f03','m03') THEN '321100'
WHEN m.alias = 'm06' THEN '320500' END,
CASE WHEN m.alias IN ('f01','f02','f04','f05','m01','m02','m04','m05') THEN '丹阳'
WHEN m.alias IN ('f03','m03') THEN '镇江'
WHEN m.alias = 'm06' THEN '苏州' END,
CASE m.alias
WHEN 'f02' THEN 'divorced' WHEN 'f06' THEN 'widowed' ELSE 'never_married' END,
'none',
CASE m.alias
WHEN 'f01' THEN 'bachelor' WHEN 'f02' THEN 'college' WHEN 'f03' THEN 'master'
WHEN 'f04' THEN 'senior_high' WHEN 'f05' THEN 'bachelor' WHEN 'f06' THEN 'junior_high'
WHEN 'm01' THEN 'bachelor' WHEN 'm02' THEN 'master' WHEN 'm03' THEN 'college'
WHEN 'm04' THEN 'senior_high' WHEN 'm05' THEN 'bachelor' WHEN 'm06' THEN 'master'
END,
CASE m.alias
WHEN 'f01' THEN 'clerical' WHEN 'f02' THEN 'teacher' WHEN 'f03' THEN 'designer'
WHEN 'f04' THEN 'factory' WHEN 'f05' THEN 'nurse' WHEN 'f06' THEN 'farmer'
WHEN 'm01' THEN 'engineer' WHEN 'm02' THEN 'manager' WHEN 'm03' THEN 'programmer'
WHEN 'm04' THEN 'sales' WHEN 'm05' THEN 'doctor' WHEN 'm06' THEN 'researcher'
END,
CASE m.alias WHEN 'f03' THEN 'sometimes' WHEN 'f06' THEN 'often' WHEN 'm02' THEN 'sometimes'
WHEN 'm04' THEN 'often' WHEN 'm05' THEN 'sometimes' ELSE 'never' END,
CASE m.alias WHEN 'f03' THEN 'often' WHEN 'f06' THEN 'often' WHEN 'm02' THEN 'often'
WHEN 'm04' THEN 'often' ELSE 'sometimes' END,
CASE WHEN m.alias IN ('f03','m06') THEN '否' ELSE '是' END,
CASE WHEN m.alias IN ('f03','m06') THEN '否' ELSE '是' END,
CASE WHEN m.alias IN ('f03','m06') THEN '恋爱' ELSE '结婚' END,
CASE m.alias
WHEN 'f01' THEN 90 WHEN 'f02' THEN 95 WHEN 'f03' THEN 85 WHEN 'f04' THEN 70
WHEN 'f05' THEN 92 WHEN 'f06' THEN 60 WHEN 'm01' THEN 88 WHEN 'm02' THEN 95
WHEN 'm03' THEN 82 WHEN 'm04' THEN 75 WHEN 'm05' THEN 97 WHEN 'm06' THEN 80
END,
'approved'
FROM demo_user_map m;
-- ============================================================
-- 5. 用户择偶偏好
-- ============================================================
INSERT INTO user_preferences (user_id, min_age, max_age, age_priority, min_height_cm, max_height_cm, height_priority, region_scope, region_priority, marital_statuses, marital_priority, min_education_code, education_priority)
SELECT m.id,
CASE WHEN m.alias LIKE 'f%' THEN 28 WHEN m.alias LIKE 'm%' THEN 22 ELSE 25 END,
CASE WHEN m.alias LIKE 'f%' THEN 40 WHEN m.alias LIKE 'm%' THEN 38 ELSE 35 END,
'required',
CASE WHEN m.alias LIKE 'f%' THEN 155 WHEN m.alias LIKE 'm%' THEN 170 ELSE 158 END,
CASE WHEN m.alias LIKE 'f%' THEN 172 WHEN m.alias LIKE 'm%' THEN 188 ELSE 185 END,
'preferred',
'["321181","321100"]',
'required',
'["never_married"]',
'required',
CASE WHEN m.alias IN ('f02','m02') THEN 'college' WHEN m.alias IN ('f01','m01','m05') THEN 'bachelor' ELSE NULL END,
'preferred'
FROM demo_user_map m;
-- ============================================================
-- 6. 实名认证(mock)
-- ============================================================
INSERT INTO user_identities (id, user_id, real_name_enc, id_number_enc, id_number_hash, gender, birth_date, verification_status, provider, verified_at)
SELECT gen_random_uuid(), m.id,
encode(('[demo_enc_' || m.alias || ']')::bytea, 'escape'),
encode(('[demo_id_' || m.alias || ']')::bytea, 'escape'),
'demo_sha256_hash_' || m.alias,
CASE WHEN m.alias LIKE 'f%' THEN 'female' ELSE 'male' END,
CASE m.alias
WHEN 'f01' THEN '1995-06-15' WHEN 'f02' THEN '1993-09-20' WHEN 'f03' THEN '1998-02-10'
WHEN 'f04' THEN '1990-11-05' WHEN 'f05' THEN '1996-07-22' WHEN 'f06' THEN '1992-04-18'
WHEN 'm01' THEN '1992-01-10' WHEN 'm02' THEN '1990-08-25' WHEN 'm03' THEN '1997-12-03'
WHEN 'm04' THEN '1988-05-30' WHEN 'm05' THEN '1994-03-14' WHEN 'm06' THEN '1999-08-08'
END,
'verified', 'mock', NOW() - INTERVAL '1 day'
FROM demo_user_map m;
-- ============================================================
-- 7. 兴趣标签
-- ============================================================
INSERT INTO user_interests (user_id, interest_code)
SELECT m.id, ic.code
FROM demo_user_map m
CROSS JOIN (
VALUES
('reading'),('cooking'),('travel'),('sports'),('music'),('outdoor'),
('photography'),('dance'),('movie'),('pets'),('fitness'),('charity'),
('gardening'),('gaming'),('hiking'),('coding'),('cars'),('running'),('research')
) ic(code)
WHERE (m.alias = 'f01' AND ic.code IN ('reading','cooking','travel'))
OR (m.alias = 'f02' AND ic.code IN ('sports','music','outdoor'))
OR (m.alias = 'f03' AND ic.code IN ('photography','dance','movie'))
OR (m.alias = 'f04' AND ic.code IN ('pets','cooking'))
OR (m.alias = 'f05' AND ic.code IN ('reading','fitness','charity'))
OR (m.alias = 'f06' AND ic.code IN ('gardening','cooking'))
OR (m.alias = 'm01' AND ic.code IN ('sports','gaming','travel'))
OR (m.alias = 'm02' AND ic.code IN ('reading','investment','hiking'))
OR (m.alias = 'm03' AND ic.code IN ('gaming','music','coding'))
OR (m.alias = 'm04' AND ic.code IN ('cars','cooking'))
OR (m.alias = 'm05' AND ic.code IN ('running','reading','charity'))
OR (m.alias = 'm06' AND ic.code IN ('research','travel','photography'));
-- ============================================================
-- 8. 隐私设置
-- ============================================================
INSERT INTO user_privacy_settings (user_id, visible_in_recommendations, visible_in_search, show_occupation, show_lifestyle_photos, receive_activity_recommendations, accept_matchmaker_recommendations)
SELECT m.id,
true,
CASE WHEN m.alias IN ('f03','f06','m04') THEN false ELSE true END,
CASE WHEN m.alias IN ('f02','f04','m02','m03') THEN false ELSE true END,
CASE WHEN m.alias IN ('f02','m02','m03') THEN false ELSE true END,
CASE WHEN m.alias IN ('f05','m03') THEN false ELSE true END,
CASE WHEN m.alias IN ('f03') THEN false ELSE true END
FROM demo_user_map m;
-- ============================================================
-- 9. 照片
-- ============================================================
INSERT INTO user_photos (id, user_id, file_key, photo_type, sort_order, review_status)
SELECT gen_random_uuid(), m.id,
'photos/demo/' || m.alias || '/avatar.jpg',
'avatar', 0, 'approved'
FROM demo_user_map m
UNION ALL
SELECT gen_random_uuid(), m.id,
'photos/demo/' || m.alias || '/lifestyle1.jpg',
'lifestyle', 1, 'approved'
FROM demo_user_map m;
-- ============================================================
-- 10. 审核任务
-- ============================================================
INSERT INTO review_tasks (id, user_id, review_type, status, assigned_operator_id, submitted_at, started_at, completed_at, final_comment, version)
SELECT gen_random_uuid(), m.id, 'initial_profile', 'approved',
(SELECT id FROM operators WHERE username='reviewer01'),
NOW() - INTERVAL '60 days', NOW() - INTERVAL '59 days', NOW() - INTERVAL '58 days',
'资料完整,信息真实', 1
FROM demo_user_map m
WHERE m.alias IN ('f01','f02','f03','m01','m02','m03','m05');
-- ============================================================
-- 11. 用户关系
-- ============================================================
WITH f01 AS (SELECT id FROM demo_user_map WHERE alias='f01'),
f02 AS (SELECT id FROM demo_user_map WHERE alias='f02'),
f03 AS (SELECT id FROM demo_user_map WHERE alias='f03'),
f04 AS (SELECT id FROM demo_user_map WHERE alias='f04'),
f05 AS (SELECT id FROM demo_user_map WHERE alias='f05'),
f06 AS (SELECT id FROM demo_user_map WHERE alias='f06'),
m01 AS (SELECT id FROM demo_user_map WHERE alias='m01'),
m02 AS (SELECT id FROM demo_user_map WHERE alias='m02'),
m03 AS (SELECT id FROM demo_user_map WHERE alias='m03'),
m04 AS (SELECT id FROM demo_user_map WHERE alias='m04'),
m05 AS (SELECT id FROM demo_user_map WHERE alias='m05'),
m06 AS (SELECT id FROM demo_user_map WHERE alias='m06')
INSERT INTO user_relations (id, user_id, target_user_id, relation_type, created_at)
VALUES
(gen_random_uuid(), (SELECT id FROM f01), (SELECT id FROM m01), 'liked', '2026-06-01T10:00:00Z'),
(gen_random_uuid(), (SELECT id FROM m01), (SELECT id FROM f01), 'liked', '2026-06-01T10:05:00Z'),
(gen_random_uuid(), (SELECT id FROM f02), (SELECT id FROM m02), 'liked', '2026-06-02T14:00:00Z'),
(gen_random_uuid(), (SELECT id FROM f03), (SELECT id FROM m03), 'liked', '2026-06-03T09:00:00Z'),
(gen_random_uuid(), (SELECT id FROM m03), (SELECT id FROM f03), 'liked', '2026-06-03T09:30:00Z'),
(gen_random_uuid(), (SELECT id FROM m04), (SELECT id FROM f02), 'liked', '2026-06-04T11:00:00Z'),
(gen_random_uuid(), (SELECT id FROM f04), (SELECT id FROM m04), 'passed', '2026-06-04T12:00:00Z'),
(gen_random_uuid(), (SELECT id FROM f05), (SELECT id FROM m05), 'liked', '2026-06-05T10:00:00Z'),
(gen_random_uuid(), (SELECT id FROM m05), (SELECT id FROM f05), 'liked', '2026-06-05T10:05:00Z'),
(gen_random_uuid(), (SELECT id FROM m06), (SELECT id FROM f01), 'liked', '2026-06-06T14:00:00Z'),
(gen_random_uuid(), (SELECT id FROM f04), (SELECT id FROM m06), 'passed', '2026-06-06T15:00:00Z'),
(gen_random_uuid(), (SELECT id FROM f06), (SELECT id FROM m04), 'blocked', '2026-06-07T09:00:00Z'),
(gen_random_uuid(), (SELECT id FROM m02), (SELECT id FROM f03), 'passed', '2026-06-07T10:00:00Z');
-- ============================================================
-- 12. Match
-- ====================================================
WITH f01 AS (SELECT id FROM demo_user_map WHERE alias='f01'),
f03 AS (SELECT id FROM demo_user_map WHERE alias='f03'),
f05 AS (SELECT id FROM demo_user_map WHERE alias='f05'),
m01 AS (SELECT id FROM demo_user_map WHERE alias='m01'),
m03 AS (SELECT id FROM demo_user_map WHERE alias='m03'),
m05 AS (SELECT id FROM demo_user_map WHERE alias='m05')
INSERT INTO matches (id, user_a_id, user_b_id, status, source, matched_at)
VALUES
(gen_random_uuid(), (SELECT id FROM f01), (SELECT id FROM m01), 'active', 'user_like', '2026-06-01T10:05:00Z'),
(gen_random_uuid(), (SELECT id FROM f03), (SELECT id FROM m03), 'active', 'user_like', '2026-06-03T09:30:00Z'),
(gen_random_uuid(), (SELECT id FROM f05), (SELECT id FROM m05), 'successful', 'user_like', '2026-06-05T10:05:00Z');
-- ============================================================
-- 13. 成功牵手请求
-- ============================================================
WITH match_f05 AS (SELECT id FROM matches WHERE status='successful' LIMIT 1),
f05 AS (SELECT id FROM demo_user_map WHERE alias='f05'),
m05 AS (SELECT id FROM demo_user_map WHERE alias='m05')
INSERT INTO relationship_success_requests (id, match_id, initiated_by, status, confirmed_by, created_at, resolved_at)
VALUES
(gen_random_uuid(), (SELECT id FROM match_f05), (SELECT id FROM f05), 'confirmed', (SELECT id FROM m05), '2026-07-01T10:00:00Z', '2026-07-01T10:30:00Z'),
(gen_random_uuid(), (SELECT id FROM matches WHERE status='active' ORDER BY created_at LIMIT 1), (SELECT id FROM f01), 'pending', NULL, '2026-07-15T14:00:00Z', NULL);
-- ============================================================
-- 14. Conversations & Messages
-- ============================================================
WITH active_matches AS (
SELECT id FROM matches WHERE status='active' ORDER BY created_at
), conv1 AS (SELECT id FROM active_matches LIMIT 1),
conv2 AS (SELECT id FROM active_matches OFFSET 1 LIMIT 1),
conv3 AS (SELECT id FROM active_matches OFFSET 2 LIMIT 1),
f01 AS (SELECT id FROM demo_user_map WHERE alias='f01'),
m01 AS (SELECT id FROM demo_user_map WHERE alias='m01'),
f03 AS (SELECT id FROM demo_user_map WHERE alias='f03'),
m03 AS (SELECT id FROM demo_user_map WHERE alias='m03'),
f05 AS (SELECT id FROM demo_user_map WHERE alias='f05'),
m05 AS (SELECT id FROM demo_user_map WHERE alias='m05')
INSERT INTO conversations (id, match_id, status, last_message_at)
VALUES
(gen_random_uuid(), (SELECT id FROM conv1), 'active', '2026-07-10T16:00:00Z'),
(gen_random_uuid(), (SELECT id FROM conv2), 'active', '2026-07-08T20:00:00Z'),
(gen_random_uuid(), (SELECT id FROM conv3), 'active', '2026-07-01T18:00:00Z');
-- conversation_members
WITH conv AS (SELECT id FROM conversations ORDER BY created_at),
f01 AS (SELECT id FROM demo_user_map WHERE alias='f01'),
m01 AS (SELECT id FROM demo_user_map WHERE alias='m01'),
f03 AS (SELECT id FROM demo_user_map WHERE alias='f03'),
m03 AS (SELECT id FROM demo_user_map WHERE alias='m03'),
f05 AS (SELECT id FROM demo_user_map WHERE alias='f05'),
m05 AS (SELECT id FROM demo_user_map WHERE alias='m05')
INSERT INTO conversation_members (conversation_id, user_id, unread_count, can_send, joined_at)
SELECT c.id, f01.id, 0, true, NOW() FROM conv c WHERE c.id = (SELECT id FROM conv LIMIT 1)
UNION ALL
SELECT c.id, m01.id, 0, true, NOW() FROM conv c WHERE c.id = (SELECT id FROM conv LIMIT 1)
UNION ALL
SELECT c.id, f03.id, 1, true, NOW() FROM conv c WHERE c.id = (SELECT id FROM conv OFFSET 1 LIMIT 1)
UNION ALL
SELECT c.id, m03.id, 0, true, NOW() FROM conv c WHERE c.id = (SELECT id FROM conv OFFSET 1 LIMIT 1)
UNION ALL
SELECT c.id, f05.id, 0, true, NOW() FROM conv c WHERE c.id = (SELECT id FROM conv OFFSET 2 LIMIT 1)
UNION ALL
SELECT c.id, m05.id, 0, true, NOW() FROM conv c WHERE c.id = (SELECT id FROM conv OFFSET 2 LIMIT 1);
-- messages
WITH conv AS (SELECT id FROM conversations ORDER BY created_at),
f01 AS (SELECT id FROM demo_user_map WHERE alias='f01'),
m01 AS (SELECT id FROM demo_user_map WHERE alias='m01'),
f03 AS (SELECT id FROM demo_user_map WHERE alias='f03'),
m03 AS (SELECT id FROM demo_user_map WHERE alias='m03'),
f05 AS (SELECT id FROM demo_user_map WHERE alias='f05'),
m05 AS (SELECT id FROM demo_user_map WHERE alias='m05')
INSERT INTO messages (id, conversation_id, sender_id, message_type, content, status, risk_level, created_at)
VALUES
(gen_random_uuid(), (SELECT id FROM conv LIMIT 1), (SELECT id FROM f01), 'text', '你好!看到你的资料觉得挺合适的~', 'sent', 'normal', '2026-06-15T14:00:00Z'),
(gen_random_uuid(), (SELECT id FROM conv LIMIT 1), (SELECT id FROM m01), 'text', '你好!谢谢你的喜欢,我也觉得挺有缘的', 'sent', 'normal', '2026-06-15T14:05:00Z'),
(gen_random_uuid(), (SELECT id FROM conv LIMIT 1), (SELECT id FROM f01), 'text', '你也在丹阳工作吗?平时喜欢做些什么?', 'sent', 'normal', '2026-06-15T14:10:00Z'),
(gen_random_uuid(), (SELECT id FROM conv OFFSET 1 LIMIT 1), (SELECT id FROM m03), 'text', '嗨,你好!很高兴认识你', 'sent', 'normal', '2026-07-05T19:30:00Z'),
(gen_random_uuid(), (SELECT id FROM conv OFFSET 1 LIMIT 1), (SELECT id FROM f03), 'text', '你好呀!我平时喜欢拍照和跳舞,你呢?', 'sent', 'normal', '2026-07-05T19:35:00Z'),
(gen_random_uuid(), (SELECT id FROM conv OFFSET 2 LIMIT 1), (SELECT id FROM m05), 'text', '你好,很高兴认识你!', 'sent', 'normal', '2026-06-10T10:00:00Z');
-- update last_message_at
UPDATE conversations SET last_message_at = (
SELECT MAX(created_at) FROM messages WHERE messages.conversation_id = conversations.id
);
-- ============================================================
-- 15. 推荐记录
-- ============================================================
WITH f01 AS (SELECT id FROM demo_user_map WHERE alias='f01'),
f03 AS (SELECT id FROM demo_user_map WHERE alias='f03'),
f05 AS (SELECT id FROM demo_user_map WHERE alias='f05'),
m01 AS (SELECT id FROM demo_user_map WHERE alias='m01'),
m03 AS (SELECT id FROM demo_user_map WHERE alias='m03'),
m05 AS (SELECT id FROM demo_user_map WHERE alias='m05'),
m06 AS (SELECT id FROM demo_user_map WHERE alias='m06')
INSERT INTO recommendation_records (id, user_id, target_user_id, source, score, level, shown_at, action, action_at, rule_version)
VALUES
(gen_random_uuid(), (SELECT id FROM f01), (SELECT id FROM m01), 'daily', 82.50, 'high', '2026-05-28T10:00:00Z', 'liked', '2026-06-01T10:00:00Z', 1),
(gen_random_uuid(), (SELECT id FROM f01), (SELECT id FROM m03), 'daily', 70.00, 'medium', '2026-05-28T10:00:00Z', 'passed','2026-05-28T10:01:00Z', 1),
(gen_random_uuid(), (SELECT id FROM m01), (SELECT id FROM f01), 'daily', 85.00, 'high', '2026-05-28T11:00:00Z', 'liked', '2026-06-01T10:05:00Z', 1),
(gen_random_uuid(), (SELECT id FROM f03), (SELECT id FROM m03), 'daily', 78.00, 'high', '2026-06-01T09:00:00Z', 'liked', '2026-06-03T09:30:00Z', 1),
(gen_random_uuid(), (SELECT id FROM m03), (SELECT id FROM f03), 'daily', 75.00, 'high', '2026-06-01T09:30:00Z', 'liked', '2026-06-03T09:30:00Z', 1),
(gen_random_uuid(), (SELECT id FROM f05), (SELECT id FROM m05), 'daily', 88.00, 'high', '2026-06-01T10:00:00Z', 'liked', '2026-06-05T10:00:00Z', 1),
(gen_random_uuid(), (SELECT id FROM m05), (SELECT id FROM f05), 'daily', 86.00, 'high', '2026-06-01T10:30:00Z', 'liked', '2026-06-05T10:05:00Z', 1),
(gen_random_uuid(), (SELECT id FROM m06), (SELECT id FROM f01), 'daily', 62.00, 'medium','2026-06-06T14:00:00Z', 'liked', '2026-06-06T14:00:00Z', 1);
-- ============================================================
-- 16. 相亲活动
-- ============================================================
WITH women_org AS (SELECT id FROM organizations WHERE type='women_federation' LIMIT 1),
trade_org AS (SELECT id FROM organizations WHERE type='trade_union' LIMIT 1),
mgr AS (SELECT id FROM operators WHERE username='activitymgr' LIMIT 1)
INSERT INTO activities (id, title, description, organizer_org_id, coorganizer_text,
start_at, end_at, location_name, location_address,
male_limit, female_limit, total_limit, min_age, max_age,
registration_start_at, registration_end_at, need_review, status, created_by)
VALUES
(gen_random_uuid(),
'丹阳公益单身联谊会(夏季场)',
'面向丹阳市区及周边乡镇的单身青年,由妇联、工会联合主办,提供安全、真实的交友平台。',
(SELECT id FROM women_org), '丹阳市总工会、丹阳市慈善基金会',
'2026-08-15T14:00:00Z', '2026-08-15T17:30:00Z',
'丹阳市文化馆多功能厅', '丹阳市丹北路168号',
15, 15, 30, 22, 40,
'2026-07-01T00:00:00Z', '2026-08-10T23:59:59Z',
true, 'registration_open', (SELECT id FROM mgr)),
(gen_random_uuid(),
'七夕特别活动·丹阳缘来是你',
'七夕节特别策划,浪漫主题相亲活动。',
(SELECT id FROM trade_org), '丹阳市新时代文明实践中心',
'2026-08-29T15:00:00Z', '2026-08-29T18:00:00Z',
'丹阳大剧院报告厅', '丹阳市书院路28号',
20, 20, 40, 25, 45,
'2026-08-01T00:00:00Z', '2026-08-25T23:59:59Z',
true, 'draft', (SELECT id FROM mgr));
-- ============================================================
-- 17. 活动报名
-- ============================================================
WITH act1 AS (SELECT id FROM activities WHERE title LIKE '夏季%' LIMIT 1),
mgr2 AS (SELECT id FROM operators WHERE username='activitymgr' LIMIT 1),
f01 AS (SELECT id FROM demo_user_map WHERE alias='f01'),
f02 AS (SELECT id FROM demo_user_map WHERE alias='f02'),
f03 AS (SELECT id FROM demo_user_map WHERE alias='f03'),
f04 AS (SELECT id FROM demo_user_map WHERE alias='f04'),
f05 AS (SELECT id FROM demo_user_map WHERE alias='f05'),
m01 AS (SELECT id FROM demo_user_map WHERE alias='m01'),
m02 AS (SELECT id FROM demo_user_map WHERE alias='m02'),
m03 AS (SELECT id FROM demo_user_map WHERE alias='m03'),
m05 AS (SELECT id FROM demo_user_map WHERE alias='m05')
INSERT INTO activity_registrations (id, activity_id, user_id, status, registered_at, reviewed_by, reviewed_at, checkin_status)
VALUES
(gen_random_uuid(), (SELECT id FROM act1), (SELECT id FROM f01), 'approved', '2026-07-05T10:00:00Z', (SELECT id FROM mgr2), '2026-07-05T10:30:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), (SELECT id FROM f03), 'approved', '2026-07-06T14:00:00Z', (SELECT id FROM mgr2), '2026-07-06T14:15:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), (SELECT id FROM f05), 'approved', '2026-07-07T09:00:00Z', (SELECT id FROM mgr2), '2026-07-07T09:20:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), (SELECT id FROM m01), 'approved', '2026-07-08T11:00:00Z', (SELECT id FROM mgr2), '2026-07-08T11:10:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), (SELECT id FROM m03), 'approved', '2026-07-09T15:00:00Z', (SELECT id FROM mgr2), '2026-07-09T15:20:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), (SELECT id FROM m05), 'approved', '2026-07-10T08:30:00Z', (SELECT id FROM mgr2), '2026-07-10T08:45:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), (SELECT id FROM f02), 'pending', '2026-07-12T10:00:00Z', NULL, NULL, 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), (SELECT id FROM m02), 'approved', '2026-07-11T16:00:00Z', (SELECT id FROM mgr2), '2026-07-11T16:30:00Z', 'not_checked_in'),
(gen_random_uuid(), (SELECT id FROM act1), (SELECT id FROM f04), 'rejected', '2026-07-13T09:00:00Z', (SELECT id FROM mgr2), '2026-07-13T09:15:00Z', 'not_checked_in');
-- ============================================================
-- 18. 活动互选意向
-- ============================================================
WITH act1 AS (SELECT id FROM activities WHERE title LIKE '夏季%' LIMIT 1),
f01 AS (SELECT id FROM demo_user_map WHERE alias='f01'),
m01 AS (SELECT id FROM demo_user_map WHERE alias='m01'),
f03 AS (SELECT id FROM demo_user_map WHERE alias='f03'),
m03 AS (SELECT id FROM demo_user_map WHERE alias='m03'),
f05 AS (SELECT id FROM demo_user_map WHERE alias='f05'),
m05 AS (SELECT id FROM demo_user_map WHERE alias='m05')
INSERT INTO activity_interests (id, source_user_id, target_user_id, activity_id, status, confirmed_at, created_at)
VALUES
(gen_random_uuid(), (SELECT id FROM f01), (SELECT id FROM m01), (SELECT id FROM act1), 'mutual', '2026-08-15T17:00:00Z', '2026-08-15T17:00:00Z'),
(gen_random_uuid(), (SELECT id FROM f03), (SELECT id FROM m03), (SELECT id FROM act1), 'mutual', '2026-08-15T17:05:00Z', '2026-08-15T17:05:00Z'),
(gen_random_uuid(), (SELECT id FROM f05), (SELECT id FROM m05), (SELECT id FROM act1), 'expressed','2026-08-15T17:10:00Z', '2026-08-15T17:10:00Z');
-- ============================================================
-- 19. 红娘服务
-- ====================================================
WITH mh_op AS (SELECT id FROM operators WHERE username='wanghongniang' LIMIT 1),
women_org AS (SELECT id FROM organizations WHERE type='women_federation' LIMIT 1),
charity_org AS (SELECT id FROM organizations WHERE type='charity_center' LIMIT 1),
f02 AS (SELECT id FROM demo_user_map WHERE alias='f02'),
f04 AS (SELECT id FROM demo_user_map WHERE alias='f04'),
f06 AS (SELECT id FROM demo_user_map WHERE alias='f06'),
m02 AS (SELECT id FROM demo_user_map WHERE alias='m02')
INSERT INTO matchmaker_services (id, user_id, service_type, description, status, organization_id, assigned_operator_id, assigned_at, completed_at)
VALUES
(gen_random_uuid(), (SELECT id FROM f02), 'recommend_partner', '离异用户希望找到合适的伴侣,需要红娘协助筛选', 'in_service', (SELECT id FROM women_org), (SELECT id FROM mh_op), '2026-06-20T10:00:00Z', NULL),
(gen_random_uuid(), (SELECT id FROM f06), 'no_match_help', '丧偶用户希望重新融入社交,找到新伴侣', 'waiting_user', (SELECT id FROM charity_org), (SELECT id FROM mh_op), '2026-06-25T14:00:00Z', NULL),
(gen_random_uuid(), (SELECT id FROM f04), 'review_preference', '用户希望调整择偶条件,请红娘帮助评估', 'completed', (SELECT id FROM women_org), (SELECT id FROM mh_op), '2026-06-15T09:00:00Z', '2026-06-20T11:00:00Z');
-- 红娘推荐
WITH ms_f02 AS (SELECT id FROM matchmaker_services WHERE user_id=(SELECT id FROM demo_user_map WHERE alias='f02') LIMIT 1),
mh_op2 AS (SELECT id FROM operators WHERE username='wanghongniang' LIMIT 1),
f02 AS (SELECT id FROM demo_user_map WHERE alias='f02'),
m02 AS (SELECT id FROM demo_user_map WHERE alias='m02')
INSERT INTO matchmaker_recommendations (id, service_id, user_id, target_user_id, operator_id, reason, status, created_at, viewed_at, responded_at)
VALUES (gen_random_uuid(), (SELECT id FROM ms_f02), (SELECT id FROM f02), (SELECT id FROM m02), (SELECT id FROM mh_op2),
'两人同在丹阳工作,年龄相仿,都离过婚有共同语言', 'viewed', '2026-06-21T10:00:00Z', '2026-06-22T09:00:00Z', NULL);
-- 红娘跟进
WITH ms_f02_2 AS (SELECT id FROM matchmaker_services WHERE user_id=(SELECT id FROM demo_user_map WHERE alias='f02') LIMIT 1),
ms_f04 AS (SELECT id FROM matchmaker_services WHERE user_id=(SELECT id FROM demo_user_map WHERE alias='f04') LIMIT 1),
mh_op3 AS (SELECT id FROM operators WHERE username='wanghongniang' LIMIT 1)
INSERT INTO matchmaker_followups (id, service_id, operator_id, followup_type, content, result_code, next_followup_at, created_at)
VALUES
(gen_random_uuid(), (SELECT id FROM ms_f02_2), (SELECT id FROM mh_op3), 'phone_call', '电话沟通用户情况,了解离异原因及择偶期望', '正常', '2026-07-01T10:00:00Z', '2026-06-22T10:00:00Z'),
(gen_random_uuid(), (SELECT id FROM ms_f04), (SELECT id FROM mh_op3), 'face_to_face', '面对面交流,帮助用户调整身高要求从170改为168', '已调整', NULL, '2026-06-18T15:00:00Z');
-- ============================================================
-- 20. 系统通知
-- ====================================================
WITH f01 AS (SELECT id FROM demo_user_map WHERE alias='f01'),
f02 AS (SELECT id FROM demo_user_map WHERE alias='f02'),
f03 AS (SELECT id FROM demo_user_map WHERE alias='f03'),
f05 AS (SELECT id FROM demo_user_map WHERE alias='f05'),
m01 AS (SELECT id FROM demo_user_map WHERE alias='m01'),
m03 AS (SELECT id FROM demo_user_map WHERE alias='m03'),
m05 AS (SELECT id FROM demo_user_map WHERE alias='m05')
INSERT INTO notifications (id, user_id, type, title, content, business_type, read_status, created_at)
VALUES
(gen_random_uuid(), (SELECT id FROM f01), 'match', '你们互相喜欢!', '张伟也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-01T10:05:00Z'),
(gen_random_uuid(), (SELECT id FROM m01), 'match', '你们互相喜欢!', '小芳也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-01T10:05:00Z'),
(gen_random_uuid(), (SELECT id FROM f03), 'match', '你们互相喜欢!', '王磊也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-03T09:30:00Z'),
(gen_random_uuid(), (SELECT id FROM m03), 'match', '你们互相喜欢!', '婷婷也喜欢了你,可以开始聊天啦~', 'match', 'unread','2026-06-03T09:30:00Z'),
(gen_random_uuid(), (SELECT id FROM f05), 'match', '你们互相喜欢!', '孙浩也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-05T10:05:00Z'),
(gen_random_uuid(), (SELECT id FROM m05), 'match', '你们互相喜欢!', '慧琴也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-05T10:05:00Z'),
(gen_random_uuid(), (SELECT id FROM f05), 'system', '恭喜牵手成功!', '您与孙浩已成功牵手,祝你们幸福!', 'match', 'read', '2026-07-01T10:30:00Z'),
(gen_random_uuid(), (SELECT id FROM m05), 'system', '恭喜牵手成功!', '您与慧琴已成功牵手,祝你们幸福!', 'match', 'read', '2026-07-01T10:30:00Z'),
(gen_random_uuid(), (SELECT id FROM f01), 'activity', '活动报名已确认', '您已成功报名「丹阳公益单身联谊会」', 'activity', 'read', '2026-07-05T10:30:00Z'),
(gen_random_uuid(), (SELECT id FROM f05), 'activity', '活动报名已确认', '您已成功报名「丹阳公益单身联谊会」', 'activity', 'unread','2026-07-07T09:20:00Z'),
(gen_random_uuid(), (SELECT id FROM f02), 'matchmaker', '红娘已为您服务', '您的红娘服务申请已被分配,红娘小王将在24小时内与您联系', 'matchmaker', 'read', '2026-06-20T10:30:00Z');
-- ============================================================
-- 21. 同意记录
-- ====================================================
WITH f01 AS (SELECT id FROM demo_user_map WHERE alias='f01'),
m01 AS (SELECT id FROM demo_user_map WHERE alias='m01')
INSERT INTO consent_records (id, user_id, type, version, agreed_at, ip_address, user_agent)
VALUES
(gen_random_uuid(), (SELECT id FROM f01), 'terms_of_service', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'),
(gen_random_uuid(), (SELECT id FROM f01), 'privacy_policy', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'),
(gen_random_uuid(), (SELECT id FROM m01), 'terms_of_service', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0'),
(gen_random_uuid(), (SELECT id FROM m01), 'privacy_policy', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0');
-- ============================================================
-- 22. 审核原因字典(仅插入不存在的)
-- ====================================================
INSERT INTO review_reasons (code, name, category, enabled, sort_order)
SELECT * FROM (VALUES
('profile_incomplete', '资料不完整', 'quality', true, 1),
('photo_unclear', '照片不清晰', 'quality', true, 2),
('fake_info', '信息疑似虚假', 'trust', true, 3),
('inappropriate_photo', '照片内容不当', 'safety', true, 4),
('duplicate_identity', '重复注册', 'duplicate', true, 5),
('suspicious_behavior', '行为异常', 'risk', true, 6),
('manual_review_needed', '需人工复核', 'quality', true, 7)
) AS t(code, name, category, enabled, sort_order)
WHERE NOT EXISTS (SELECT 1 FROM review_reasons r WHERE r.code = t.code);
SET session_replication_role = 'origin';
-- ============================================================
-- 验证数据量
-- ============================================================
DO $$
DECLARE
u_cnt INTEGER; op_cnt INTEGER; m_cnt INTEGER; a_cnt INTEGER; r_cnt INTEGER; n_cnt INTEGER; p_cnt INTEGER;
BEGIN
SELECT COUNT(*) INTO u_cnt FROM users WHERE deleted_at IS NULL;
SELECT COUNT(*) INTO op_cnt FROM operators;
SELECT COUNT(*) INTO m_cnt FROM matches;
SELECT COUNT(*) INTO a_cnt FROM activities WHERE deleted_at IS NULL;
SELECT COUNT(*) INTO r_cnt FROM user_relations;
SELECT COUNT(*) INTO n_cnt FROM notifications;
SELECT COUNT(*) INTO p_cnt FROM user_profiles;
RAISE NOTICE '✅ Demo 数据填充完成:';
RAISE NOTICE ' 用户: %人 | 资料: %条 | 操作员: %人', u_cnt, p_cnt, op_cnt;
RAISE NOTICE ' Match: %对 | 关系: %条 | 活动: %个 | 通知: %条', m_cnt, r_cnt, a_cnt, n_cnt;
END $$;
@@ -0,0 +1,409 @@
SET session_replication_role = 'replica';
-- 1. 组织
INSERT INTO organizations (id, name, type, contact_name, status) VALUES
('c74863d4-be10-4efa-b22c-f3f84e2e4e59', '丹阳市妇女联合会', 'women_federation', '张丽华', 'active'),
('a35f0043-be09-4bdf-ad5d-05a72ff19c2a', '丹阳市总工会', 'trade_union', '李明远', 'active'),
('bcd9e5b6-3b66-454c-96d7-3fade6866135', '丹阳市慈善基金会', 'charity_center', '王秀英', 'active');
-- 2. 工作人员
INSERT INTO operators (id, organization_id, name, username, password_hash, status) VALUES
('f54eedf5-a281-4289-a63d-57de1ea83fbc', 'c74863d4-be10-4efa-b22c-f3f84e2e4e59', '陈主任', 'admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'),
('a98c0d97-d272-4577-887e-5c05e27db19b', 'c74863d4-be10-4efa-b22c-f3f84e2e4e59', '红娘小王', 'wanghongniang', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'),
('e9312b05-c263-4901-8145-0b38e4d81c45', 'bcd9e5b6-3b66-454c-96d7-3fade6866135', '审核员小张', 'reviewer01', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'),
('b4cdeb91-bbce-4587-be58-22ff55ef89da', 'a35f0043-be09-4bdf-ad5d-05a72ff19c2a', '活动管理员赵', 'activitymgr', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active');
INSERT INTO operator_roles (operator_id, role_id) VALUES ('f54eedf5-a281-4289-a63d-57de1ea83fbc', '00000000-0000-0000-0000-000000000001');
INSERT INTO operator_roles (operator_id, role_id) VALUES ('f54eedf5-a281-4289-a63d-57de1ea83fbc', '00000000-0000-0000-0000-000000000002');
INSERT INTO operator_roles (operator_id, role_id) VALUES ('a98c0d97-d272-4577-887e-5c05e27db19b', '00000000-0000-0000-0000-000000000005');
INSERT INTO operator_roles (operator_id, role_id) VALUES ('a98c0d97-d272-4577-887e-5c05e27db19b', '00000000-0000-0000-0000-000000000006');
INSERT INTO operator_roles (operator_id, role_id) VALUES ('e9312b05-c263-4901-8145-0b38e4d81c45', '00000000-0000-0000-0000-000000000004');
INSERT INTO operator_roles (operator_id, role_id) VALUES ('e9312b05-c263-4901-8145-0b38e4d81c45', '00000000-0000-0000-0000-000000000007');
INSERT INTO operator_roles (operator_id, role_id) VALUES ('b4cdeb91-bbce-4587-be58-22ff55ef89da', '00000000-0000-0000-0000-000000000006');
INSERT INTO operator_roles (operator_id, role_id) VALUES ('b4cdeb91-bbce-4587-be58-22ff55ef89da', '00000000-0000-0000-0000-000000000008');
-- 3. 用户 12人
INSERT INTO users (id, wechat_openid, account_status, relationship_status, recommendation_enabled, created_at) VALUES
('c4541dae-c864-459e-b5db-3381867ffbd1', 'demo_openid_f01', 'normal', 'searching', true, '2026-03-15T10:00:00Z'),
('f047dbe2-0202-4c57-aa12-1aed76253b62', 'demo_openid_f02', 'normal', 'searching', true, '2026-03-20T14:30:00Z'),
('cdef6f94-f406-4f37-a5c1-319569fc4e69', 'demo_openid_f03', 'normal', 'searching', true, '2026-04-01T09:15:00Z'),
('2db3db2d-ef0f-4f1e-8964-28be1566d1a9', 'demo_openid_f04', 'normal', 'paused', true, '2026-04-10T16:00:00Z'),
('84431e32-c8f7-48d4-8e0e-fd14d86837e5', 'demo_openid_f05', 'normal', 'searching', true, '2026-05-01T11:20:00Z'),
('bc5ca4a9-08b5-413c-8d80-3afc76fbeb97', 'demo_openid_f06', 'normal', 'searching', true, '2026-05-15T08:45:00Z'),
('fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'demo_openid_m01', 'normal', 'searching', true, '2026-03-10T09:00:00Z'),
('205ddb91-56ef-4a8e-ade1-8cb35bb4affa', 'demo_openid_m02', 'normal', 'getting_to_know', true, '2026-03-25T13:00:00Z'),
('f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'demo_openid_m03', 'normal', 'searching', true, '2026-04-05T15:30:00Z'),
('c9f5c328-04fe-4ec6-92af-6073df3af0b0', 'demo_openid_m04', 'normal', 'searching', true, '2026-04-20T10:00:00Z'),
('34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'demo_openid_m05', 'normal', 'matched_successfully', true, '2026-05-01T14:00:00Z'),
('b8846d00-ed0d-4c46-8f36-56c392b9c803', 'demo_openid_m06', 'normal', 'searching', true, '2026-05-10T16:30:00Z');
-- 4. 用户资料
INSERT INTO user_profiles (user_id, display_name, gender, birth_date, height_cm, region_code, region_name, marital_status, children_status, education_code, occupation_code, smoking_status, drinking_status, long_term_danyang, future_danyang, relationship_goal, profile_completion, profile_status) VALUES
('c4541dae-c864-459e-b5db-3381867ffbd1', '小芳', 'female', '1995-06-15', 162, '321181', '丹阳', 'never_married', 'none', 'bachelor', 'clerical', 'never', 'sometimes', '是', '是', '结婚', 90, 'approved'),
('f047dbe2-0202-4c57-aa12-1aed76253b62', '晓燕', 'female', '1993-09-20', 165, '321181', '丹阳', 'divorced', 'none', 'college', 'teacher', 'never', 'never', '是', '是', '结婚', 95, 'approved'),
('cdef6f94-f406-4f37-a5c1-319569fc4e69', '婷婷', 'female', '1998-02-10', 158, '321100', '镇江', 'never_married', 'none', 'master', 'designer', 'sometimes', 'often', '是', '否', '恋爱', 85, 'approved'),
('2db3db2d-ef0f-4f1e-8964-28be1566d1a9', '美玲', 'female', '1990-11-05', 160, '321181', '丹阳', 'never_married', 'none', 'senior_high', 'factory', 'never', 'never', '是', '是', '结婚', 70, 'approved'),
('84431e32-c8f7-48d4-8e0e-fd14d86837e5', '慧琴', 'female', '1996-07-22', 163, '321181', '丹阳', 'never_married', 'none', 'bachelor', 'nurse', 'never', 'sometimes', '是', '是', '结婚', 92, 'approved'),
('bc5ca4a9-08b5-413c-8d80-3afc76fbeb97', '秀英', 'female', '1992-04-18', 157, '321181', '丹阳', 'widowed', 'none', 'junior_high', 'farmer', 'often', 'often', '是', '是', '结婚', 60, 'approved'),
('fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', '张伟', 'male', '1992-01-10', 175, '321181', '丹阳', 'never_married', 'none', 'bachelor', 'engineer', 'never', 'sometimes', '是', '是', '结婚', 88, 'approved'),
('205ddb91-56ef-4a8e-ade1-8cb35bb4affa', '李强', 'male', '1990-08-25', 178, '321181', '丹阳', 'divorced', 'none', 'master', 'manager', 'sometimes', 'often', '是', '是', '结婚', 95, 'approved'),
('f81778e0-ec9e-472e-b7f4-6773e8e3dc81', '王磊', 'male', '1997-12-03', 180, '321100', '镇江', 'never_married', 'none', 'college', 'programmer', 'never', 'never', '是', '是', '恋爱', 82, 'approved'),
('c9f5c328-04fe-4ec6-92af-6073df3af0b0', '赵明', 'male', '1988-05-30', 172, '321181', '丹阳', 'never_married', 'none', 'senior_high', 'sales', 'often', 'often', '否', '是', '结婚', 75, 'approved'),
('34fb0bd1-4703-4744-a4ae-35d5059f5d32', '孙浩', 'male', '1994-03-14', 182, '321181', '丹阳', 'never_married', 'none', 'bachelor', 'doctor', 'never', 'sometimes', '是', '是', '结婚', 97, 'approved'),
('b8846d00-ed0d-4c46-8f36-56c392b9c803', '周洋', 'male', '1999-08-08', 176, '320500', '苏州', 'never_married', 'none', 'master', 'researcher', 'never', 'never', '是', '否', '恋爱', 80, 'approved');
-- 5. 用户择偶偏好
INSERT INTO user_preferences (user_id, min_age, max_age, age_priority, min_height_cm, max_height_cm, height_priority, region_scope, region_priority, marital_statuses, marital_priority, min_education_code, education_priority) VALUES
('c4541dae-c864-459e-b5db-3381867ffbd1', 28, 38, 'required', 170, 185, 'required', '["321181","321100"]', 'required', '["never_married"]', 'required', 'bachelor', 'preferred'),
('f047dbe2-0202-4c57-aa12-1aed76253b62', 28, 40, 'required', 170, 188, 'required', '["321181"]', 'required', '["never_married","divorced"]', 'preferred', 'college', 'preferred'),
('cdef6f94-f406-4f37-a5c1-319569fc4e69', 25, 35, 'preferred', 172, 185, 'preferred', '["321181","321100","320500"]', 'preferred', '["never_married"]', 'required', NULL, NULL),
('2db3db2d-ef0f-4f1e-8964-28be1566d1a9', 30, 45, 'required', 168, 185, 'required', '["321181"]', 'required', '["never_married","divorced"]', 'preferred', 'senior_high', 'preferred'),
('84431e32-c8f7-48d4-8e0e-fd14d86837e5', 27, 36, 'required', 172, 186, 'required', '["321181","321100"]', 'preferred', '["never_married"]', 'required', 'bachelor', 'preferred'),
('bc5ca4a9-08b5-413c-8d80-3afc76fbeb97', 30, 50, 'required', 165, 185, 'required', '["321181"]', 'required', '["never_married","divorced","widowed"]', 'preferred', NULL, NULL),
('fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 22, 32, 'required', 155, 170, 'preferred', '["321181","321100"]', 'required', '["never_married"]', 'required', 'junior_high', 'preferred'),
('205ddb91-56ef-4a8e-ade1-8cb35bb4affa', 25, 38, 'preferred', 158, 172, 'preferred', '["321181"]', 'preferred', '["never_married","divorced"]', 'preferred', 'college', 'preferred'),
('f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 22, 30, 'preferred', 155, 168, 'preferred', '["321181","321100","320500"]', 'preferred', '["never_married"]', 'required', 'college', 'preferred'),
('c9f5c328-04fe-4ec6-92af-6073df3af0b0', 25, 40, 'preferred', 155, 170, 'preferred', '["321181"]', 'required', '["never_married","divorced"]', 'preferred', NULL, NULL),
('34fb0bd1-4703-4744-a4ae-35d5059f5d32', 23, 33, 'required', 158, 170, 'preferred', '["321181","321100"]', 'preferred', '["never_married"]', 'required', 'bachelor', 'preferred'),
('b8846d00-ed0d-4c46-8f36-56c392b9c803', 22, 32, 'preferred', 155, 170, 'preferred', '["321181","321100","320500"]', 'preferred', '["never_married"]', 'required', 'master', 'preferred');
-- 6. 实名认证(mock)
INSERT INTO user_identities (id, user_id, real_name_enc, id_number_enc, id_number_hash, gender, birth_date, verification_status, provider, verified_at) VALUES
('da330615-46ad-4afd-997c-f9accb3808bc', 'c4541dae-c864-459e-b5db-3381867ffbd1', E'\\xenc_f01', E'\\xenc_id_f01', 'demo_sha256_f01', 'female', '1995-06-15', 'verified', 'mock', '2026-03-16T10:00:00Z'),
('58eccd88-b1ba-4316-8eb8-d0900d0aea0e', 'f047dbe2-0202-4c57-aa12-1aed76253b62', E'\\xenc_f02', E'\\xenc_id_f02', 'demo_sha256_f02', 'female', '1993-09-20', 'verified', 'mock', '2026-03-16T10:00:00Z'),
('f3abca38-b593-4375-9b64-2e792b1614a2', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', E'\\xenc_f03', E'\\xenc_id_f03', 'demo_sha256_f03', 'female', '1998-02-10', 'verified', 'mock', '2026-03-16T10:00:00Z'),
('f01e9bcf-5044-4674-baa5-d98c36744925', '2db3db2d-ef0f-4f1e-8964-28be1566d1a9', E'\\xenc_f04', E'\\xenc_id_f04', 'demo_sha256_f04', 'female', '1990-11-05', 'verified', 'mock', '2026-03-16T10:00:00Z'),
('a40fb330-0b08-4a48-9bf3-867ee7bdf51d', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', E'\\xenc_f05', E'\\xenc_id_f05', 'demo_sha256_f05', 'female', '1996-07-22', 'verified', 'mock', '2026-03-16T10:00:00Z'),
('575885c7-7a1c-415e-be6e-452e06610204', 'bc5ca4a9-08b5-413c-8d80-3afc76fbeb97', E'\\xenc_f06', E'\\xenc_id_f06', 'demo_sha256_f06', 'female', '1992-04-18', 'verified', 'mock', '2026-03-16T10:00:00Z'),
('758ef8a8-404c-4b76-900a-ed7a2c568b6b', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', E'\\xenc_m01', E'\\xenc_id_m01', 'demo_sha256_m01', 'male', '1992-01-10', 'verified', 'mock', '2026-03-16T10:00:00Z'),
('4a3618ea-060c-429c-9c7f-83abf39630df', '205ddb91-56ef-4a8e-ade1-8cb35bb4affa', E'\\xenc_m02', E'\\xenc_id_m02', 'demo_sha256_m02', 'male', '1990-08-25', 'verified', 'mock', '2026-03-16T10:00:00Z'),
('2e3299e6-cde5-4cb2-9298-942a5f2a310a', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', E'\\xenc_m03', E'\\xenc_id_m03', 'demo_sha256_m03', 'male', '1997-12-03', 'verified', 'mock', '2026-03-16T10:00:00Z'),
('4c8a6058-f8d8-42d8-9f20-9435cc823696', 'c9f5c328-04fe-4ec6-92af-6073df3af0b0', E'\\xenc_m04', E'\\xenc_id_m04', 'demo_sha256_m04', 'male', '1988-05-30', 'verified', 'mock', '2026-03-16T10:00:00Z'),
('77a40aa0-7cd6-4571-b676-7f985da446e1', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', E'\\xenc_m05', E'\\xenc_id_m05', 'demo_sha256_m05', 'male', '1994-03-14', 'verified', 'mock', '2026-03-16T10:00:00Z'),
('177fbf84-92bb-40d7-adb2-11e9ab9e7b05', 'b8846d00-ed0d-4c46-8f36-56c392b9c803', E'\\xenc_m06', E'\\xenc_id_m06', 'demo_sha256_m06', 'male', '1999-08-08', 'verified', 'mock', '2026-03-16T10:00:00Z');
-- 7. 兴趣标签
INSERT INTO user_interests (user_id, interest_code) VALUES
('c4541dae-c864-459e-b5db-3381867ffbd1', 'reading'),
('c4541dae-c864-459e-b5db-3381867ffbd1', 'cooking'),
('c4541dae-c864-459e-b5db-3381867ffbd1', 'travel'),
('f047dbe2-0202-4c57-aa12-1aed76253b62', 'sports'),
('f047dbe2-0202-4c57-aa12-1aed76253b62', 'music'),
('f047dbe2-0202-4c57-aa12-1aed76253b62', 'outdoor'),
('cdef6f94-f406-4f37-a5c1-319569fc4e69', 'photography'),
('cdef6f94-f406-4f37-a5c1-319569fc4e69', 'dance'),
('cdef6f94-f406-4f37-a5c1-319569fc4e69', 'movie'),
('2db3db2d-ef0f-4f1e-8964-28be1566d1a9', 'pets'),
('2db3db2d-ef0f-4f1e-8964-28be1566d1a9', 'cooking'),
('84431e32-c8f7-48d4-8e0e-fd14d86837e5', 'reading'),
('84431e32-c8f7-48d4-8e0e-fd14d86837e5', 'fitness'),
('84431e32-c8f7-48d4-8e0e-fd14d86837e5', 'charity'),
('bc5ca4a9-08b5-413c-8d80-3afc76fbeb97', 'gardening'),
('bc5ca4a9-08b5-413c-8d80-3afc76fbeb97', 'cooking'),
('fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'sports'),
('fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'gaming'),
('fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'travel'),
('205ddb91-56ef-4a8e-ade1-8cb35bb4affa', 'reading'),
('205ddb91-56ef-4a8e-ade1-8cb35bb4affa', 'investment'),
('205ddb91-56ef-4a8e-ade1-8cb35bb4affa', 'hiking'),
('f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'gaming'),
('f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'music'),
('f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'coding'),
('c9f5c328-04fe-4ec6-92af-6073df3af0b0', 'cars'),
('c9f5c328-04fe-4ec6-92af-6073df3af0b0', 'cooking'),
('34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'running'),
('34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'reading'),
('34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'charity'),
('b8846d00-ed0d-4c46-8f36-56c392b9c803', 'research'),
('b8846d00-ed0d-4c46-8f36-56c392b9c803', 'travel'),
('b8846d00-ed0d-4c46-8f36-56c392b9c803', 'photography');
-- 8. 隐私设置
INSERT INTO user_privacy_settings (user_id, visible_in_recommendations, visible_in_search, show_occupation, show_lifestyle_photos, receive_activity_recommendations, accept_matchmaker_recommendations) VALUES
('c4541dae-c864-459e-b5db-3381867ffbd1', true, true, true, true, true, true),
('f047dbe2-0202-4c57-aa12-1aed76253b62', true, true, true, false, true, true),
('cdef6f94-f406-4f37-a5c1-319569fc4e69', true, false, true, true, true, false),
('2db3db2d-ef0f-4f1e-8964-28be1566d1a9', true, true, false, true, true, true),
('84431e32-c8f7-48d4-8e0e-fd14d86837e5', true, true, true, true, false, true),
('bc5ca4a9-08b5-413c-8d80-3afc76fbeb97', true, false, true, true, true, true),
('fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', true, true, true, true, true, true),
('205ddb91-56ef-4a8e-ade1-8cb35bb4affa', true, true, true, false, true, true),
('f81778e0-ec9e-472e-b7f4-6773e8e3dc81', true, true, true, true, true, false),
('c9f5c328-04fe-4ec6-92af-6073df3af0b0', true, false, true, true, true, true),
('34fb0bd1-4703-4744-a4ae-35d5059f5d32', true, true, true, true, true, true),
('b8846d00-ed0d-4c46-8f36-56c392b9c803', true, true, true, true, true, true);
-- 9. 照片
INSERT INTO user_photos (id, user_id, file_key, photo_type, sort_order, review_status) VALUES
('48ad218e-6776-4a71-aebd-a82c0e727b68', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'photos/demo/f01/avatar.jpg', 'avatar', 0, 'approved'),
('1ce92025-554d-4f54-8d95-f469bcba6dc4', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'photos/demo/f01/lifestyle1.jpg', 'lifestyle', 1, 'approved'),
('c5e0ecd6-2aa3-488c-acf5-18f2a71879d5', 'f047dbe2-0202-4c57-aa12-1aed76253b62', 'photos/demo/f02/avatar.jpg', 'avatar', 0, 'approved'),
('d63c7dfc-4280-4adb-a0fb-16bea69b804e', 'f047dbe2-0202-4c57-aa12-1aed76253b62', 'photos/demo/f02/lifestyle1.jpg', 'lifestyle', 1, 'approved'),
('6b6dfd9b-e5de-41a6-9d86-567149c87457', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 'photos/demo/f03/avatar.jpg', 'avatar', 0, 'approved'),
('e5a64a34-ce55-4f55-99d1-8399a94c0ca9', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 'photos/demo/f03/lifestyle1.jpg', 'lifestyle', 1, 'approved'),
('2f7b7db2-bfbb-424c-ae23-246f0ef6e736', '2db3db2d-ef0f-4f1e-8964-28be1566d1a9', 'photos/demo/f04/avatar.jpg', 'avatar', 0, 'approved'),
('e6373dd7-2f65-40b3-8495-d39a6d85bc38', '2db3db2d-ef0f-4f1e-8964-28be1566d1a9', 'photos/demo/f04/lifestyle1.jpg', 'lifestyle', 1, 'approved'),
('d06a1fab-a238-4026-a531-9ad0cd6d0964', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', 'photos/demo/f05/avatar.jpg', 'avatar', 0, 'approved'),
('897dcb17-cbd1-477d-9d4f-48b9e1259f2f', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', 'photos/demo/f05/lifestyle1.jpg', 'lifestyle', 1, 'approved'),
('17c33ec0-f17c-4544-8a91-d2dae2261d7b', 'bc5ca4a9-08b5-413c-8d80-3afc76fbeb97', 'photos/demo/f06/avatar.jpg', 'avatar', 0, 'approved'),
('5076173d-d28e-4f0b-869f-b7b032fc44d8', 'bc5ca4a9-08b5-413c-8d80-3afc76fbeb97', 'photos/demo/f06/lifestyle1.jpg', 'lifestyle', 1, 'approved'),
('527404ea-5110-45dd-9446-90eb7531b096', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'photos/demo/m01/avatar.jpg', 'avatar', 0, 'approved'),
('5bb6b2b9-b398-49d6-ae42-5105ed0e485b', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'photos/demo/m01/lifestyle1.jpg', 'lifestyle', 1, 'approved'),
('d5ca9b88-6f82-4a4b-87ba-e2d40baa89e6', '205ddb91-56ef-4a8e-ade1-8cb35bb4affa', 'photos/demo/m02/avatar.jpg', 'avatar', 0, 'approved'),
('17d5b522-6653-4d5c-a9b0-89d17357cbba', '205ddb91-56ef-4a8e-ade1-8cb35bb4affa', 'photos/demo/m02/lifestyle1.jpg', 'lifestyle', 1, 'approved'),
('036b1eec-b4c4-4596-815e-4500400835af', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'photos/demo/m03/avatar.jpg', 'avatar', 0, 'approved'),
('4db14b12-26da-44a5-a901-e01cc6f7ced2', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'photos/demo/m03/lifestyle1.jpg', 'lifestyle', 1, 'approved'),
('42e0a447-9f30-401e-beda-9fe9fa31c1b9', 'c9f5c328-04fe-4ec6-92af-6073df3af0b0', 'photos/demo/m04/avatar.jpg', 'avatar', 0, 'approved'),
('dffdc05a-3fa9-43f6-8624-fac879d8c99b', 'c9f5c328-04fe-4ec6-92af-6073df3af0b0', 'photos/demo/m04/lifestyle1.jpg', 'lifestyle', 1, 'approved'),
('684196ca-b76c-4028-94d1-dda8f2d167ff', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'photos/demo/m05/avatar.jpg', 'avatar', 0, 'approved'),
('96afba03-b70b-4d2d-be25-13a94f8c9f5f', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'photos/demo/m05/lifestyle1.jpg', 'lifestyle', 1, 'approved'),
('cd94a30d-a667-495f-8a89-575a906b37fa', 'b8846d00-ed0d-4c46-8f36-56c392b9c803', 'photos/demo/m06/avatar.jpg', 'avatar', 0, 'approved'),
('c99f72ef-77e1-4785-a292-50d4499eae2b', 'b8846d00-ed0d-4c46-8f36-56c392b9c803', 'photos/demo/m06/lifestyle1.jpg', 'lifestyle', 1, 'approved');
-- 10. 审核任务
INSERT INTO review_tasks (id, user_id, review_type, status, assigned_operator_id, submitted_at, started_at, completed_at, final_comment, version) VALUES
('2a3d4499-444d-48c1-b648-05e97a195253', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'initial_profile', 'approved', 'e9312b05-c263-4901-8145-0b38e4d81c45', '2026-03-15T11:00:00Z', '2026-03-15T11:30:00Z', '2026-03-15T12:00:00Z', '资料完整', 1),
('2f6fa325-3318-44e2-893f-0e148a200ce0', 'f047dbe2-0202-4c57-aa12-1aed76253b62', 'initial_profile', 'approved', 'e9312b05-c263-4901-8145-0b38e4d81c45', '2026-03-20T11:00:00Z', '2026-03-20T11:30:00Z', '2026-03-20T12:00:00Z', '资料完整', 1),
('00ab8ee6-8a94-4d20-839f-d52a018afa19', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 'initial_profile', 'approved', 'e9312b05-c263-4901-8145-0b38e4d81c45', '2026-04-01T11:00:00Z', '2026-04-01T11:30:00Z', '2026-04-01T12:00:00Z', '资料完整', 1),
('e4043790-9aa1-4de8-8983-431bf277f8be', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'initial_profile', 'approved', 'e9312b05-c263-4901-8145-0b38e4d81c45', '2026-03-10T11:00:00Z', '2026-03-10T11:30:00Z', '2026-03-10T12:00:00Z', '资料完整', 1),
('9befa465-201f-4aa6-bedf-2b22bbf3093d', '205ddb91-56ef-4a8e-ade1-8cb35bb4affa', 'initial_profile', 'approved', 'e9312b05-c263-4901-8145-0b38e4d81c45', '2026-03-25T11:00:00Z', '2026-03-25T11:30:00Z', '2026-03-25T12:00:00Z', '资料完整', 1),
('2d653f28-a054-430e-b6f9-5e3cfe471e06', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'initial_profile', 'approved', 'e9312b05-c263-4901-8145-0b38e4d81c45', '2026-04-05T11:00:00Z', '2026-04-05T11:30:00Z', '2026-04-05T12:00:00Z', '资料完整', 1),
('88477767-1aed-4490-8fa4-2591a8e498eb', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'initial_profile', 'approved', 'e9312b05-c263-4901-8145-0b38e4d81c45', '2026-05-01T11:00:00Z', '2026-05-01T11:30:00Z', '2026-05-01T12:00:00Z', '资料完整', 1);
-- 11. 用户关系
INSERT INTO user_relations (id, user_id, target_user_id, relation_type, created_at) VALUES
('bda459e2-dc16-4c08-8381-ebfe7eed2f37', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'liked', '2026-06-01T10:00:00Z'),
('0fc82925-2b92-4c4e-a5a5-c4a8a987b2b2', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'liked', '2026-06-01T10:05:00Z'),
('aaa0e94c-67d1-46d1-801e-23ad8d15336c', 'f047dbe2-0202-4c57-aa12-1aed76253b62', '205ddb91-56ef-4a8e-ade1-8cb35bb4affa', 'liked', '2026-06-02T14:00:00Z'),
('3cb1c7c5-d00f-484e-abaf-e73e61197c48', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'liked', '2026-06-03T09:00:00Z'),
('6d14800d-206c-48f0-bcbe-13294f2dace8', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 'liked', '2026-06-03T09:30:00Z'),
('6ebe4be5-9284-4a7f-9957-ef5a55bcf73e', 'c9f5c328-04fe-4ec6-92af-6073df3af0b0', 'f047dbe2-0202-4c57-aa12-1aed76253b62', 'liked', '2026-06-04T11:00:00Z'),
('8f402a22-fb94-4714-af2b-51a9eae647b6', '2db3db2d-ef0f-4f1e-8964-28be1566d1a9', 'c9f5c328-04fe-4ec6-92af-6073df3af0b0', 'passed', '2026-06-04T12:00:00Z'),
('15528215-d21f-42c3-bd63-fdb118f376d3', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'liked', '2026-06-05T10:00:00Z'),
('3c2b7e96-cf38-4c0c-899e-40eff50e0c5d', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', 'liked', '2026-06-05T10:05:00Z'),
('15e580c3-3182-4131-a332-462d76626f9d', 'b8846d00-ed0d-4c46-8f36-56c392b9c803', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'liked', '2026-06-06T14:00:00Z'),
('d279e35a-af73-45b4-847b-9e61c0f4e912', '2db3db2d-ef0f-4f1e-8964-28be1566d1a9', 'b8846d00-ed0d-4c46-8f36-56c392b9c803', 'passed', '2026-06-06T15:00:00Z'),
('0d038769-c289-4ca0-95e1-664485b1cdf1', 'bc5ca4a9-08b5-413c-8d80-3afc76fbeb97', 'c9f5c328-04fe-4ec6-92af-6073df3af0b0', 'blocked', '2026-06-07T09:00:00Z'),
('a93b823c-515f-4b2e-a42e-3038c0dd6bb8', '205ddb91-56ef-4a8e-ade1-8cb35bb4affa', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 'passed', '2026-06-07T10:00:00Z');
-- 12. Match
INSERT INTO matches (id, user_a_id, user_b_id, status, source, matched_at) VALUES
('66dc8358-60a5-49d8-bdd2-fb191c6fe1ec', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'active', 'user_like', '2026-06-01T10:05:00Z'),
('e916d86e-5ed3-4ab7-b657-e5bbcf8d8649', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'active', 'user_like', '2026-06-03T09:30:00Z'),
('5b06ec2b-2ca7-4a11-811a-15b9e97a8a0c', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'successful', 'user_like', '2026-06-05T10:05:00Z');
-- 13. 成功牵手请求
INSERT INTO relationship_success_requests (id, match_id, initiated_by, status, confirmed_by, created_at, resolved_at) VALUES
('1d1b187e-bfec-4b5d-931a-165a543a0cce', '5b06ec2b-2ca7-4a11-811a-15b9e97a8a0c', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', 'confirmed', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', '2026-07-01T10:00:00Z', '2026-07-01T10:30:00Z'),
('a9c95cd2-953e-418a-8694-060f39f02d56', '66dc8358-60a5-49d8-bdd2-fb191c6fe1ec', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'pending', NULL, '2026-07-15T14:00:00Z', NULL);
-- 14. Conversations & Members
INSERT INTO conversations (id, match_id, status, last_message_at) VALUES
('d414d2ef-88a3-4ad1-a9e6-e4e133aa406f', '66dc8358-60a5-49d8-bdd2-fb191c6fe1ec', 'active', '2026-07-10T16:00:00Z'),
('376cb263-b4d5-4004-83cb-020136e27951', 'e916d86e-5ed3-4ab7-b657-e5bbcf8d8649', 'active', '2026-07-08T20:00:00Z'),
('f1166385-e9b3-456f-8853-36dcdf2d6585', '5b06ec2b-2ca7-4a11-811a-15b9e97a8a0c', 'active', '2026-07-01T18:00:00Z');
INSERT INTO conversation_members (conversation_id, user_id, unread_count, can_send, joined_at) VALUES
('d414d2ef-88a3-4ad1-a9e6-e4e133aa406f', 'c4541dae-c864-459e-b5db-3381867ffbd1', 0, true, '2026-06-01T10:05:00Z'),
('d414d2ef-88a3-4ad1-a9e6-e4e133aa406f', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 0, true, '2026-06-01T10:05:00Z'),
('376cb263-b4d5-4004-83cb-020136e27951', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 1, true, '2026-06-03T09:30:00Z'),
('376cb263-b4d5-4004-83cb-020136e27951', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 0, true, '2026-06-03T09:30:00Z'),
('f1166385-e9b3-456f-8853-36dcdf2d6585', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', 0, true, '2026-06-05T10:05:00Z'),
('f1166385-e9b3-456f-8853-36dcdf2d6585', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', 0, true, '2026-06-05T10:05:00Z');
INSERT INTO messages (id, conversation_id, sender_id, message_type, content, status, risk_level, created_at) VALUES
('1c18c46c-b0cb-44fd-9f6e-76aaff8f4c94', 'd414d2ef-88a3-4ad1-a9e6-e4e133aa406f', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'text', '你好!看到你的资料觉得挺合适的~', 'sent', 'normal', '2026-06-15T14:00:00Z'),
('b334b8b9-d265-4616-9ad5-b492b84347a8', 'd414d2ef-88a3-4ad1-a9e6-e4e133aa406f', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'text', '你好!谢谢你的喜欢,我也觉得挺有缘的', 'sent', 'normal', '2026-06-15T14:05:00Z'),
('bdf6f634-d923-413f-8e96-73cd596e4a6e', 'd414d2ef-88a3-4ad1-a9e6-e4e133aa406f', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'text', '你也在丹阳工作吗?平时喜欢做些什么?', 'sent', 'normal', '2026-06-15T14:10:00Z'),
('512e7b14-e671-4cbb-b2e7-e3e90471d42f', '376cb263-b4d5-4004-83cb-020136e27951', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'text', '嗨,你好!很高兴认识你', 'sent', 'normal', '2026-07-05T19:30:00Z'),
('e5bc8ec6-0edf-4c0d-998d-719460163dae', '376cb263-b4d5-4004-83cb-020136e27951', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 'text', '你好呀!我平时喜欢拍照和跳舞,你呢?', 'sent', 'normal', '2026-07-05T19:35:00Z'),
('b0067406-d65b-4347-b306-c86e99e06fa0', 'f1166385-e9b3-456f-8853-36dcdf2d6585', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'text', '你好,很高兴认识你!', 'sent', 'normal', '2026-06-10T10:00:00Z');
UPDATE conversations SET last_message_at = (SELECT MAX(created_at) FROM messages WHERE messages.conversation_id = conversations.id);
-- 15. 推荐记录
INSERT INTO recommendation_records (id, user_id, target_user_id, source, score, level, shown_at, action, action_at, rule_version) VALUES
('61c4c3c5-47d7-4992-ab99-da2ec12d2954', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'daily', 82.5, 'high', '2026-05-28T10:00:00Z', 'liked', '2026-06-01T10:00:00Z', 1),
('246fc1b0-b892-4881-8a0c-1537a8fa267b', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'daily', 70.0, 'medium', '2026-05-28T10:00:00Z', 'passed', '2026-05-28T10:01:00Z', 1),
('0763ff52-ed3d-453c-b801-df90992924b5', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'daily', 85.0, 'high', '2026-05-28T11:00:00Z', 'liked', '2026-06-01T10:05:00Z', 1),
('d8004de7-ad32-4298-988e-1be9230e78b6', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'daily', 78.0, 'high', '2026-06-01T09:00:00Z', 'liked', '2026-06-03T09:30:00Z', 1),
('9d9b26cf-4bf6-49e8-9a33-56d8d091e3c5', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 'daily', 75.0, 'high', '2026-06-01T09:30:00Z', 'liked', '2026-06-03T09:30:00Z', 1),
('4b3a63b1-3104-49b9-a3a2-10641d34bbf7', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'daily', 88.0, 'high', '2026-06-01T10:00:00Z', 'liked', '2026-06-05T10:00:00Z', 1),
('1733c991-5d02-4f2b-b1cf-0531ee322508', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', 'daily', 86.0, 'high', '2026-06-01T10:30:00Z', 'liked', '2026-06-05T10:05:00Z', 1),
('9316d0f2-c77c-4cd4-8308-a32d9513de89', 'b8846d00-ed0d-4c46-8f36-56c392b9c803', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'daily', 62.0, 'medium', '2026-06-06T14:00:00Z', 'liked', '2026-06-06T14:00:00Z', 1);
-- 16. 相亲活动
INSERT INTO activities (id, title, description, organizer_org_id, coorganizer_text, start_at, end_at, location_name, location_address, male_limit, female_limit, total_limit, min_age, max_age, registration_start_at, registration_end_at, need_review, status, created_by) VALUES
('ed89a418-c049-43cc-9cca-a71e403a451a', '丹阳公益单身联谊会(夏季场)', '面向丹阳市区及周边乡镇的单身青年,由妇联、工会联合主办。', 'c74863d4-be10-4efa-b22c-f3f84e2e4e59', '丹阳市总工会、丹阳市慈善基金会', '2026-08-15T14:00:00Z', '2026-08-15T17:30:00Z', '丹阳市文化馆多功能厅', '丹阳市丹北路168号', 15, 15, 30, 22, 40, '2026-07-01T00:00:00Z', '2026-08-10T23:59:59Z', true, 'registration_open', 'b4cdeb91-bbce-4587-be58-22ff55ef89da'),
('3fd86a27-605c-48ac-8f97-2bbb205f3a98', '七夕特别活动·丹阳缘来是你', '七夕节特别策划,浪漫主题相亲活动。', 'a35f0043-be09-4bdf-ad5d-05a72ff19c2a', '丹阳市新时代文明实践中心', '2026-08-29T15:00:00Z', '2026-08-29T18:00:00Z', '丹阳大剧院报告厅', '丹阳市书院路28号', 20, 20, 40, 25, 45, '2026-08-01T00:00:00Z', '2026-08-25T23:59:59Z', true, 'draft', 'b4cdeb91-bbce-4587-be58-22ff55ef89da');
-- 17. 活动报名
INSERT INTO activity_registrations (id, activity_id, user_id, status, registered_at, reviewed_by, reviewed_at, checkin_status) VALUES
('d094b282-21ab-4b79-9dfa-f5377a660473', 'ed89a418-c049-43cc-9cca-a71e403a451a', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'approved', '2026-07-05T10:00:00Z', 'b4cdeb91-bbce-4587-be58-22ff55ef89da', '2026-07-05T10:30:00Z', 'not_checked_in'),
('b82c965d-2392-448e-9dc2-a6b7fc064346', 'ed89a418-c049-43cc-9cca-a71e403a451a', 'f047dbe2-0202-4c57-aa12-1aed76253b62', 'pending', '2026-07-12T10:00:00Z', NULL, NULL, 'not_checked_in'),
('f4c7440e-76c2-4a41-b56d-ee4e7a6c48b4', 'ed89a418-c049-43cc-9cca-a71e403a451a', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 'approved', '2026-07-06T14:00:00Z', 'b4cdeb91-bbce-4587-be58-22ff55ef89da', '2026-07-06T14:15:00Z', 'not_checked_in'),
('7a5c3536-c2c9-4fc3-ab54-5ce8ee6a3e2b', 'ed89a418-c049-43cc-9cca-a71e403a451a', '2db3db2d-ef0f-4f1e-8964-28be1566d1a9', 'rejected', '2026-07-13T09:00:00Z', 'b4cdeb91-bbce-4587-be58-22ff55ef89da', '2026-07-13T09:15:00Z', 'not_checked_in'),
('ef981d5b-98ca-4a1b-b29f-c465a9f6d9e8', 'ed89a418-c049-43cc-9cca-a71e403a451a', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', 'approved', '2026-07-07T09:00:00Z', 'b4cdeb91-bbce-4587-be58-22ff55ef89da', '2026-07-07T09:20:00Z', 'not_checked_in'),
('e3f8c9aa-54d6-401f-9135-75fdad8c5cc6', 'ed89a418-c049-43cc-9cca-a71e403a451a', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'approved', '2026-07-08T11:00:00Z', 'b4cdeb91-bbce-4587-be58-22ff55ef89da', '2026-07-08T11:10:00Z', 'not_checked_in'),
('a2f14159-c7e0-442d-89af-f3bfc24a15c9', 'ed89a418-c049-43cc-9cca-a71e403a451a', '205ddb91-56ef-4a8e-ade1-8cb35bb4affa', 'approved', '2026-07-11T16:00:00Z', 'b4cdeb91-bbce-4587-be58-22ff55ef89da', '2026-07-11T16:30:00Z', 'not_checked_in'),
('5a0ef97f-1c72-4c1d-a163-84f04a25f3ea', 'ed89a418-c049-43cc-9cca-a71e403a451a', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'approved', '2026-07-09T15:00:00Z', 'b4cdeb91-bbce-4587-be58-22ff55ef89da', '2026-07-09T15:20:00Z', 'not_checked_in'),
('dd669f4a-2464-4f7f-b88a-a29cf5895791', 'ed89a418-c049-43cc-9cca-a71e403a451a', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'approved', '2026-07-10T08:30:00Z', 'b4cdeb91-bbce-4587-be58-22ff55ef89da', '2026-07-10T08:45:00Z', 'not_checked_in');
-- 18. 活动互选意向
INSERT INTO activity_interests (id, source_user_id, target_user_id, activity_id, status, confirmed_at, created_at) VALUES
('d16a150e-c4c4-4311-a1ce-840804ff4003', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'ed89a418-c049-43cc-9cca-a71e403a451a', 'mutual', '2026-08-15T17:00:00Z', '2026-08-15T17:00:00Z'),
('659f8441-ea7c-4fba-9d5a-557f10b02a03', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'ed89a418-c049-43cc-9cca-a71e403a451a', 'mutual', '2026-08-15T17:05:00Z', '2026-08-15T17:05:00Z'),
('a0f2cf79-d884-4584-8ee4-51772660e670', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'ed89a418-c049-43cc-9cca-a71e403a451a', 'expressed', '2026-08-15T17:10:00Z', '2026-08-15T17:10:00Z');
-- 19. 红娘服务
INSERT INTO matchmaker_services (id, user_id, service_type, description, status, organization_id, assigned_operator_id, assigned_at, completed_at) VALUES
('a85dc667-3d0c-4f0f-9eea-03dc213f9bec', 'f047dbe2-0202-4c57-aa12-1aed76253b62', 'recommend_partner', '离异用户希望找到合适的伴侣', 'in_service', 'c74863d4-be10-4efa-b22c-f3f84e2e4e59', 'a98c0d97-d272-4577-887e-5c05e27db19b', '2026-06-20T10:00:00Z', NULL),
('f0297c00-59cb-4f3e-ae86-c31fb4e55e6a', 'bc5ca4a9-08b5-413c-8d80-3afc76fbeb97', 'no_match_help', '丧偶用户希望重新融入社交', 'waiting_user', 'bcd9e5b6-3b66-454c-96d7-3fade6866135', 'a98c0d97-d272-4577-887e-5c05e27db19b', '2026-06-25T14:00:00Z', NULL),
('dd07da6e-d6b4-461c-be3c-2a0279c10c4a', '2db3db2d-ef0f-4f1e-8964-28be1566d1a9', 'review_preference', '用户希望调整择偶条件', 'completed', 'c74863d4-be10-4efa-b22c-f3f84e2e4e59', 'a98c0d97-d272-4577-887e-5c05e27db19b', '2026-06-15T09:00:00Z', '2026-06-20T11:00:00Z');
INSERT INTO matchmaker_recommendations (id, service_id, user_id, target_user_id, operator_id, reason, status, created_at, viewed_at, responded_at) VALUES
('e1c1cf64-24e5-4e6d-a02c-f11a154a0ccd', 'a85dc667-3d0c-4f0f-9eea-03dc213f9bec', 'f047dbe2-0202-4c57-aa12-1aed76253b62', '205ddb91-56ef-4a8e-ade1-8cb35bb4affa', 'a98c0d97-d272-4577-887e-5c05e27db19b', '两人同在丹阳工作,年龄相仿,都离过婚有共同语言', 'viewed', '2026-06-21T10:00:00Z', '2026-06-22T09:00:00Z', NULL);
INSERT INTO matchmaker_followups (id, service_id, operator_id, followup_type, content, result_code, next_followup_at, created_at) VALUES
('8cd728c6-8215-4941-994c-139d867efec9', 'a85dc667-3d0c-4f0f-9eea-03dc213f9bec', 'a98c0d97-d272-4577-887e-5c05e27db19b', 'phone_call', '电话沟通用户情况,了解离异原因及择偶期望', '正常', '2026-07-01T10:00:00Z', '2026-06-22T10:00:00Z'),
('1e952261-23aa-4a47-8de4-b906d7fb65e5', 'dd07da6e-d6b4-461c-be3c-2a0279c10c4a', 'a98c0d97-d272-4577-887e-5c05e27db19b', 'face_to_face', '面对面交流,帮助用户调整身高要求从170改为168', '已调整', NULL, '2026-06-18T15:00:00Z');
-- 20. 系统通知
INSERT INTO notifications (id, user_id, type, title, content, business_type, read_status, created_at) VALUES
('7ce61e30-5dae-464c-a597-5c5b0897889c', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'match', '你们互相喜欢!', '张伟也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-01T10:05:00Z'),
('8f237f69-b647-4055-98fe-0b391d3997ac', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'match', '你们互相喜欢!', '小芳也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-01T10:05:00Z'),
('866d0a81-366f-41fa-a8f4-12b0e0263a69', 'cdef6f94-f406-4f37-a5c1-319569fc4e69', 'match', '你们互相喜欢!', '王磊也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-03T09:30:00Z'),
('892484ed-69c0-45bb-9581-18b74cea65be', 'f81778e0-ec9e-472e-b7f4-6773e8e3dc81', 'match', '你们互相喜欢!', '婷婷也喜欢了你,可以开始聊天啦~', 'match', 'unread', '2026-06-03T09:30:00Z'),
('cff60e91-2b3b-4969-b84e-f61c7f4f1a32', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', 'match', '你们互相喜欢!', '孙浩也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-05T10:05:00Z'),
('4365fe9f-ac11-4039-9d73-f5a0cb0aa782', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'match', '你们互相喜欢!', '慧琴也喜欢了你,可以开始聊天啦~', 'match', 'read', '2026-06-05T10:05:00Z'),
('a5ca22bf-c269-4840-a7f3-79df800a9dfd', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', 'system', '恭喜牵手成功!', '您与孙浩已成功牵手,祝你们幸福!', 'match', 'read', '2026-07-01T10:30:00Z'),
('7439e900-c532-4d23-a231-9fd0ef967387', '34fb0bd1-4703-4744-a4ae-35d5059f5d32', 'system', '恭喜牵手成功!', '您与慧琴已成功牵手,祝你们幸福!', 'match', 'read', '2026-07-01T10:30:00Z'),
('c5e0d1b1-b840-4d64-9c5b-f4ccbd466a90', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'activity', '活动报名已确认', '您已成功报名「丹阳公益单身联谊会」', 'activity', 'read', '2026-07-05T10:30:00Z'),
('b1bac483-1813-4196-b19a-b49f8fdabbfb', '84431e32-c8f7-48d4-8e0e-fd14d86837e5', 'activity', '活动报名已确认', '您已成功报名「丹阳公益单身联谊会」', 'activity', 'unread', '2026-07-07T09:20:00Z'),
('f0ec9306-5764-4980-850c-6c9cb09f2771', 'f047dbe2-0202-4c57-aa12-1aed76253b62', 'matchmaker', '红娘已为您服务', '您的红娘服务申请已被分配,红娘小王将在24小时内与您联系', 'matchmaker', 'read', '2026-06-20T10:30:00Z');
-- 21. 同意记录
INSERT INTO consent_records (id, user_id, type, version, agreed_at, ip_address, user_agent) VALUES
('36f6a591-6cf0-4ca1-b146-c52c9706d463', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'terms_of_service', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'),
('e7c45af8-5a56-4f46-bd8e-04b7a779b7a6', 'c4541dae-c864-459e-b5db-3381867ffbd1', 'privacy_policy', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'),
('c479dc80-f0d8-4988-8f89-d1f833de64c5', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'terms_of_service', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0'),
('d344037f-b275-49fb-990f-0d7f4bda9291', 'fc27c8c4-7e7e-40b3-8e2e-0e9f0c0d73c7', 'privacy_policy', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0');
-- 22. 审核原因字典
INSERT INTO review_reasons (code, name, category, enabled, sort_order) VALUES
('profile_incomplete', '资料不完整', 'quality', true, 1),
('photo_unclear', '照片不清晰', 'quality', true, 2),
('fake_info', '信息疑似虚假', 'trust', true, 3),
('inappropriate_photo', '照片内容不当', 'safety', true, 4),
('duplicate_identity', '重复注册', 'duplicate', true, 5),
('suspicious_behavior', '行为异常', 'risk', true, 6),
('manual_review_needed', '需人工复核', 'quality', true, 7);
SET session_replication_role = 'origin';
DO $$ DECLARE u_cnt INTEGER; op_cnt INTEGER; m_cnt INTEGER; a_cnt INTEGER; p_cnt INTEGER;
BEGIN SELECT COUNT(*) INTO u_cnt FROM users WHERE deleted_at IS NULL;
SELECT COUNT(*) INTO op_cnt FROM operators; SELECT COUNT(*) INTO m_cnt FROM matches;
SELECT COUNT(*) INTO a_cnt FROM activities WHERE deleted_at IS NULL;
SELECT COUNT(*) INTO p_cnt FROM user_profiles;
RAISE NOTICE '========================================';
RAISE NOTICE 'Demo 数据填充完成!';
RAISE NOTICE ' 用户: %人 | 资料: %条 | 操作员: %人', u_cnt, p_cnt, op_cnt;
RAISE NOTICE ' Match: %对 | 活动: %个', m_cnt, a_cnt;
RAISE NOTICE '========================================';
END $$;
+419
View File
@@ -0,0 +1,419 @@
-- ============================================================
-- 丹阳公益婚恋服务平台 — Demo Seed 数据脚本
-- 版本: 1.0.0-RC.2
-- 说明: 生成演示用数据,含组织、工作人员、用户、活动、聊天等
-- 执行方式: psql -d danyang_match -f backend/src/main/resources/db/demo-seed.sql
-- ============================================================
-- 禁用外键检查,允许乱序插入
SET session_replication_role = 'replica';
-- ============================================================
-- 1. 组织(organizations)
-- ============================================================
INSERT INTO organizations (id, name, type, contact_name, status) VALUES
('org-danyang-women', '丹阳市妇女联合会', 'women_federation', '张丽华', 'active'),
('org-danyang-trade', '丹阳市总工会', 'trade_union', '李明远', 'active'),
('org-danyang-charity', '丹阳市慈善基金会', 'charity_center', '王秀英', 'active');
-- ============================================================
-- 2. 工作人员(operators)— 密码均为 BCrypt hash of "demo123"
-- ============================================================
INSERT INTO operators (id, organization_id, name, username, password_hash, status) VALUES
('op-admin-001', 'org-danyang-women', '陈主任', 'admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'),
('op-mh001', 'org-danyang-women', '红娘小王', 'wanghongniang', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'),
('op-rv001', 'org-danyang-charity', '审核员小张', 'reviewer01', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active'),
('op-act01', 'org-danyang-trade', '活动管理员赵', 'activitymgr', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHdBfKYuPIiCTB6MJJDEaK', 'active');
-- 操作员角色绑定
INSERT INTO operator_roles (operator_id, role_id) VALUES
('op-admin-001', '00000000-0000-0000-0000-000000000001'),
('op-admin-001', '00000000-0000-0000-0000-000000000002'),
('op-mh001', '00000000-0000-0000-0000-000000000005'),
('op-mh001', '00000000-0000-0000-0000-000000000006'),
('op-rv001', '00000000-0000-0000-0000-000000000004'),
('op-rv001', '00000000-0000-0000-0000-000000000007'),
('op-act01', '00000000-0000-0000-0000-000000000006'),
('op-act01', '00000000-0000-0000-0000-000000000008');
-- ============================================================
-- 3. Demo 用户 — 12人(6男6女)
-- ============================================================
INSERT INTO users (id, wechat_openid, phone, account_status, relationship_status, recommendation_enabled, created_at) VALUES
('user-f01', 'demo_openid_f01', NULL, 'normal', 'searching', true, '2026-03-15T10:00:00Z'),
('user-f02', 'demo_openid_f02', NULL, 'normal', 'searching', true, '2026-03-20T14:30:00Z'),
('user-f03', 'demo_openid_f03', NULL, 'normal', 'searching', true, '2026-04-01T09:15:00Z'),
('user-f04', 'demo_openid_f04', NULL, 'normal', 'paused', true, '2026-04-10T16:00:00Z'),
('user-f05', 'demo_openid_f05', NULL, 'normal', 'searching', true, '2026-05-01T11:20:00Z'),
('user-f06', 'demo_openid_f06', NULL, 'normal', 'searching', true, '2026-05-15T08:45:00Z'),
('user-m01', 'demo_openid_m01', NULL, 'normal', 'searching', true, '2026-03-10T09:00:00Z'),
('user-m02', 'demo_openid_m02', NULL, 'normal', 'getting_to_know', true, '2026-03-25T13:00:00Z'),
('user-m03', 'demo_openid_m03', NULL, 'normal', 'searching', true, '2026-04-05T15:30:00Z'),
('user-m04', 'demo_openid_m04', NULL, 'normal', 'searching', true, '2026-04-20T10:00:00Z'),
('user-m05', 'demo_openid_m05', NULL, 'normal', 'matched_successfully', true, '2026-05-01T14:00:00Z'),
('user-m06', 'demo_openid_m06', NULL, 'normal', 'searching', true, '2026-05-10T16:30:00Z');
-- ============================================================
-- 4. 用户资料(user_profiles)
-- ============================================================
INSERT INTO user_profiles (
user_id, display_name, gender, birth_date, height_cm,
region_code, region_name, marital_status, children_status,
education_code, occupation_code, smoking_status, drinking_status,
long_term_danyang, future_danyang, relationship_goal, profile_completion, profile_status
) VALUES
('user-f01', '小芳', 'female', '1995-06-15', 162, '321181', '丹阳', 'never_married', 'none', 'bachelor', 'clerical', 'never', 'sometimes', '是', '是', '结婚', 90, 'approved'),
('user-f02', '晓燕', 'female', '1993-09-20', 165, '321181', '丹阳', 'divorced', 'none', 'college', 'teacher', 'never', 'never', '是', '是', '结婚', 95, 'approved'),
('user-f03', '婷婷', 'female', '1998-02-10', 158, '321100', '镇江', 'never_married', 'none', 'master', 'designer', 'sometimes', 'often', '是', '否', '恋爱', 85, 'approved'),
('user-f04', '美玲', 'female', '1990-11-05', 160, '321181', '丹阳', 'never_married', 'none', 'senior_high', 'factory', 'never', 'never', '是', '是', '结婚', 70, 'approved'),
('user-f05', '慧琴', 'female', '1996-07-22', 163, '321181', '丹阳', 'never_married', 'none', 'bachelor', 'nurse', 'never', 'sometimes','是', '是', '结婚', 92, 'approved'),
('user-f06', '秀英', 'female', '1992-04-18', 157, '321181', '丹阳', 'widowed', 'none', 'junior_high','farmer', 'often', 'often', '是', '是', '结婚', 60, 'approved'),
('user-m01', '张伟', 'male', '1992-01-10', 175, '321181', '丹阳', 'never_married', 'none', 'bachelor', 'engineer', 'never', 'sometimes','是', '是', '结婚', 88, 'approved'),
('user-m02', '李强', 'male', '1990-08-25', 178, '321181', '丹阳', 'divorced', 'none', 'master', 'manager', 'sometimes', 'often', '是', '是', '结婚', 95, 'approved'),
('user-m03', '王磊', 'male', '1997-12-03', 180, '321100', '镇江', 'never_married', 'none', 'college', 'programmer', 'never', 'never', '是', '是', '恋爱', 82, 'approved'),
('user-m04', '赵明', 'male', '1988-05-30', 172, '321181', '丹阳', 'never_married', 'none', 'senior_high','sales', 'often', 'often', '否', '是', '结婚', 75, 'approved'),
('user-m05', '孙浩', 'male', '1994-03-14', 182, '321181', '丹阳', 'never_married', 'none', 'bachelor', 'doctor', 'never', 'sometimes','是', '是', '结婚', 97, 'approved'),
('user-m06', '周洋', 'male', '1999-08-08', 176, '320500', '苏州', 'never_married', 'none', 'master', 'researcher', 'never', 'never', '是', '否', '恋爱', 80, 'approved');
-- ============================================================
-- 5. 用户择偶偏好(user_preferences)
-- ============================================================
INSERT INTO user_preferences (
user_id, min_age, max_age, age_priority,
min_height_cm, max_height_cm, height_priority,
region_scope, region_priority,
marital_statuses, marital_priority,
min_education_code, education_priority
) VALUES
('user-f01', 28, 38, 'required', 170, 185, 'required',
'["321181","321100"]', 'required', '["never_married"]', 'required', 'bachelor', 'preferred'),
('user-f02', 28, 40, 'required', 170, 188, 'required',
'["321181"]', 'required', '["never_married","divorced"]', 'preferred', 'college', 'preferred'),
('user-f03', 25, 35, 'preferred', 172, 185, 'preferred',
'["321181","321100","320500"]', 'preferred', '["never_married"]', 'required', NULL, NULL),
('user-f04', 30, 45, 'required', 168, 185, 'required',
'["321181"]', 'required', '["never_married","divorced"]', 'preferred', 'senior_high', 'preferred'),
('user-f05', 27, 36, 'required', 172, 186, 'required',
'["321181","321100"]', 'preferred', '["never_married"]', 'required', 'bachelor', 'preferred'),
('user-f06', 30, 50, 'required', 165, 185, 'required',
'["321181"]', 'required', '["never_married","divorced","widowed"]', 'preferred', NULL, NULL),
('user-m01', 22, 32, 'required', 155, 170, 'preferred',
'["321181","321100"]', 'required', '["never_married"]', 'required', 'junior_high', 'preferred'),
('user-m02', 25, 38, 'preferred', 158, 172, 'preferred',
'["321181"]', 'preferred', '["never_married","divorced"]', 'preferred', 'college', 'preferred'),
('user-m03', 22, 30, 'preferred', 155, 168, 'preferred',
'["321181","321100","320500"]', 'preferred', '["never_married"]', 'required', 'college', 'preferred'),
('user-m04', 25, 40, 'preferred', 155, 170, 'preferred',
'["321181"]', 'required', '["never_married","divorced"]', 'preferred', NULL, NULL),
('user-m05', 23, 33, 'required', 158, 170, 'preferred',
'["321181","321100"]', 'preferred', '["never_married"]', 'required', 'bachelor', 'preferred'),
('user-m06', 22, 32, 'preferred', 155, 170, 'preferred',
'["321181","321100","320500"]', 'preferred', '["never_married"]', 'required', 'master', 'preferred');
-- ============================================================
-- 6. 实名认证(user_identities)— mock
-- ============================================================
INSERT INTO user_identities (
user_id, real_name_enc, id_number_enc, id_number_hash,
gender, birth_date, verification_status, provider, verified_at
) VALUES
('user-f01', E'\\xencrypted_f01', E'\\xencrypted_f01_id', 'sha256_f01', 'female', '1995-06-15', 'verified', 'mock', '2026-03-16T10:00:00Z'),
('user-f02', E'\\xencrypted_f02', E'\\xencrypted_f02_id', 'sha256_f02', 'female', '1993-09-20', 'verified', 'mock', '2026-03-21T14:30:00Z'),
('user-f03', E'\\xencrypted_f03', E'\\xencrypted_f03_id', 'sha256_f03', 'female', '1998-02-10', 'verified', 'mock', '2026-04-02T09:15:00Z'),
('user-f04', E'\\xencrypted_f04', E'\\xencrypted_f04_id', 'sha256_f04', 'female', '1990-11-05', 'verified', 'mock', '2026-04-11T16:00:00Z'),
('user-f05', E'\\xencrypted_f05', E'\\xencrypted_f05_id', 'sha256_f05', 'female', '1996-07-22', 'verified', 'mock', '2026-05-02T11:20:00Z'),
('user-f06', E'\\xencrypted_f06', E'\\xencrypted_f06_id', 'sha256_f06', 'female', '1992-04-18', 'verified', 'mock', '2026-05-16T08:45:00Z'),
('user-m01', E'\\xencrypted_m01', E'\\xencrypted_m01_id', 'sha256_m01', 'male', '1992-01-10', 'verified', 'mock', '2026-03-11T09:00:00Z'),
('user-m02', E'\\xencrypted_m02', E'\\xencrypted_m02_id', 'sha256_m02', 'male', '1990-08-25', 'verified', 'mock', '2026-03-26T13:00:00Z'),
('user-m03', E'\\xencrypted_m03', E'\\xencrypted_m03_id', 'sha256_m03', 'male', '1997-12-03', 'verified', 'mock', '2026-04-06T15:30:00Z'),
('user-m04', E'\\xencrypted_m04', E'\\xencrypted_m04_id', 'sha256_m04', 'male', '1988-05-30', 'verified', 'mock', '2026-04-21T10:00:00Z'),
('user-m05', E'\\xencrypted_m05', E'\\xencrypted_m05_id', 'sha256_m05', 'male', '1994-03-14', 'verified', 'mock', '2026-05-02T14:00:00Z'),
('user-m06', E'\\xencrypted_m06', E'\\xencrypted_m06_id', 'sha256_m06', 'male', '1999-08-08', 'verified', 'mock', '2026-05-11T16:30:00Z');
-- ============================================================
-- 7. 兴趣标签(user_interests)
-- ============================================================
INSERT INTO user_interests (user_id, interest_code) VALUES
('user-f01', 'reading'), ('user-f01', 'cooking'), ('user-f01', 'travel'),
('user-f02', 'sports'), ('user-f02', 'music'), ('user-f02', 'outdoor'),
('user-f03', 'photography'), ('user-f03', 'dance'), ('user-f03', 'movie'),
('user-f04', 'pets'), ('user-f04', 'cooking'),
('user-f05', 'reading'), ('user-f05', 'fitness'), ('user-f05', 'charity'),
('user-f06', 'gardening'), ('user-f06', 'cooking'),
('user-m01', 'sports'), ('user-m01', 'gaming'), ('user-m01', 'travel'),
('user-m02', 'reading'), ('user-m02', 'investment'), ('user-m02', 'hiking'),
('user-m03', 'gaming'), ('user-m03', 'music'), ('user-m03', 'coding'),
('user-m04', 'cars'), ('user-m04', 'cooking'),
('user-m05', 'running'), ('user-m05', 'reading'), ('user-m05', 'charity'),
('user-m06', 'research'), ('user-m06', 'travel'), ('user-m06', 'photography');
-- ============================================================
-- 8. 隐私设置(user_privacy_settings)
-- ============================================================
INSERT INTO user_privacy_settings (
user_id, visible_in_recommendations, visible_in_search,
show_occupation, show_lifestyle_photos,
receive_activity_recommendations, accept_matchmaker_recommendations
) VALUES
('user-f01', true, true, true, true, true, true),
('user-f02', true, true, true, false, true, true),
('user-f03', true, false, true, true, true, false),
('user-f04', true, true, false, true, true, true),
('user-f05', true, true, true, true, false,true),
('user-f06', true, false, true, true, true, true),
('user-m01', true, true, true, true, true, true),
('user-m02', true, true, true, false, true, true),
('user-m03', true, true, true, true, true, false),
('user-m04', true, false, true, true, true, true),
('user-m05', true, true, true, true, true, true),
('user-m06', true, true, true, true, true, true);
-- ============================================================
-- 9. 照片(user_photos)
-- ============================================================
INSERT INTO user_photos (id, user_id, file_key, photo_type, sort_order, review_status) VALUES
('photo-f01-a', 'user-f01', 'photos/user-f01/avatar/001.jpg', 'avatar', 0, 'approved'),
('photo-f01-l1','user-f01', 'photos/user-f01/lifestyle/001.jpg','lifestyle',1, 'approved'),
('photo-f01-l2','user-f01', 'photos/user-f01/lifestyle/002.jpg','lifestyle',2, 'approved'),
('photo-f02-a', 'user-f02', 'photos/user-f02/avatar/001.jpg', 'avatar', 0, 'approved'),
('photo-f02-l1','user-f02', 'photos/user-f02/lifestyle/001.jpg','lifestyle',1, 'approved'),
('photo-f03-a', 'user-f03', 'photos/user-f03/avatar/001.jpg', 'avatar', 0, 'approved'),
('photo-f03-l1','user-f03', 'photos/user-f03/lifestyle/001.jpg','lifestyle',1, 'approved'),
('photo-f03-l2','user-f03', 'photos/user-f03/lifestyle/002.jpg','lifestyle',2, 'approved'),
('photo-f04-a', 'user-f04', 'photos/user-f04/avatar/001.jpg', 'avatar', 0, 'approved'),
('photo-f05-a', 'user-f05', 'photos/user-f05/avatar/001.jpg', 'avatar', 0, 'approved'),
('photo-f05-l1','user-f05', 'photos/user-f05/lifestyle/001.jpg','lifestyle',1, 'approved'),
('photo-f06-a', 'user-f06', 'photos/user-f06/avatar/001.jpg', 'avatar', 0, 'approved'),
('photo-m01-a', 'user-m01', 'photos/user-m01/avatar/001.jpg', 'avatar', 0, 'approved'),
('photo-m01-l1','user-m01', 'photos/user-m01/lifestyle/001.jpg','lifestyle',1, 'approved'),
('photo-m01-l2','user-m01', 'photos/user-m01/lifestyle/002.jpg','lifestyle',2, 'approved'),
('photo-m02-a', 'user-m02', 'photos/user-m02/avatar/001.jpg', 'avatar', 0, 'approved'),
('photo-m02-l1','user-m02', 'photos/user-m02/lifestyle/001.jpg','lifestyle',1, 'approved'),
('photo-m03-a', 'user-m03', 'photos/user-m03/avatar/001.jpg', 'avatar', 0, 'approved'),
('photo-m03-l1','user-m03', 'photos/user-m03/lifestyle/001.jpg','lifestyle',1, 'approved'),
('photo-m04-a', 'user-m04', 'photos/user-m04/avatar/001.jpg', 'avatar', 0, 'approved'),
('photo-m05-a', 'user-m05', 'photos/user-m05/avatar/001.jpg', 'avatar', 0, 'approved'),
('photo-m05-l1','user-m05', 'photos/user-m05/lifestyle/001.jpg','lifestyle',1, 'approved'),
('photo-m05-l2','user-m05', 'photos/user-m05/lifestyle/002.jpg','lifestyle',2, 'approved'),
('photo-m06-a', 'user-m06', 'photos/user-m06/avatar/001.jpg', 'avatar', 0, 'approved');
-- ============================================================
-- 10. 审核任务(review_tasks)
-- ============================================================
INSERT INTO review_tasks (id, user_id, review_type, status, assigned_operator_id, submitted_at, started_at, completed_at, final_comment, version) VALUES
('rt-f01', 'user-f01', 'initial_profile', 'approved', 'op-rv001', '2026-03-15T11:00:00Z', '2026-03-15T11:30:00Z', '2026-03-15T12:00:00Z', '资料完整,信息真实', 1),
('rt-f02', 'user-f02', 'initial_profile', 'approved', 'op-rv001', '2026-03-20T15:00:00Z', '2026-03-20T15:30:00Z', '2026-03-20T16:00:00Z', '资料完整', 1),
('rt-f03', 'user-f03', 'initial_profile', 'approved', 'op-rv001', '2026-04-01T10:00:00Z', '2026-04-01T10:30:00Z', '2026-04-01T11:00:00Z', '资料完整', 1),
('rt-m01', 'user-m01', 'initial_profile', 'approved', 'op-rv001', '2026-03-10T10:00:00Z', '2026-03-10T10:30:00Z', '2026-03-10T11:00:00Z', '资料完整', 1),
('rt-m02', 'user-m02', 'initial_profile', 'approved', 'op-rv001', '2026-03-25T14:00:00Z', '2026-03-25T14:30:00Z', '2026-03-25T15:00:00Z', '资料完整', 1),
('rt-m03', 'user-m03', 'initial_profile', 'approved', 'op-rv001', '2026-04-05T16:00:00Z', '2026-04-05T16:30:00Z', '2026-04-05T17:00:00Z', '资料完整', 1),
('rt-m05', 'user-m05', 'initial_profile', 'approved', 'op-rv001', '2026-05-01T15:00:00Z', '2026-05-01T15:30:00Z', '2026-05-01T16:00:00Z', '资料完整', 1);
-- ============================================================
-- 11. 用户关系(user_relations)
-- ============================================================
INSERT INTO user_relations (id, user_id, target_user_id, relation_type, created_at) VALUES
('rel-f01-m01-a', 'user-f01', 'user-m01', 'liked', '2026-06-01T10:00:00Z'),
('rel-f01-m01-b', 'user-m01', 'user-f01', 'liked', '2026-06-01T10:05:00Z'),
('rel-f02-m02', 'user-f02', 'user-m02', 'liked', '2026-06-02T14:00:00Z'),
('rel-f03-m03', 'user-f03', 'user-m03', 'liked', '2026-06-03T09:00:00Z'),
('rel-m03-f03', 'user-m03', 'user-f03', 'liked', '2026-06-03T09:30:00Z'),
('rel-m04-f02', 'user-m04', 'user-f02', 'liked', '2026-06-04T11:00:00Z'),
('rel-f04-m04', 'user-f04', 'user-m04', 'passed', '2026-06-04T12:00:00Z'),
('rel-f05-m05', 'user-f05', 'user-m05', 'liked', '2026-06-05T10:00:00Z'),
('rel-f05-m05-b', 'user-m05', 'user-f05', 'liked', '2026-06-05T10:05:00Z'),
('rel-m06-f01', 'user-m06', 'user-f01', 'liked', '2026-06-06T14:00:00Z'),
('rel-f04-m06', 'user-f04', 'user-m06', 'passed', '2026-06-06T15:00:00Z'),
('rel-f06-m04', 'user-f06', 'user-m04', 'blocked', '2026-06-07T09:00:00Z'),
('rel-m02-f03', 'user-m02', 'user-f03', 'passed', '2026-06-07T10:00:00Z');
-- ============================================================
-- 12. Match(双向匹配)
-- ============================================================
INSERT INTO matches (id, user_a_id, user_b_id, status, source, matched_at) VALUES
('match-f01-m01', 'user-f01', 'user-m01', 'active', 'user_like', '2026-06-01T10:05:00Z'),
('match-f03-m03', 'user-f03', 'user-m03', 'active', 'user_like', '2026-06-03T09:30:00Z'),
('match-f05-m05', 'user-f05', 'user-m05', 'successful', 'user_like', '2026-06-05T10:05:00Z');
-- ============================================================
-- 13. 成功牵手请求(relationship_success_requests)
-- ============================================================
INSERT INTO relationship_success_requests (id, match_id, initiated_by, status, confirmed_by, created_at, resolved_at) VALUES
('rsr-f05-m05', 'match-f05-m05', 'user-f05', 'confirmed', 'user-m05', '2026-07-01T10:00:00Z', '2026-07-01T10:30:00Z'),
('rsr-f01-m01', 'match-f01-m01', 'user-f01', 'pending', NULL, '2026-07-15T14:00:00Z', NULL);
-- ============================================================
-- 14. Conversations & Messages
-- ============================================================
INSERT INTO conversations (id, match_id, status, last_message_id, last_message_at) VALUES
('conv-f01-m01', 'match-f01-m01', 'active', 'msg-f01-m01-3', '2026-07-10T16:00:00Z'),
('conv-f03-m03', 'match-f03-m03', 'active', 'msg-f03-m03-2', '2026-07-08T20:00:00Z'),
('conv-f05-m05', 'match-f05-m05', 'active', 'msg-f05-m05-1', '2026-07-01T18:00:00Z');
INSERT INTO conversation_members (conversation_id, user_id, last_read_message_id, unread_count, can_send, joined_at) VALUES
('conv-f01-m01', 'user-f01', 'msg-f01-m01-3', 0, true, '2026-06-01T10:05:00Z'),
('conv-f01-m01', 'user-m01', 'msg-f01-m01-3', 0, true, '2026-06-01T10:05:00Z'),
('conv-f03-m03', 'user-f03', 'msg-f03-m03-2', 1, true, '2026-06-03T09:30:00Z'),
('conv-f03-m03', 'user-m03', 'msg-f03-m03-2', 0, true, '2026-06-03T09:30:00Z'),
('conv-f05-m05', 'user-f05', 'msg-f05-m05-1', 0, true, '2026-06-05T10:05:00Z'),
('conv-f05-m05', 'user-m05', 'msg-f05-m05-1', 0, true, '2026-06-05T10:05:00Z');
INSERT INTO messages (id, conversation_id, sender_id, message_type, content, status, risk_level, created_at) VALUES
('msg-f01-m01-1', 'conv-f01-m01', 'user-f01', 'text', '你好!看到你的资料觉得挺合适的~', 'sent', 'normal', '2026-06-15T14:00:00Z'),
('msg-f01-m01-2', 'conv-f01-m01', 'user-m01', 'text', '你好!谢谢你的喜欢,我也觉得挺有缘的', 'sent', 'normal', '2026-06-15T14:05:00Z'),
('msg-f01-m01-3', 'conv-f01-m01', 'user-f01', 'text', '你也在丹阳工作吗?平时喜欢做些什么?', 'sent', 'normal', '2026-06-15T14:10:00Z'),
('msg-f03-m03-1', 'conv-f03-m03', 'user-m03', 'text', '嗨,你好!很高兴认识你', 'sent', 'normal', '2026-07-05T19:30:00Z'),
('msg-f03-m03-2', 'conv-f03-m03', 'user-f03', 'text', '你好呀!我平时喜欢拍照和跳舞,你呢?', 'sent', 'normal', '2026-07-05T19:35:00Z'),
('msg-f05-m05-1', 'conv-f05-m05', 'user-m05', 'text', '你好,很高兴认识你!', 'sent', 'normal', '2026-06-10T10:00:00Z');
-- ============================================================
-- 15. 推荐记录(recommendation_records)
-- ============================================================
INSERT INTO recommendation_records (id, user_id, target_user_id, source, score, level, shown_at, action, action_at, rule_version) VALUES
('rec-f01-m01', 'user-f01', 'user-m01', 'daily', 82.50, 'high', '2026-05-28T10:00:00Z', 'liked', '2026-06-01T10:00:00Z', 1),
('rec-f01-m03', 'user-f01', 'user-m03', 'daily', 70.00, 'medium', '2026-05-28T10:00:00Z', 'passed','2026-05-28T10:01:00Z', 1),
('rec-f01-m02', 'user-f01', 'user-m02', 'daily', 65.00, 'medium', '2026-05-28T10:00:00Z', 'passed','2026-05-28T10:02:00Z', 1),
('rec-m01-f01', 'user-m01', 'user-f01', 'daily', 85.00, 'high', '2026-05-28T11:00:00Z', 'liked', '2026-06-01T10:05:00Z', 1),
('rec-m01-f03', 'user-m01', 'user-f03', 'daily', 60.00, 'normal','2026-05-28T11:00:00Z', 'passed','2026-05-28T11:01:00Z', 1),
('rec-f03-m03', 'user-f03', 'user-m03', 'daily', 78.00, 'high', '2026-06-01T09:00:00Z', 'liked', '2026-06-03T09:30:00Z', 1),
('rec-m03-f03', 'user-m03', 'user-f03', 'daily', 75.00, 'high', '2026-06-01T09:30:00Z', 'liked', '2026-06-03T09:30:00Z', 1),
('rec-f05-m05', 'user-f05', 'user-m05', 'daily', 88.00, 'high', '2026-06-01T10:00:00Z', 'liked', '2026-06-05T10:00:00Z', 1),
('rec-m05-f05', 'user-m05', 'user-f05', 'daily', 86.00, 'high', '2026-06-01T10:30:00Z', 'liked', '2026-06-05T10:05:00Z', 1),
('rec-m06-f01', 'user-m06', 'user-f01', 'daily', 62.00, 'medium','2026-06-06T14:00:00Z', 'liked', '2026-06-06T14:00:00Z', 1);
-- ============================================================
-- 16. 相亲活动(activities)
-- ============================================================
INSERT INTO activities (
id, title, description, organizer_org_id, coorganizer_text,
start_at, end_at, location_name, location_address,
male_limit, female_limit, total_limit,
min_age, max_age,
registration_start_at, registration_end_at,
need_review, status, created_by
) VALUES
('act-001',
'丹阳公益单身联谊会(夏季场)',
'面向丹阳市区及周边乡镇的单身青年,由妇联、工会联合主办,提供安全、真实的交友平台。现场设有互动游戏、自由交流环节,红娘全程辅助。',
'org-danyang-women',
'丹阳市总工会、丹阳市慈善基金会',
'2026-08-15T14:00:00Z', '2026-08-15T17:30:00Z',
'丹阳市文化馆多功能厅', '丹阳市丹北路168号',
15, 15, 30, 22, 40,
'2026-07-01T00:00:00Z', '2026-08-10T23:59:59Z',
true, 'registration_open', 'op-admin-001'),
('act-002',
'七夕特别活动·丹阳缘来是你',
'七夕节特别策划,浪漫主题相亲活动。适合寻找认真关系的单身人士。',
'org-danyang-trade',
'丹阳市新时代文明实践中心',
'2026-08-29T15:00:00Z', '2026-08-29T18:00:00Z',
'丹阳大剧院报告厅', '丹阳市书院路28号',
20, 20, 40, 25, 45,
'2026-08-01T00:00:00Z', '2026-08-25T23:59:59Z',
true, 'draft', 'op-act01');
-- ============================================================
-- 17. 活动报名(activity_registrations)
-- ============================================================
INSERT INTO activity_registrations (id, activity_id, user_id, status, registered_at, reviewed_by, reviewed_at, checkin_status) VALUES
('reg-001-f01', 'act-001', 'user-f01', 'approved', '2026-07-05T10:00:00Z', 'op-act01', '2026-07-05T10:30:00Z', 'not_checked_in'),
('reg-001-f03', 'act-001', 'user-f03', 'approved', '2026-07-06T14:00:00Z', 'op-act01', '2026-07-06T14:15:00Z', 'not_checked_in'),
('reg-001-f05', 'act-001', 'user-f05', 'approved', '2026-07-07T09:00:00Z', 'op-act01', '2026-07-07T09:20:00Z', 'not_checked_in'),
('reg-001-m01', 'act-001', 'user-m01', 'approved', '2026-07-08T11:00:00Z', 'op-act01', '2026-07-08T11:10:00Z', 'not_checked_in'),
('reg-001-m03', 'act-001', 'user-m03', 'approved', '2026-07-09T15:00:00Z', 'op-act01', '2026-07-09T15:20:00Z', 'not_checked_in'),
('reg-001-m05', 'act-001', 'user-m05', 'approved', '2026-07-10T08:30:00Z', 'op-act01', '2026-07-10T08:45:00Z', 'not_checked_in'),
('reg-001-f02', 'act-001', 'user-f02', 'pending', '2026-07-12T10:00:00Z', NULL, NULL, 'not_checked_in'),
('reg-001-m02', 'act-001', 'user-m02', 'approved', '2026-07-11T16:00:00Z', 'op-act01', '2026-07-11T16:30:00Z', 'not_checked_in'),
('reg-001-f04', 'act-001', 'user-f04', 'rejected', '2026-07-13T09:00:00Z', 'op-act01', '2026-07-13T09:15:00Z', 'not_checked_in');
-- ============================================================
-- 18. 活动互选意向(activity_interests)
-- ============================================================
INSERT INTO activity_interests (id, source_user_id, target_user_id, activity_id, status, confirmed_at, created_at) VALUES
('ai-f01-m01', 'user-f01', 'user-m01', 'act-001', 'mutual', '2026-08-15T17:00:00Z', '2026-08-15T17:00:00Z'),
('ai-f03-m03', 'user-f03', 'user-m03', 'act-001', 'mutual', '2026-08-15T17:05:00Z', '2026-08-15T17:05:00Z'),
('ai-f05-m05', 'user-f05', 'user-m05', 'act-001', 'expressed','2026-08-15T17:10:00Z', '2026-08-15T17:10:00Z');
-- ============================================================
-- 19. 红娘服务(matchmaker_services)
-- ============================================================
INSERT INTO matchmaker_services (id, user_id, service_type, description, status, organization_id, assigned_operator_id, assigned_at, completed_at) VALUES
('ms-f02', 'user-f02', 'recommend_partner', '离异用户希望找到合适的伴侣,需要红娘协助筛选',
'in_service', 'org-danyang-women', 'op-mh001', '2026-06-20T10:00:00Z', NULL),
('ms-f06', 'user-f06', 'no_match_help', '丧偶用户希望重新融入社交,找到新伴侣',
'waiting_user', 'org-danyang-charity', 'op-mh001', '2026-06-25T14:00:00Z', NULL),
('ms-f04', 'user-f04', 'review_preference', '用户希望调整择偶条件,请红娘帮助评估',
'completed', 'org-danyang-women', 'op-mh001', '2026-06-15T09:00:00Z', '2026-06-20T11:00:00Z');
-- 红娘推荐记录
INSERT INTO matchmaker_recommendations (id, service_id, user_id, target_user_id, operator_id, reason, status, created_at, viewed_at, responded_at) VALUES
('mr-f02-m02', 'ms-f02', 'user-f02', 'user-m02', 'op-mh001',
'两人同在丹阳工作,年龄相仿,都离过婚有共同语言',
'viewed', '2026-06-21T10:00:00Z', '2026-06-22T09:00:00Z', NULL);
-- 红娘跟进记录
INSERT INTO matchmaker_followups (id, service_id, operator_id, followup_type, content, result_code, next_followup_at, created_at) VALUES
('mf-f02-1', 'ms-f02', 'op-mh001', 'phone_call', '电话沟通用户情况,了解离异原因及择偶期望', '正常', '2026-07-01T10:00:00Z', '2026-06-22T10:00:00Z'),
('mf-f04-1', 'ms-f04', 'op-mh001', 'face_to_face', '面对面交流,帮助用户调整身高要求从170改为168', '已调整', NULL, '2026-06-18T15:00:00Z');
-- ============================================================
-- 20. 系统通知(notifications)
-- ============================================================
INSERT INTO notifications (id, user_id, type, title, content, business_type, business_id, read_status, created_at) VALUES
('notif-match-f01', 'user-f01', 'match', '你们互相喜欢!', '张伟也喜欢了你,可以开始聊天啦~', 'match', 'match-f01-m01', 'read', '2026-06-01T10:05:00Z'),
('notif-match-m01', 'user-m01', 'match', '你们互相喜欢!', '小芳也喜欢了你,可以开始聊天啦~', 'match', 'match-f01-m01', 'read', '2026-06-01T10:05:00Z'),
('notif-match-f03', 'user-f03', 'match', '你们互相喜欢!', '王磊也喜欢了你,可以开始聊天啦~', 'match', 'match-f03-m03', 'read', '2026-06-03T09:30:00Z'),
('notif-match-m03', 'user-m03', 'match', '你们互相喜欢!', '婷婷也喜欢了你,可以开始聊天啦~', 'match', 'match-f03-m03', 'unread','2026-06-03T09:30:00Z'),
('notif-match-f05', 'user-f05', 'match', '你们互相喜欢!', '孙浩也喜欢了你,可以开始聊天啦~', 'match', 'match-f05-m05', 'read', '2026-06-05T10:05:00Z'),
('notif-match-m05', 'user-m05', 'match', '你们互相喜欢!', '慧琴也喜欢了你,可以开始聊天啦~', 'match', 'match-f05-m05', 'read', '2026-06-05T10:05:00Z'),
('notif-success-f05','user-f05', 'system', '恭喜牵手成功!', '您与孙浩已成功牵手,祝你们幸福!', 'match', 'match-f05-m05', 'read', '2026-07-01T10:30:00Z'),
('notif-success-m05','user-m05', 'system', '恭喜牵手成功!', '您与慧琴已成功牵手,祝你们幸福!', 'match', 'match-f05-m05', 'read', '2026-07-01T10:30:00Z'),
('notif-act-001-f01','user-f01', 'activity', '活动报名已确认', '您已成功报名「丹阳公益单身联谊会」,活动时间:2026-08-15 14:00', 'activity', 'act-001', 'read', '2026-07-05T10:30:00Z'),
('notif-act-001-f05','user-f05', 'activity', '活动报名已确认', '您已成功报名「丹阳公益单身联谊会」,活动时间:2026-08-15 14:00', 'activity', 'act-001', 'unread','2026-07-07T09:20:00Z'),
('notif-mh-f02', 'user-f02', 'matchmaker','红娘已为您服务', '您的红娘服务申请已被分配,红娘小王将在24小时内与您联系', 'matchmaker', 'ms-f02', 'read', '2026-06-20T10:30:00Z');
-- ============================================================
-- 21. 同意记录(consent_records)
-- ============================================================
INSERT INTO consent_records (id, user_id, type, version, agreed_at, ip_address, user_agent) VALUES
('cr-f01', 'user-f01', 'terms_of_service', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'),
('cr-f01', 'user-f01', 'privacy_policy', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'),
('cr-m01', 'user-m01', 'terms_of_service', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0'),
('cr-m01', 'user-m01', 'privacy_policy', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0');
-- ============================================================
-- 22. 审核原因字典(review_reasons)
-- ============================================================
INSERT INTO review_reasons (code, name, category, enabled, sort_order) VALUES
('profile_incomplete', '资料不完整', 'quality', true, 1),
('photo_unclear', '照片不清晰', 'quality', true, 2),
('fake_info', '信息疑似虚假', 'trust', true, 3),
('inappropriate_photo', '照片内容不当', 'safety', true, 4),
('duplicate_identity', '重复注册', 'duplicate', true, 5),
('suspicious_behavior', '行为异常', 'risk', true, 6),
('manual_review_needed', '需人工复核', 'quality', true, 7);
-- 启用 replication
SET session_replication_role = 'origin';
-- ============================================================
-- 验证数据量
-- ============================================================
DO $$
DECLARE
u_cnt INTEGER; o_cnt INTEGER; op_cnt INTEGER; m_cnt INTEGER;
a_cnt INTEGER; r_cnt INTEGER; n_cnt INTEGER;
BEGIN
SELECT COUNT(*) INTO u_cnt FROM users WHERE deleted_at IS NULL;
SELECT COUNT(*) INTO o_cnt FROM organizations;
SELECT COUNT(*) INTO op_cnt FROM operators;
SELECT COUNT(*) INTO m_cnt FROM matches;
SELECT COUNT(*) INTO a_cnt FROM activities WHERE deleted_at IS NULL;
SELECT COUNT(*) INTO r_cnt FROM user_relations;
SELECT COUNT(*) INTO n_cnt FROM notifications;
RAISE NOTICE '📊 Demo 数据已生成:';
RAISE NOTICE ' 用户: %人 | 组织: %个 | 操作员: %人', u_cnt, o_cnt, op_cnt;
RAISE NOTICE ' Match: %对 | 关系: %条 | 活动: %个 | 通知: %条', m_cnt, r_cnt, a_cnt, n_cnt;
END $$;
@@ -0,0 +1,222 @@
-- V001__init_base_tables.sql
-- 第一阶段迁移:基础用户表与组织架构表
-- 用户账号表
CREATE TABLE IF NOT EXISTS 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
);
CREATE UNIQUE INDEX uk_users_openid ON users(wechat_openid) WHERE deleted_at IS NULL;
CREATE UNIQUE INDEX uk_users_phone ON users(phone) WHERE phone IS NOT NULL AND deleted_at IS NULL;
CREATE UNIQUE INDEX uk_users_unionid ON users(wechat_unionid) WHERE wechat_unionid IS NOT NULL AND deleted_at IS NULL;
ALTER TABLE users ADD CONSTRAINT chk_user_account_status CHECK (account_status IN (
'normal', 'reviewing_risk', 'limited', 'suspended', 'banned', 'closed'
));
ALTER TABLE users ADD CONSTRAINT chk_user_relationship_status CHECK (relationship_status IN (
'searching', 'getting_to_know', 'paused', 'matched_successfully', 'service_exited'
));
-- 组织表
CREATE TABLE IF NOT EXISTS 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()
);
ALTER TABLE organizations ADD CONSTRAINT chk_org_type CHECK (type IN (
'women_federation', 'trade_union', 'charity_center', 'volunteer_team', 'civil_affairs_partner', 'other'
));
ALTER TABLE organizations ADD CONSTRAINT chk_org_status CHECK (status IN ('active', 'inactive'));
-- 工作人员表
CREATE TABLE IF NOT EXISTS operators (
id UUID PRIMARY KEY,
organization_id UUID REFERENCES organizations(id),
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()
);
CREATE UNIQUE INDEX uk_operator_username ON operators(username);
-- 角色表
CREATE TABLE IF NOT EXISTS 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()
);
-- 权限表
CREATE TABLE IF NOT EXISTS permissions (
id UUID PRIMARY KEY,
code VARCHAR(128) NOT NULL UNIQUE,
name VARCHAR(200) NOT NULL,
module VARCHAR(64) NOT NULL,
description VARCHAR(500)
);
-- 角色权限关联
CREATE TABLE IF NOT EXISTS role_permissions (
role_id UUID NOT NULL REFERENCES roles(id),
permission_id UUID NOT NULL REFERENCES permissions(id),
PRIMARY KEY (role_id, permission_id)
);
-- 操作员角色关联
CREATE TABLE IF NOT EXISTS operator_roles (
operator_id UUID NOT NULL REFERENCES operators(id),
role_id UUID NOT NULL REFERENCES roles(id),
PRIMARY KEY (operator_id, role_id)
);
-- 审计日志表
CREATE TABLE IF NOT EXISTS audit_logs (
id UUID PRIMARY KEY,
operator_id UUID REFERENCES operators(id),
organization_id UUID REFERENCES organizations(id),
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()
);
CREATE INDEX idx_audit_logs_operator ON audit_logs(operator_id, created_at DESC);
CREATE INDEX idx_audit_logs_resource ON audit_logs(resource_type, resource_id);
CREATE INDEX idx_audit_logs_created ON audit_logs(created_at DESC);
-- 敏感访问日志表
CREATE TABLE IF NOT EXISTS sensitive_access_logs (
id UUID PRIMARY KEY,
operator_id UUID NOT NULL REFERENCES operators(id),
user_id UUID NOT NULL REFERENCES users(id),
data_type VARCHAR(64) NOT NULL,
reason VARCHAR(500),
ip VARCHAR(64),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_sensitive_access_operator ON sensitive_access_logs(operator_id, created_at DESC);
CREATE INDEX idx_sensitive_access_user ON sensitive_access_logs(user_id, created_at DESC);
-- 系统配置表
CREATE TABLE IF NOT EXISTS system_configs (
config_key VARCHAR(128) PRIMARY KEY,
config_value JSONB NOT NULL,
description VARCHAR(500),
updated_by UUID REFERENCES operators(id),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 初始化默认角色
INSERT INTO roles (id, code, name, description, system_role) VALUES
('00000000-0000-0000-0000-000000000001', 'super_admin', '超级管理员', '系统超级管理员,拥有全部权限', TRUE),
('00000000-0000-0000-0000-000000000002', 'platform_admin', '平台管理员', '平台运营管理员', TRUE),
('00000000-0000-0000-0000-000000000003', 'organization_admin', '机构管理员', '机构级别管理员', TRUE),
('00000000-0000-0000-0000-000000000004', 'reviewer', '审核员', '负责用户资料审核', TRUE),
('00000000-0000-0000-0000-000000000005', 'matchmaker', '公益红娘', '提供人工婚恋服务', TRUE),
('00000000-0000-0000-0000-000000000006', 'activity_manager', '活动管理员', '负责相亲活动管理', TRUE),
('00000000-0000-0000-0000-000000000007', 'risk_operator', '风控人员', '负责举报处理与风控', TRUE),
('00000000-0000-0000-0000-000000000008', 'volunteer', '志愿者', '活动现场辅助人员', TRUE),
('00000000-0000-0000-0000-000000000009', 'data_viewer', '数据查看者', '仅查看统计数据', TRUE);
-- 初始化基础权限
INSERT INTO permissions (id, code, name, module, description) VALUES
-- 用户管理权限
('10000000-0000-0000-0000-000000000001', 'user.view', '查看用户', 'user', '查看用户基本信息'),
('10000000-0000-0000-0000-000000000002', 'user.sensitive.view', '查看敏感信息', 'user', '查看身份证等敏感信息(需特殊授权)'),
('10000000-0000-0000-0000-000000000003', 'user.status.change', '修改用户状态', 'user', '修改账号状态'),
-- 审核权限
('10000000-0000-0000-0000-000000000010', 'review.view', '查看审核任务', 'review', '查看待审核用户资料'),
('10000000-0000-0000-0000-000000000011', 'review.process', '处理审核任务', 'review', '审核通过/退回/需修改'),
-- 红娘权限
('10000000-0000-0000-0000-000000000020', 'matchmaker.view', '查看红娘服务', 'matchmaker', '查看服务申请列表'),
('10000000-0000-0000-0000-000000000021', 'matchmaker.assign', '分配红娘服务', 'matchmaker', '分配服务任务给红娘'),
('10000000-0000-0000-0000-000000000022', 'matchmaker.service', '执行红娘服务', 'matchmaker', '处理红娘服务'),
-- 活动权限
('10000000-0000-0000-0000-000000000030', 'activity.view', '查看活动', 'activity', '查看活动列表'),
('10000000-0000-0000-0000-000000000031', 'activity.create', '创建活动', 'activity', '创建新的相亲活动'),
('10000000-0000-0000-0000-000000000032', 'activity.review_registration', '审核活动报名', 'activity', '审核用户活动报名'),
-- 风控权限
('10000000-0000-0000-0000-000000000040', 'risk.report.view', '查看举报', 'risk', '查看举报列表'),
('10000000-0000-0000-0000-000000000041', 'risk.report.process', '处理举报', 'risk', '处理举报并处置'),
('10000000-0000-0000-0000-000000000042', 'risk.user.ban', '封禁用户', 'risk', '对用户进行封禁处置'),
-- 权限管理
('10000000-0000-0000-0000-000000000050', 'organization.manage', '管理组织', 'organization', '管理公益组织'),
('10000000-0000-0000-0000-000000000051', 'permission.manage', '管理权限', 'permission', '管理角色与权限'),
-- 统计权限
('10000000-0000-0000-0000-000000000060', 'analytics.view', '查看统计', 'analytics', '查看数据统计'),
-- 数据导出
('10000000-0000-0000-0000-000000000070', 'data.export', '导出数据', 'data', '导出用户数据(需脱敏+审计)');
-- 为 super_admin 分配全部权限
INSERT INTO role_permissions (role_id, permission_id)
SELECT '00000000-0000-0000-0000-000000000001', id FROM permissions;
-- 初始化兴趣字典
CREATE TABLE IF NOT EXISTS 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
);
INSERT INTO interest_dictionary (code, name, sort_order) VALUES
('travel', '旅行', 1),
('reading', '阅读', 2),
('sports', '运动', 3),
('fitness', '健身', 4),
('photography', '摄影', 5),
('movie', '电影', 6),
('music', '音乐', 7),
('food', '美食', 8),
('cooking', '烹饪', 9),
('outdoor', '户外', 10),
('pets', '宠物', 11),
('games', '游戏', 12),
('culture', '文化', 13),
('charity', '公益', 14),
('shopping', '购物', 15),
('painting', '绘画', 16),
('dance', '舞蹈', 17),
('hiking', '徒步', 18);
-- 初始化默认匹配规则配置
INSERT INTO system_configs (config_key, config_value, description) VALUES
('match_rule_version', '1', '当前生效的匹配规则版本'),
('daily_recommendation_limit', '6', '每日推荐人数上限'),
('match_score_threshold', '60', '推荐最低阈值分数'),
('recommendation_cooldown_days', '180', 'Pass冷却天数'),
('max_profile_photos', '6', '最大照片数量'),
('max_interest_tags', '8', '最大兴趣标签数量'),
('activity_default_need_review', 'true', '活动报名默认需要审核'),
('activity_mutual_max_selection', '3', '活动互选最大人数'),
('activity_mutual_deadline_hours', '48', '活动互选截止时间(小时)');
@@ -0,0 +1,151 @@
-- V002__add_user_and_verification_tables.sql
-- 用户账号、实名认证、Profile、偏好表
-- user_identities 实名认证表
CREATE TABLE IF NOT EXISTS 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 DEFAULT 'not_verified',
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)
);
CREATE UNIQUE INDEX uk_identity_user ON user_identities(user_id);
CREATE UNIQUE INDEX uk_identity_hash ON user_identities(id_number_hash)
WHERE verification_status = 'verified';
ALTER TABLE user_identities ADD CONSTRAINT chk_identity_status
CHECK (verification_status IN ('not_verified', 'verifying', 'verified', 'failed', 'manual_review'));
-- user_profiles 婚恋资料表
CREATE TABLE IF NOT EXISTS 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)
);
ALTER TABLE user_profiles ADD CONSTRAINT chk_profile_gender CHECK (gender IN ('male', 'female', 'other'));
ALTER TABLE user_profiles ADD CONSTRAINT chk_profile_marital CHECK (marital_status IN ('never_married', 'divorced', 'widowed'));
ALTER TABLE user_profiles ADD CONSTRAINT chk_profile_children CHECK (children_status IN ('none', 'yes'));
ALTER TABLE user_profiles ADD CONSTRAINT chk_profile_edu CHECK (education_code IN ('primary', 'junior_high', 'senior_high', 'vocational', 'college', 'bachelor', 'master', 'doctor'));
ALTER TABLE user_profiles ADD CONSTRAINT chk_profile_smoking CHECK (smoking_status IN ('never', 'sometimes', 'often'));
ALTER TABLE user_profiles ADD CONSTRAINT chk_profile_drinking CHECK (drinking_status IN ('never', 'sometimes', 'often'));
ALTER TABLE user_profiles ADD CONSTRAINT chk_profile_completion CHECK (profile_completion >= 0 AND profile_completion <= 100);
ALTER TABLE user_profiles ADD CONSTRAINT chk_profile_status CHECK (profile_status IN ('in_progress', 'completed', 'pending_review', 'approved', 'need_edit', 'rejected'));
-- user_preferences 择偶条件表
CREATE TABLE IF NOT EXISTS 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_pref_user FOREIGN KEY (user_id) REFERENCES users(id)
);
ALTER TABLE user_preferences ADD CONSTRAINT chk_pref_priority CHECK (age_priority IN ('required', 'preferred'));
-- user_interests 兴趣关系表
CREATE TABLE IF NOT EXISTS 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)
);
-- user_photos 用户照片表
CREATE TABLE IF NOT EXISTS user_photos (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
file_key VARCHAR(512) NOT NULL,
photo_type VARCHAR(32) NOT NULL DEFAULT 'lifestyle',
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)
);
CREATE UNIQUE INDEX uk_user_avatar ON user_photos(user_id)
WHERE photo_type = 'avatar' AND deleted_at IS NULL;
ALTER TABLE user_photos ADD CONSTRAINT chk_photo_type CHECK (photo_type IN ('avatar', 'lifestyle'));
ALTER TABLE user_photos ADD CONSTRAINT chk_photo_review_status CHECK (review_status IN ('pending', 'approved', 'need_edit', 'rejected'));
-- user_privacy_settings 隐私设置表
CREATE TABLE IF NOT EXISTS 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)
);
-- consent_records 用户同意记录表
CREATE TABLE IF NOT EXISTS consent_records (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
type VARCHAR(64) NOT NULL,
version VARCHAR(32) NOT NULL,
agreed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
ip_address VARCHAR(64),
user_agent VARCHAR(500),
FOREIGN KEY (user_id) REFERENCES users(id)
);
CREATE INDEX idx_consent_user ON consent_records(user_id, agreed_at DESC);
@@ -0,0 +1,109 @@
-- V003__add_review_and_relation_tables.sql
-- 审核、关系、匹配表
-- review_tasks 审核任务
CREATE TABLE IF NOT EXISTS review_tasks (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
review_type VARCHAR(32) NOT NULL DEFAULT 'initial_profile',
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),
FOREIGN KEY (assigned_operator_id) REFERENCES operators(id)
);
CREATE INDEX idx_review_tasks_status_time ON review_tasks(status, submitted_at);
CREATE INDEX idx_review_tasks_operator ON review_tasks(assigned_operator_id, status);
ALTER TABLE review_tasks ADD CONSTRAINT chk_review_type CHECK (review_type IN ('initial_profile', 'profile_change', 'photo_change', 'marital_status_change', 'risk_recheck'));
ALTER TABLE review_tasks ADD CONSTRAINT chk_review_status CHECK (status IN ('pending', 'processing', 'approved', 'need_edit', 'rejected'));
-- review_items 审核明细
CREATE TABLE IF NOT EXISTS review_items (
id UUID PRIMARY KEY,
review_task_id UUID NOT NULL,
item_type VARCHAR(32) NOT NULL,
status VARCHAR(32) NOT NULL DEFAULT 'pending',
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)
);
ALTER TABLE review_items ADD CONSTRAINT chk_item_type CHECK (item_type IN ('avatar', 'lifestyle_photos', 'basic_profile', 'self_intro', 'relationship_profile'));
ALTER TABLE review_items ADD CONSTRAINT chk_item_status CHECK (status IN ('pending', 'approved', 'need_edit', 'abnormal'));
-- review_reasons 审核原因字典
CREATE TABLE IF NOT EXISTS 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
);
-- user_relations 用户单向关系
CREATE TABLE IF NOT EXISTS 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)
);
CREATE UNIQUE INDEX uk_user_relation ON user_relations(user_id, target_user_id, relation_type);
ALTER TABLE user_relations ADD CONSTRAINT chk_relation_type CHECK (relation_type IN ('liked', 'passed', 'blocked'));
-- matches 双向匹配表
CREATE TABLE IF NOT EXISTS 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)
);
CREATE UNIQUE INDEX uk_match_pair ON matches(user_a_id, user_b_id);
CREATE INDEX idx_match_status ON matches(status, matched_at DESC);
ALTER TABLE matches ADD CONSTRAINT chk_match_status CHECK (status IN ('active', 'getting_to_know', 'unmatched', 'successful'));
ALTER TABLE matches ADD CONSTRAINT chk_match_source CHECK (source IN ('user_like', 'activity_mutual', 'matchmaker'));
-- relationship_success_requests 成功牵手请求
CREATE TABLE IF NOT EXISTS 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)
);
CREATE INDEX idx_success_request_match ON relationship_success_requests(match_id, status);
ALTER TABLE relationship_success_requests ADD CONSTRAINT chk_success_status CHECK (status IN ('pending', 'confirmed', 'declined'));
@@ -0,0 +1,97 @@
-- V004__add_messaging_and_recommendation_tables.sql
-- 推荐、聊天消息表
-- recommendation_records 推荐记录
CREATE TABLE IF NOT EXISTS recommendation_records (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
target_user_id UUID NOT NULL,
source VARCHAR(32) NOT NULL DEFAULT 'daily',
score NUMERIC(5,2),
level VARCHAR(16),
reasons JSONB,
shown_at TIMESTAMPTZ NOT NULL,
action VARCHAR(32),
action_at TIMESTAMPTZ,
rule_version INT NOT NULL DEFAULT 1,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (target_user_id) REFERENCES users(id)
);
CREATE INDEX idx_recommend_user_time ON recommendation_records(user_id, shown_at DESC);
CREATE INDEX idx_recommend_pair ON recommendation_records(user_id, target_user_id);
ALTER TABLE recommendation_records ADD CONSTRAINT chk_rec_source CHECK (source IN ('daily', 'discover', 'matchmaker', 'activity'));
ALTER TABLE recommendation_records ADD CONSTRAINT chk_rec_level CHECK (level IN ('high', 'medium', 'normal'));
ALTER TABLE recommendation_records ADD CONSTRAINT chk_rec_action CHECK (action IN ('liked', 'passed', 'blocked', 'matched', NULL));
-- conversations 会话表
CREATE TABLE IF NOT EXISTS 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)
);
ALTER TABLE conversations ADD CONSTRAINT chk_conversation_status CHECK (status IN ('active', 'unmatched', 'blocked'));
-- conversation_members 会话成员表
CREATE TABLE IF NOT EXISTS 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 消息表
CREATE TABLE IF NOT EXISTS 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)
);
CREATE UNIQUE INDEX uk_message_client_id ON messages(sender_id, client_message_id)
WHERE client_message_id IS NOT NULL;
CREATE INDEX idx_messages_conversation_time ON messages(conversation_id, created_at DESC);
ALTER TABLE messages ADD CONSTRAINT chk_msg_type CHECK (message_type IN ('text', 'image', 'system', 'risk_notice'));
ALTER TABLE messages ADD CONSTRAINT chk_msg_status CHECK (status IN ('sent', 'delivered', 'failed'));
ALTER TABLE messages ADD CONSTRAINT chk_msg_risk_level CHECK (risk_level IN (NULL, 'normal', 'warning', 'high'));
-- notifications 系统通知表
CREATE TABLE IF NOT EXISTS 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)
);
CREATE INDEX idx_notifications_user ON notifications(user_id, read_status, created_at DESC);
ALTER TABLE notifications ADD CONSTRAINT chk_notification_type CHECK (type IN ('review', 'match', 'matchmaker', 'activity', 'risk', 'account', 'system'));
ALTER TABLE notifications ADD CONSTRAINT chk_read_status CHECK (read_status IN ('unread', 'read'));
@@ -0,0 +1,4 @@
-- V005__add_review_tables.sql
-- 为 review_tasks 补充用户查询索引(review_tasks 表已在 V003 中创建)
CREATE INDEX IF NOT EXISTS idx_review_tasks_user ON review_tasks(user_id, created_at DESC);
@@ -0,0 +1,38 @@
-- V006__add_match_tables.sql
-- 推荐与匹配相关表补充(仅添加 V004 未创建的补充内容)
-- match_rule_configs 匹配规则配置表
CREATE TABLE IF NOT EXISTS match_rule_configs (
id UUID PRIMARY KEY,
version INT NOT NULL,
status VARCHAR(16) NOT NULL DEFAULT 'draft',
age_weight INT NOT NULL DEFAULT 15,
region_weight INT NOT NULL DEFAULT 15,
marital_weight INT NOT NULL DEFAULT 10,
children_weight INT NOT NULL DEFAULT 10,
education_weight INT NOT NULL DEFAULT 5,
height_weight INT NOT NULL DEFAULT 5,
marriage_plan_weight INT NOT NULL DEFAULT 15,
settlement_weight INT NOT NULL DEFAULT 10,
lifestyle_weight INT NOT NULL DEFAULT 10,
interest_weight INT NOT NULL DEFAULT 5,
minimum_score INT NOT NULL DEFAULT 60,
created_by UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
activated_at TIMESTAMPTZ
);
CREATE INDEX IF NOT EXISTS idx_match_rule_version ON match_rule_configs(version DESC);
CREATE INDEX IF NOT EXISTS idx_match_rule_status ON match_rule_configs(status) WHERE status = 'active';
-- 初始化默认匹配规则(version=1, status=active)
INSERT INTO match_rule_configs (id, version, status, age_weight, region_weight, marital_weight,
children_weight, education_weight, height_weight, marriage_plan_weight, settlement_weight,
lifestyle_weight, interest_weight, minimum_score)
VALUES (
'00000000-0000-0000-0000-000000000100',
1, 'active',
15, 15, 10, 10, 5, 5, 15, 10, 10, 5,
60
)
ON CONFLICT DO NOTHING;
@@ -0,0 +1,2 @@
-- V007__add_relationship_tables.sql
-- 用户关系与匹配表(已在 V003 中创建,本文件保留为占位)
@@ -0,0 +1,65 @@
-- V008__add_messaging_tables.sql
-- 聊天消息表补充(如V004未完整创建则执行)
-- conversations 会话表
CREATE TABLE IF NOT EXISTS 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)
);
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'chk_conversation_status') THEN
ALTER TABLE conversations ADD CONSTRAINT chk_conversation_status CHECK (status IN ('active', 'unmatched', 'blocked'));
END IF;
END $$;
-- conversation_members 会话成员表
CREATE TABLE IF NOT EXISTS 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 消息表
CREATE TABLE IF NOT EXISTS 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)
);
CREATE INDEX IF NOT EXISTS idx_messages_conversation_time ON messages(conversation_id, created_at DESC);
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'chk_msg_type') THEN
ALTER TABLE messages ADD CONSTRAINT chk_msg_type CHECK (message_type IN ('text', 'image', 'system', 'risk_notice'));
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'chk_msg_status') THEN
ALTER TABLE messages ADD CONSTRAINT chk_msg_status CHECK (status IN ('sent', 'delivered', 'failed'));
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'chk_msg_risk_level') THEN
ALTER TABLE messages ADD CONSTRAINT chk_msg_risk_level CHECK (risk_level IN (NULL, 'normal', 'warning', 'high'));
END IF;
END $$;
@@ -0,0 +1,74 @@
-- V009__add_matchmaker_tables.sql
-- 公益红娘服务表
-- matchmaker_services 红娘服务表
CREATE TABLE IF NOT EXISTS 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)
);
CREATE INDEX idx_matchmaker_status ON matchmaker_services(status, created_at);
CREATE INDEX idx_matchmaker_operator ON matchmaker_services(assigned_operator_id, status);
CREATE INDEX idx_matchmaker_user ON matchmaker_services(user_id, created_at DESC);
ALTER TABLE matchmaker_services ADD CONSTRAINT chk_matchmaker_service_type CHECK (service_type IN (
'recommend_partner', 'review_preference', 'contact_intention',
'join_activity', 'no_match_help', 'chat_help', 'other'
));
ALTER TABLE matchmaker_services ADD CONSTRAINT chk_matchmaker_status CHECK (status IN (
'submitted', 'assigned', 'in_service', 'waiting_user', 'completed', 'cancelled'
));
-- matchmaker_recommendations 红娘推荐表
CREATE TABLE IF NOT EXISTS 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)
);
CREATE INDEX idx_matchmaker_rec_service ON matchmaker_recommendations(service_id);
CREATE INDEX idx_matchmaker_rec_user ON matchmaker_recommendations(user_id);
ALTER TABLE matchmaker_recommendations ADD CONSTRAINT chk_rec_status CHECK (status IN (
'pending_view', 'viewed', 'responded'
));
-- matchmaker_followups 红娘跟进表
CREATE TABLE IF NOT EXISTS 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)
);
CREATE INDEX idx_matchmaker_fu_service ON matchmaker_followups(service_id);
CREATE INDEX idx_matchmaker_fu_operator ON matchmaker_followups(operator_id, created_at DESC);
@@ -0,0 +1,70 @@
-- V010__add_activity_tables.sql
-- 公益活动表(如V004未完整创建则执行)
-- activities 活动表
CREATE TABLE IF NOT EXISTS 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)
);
CREATE INDEX idx_activities_status ON activities(status, start_at);
CREATE INDEX idx_activities_organizer ON activities(organizer_org_id, status);
ALTER TABLE activities ADD CONSTRAINT chk_activity_status CHECK (status IN (
'draft', 'registration_open', 'registration_closed', 'ongoing', 'ended', 'cancelled'
));
-- activity_registrations 活动报名表
CREATE TABLE IF NOT EXISTS 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(),
deleted_at TIMESTAMPTZ,
FOREIGN KEY (activity_id) REFERENCES activities(id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (reviewed_by) REFERENCES operators(id),
UNIQUE(activity_id, user_id)
);
CREATE INDEX idx_activity_reg_activity ON activity_registrations(activity_id, status);
CREATE INDEX idx_activity_reg_user ON activity_registrations(user_id, status);
ALTER TABLE activity_registrations ADD CONSTRAINT chk_reg_status CHECK (status IN (
'pending', 'approved', 'rejected', 'cancelled'
));
ALTER TABLE activity_registrations ADD CONSTRAINT chk_checkin_status CHECK (checkin_status IN (
'not_checked_in', 'checked_in'
));
@@ -0,0 +1,28 @@
-- V011__add_activity_interests.sql
-- 活动互选表:活动结束后,用户可对其他参与者表达进一步了解意愿
CREATE TABLE IF NOT EXISTS activity_interests (
id UUID PRIMARY KEY,
source_user_id UUID NOT NULL,
target_user_id UUID NOT NULL,
activity_id UUID NOT NULL,
status VARCHAR(32) NOT NULL DEFAULT 'expressed',
-- 'expressed' = 单方面表达意向(保密)
-- 'mutual' = 双方均表达,已建立活动互选关系
confirmed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ,
FOREIGN KEY (source_user_id) REFERENCES users(id),
FOREIGN KEY (target_user_id) REFERENCES users(id),
FOREIGN KEY (activity_id) REFERENCES activities(id),
UNIQUE(activity_id, source_user_id, target_user_id)
);
CREATE INDEX idx_activity_interest_source ON activity_interests(source_user_id, status);
CREATE INDEX idx_activity_interest_target ON activity_interests(target_user_id, status);
CREATE INDEX idx_activity_interest_activity ON activity_interests(activity_id, status);
ALTER TABLE activity_interests ADD CONSTRAINT chk_ai_status CHECK (
status IN ('expressed', 'mutual')
);
@@ -0,0 +1,76 @@
-- V012__add_risk_and_report_tables.sql
-- 举报与风控表
-- reports 举报表
CREATE TABLE IF NOT EXISTS reports (
id UUID PRIMARY KEY,
reporter_user_id UUID NOT NULL,
reported_user_id UUID,
reason_type VARCHAR(64) NOT NULL,
description TEXT,
evidence_file_ids TEXT,
status VARCHAR(32) NOT NULL DEFAULT 'pending',
process_result VARCHAR(64),
processed_by UUID,
processed_at TIMESTAMPTZ,
process_note TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ,
FOREIGN KEY (reporter_user_id) REFERENCES users(id),
FOREIGN KEY (reported_user_id) REFERENCES users(id),
FOREIGN KEY (processed_by) REFERENCES operators(id)
);
CREATE INDEX idx_reports_reporter ON reports(reporter_user_id, status);
CREATE INDEX idx_reports_reported ON reports(reported_user_id, status);
CREATE INDEX idx_reports_status_priority ON reports(status, reason_type, created_at);
ALTER TABLE reports ADD CONSTRAINT chk_report_status CHECK (
status IN ('pending', 'processing', 'resolved', 'rejected', 'dismissed')
);
-- risk_events 风险事件表
CREATE TABLE IF NOT EXISTS risk_events (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
event_type VARCHAR(64) NOT NULL,
score INT NOT NULL DEFAULT 0,
source VARCHAR(32) NOT NULL DEFAULT 'auto',
source_id VARCHAR(128),
note TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ,
FOREIGN KEY (user_id) REFERENCES users(id)
);
CREATE INDEX idx_risk_events_user ON risk_events(user_id, created_at DESC);
CREATE INDEX idx_risk_events_type ON risk_events(event_type, created_at DESC);
-- risk_actions 风险处置记录表
CREATE TABLE IF NOT EXISTS risk_actions (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
action_type VARCHAR(64) NOT NULL,
reason VARCHAR(256) NOT NULL,
reason_detail TEXT,
created_by UUID NOT NULL,
effective_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
expires_at TIMESTAMPTZ,
status VARCHAR(32) NOT NULL DEFAULT 'active',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (created_by) REFERENCES operators(id)
);
CREATE INDEX idx_risk_actions_user ON risk_actions(user_id, status);
CREATE INDEX idx_risk_actions_active ON risk_actions(status, effective_at) WHERE status = 'active';
ALTER TABLE risk_actions ADD CONSTRAINT chk_risk_action_type CHECK (
action_type IN ('warning', 'feature_limit', 'temporary_suspend', 'ban')
);
ALTER TABLE risk_actions ADD CONSTRAINT chk_risk_action_status CHECK (
status IN ('active', 'resolved', 'expired')
);
@@ -0,0 +1,33 @@
-- V013__add_appeals_table.sql
-- 申诉表
CREATE TABLE IF NOT EXISTS appeals (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
appeal_type VARCHAR(64) NOT NULL,
related_action_id UUID,
reason TEXT NOT NULL,
evidence TEXT,
contact_method VARCHAR(256),
status VARCHAR(32) NOT NULL DEFAULT 'pending',
decision_note TEXT,
reviewed_by UUID,
reviewed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (related_action_id) REFERENCES risk_actions(id),
FOREIGN KEY (reviewed_by) REFERENCES operators(id)
);
CREATE INDEX idx_appeals_user ON appeals(user_id, status);
CREATE INDEX idx_appeals_status ON appeals(status, created_at);
CREATE INDEX idx_appeals_action ON appeals(related_action_id, status);
ALTER TABLE appeals ADD CONSTRAINT chk_appeal_status CHECK (
status IN ('pending', 'reviewing', 'approved', 'rejected', 'escalated')
);
ALTER TABLE appeals ADD CONSTRAINT chk_appeal_type CHECK (
appeal_type IN ('ban_appeal', 'suspend_appeal')
);
@@ -0,0 +1,26 @@
-- V014__add_consent_and_privacy_tables.sql
-- 补充 consent_records 和 user_privacy_settings 的缺失字段与索引
-- 为 consent_records 添加 V002 中未包含的新字段
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'consent_records' AND column_name = 'consent_type') THEN
ALTER TABLE consent_records ADD COLUMN consent_type VARCHAR(64);
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'consent_records' AND column_name = 'agreed') THEN
ALTER TABLE consent_records ADD COLUMN agreed BOOLEAN NOT NULL DEFAULT TRUE;
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'consent_records' AND column_name = 'deleted_at') THEN
ALTER TABLE consent_records ADD COLUMN deleted_at TIMESTAMPTZ;
END IF;
END $$;
CREATE INDEX IF NOT EXISTS idx_consent_user_type ON consent_records(user_id, consent_type, deleted_at);
-- 为 user_privacy_settings 添加缺失字段
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'user_privacy_settings' AND column_name = 'deleted_at') THEN
ALTER TABLE user_privacy_settings ADD COLUMN deleted_at TIMESTAMPTZ;
END IF;
END $$;
@@ -0,0 +1,87 @@
-- ============================================================
-- V015: V1.1 新增角色与权限域
-- 新增4个角色 + 7个权限域(~30个权限)
-- ============================================================
-- ========== 新增角色 ==========
INSERT INTO roles (id, code, name, description, system_role) VALUES
('00000000-0000-0000-0000-000000000010', 'service_station_operator', '服务站运营人员', '善缘服务站现场运营,处理预约和现场任务', TRUE),
('00000000-0000-0000-0000-000000000011', 'counselor', '婚恋咨询人员', '公益婚恋咨询师,仅处理被分配的服务', TRUE),
('00000000-0000-0000-0000-000000000012', 'counseling_manager', '咨询管理员', '管理咨询预约分配和服务流程', TRUE),
('00000000-0000-0000-0000-000000000013', 'content_editor', '内容编辑员', '管理公益内容文章,无用户数据权限', TRUE);
-- ========== 新增权限:Banner 域 ==========
INSERT INTO permissions (id, code, name, module, description) VALUES
('20000000-0000-0000-0000-000000000100', 'banner.view', '查看Banner', 'banner', '查看首页Banner列表'),
('20000000-0000-0000-0000-000000000101', 'banner.create', '创建Banner', 'banner', '创建新的首页Banner'),
('20000000-0000-0000-0000-000000000102', 'banner.edit', '编辑Banner', 'banner', '编辑已有Banner'),
('20000000-0000-0000-0000-000000000103', 'banner.publish', '发布Banner', 'banner', '上架/发布Banner'),
('20000000-0000-0000-0000-000000000104', 'banner.disable', '禁用Banner', 'banner', '下架/禁用Banner'),
('20000000-0000-0000-0000-000000000105', 'banner.reorder', '重排Banner', 'banner', '调整Banner排序');
-- ========== 新增权限:Counseling 域 ==========
INSERT INTO permissions (id, code, name, module, description) VALUES
('20000000-0000-0000-0000-000000000200', 'counseling.service.view', '查看咨询服务', 'counseling', '查看分配的咨询服务列表'),
('20000000-0000-0000-0000-000000000201', 'counseling.service.assign', '分配咨询服务', 'counseling', '将咨询分配给咨询师'),
('20000000-0000-0000-0000-000000000202', 'counseling.service.process', '处理咨询服务', 'counseling', '执行咨询服务(开始/完成/跟进)'),
('20000000-0000-0000-0000-000000000203', 'counseling.note.view', '查看咨询备注', 'counseling', '查看咨询敏感备注(需特殊授权)'),
('20000000-0000-0000-0000-000000000204', 'counseling.note.create', '创建咨询备注', 'counseling', '添加咨询服务摘要记录');
-- ========== 新增权限:Content 域 ==========
INSERT INTO permissions (id, code, name, module, description) VALUES
('20000000-0000-0000-0000-000000000300', 'content.view', '查看内容', 'content', '浏览公益文章内容'),
('20000000-0000-0000-0000-000000000301', 'content.create', '创建内容', 'content', '创建公益文章'),
('20000000-0000-0000-0000-000000000302', 'content.edit', '编辑内容', 'content', '编辑已有文章'),
('20000000-0000-0000-0000-000000000303', 'content.publish', '发布内容', 'content', '发布/上架文章'),
('20000000-0000-0000-0000-000000000304', 'content.offline', '下架内容', 'content', '下架/离线文章');
-- ========== 新增权限:Service Location 域 ==========
INSERT INTO permissions (id, code, name, module, description) VALUES
('20000000-0000-0000-0000-000000000400', 'service_location.view', '查看服务站', 'service_location', '查看善缘服务站信息'),
('20000000-0000-0000-0000-000000000401', 'service_location.manage', '管理服务站', 'service_location', '维护服务站信息(地址/时间/状态)');
-- ========== 新增权限:Service Appointment 域 ==========
INSERT INTO permissions (id, code, name, module, description) VALUES
('20000000-0000-0000-0000-000000000500', 'service_appointment.view', '查看预约', 'service_appointment', '查看服务预约列表'),
('20000000-0000-0000-0000-000000000501', 'service_appointment.assign', '分配预约', 'service_appointment', '将预约分配给工作人员'),
('20000000-0000-0000-0000-000000000502', 'service_appointment.confirm', '确认预约', 'service_appointment', '确认用户服务预约'),
('20000000-0000-0000-0000-000000000503', 'service_appointment.complete', '完成预约', 'service_appointment', '标记预约已完成'),
('20000000-0000-0000-0000-000000000504', 'service_appointment.cancel', '取消预约', 'service_appointment', '取消服务预约');
-- ========== 新增权限:Local Eligibility 域 ==========
INSERT INTO permissions (id, code, name, module, description) VALUES
('20000000-0000-0000-0000-000000000600', 'local_eligibility.view', '查看本地资格', 'local_eligibility', '查看用户本地资格状态'),
('20000000-0000-0000-0000-000000000601', 'local_eligibility.review', '审核本地资格', 'local_eligibility', '审核用户本地资格声明和佐证'),
('20000000-0000-0000-0000-000000000602', 'local_eligibility.evidence.view', '查看资格佐证', 'local_eligibility', '查看本地资格原始佐证文件(需特殊授权+审计)');
-- ========== 新增权限:Service Program 域 ==========
INSERT INTO permissions (id, code, name, module, description) VALUES
('20000000-0000-0000-0000-000000000700', 'service_program.view', '查看服务项目', 'service_program', '查看专项公益服务项目'),
('20000000-0000-0000-0000-000000000701', 'service_program.manage', '管理服务项目', 'service_program', '创建/编辑/管理专项服务项目');
-- ========== 角色 → 权限分配 ==========
-- service_station_operator: 仅处理现场预约和服务(不含身份证/用户全库)
INSERT INTO role_permissions (role_id, permission_id)
SELECT '00000000-0000-0000-0000-000000000010', id FROM permissions
WHERE code IN ('service_location.view', 'service_appointment.view', 'service_appointment.confirm', 'service_appointment.complete');
-- counselor: 仅查看和处理被分配的服务(无用户全库/身份证/聊天权限)
INSERT INTO role_permissions (role_id, permission_id)
SELECT '00000000-0000-0000-0000-000000000011', id FROM permissions
WHERE code IN ('counseling.service.view', 'counseling.service.process', 'counseling.note.create');
-- counseling_manager: 可分配、查看和管理咨询(含敏感备注查看权限)
INSERT INTO role_permissions (role_id, permission_id)
SELECT '00000000-0000-0000-0000-000000000012', id FROM permissions
WHERE code IN ('counseling.service.view', 'counseling.service.assign', 'counseling.service.process', 'counseling.note.view');
-- content_editor: 仅内容管理,明确无用户数据权限
INSERT INTO role_permissions (role_id, permission_id)
SELECT '00000000-0000-0000-0000-000000000013', id FROM permissions
WHERE code IN ('content.view', 'content.create', 'content.edit', 'content.publish', 'content.offline');
-- platform_admin: 扩展包含所有V1.1新增权限
INSERT INTO role_permissions (role_id, permission_id)
SELECT '00000000-0000-0000-0000-000000000002', id FROM permissions
WHERE id >= '20000000-0000-0000-0000-000000000100';
@@ -0,0 +1,46 @@
-- ============================================================
-- V016: V1.1 实名认证扩展 — 人脸核验预留
-- 增加 verification_level / liveness_verification_status / verification_provider 字段
-- 同时新增 Feature Flag 系统配置
-- ============================================================
-- ========== 1. user_identities 扩展字段 ==========
ALTER TABLE user_identities ADD COLUMN IF NOT EXISTS verification_level VARCHAR(32) DEFAULT 'basic';
ALTER TABLE user_identities ADD COLUMN IF NOT EXISTS liveness_verification_status VARCHAR(32) DEFAULT 'not_required';
ALTER TABLE user_identities ADD COLUMN IF NOT EXISTS verification_provider VARCHAR(64);
-- verification_level 约束:basic / enhanced / facial
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'chk_identity_verification_level'
) THEN
ALTER TABLE user_identities ADD CONSTRAINT chk_identity_verification_level
CHECK (verification_level IN ('basic', 'enhanced', 'facial'));
END IF;
END
$$;
-- liveness_verification_status 约束:not_required / not_started / in_progress / passed / failed
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'chk_identity_liveness_status'
) THEN
ALTER TABLE user_identities ADD CONSTRAINT chk_identity_liveness_status
CHECK (liveness_verification_status IN ('not_required', 'not_started', 'in_progress', 'passed', 'failed'));
END IF;
END
$$;
-- ========== 2. 新增 Feature Flag 系统配置 ==========
-- Note: Default values for V1.1 feature flags are configured in application.yml
-- INSERT INTO system_configs (config_key, config_value, description) VALUES
-- ('livenessVerification.enabled', to_jsonb(false), '人脸核验功能开关(V1.1预留,默认关闭)'),
-- ('localEligibility.evidencePolicy', to_jsonb('need_based'), '本地资格佐证策略'),
-- ('counseling.enabled', to_jsonb(true), '婚恋咨询功能开关'),
-- ('premarital.enabled', to_jsonb(true), '婚前辅导功能开关'),
-- ('serviceLocation.enabled', to_jsonb(true), '善缘服务站功能开关'),
-- ('content.enabled', to_jsonb(true), '内容中心功能开关'),
-- ('localEligibility.enabled', to_jsonb(true), '本地资格功能开关'),
-- ('banner.maxActiveCount', to_jsonb(5), 'Banner最大活跃数量');
@@ -0,0 +1,44 @@
-- ============================================================
-- V017: V1.1 本地资格 — user_local_eligibilities + local_eligibility_evidences
-- ============================================================
-- 本地资格表:每个用户一条,声明丹阳户籍/工作/居住/其他
CREATE TABLE IF NOT EXISTS user_local_eligibilities (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL UNIQUE REFERENCES users(id),
eligibility_type VARCHAR(32) NOT NULL DEFAULT 'other',
declared_region_code VARCHAR(32),
verification_status VARCHAR(32) NOT NULL DEFAULT 'declared',
review_task_id UUID REFERENCES review_tasks(id),
verified_at TIMESTAMPTZ,
verified_by UUID REFERENCES operators(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_local_elig_user ON user_local_eligibilities(user_id);
CREATE INDEX idx_local_elig_status ON user_local_eligibilities(verification_status);
ALTER TABLE user_local_eligibilities ADD CONSTRAINT chk_elig_type
CHECK (eligibility_type IN ('household_registration', 'residence', 'employment', 'other'));
ALTER TABLE user_local_eligibilities ADD CONSTRAINT chk_elig_verify_status
CHECK (verification_status IN ('declared', 'needs_evidence', 'pending_review', 'verified', 'rejected'));
-- 本地资格佐证文件表
CREATE TABLE IF NOT EXISTS local_eligibility_evidences (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
local_eligibility_id UUID NOT NULL REFERENCES user_local_eligibilities(id) ON DELETE CASCADE,
file_key VARCHAR(256) NOT NULL,
evidence_type VARCHAR(64) NOT NULL DEFAULT 'other',
status VARCHAR(32) NOT NULL DEFAULT 'uploaded',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_evidence_elig ON local_eligibility_evidences(local_eligibility_id);
ALTER TABLE local_eligibility_evidences ADD CONSTRAINT chk_evidence_type
CHECK (evidence_type IN ('employment_proof', 'residence_proof', 'household_proof', 'other'));
ALTER TABLE local_eligibility_evidences ADD CONSTRAINT chk_evidence_status
CHECK (status IN ('uploaded', 'reviewing', 'approved', 'rejected'));
@@ -0,0 +1,24 @@
-- ============================================================
-- V018: V1.1 本地资格审核复用 — review_tasks 扩展
-- 新增 review_type=local_eligibility + 本地资格审核索引
-- 不含第二套审核引擎,完全复用现有 review_tasks/review_items
-- ============================================================
-- 1. 扩展 review_type CHECK 约束,新增 local_eligibility
ALTER TABLE review_tasks DROP CONSTRAINT IF EXISTS chk_review_type;
ALTER TABLE review_tasks ADD CONSTRAINT chk_review_type
CHECK (review_type IN (
'initial_profile', 'profile_change', 'photo_change',
'marital_status_change', 'risk_recheck',
'local_eligibility'
));
-- 2. 本地资格审核队列索引(加速 pending + processing 查询)
CREATE INDEX IF NOT EXISTS idx_review_tasks_local_elig
ON review_tasks (status, submitted_at)
WHERE review_type = 'local_eligibility';
-- 3. 佐证文件访问审计触发(通过敏感访问日志表记录)
-- sensitive_access_logs 表已在 V001 创建,无需新建
-- 业务层在访问 local_eligibility_evidences.file_id 时调用审计接口
@@ -0,0 +1,59 @@
-- ============================================================
-- V019: V1.1 首页 Banner + 聚合首页 API 基础
-- 创建 home_banners 表 + service_locations 表(单阵地)
-- ============================================================
-- ========== home_banners 表 ==========
CREATE TABLE IF NOT EXISTS home_banners (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(200) NOT NULL,
subtitle VARCHAR(300),
image_file_id UUID,
button_text VARCHAR(64),
target_type VARCHAR(64) NOT NULL DEFAULT 'none',
target_value VARCHAR(200),
audience_scope VARCHAR(64) NOT NULL DEFAULT 'all',
sort_order INT NOT NULL DEFAULT 0,
start_at TIMESTAMPTZ,
end_at TIMESTAMPTZ,
status VARCHAR(32) NOT NULL DEFAULT 'active',
created_by UUID REFERENCES operators(id),
updated_by UUID REFERENCES operators(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
ALTER TABLE home_banners ADD CONSTRAINT chk_banner_target_type
CHECK (target_type IN ('activity', 'matchmaker', 'counseling', 'premarital', 'service_location', 'article', 'internal_page', 'none'));
ALTER TABLE home_banners ADD CONSTRAINT chk_banner_audience_scope
CHECK (audience_scope IN ('all', 'onboarding', 'searching', 'getting_to_know', 'successful'));
ALTER TABLE home_banners ADD CONSTRAINT chk_banner_status
CHECK (status IN ('draft', 'scheduled', 'active', 'inactive', 'expired'));
CREATE INDEX idx_home_banners_display ON home_banners(status, start_at, end_at, sort_order)
WHERE status IN ('active', 'scheduled');
-- ========== service_locations 表(万善公园婚姻登记处作为首个阵地) ==========
CREATE TABLE IF NOT EXISTS service_locations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(128) NOT NULL,
short_name VARCHAR(64),
address TEXT NOT NULL,
latitude DECIMAL(10, 7),
longitude DECIMAL(10, 7),
contact_phone_enc TEXT,
contact_phone_display VARCHAR(32),
opening_hours_text TEXT,
service_description TEXT,
cover_file_id UUID,
primary_organization_id UUID REFERENCES organizations(id),
notice_text TEXT,
status VARCHAR(32) NOT NULL DEFAULT 'active',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
ALTER TABLE service_locations ADD CONSTRAINT chk_service_location_status
CHECK (status IN ('active', 'inactive', 'closed'));
@@ -0,0 +1,13 @@
-- ============================================================
-- V020: V1.1 通知类型扩展
-- 新增 appointment/counseling/premarital/local_eligibility/service_location
-- ============================================================
-- 扩展 notifications.type 约束
ALTER TABLE notifications DROP CONSTRAINT IF EXISTS chk_notification_type;
ALTER TABLE notifications ADD CONSTRAINT chk_notification_type
CHECK (type IN (
'review', 'match', 'matchmaker', 'activity', 'risk', 'account', 'system',
'appointment', 'counseling', 'premarital', 'local_eligibility', 'service_location'
));
@@ -0,0 +1,51 @@
-- ============================================================
-- V021: V1.1 Phase 13 - 服务预约表 + 转介追踪字段扩展
-- ============================================================
-- ========== service_appointments 表 ==========
CREATE TABLE IF NOT EXISTS service_appointments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
service_location_id UUID REFERENCES service_locations(id),
service_type VARCHAR(64) NOT NULL,
preferred_date DATE,
preferred_time_slot VARCHAR(32),
user_note TEXT,
status VARCHAR(32) NOT NULL DEFAULT 'submitted',
assigned_operator_id UUID REFERENCES operators(id),
confirmed_start_at TIMESTAMPTZ,
confirmed_end_at TIMESTAMPTZ,
cancelled_by UUID REFERENCES operators(id),
cancel_reason VARCHAR(500),
source VARCHAR(64) NOT NULL DEFAULT 'user_self',
request_source VARCHAR(64) NOT NULL DEFAULT 'user_self',
created_by_operator_id UUID REFERENCES operators(id),
user_confirmed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
ALTER TABLE service_appointments ADD CONSTRAINT chk_appointment_status
CHECK (status IN ('submitted', 'pending_confirmation', 'confirmed', 'completed', 'cancelled'));
ALTER TABLE service_appointments ADD CONSTRAINT chk_source_type
CHECK (source IN ('user_self', 'matchmaker_referral', 'activity_followup', 'service_station', 'operator_assisted'));
CREATE INDEX idx_appointments_user ON service_appointments(user_id, status) WHERE deleted_at IS NULL;
CREATE INDEX idx_appointments_location_date ON service_appointments(service_location_id, preferred_date, status) WHERE deleted_at IS NULL;
-- ========== 为 activity_registrations 添加转介追踪字段 ==========
ALTER TABLE activity_registrations ADD COLUMN IF NOT EXISTS source VARCHAR(64) NOT NULL DEFAULT 'user_self';
ALTER TABLE activity_registrations ADD COLUMN IF NOT EXISTS request_source VARCHAR(64) NOT NULL DEFAULT 'user_self';
ALTER TABLE activity_registrations ADD COLUMN IF NOT EXISTS created_by_operator_id UUID REFERENCES operators(id);
ALTER TABLE activity_registrations ADD COLUMN IF NOT EXISTS user_confirmed_at TIMESTAMPTZ;
ALTER TABLE activity_registrations ADD CONSTRAINT chk_reg_source CHECK (
source IN ('user_self', 'matchmaker_referral', 'activity_followup', 'service_station', 'operator_assisted')
);
-- ========== 为 matchmaker services 添加转介目标字段 ==========
ALTER TABLE matchmaker_services ADD COLUMN IF NOT EXISTS referral_target_type VARCHAR(64);
ALTER TABLE matchmaker_services ADD COLUMN IF NOT EXISTS referral_target_id VARCHAR(128);
ALTER TABLE matchmaker_services ADD COLUMN IF NOT EXISTS referral_source_type VARCHAR(64) NOT NULL DEFAULT 'manual';
@@ -0,0 +1,67 @@
-- ============================================================
-- V022: V1.1 Phase 13A - 婚恋咨询 + 婚前辅导 表结构
-- ============================================================
-- ========== counseling_services 表 ==========
CREATE TABLE IF NOT EXISTS counseling_services (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
service_type VARCHAR(64) NOT NULL,
request_source VARCHAR(64) NOT NULL DEFAULT 'user_self',
user_request_summary TEXT,
organization_id UUID REFERENCES organizations(id),
assigned_operator_id UUID REFERENCES operators(id),
status VARCHAR(32) NOT NULL DEFAULT 'pending',
preferred_service_mode VARCHAR(32), -- online / offline
preferred_time VARCHAR(128),
scheduled_start_at TIMESTAMPTZ,
scheduled_end_at TIMESTAMPTZ,
consent_version VARCHAR(32),
consented_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
closed_reason VARCHAR(500),
companion_user_id UUID REFERENCES users(id),
created_by_operator_id UUID REFERENCES operators(id),
user_confirmed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
ALTER TABLE counseling_services ADD CONSTRAINT chk_counseling_service_type
CHECK (service_type IN (
'relationship_guidance', 'emotional_support',
'premarital_guidance', 'anti_fraud_guidance'
));
ALTER TABLE counseling_services ADD CONSTRAINT chk_counseling_status
CHECK (status IN (
'pending', 'assigned', 'scheduled', 'in_progress',
'completed', 'cancelled', 'closed'
));
ALTER TABLE counseling_services ADD CONSTRAINT chk_request_source
CHECK (request_source IN (
'user_self', 'matchmaker_referral', 'activity_followup',
'service_station', 'operator_assisted'
));
CREATE INDEX idx_counseling_user ON counseling_services(user_id, status) WHERE deleted_at IS NULL;
CREATE INDEX idx_counseling_assigned ON counseling_services(assigned_operator_id, status) WHERE deleted_at IS NULL;
CREATE INDEX idx_counseling_scheduled ON counseling_services(scheduled_start_at) WHERE deleted_at IS NULL;
-- ========== counseling_followups 表 ==========
CREATE TABLE IF NOT EXISTS counseling_followups (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
counseling_id UUID NOT NULL REFERENCES counseling_services(id),
operator_id UUID NOT NULL REFERENCES operators(id),
followup_type VARCHAR(32),
content TEXT NOT NULL,
result_code VARCHAR(64),
next_followup_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_followups_counseling ON counseling_followups(counseling_id);
CREATE INDEX idx_followups_operator ON counseling_followups(operator_id, created_at DESC);
@@ -0,0 +1,48 @@
-- ============================================================
-- V023: V1.1 Phase 14 - 多类型公益活动扩展
-- ============================================================
-- ========== activities 新增字段 ==========
ALTER TABLE activities ADD COLUMN IF NOT EXISTS activity_type VARCHAR(64) NOT NULL DEFAULT 'matchmaking';
ALTER TABLE activities ADD COLUMN IF NOT EXISTS registration_policy TEXT;
ALTER TABLE activities ADD COLUMN IF NOT EXISTS target_group VARCHAR(200);
ALTER TABLE activities ADD COLUMN IF NOT EXISTS industry_scope VARCHAR(200);
ALTER TABLE activities ADD COLUMN IF NOT EXISTS post_event_interest_enabled BOOLEAN NOT NULL DEFAULT FALSE;
ALTER TABLE activities ADD CONSTRAINT chk_activity_type
CHECK (activity_type IN (
'matchmaking', 'interest_social', 'relationship_education',
'premarital_guidance', 'marriage_custom_culture', 'anti_fraud'
));
-- ========== activity_organizations 多组织关联表 ==========
CREATE TABLE IF NOT EXISTS activity_organizations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
activity_id UUID NOT NULL REFERENCES activities(id),
organization_id UUID NOT NULL REFERENCES organizations(id),
role VARCHAR(32) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(activity_id, organization_id)
);
ALTER TABLE activity_organizations ADD CONSTRAINT chk_org_role
CHECK (role IN ('host', 'organizer', 'co_organizer', 'partner', 'venue_partner'));
CREATE INDEX idx_activity_org_activity ON activity_organizations(activity_id);
CREATE INDEX idx_activity_org_org ON activity_organizations(organization_id);
-- ========== activity_capacity_groups 容量分组表 ==========
CREATE TABLE IF NOT EXISTS activity_capacity_groups (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
activity_id UUID NOT NULL REFERENCES activities(id),
group_code VARCHAR(32) NOT NULL,
rule_definition TEXT,
capacity INT NOT NULL DEFAULT 0,
approved_count INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(activity_id, group_code)
);
CREATE INDEX idx_capacity_group_activity ON activity_capacity_groups(activity_id);
@@ -0,0 +1,34 @@
-- ============================================================
-- V024: V1.1 Phase 16 - 活动互选二阶段同意重构
-- ============================================================
-- ========== activity_mutual_connection_consents 表 ==========
-- 记录每对用户在活动中各自的同意状态(二阶段确认)
CREATE TABLE IF NOT EXISTS activity_mutual_connection_consents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
activity_id UUID NOT NULL REFERENCES activities(id),
user_a_id UUID NOT NULL,
user_b_id UUID NOT NULL,
user_a_status VARCHAR(32) NOT NULL DEFAULT 'pending', -- pending / accepted / declined
user_b_status VARCHAR(32) NOT NULL DEFAULT 'pending', -- pending / accepted / declined
both_confirmed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(activity_id, user_a_id, user_b_id)
);
ALTER TABLE activity_mutual_connection_consents ADD CONSTRAINT chk_consent_status
CHECK (user_a_status IN ('pending', 'accepted', 'declined')
AND user_b_status IN ('pending', 'accepted', 'declined'));
-- 唯一约束:同一对用户在同一个活动中只能有一个活跃同意记录
--(通过 activity_id + LEAST(user_a_id, user_b_id) + GREATEST 实现)
CREATE UNIQUE INDEX idx_mutual_consents_pair_unique
ON activity_mutual_connection_consents(activity_id,
LEAST(user_a_id, user_b_id),
GREATEST(user_a_id, user_b_id));
CREATE INDEX idx_mutual_consents_user_a ON activity_mutual_connection_consents(user_a_id, user_a_status);
CREATE INDEX idx_mutual_consents_user_b ON activity_mutual_connection_consents(user_b_id, user_b_status);
CREATE INDEX idx_mutual_consents_both ON activity_mutual_connection_consents(activity_id, user_a_status, user_b_status)
WHERE user_a_status = 'accepted' AND user_b_status = 'accepted';
@@ -0,0 +1,17 @@
-- ============================================================
-- V025: V1.1 Phase 17 - 风险来源扩展(咨询/服务站/活动)
-- ============================================================
-- 扩展 risk_events.event_type CHECK 约束
ALTER TABLE risk_events DROP CONSTRAINT IF EXISTS chk_risk_event_type;
ALTER TABLE risk_events ADD CONSTRAINT chk_risk_event_type
CHECK (event_type IN (
'abuse_report', 'high_risk_message', 'manual_flag',
'fake_marital_status_report', 'counseling_risk',
'appointment_risk', 'activity_risk'
));
-- 扩展 risk_actions.action_type CHECK 约束,支持人工风险标记
ALTER TABLE risk_actions DROP CONSTRAINT IF EXISTS chk_risk_action_type;
ALTER TABLE risk_actions ADD CONSTRAINT chk_risk_action_type
CHECK (action_type IN ('warning', 'feature_limit', 'temporary_suspend', 'ban', 'manual_flag'));
@@ -0,0 +1,106 @@
-- ============================================================
-- V026: V1.1 Phase 19 - 内容管理 + 专项公益服务项目 + 组织关系
-- ============================================================
-- ========== content_categories 表 ==========
CREATE TABLE IF NOT EXISTS content_categories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(128) NOT NULL,
code VARCHAR(64) NOT NULL,
description TEXT,
sort_order INT NOT NULL DEFAULT 0,
status VARCHAR(32) NOT NULL DEFAULT 'active',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(code)
);
ALTER TABLE content_categories ADD CONSTRAINT chk_category_status
CHECK (status IN ('active', 'inactive'));
-- ========== content_articles 表 ==========
CREATE TABLE IF NOT EXISTS content_articles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
category_id UUID REFERENCES content_categories(id),
title VARCHAR(200) NOT NULL,
summary VARCHAR(500),
content TEXT,
cover_file_id UUID,
author_operator_id UUID REFERENCES operators(id),
status VARCHAR(32) NOT NULL DEFAULT 'draft',
publish_at TIMESTAMPTZ,
view_count INT NOT NULL DEFAULT 0,
sort_order INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
ALTER TABLE content_articles ADD CONSTRAINT chk_article_status
CHECK (status IN ('draft', 'scheduled', 'published', 'offline'));
CREATE INDEX idx_articles_category ON content_articles(category_id, status) WHERE deleted_at IS NULL;
CREATE INDEX idx_articles_publish ON content_articles(status, publish_at) WHERE deleted_at IS NULL;
-- ========== service_programs 表 ==========
CREATE TABLE IF NOT EXISTS service_programs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(128) NOT NULL,
description TEXT,
cover_file_id UUID,
organizer_org_id UUID REFERENCES organizations(id),
start_at TIMESTAMPTZ,
end_at TIMESTAMPTZ,
status VARCHAR(32) NOT NULL DEFAULT 'draft',
created_by UUID REFERENCES operators(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
ALTER TABLE service_programs ADD CONSTRAINT chk_program_status
CHECK (status IN ('draft', 'active', 'ended', 'cancelled'));
CREATE INDEX idx_programs_status ON service_programs(status, start_at) WHERE deleted_at IS NULL;
-- ========== service_program_members 表 ==========
CREATE TABLE IF NOT EXISTS service_program_members (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
program_id UUID NOT NULL REFERENCES service_programs(id),
user_id UUID NOT NULL REFERENCES users(id),
status VARCHAR(32) NOT NULL DEFAULT 'pending',
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
approved_at TIMESTAMPTZ,
approved_by UUID REFERENCES operators(id),
rejected_reason VARCHAR(500),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(program_id, user_id)
);
ALTER TABLE service_program_members ADD CONSTRAINT chk_program_member_status
CHECK (status IN ('pending', 'approved', 'rejected', 'withdrawn'));
CREATE INDEX idx_program_members_program ON service_program_members(program_id, status);
CREATE INDEX idx_program_members_user ON service_program_members(user_id, status);
-- ========== organization_relationships 表 ==========
CREATE TABLE IF NOT EXISTS organization_relationships (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
org_a_id UUID NOT NULL REFERENCES organizations(id),
org_b_id UUID NOT NULL REFERENCES organizations(id),
relationship_type VARCHAR(64) NOT NULL,
description TEXT,
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
ended_at TIMESTAMPTZ,
created_by UUID REFERENCES operators(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(org_a_id, org_b_id, relationship_type)
);
ALTER TABLE organization_relationships ADD CONSTRAINT chk_rel_type
CHECK (relationship_type IN ('partner', 'venue_partner', 'referral_partner', 'sponsor', 'collaborator'));
CREATE INDEX idx_org_rel_a ON organization_relationships(org_a_id, relationship_type);
CREATE INDEX idx_org_rel_b ON organization_relationships(org_b_id, relationship_type);
@@ -0,0 +1,41 @@
-- ============================================================
-- V027: V1.1 Production 初始化种子数据
-- Phase 26: Production Initialization
-- ============================================================
-- ========== T01: Seed Content Categories ==========
INSERT INTO content_categories (id, name, code, description, sort_order, status, created_at) VALUES
(gen_random_uuid(), '婚恋课堂', 'marriage_class', '婚恋 relationship 知识和技巧', 1, 'active', NOW()),
(gen_random_uuid(), '婚恋反诈', 'anti_fraud', '婚恋诈骗识别与防范知识', 2, 'active', NOW()),
(gen_random_uuid(), '婚前辅导', 'premarital_edu', '婚前准备与关系建立指导', 3, 'active', NOW()),
(gen_random_uuid(), '婚俗新风', 'custom_culture', '传统婚俗与文明新风尚', 4, 'active', NOW());
-- ========== T02: Seed Activity Types (already in CHECK constraint, no DB seed needed) ==========
-- Activity types are validated by CHECK constraint: matchmaking, interest_social, relationship_education, premarital_guidance, marriage_custom_culture, anti_fraud
-- ========== T03: Seed Service Types ==========
-- Service types are validated by CHECK constraints in respective tables
-- ========== T04: Initialize 万善公园服务站 ==========
INSERT INTO service_locations (id, name, short_name, address, latitude, longitude, contact_phone_display, opening_hours_text, service_description, status, created_at) VALUES
(gen_random_uuid(), '万善公园婚姻登记处善缘服务站', '万善公园站', '丹阳市云阳街道万善公园内', 31.9086, 119.5281, '0511-88888888',
'周一至周五 9:00-17:00
周六 9:00-12:00(法定节假日除外)',
'提供公益红娘服务、婚恋咨询预约、婚前辅导、本地资格核验等综合婚姻服务',
'active', NOW());
-- ========== T05: Initialize Banners ==========
INSERT INTO home_banners (id, title, subtitle, button_text, target_type, target_value, audience_scope, sort_order, start_at, end_at, status, created_at) VALUES
(gen_random_uuid(), '公益婚恋服务', '实名认证 · 本地资格 · 人工审核 · 双向匹配', '立即体验', 'internal_page', 'home', 'all', 1, NOW() - INTERVAL '30 days', NOW() + INTERVAL '365 days', 'active', NOW()),
(gen_random_uuid(), '万善公园服务站', '每周三、五下午开设公益红娘服务', '查看服务站', 'service_location', NULL, 'all', 2, NOW() - INTERVAL '30 days', NOW() + INTERVAL '365 days', 'active', NOW()),
(gen_random_uuid(), '公益活动报名中', '近期有多场交友活动,欢迎参加', '查看全部活动', 'activity', NULL, 'all', 3, NOW() - INTERVAL '30 days', NOW() + INTERVAL '90 days', 'active', NOW());
-- ========== T06: Initialize Feature Flags (if using DB-based feature flags) ==========
-- Feature flags are configured via application.yml / application-dev.yml / application-docker.yml
-- No DB seed needed for Phase 26
-- ========== T07: Seed Roles/Permissions ==========
-- Roles and permissions were already seeded in V015__add_v11_roles_and_permissions.sql
-- Verify they exist:
SELECT COUNT(*) as role_count FROM roles WHERE id::text LIKE '30000000-%';
SELECT COUNT(*) as permission_count FROM permissions WHERE id::text LIKE '20000000-%';