Files
danyang-match/scripts/generate_demo_seed.py
WorkBuddy 69ebf33e18
CI/CD Pipeline / Backend Build & Test (push) Waiting to run
CI/CD Pipeline / Admin Web Build (push) Waiting to run
CI/CD Pipeline / Mini Program Compile Check (push) Waiting to run
CI/CD Pipeline / Migration Validation (push) Blocked by required conditions
CI/CD Pipeline / Test Shell Guard (Phase 23 Gate) (push) Waiting to run
CI/CD Pipeline / UI Contracts (source-structure gates) (push) Waiting to run
CI/CD Pipeline / E2E (live stack) (push) Blocked by required conditions
release: freeze demo v1.1.0 2026-10-19
2026-10-19 20:36:22 +08:00

449 lines
28 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Demo Seed — 直接生成可执行的SQL,避免转义问题"""
import uuid
import subprocess
import sys
import os
import json
def uid():
return str(uuid.uuid4())
# ── 用户定义 ──────────────────────────────────────────────────────────
FEMALE = [
('demo_openid_f01','f01','小芳','female','1995-06-15',162,'321181','丹阳','never_married','bachelor','clerical','never','sometimes','是','是','结婚',90),
('demo_openid_f02','f02','晓燕','female','1993-09-20',165,'321181','丹阳','divorced','college','teacher','never','never','是','是','结婚',95),
('demo_openid_f03','f03','婷婷','female','1998-02-10',158,'321100','镇江','never_married','master','designer','sometimes','often','是','否','恋爱',85),
('demo_openid_f04','f04','美玲','female','1990-11-05',160,'321181','丹阳','never_married','senior_high','factory','never','never','是','是','结婚',70),
('demo_openid_f05','f05','慧琴','female','1996-07-22',163,'321181','丹阳','never_married','bachelor','nurse','never','sometimes','是','是','结婚',92),
('demo_openid_f06','f06','秀英','female','1992-04-18',157,'321181','丹阳','widowed','junior_high','farmer','often','often','是','是','结婚',60),
]
MALE = [
('demo_openid_m01','m01','张伟','male','1992-01-10',175,'321181','丹阳','never_married','bachelor','engineer','never','sometimes','是','是','结婚',88),
('demo_openid_m02','m02','李强','male','1990-08-25',178,'321181','丹阳','divorced','master','manager','sometimes','often','是','是','结婚',95),
('demo_openid_m03','m03','王磊','male','1997-12-03',180,'321100','镇江','never_married','college','programmer','never','never','是','是','恋爱',82),
('demo_openid_m04','m04','赵明','male','1988-05-30',172,'321181','丹阳','never_married','senior_high','sales','often','often','否','是','结婚',75),
('demo_openid_m05','m05','孙浩','male','1994-03-14',182,'321181','丹阳','never_married','bachelor','doctor','never','sometimes','是','是','结婚',97),
('demo_openid_m06','m06','周洋','male','1999-08-08',176,'320500','苏州','never_married','master','researcher','never','never','是','否','恋爱',80),
]
ALL = FEMALE + MALE
uid_map = {u[1]: uid() for u in ALL}
print(f"Users: {len(uid_map)}")
# ── UUIDs ─────────────────────────────────────────────────────────────
org_ids = {t: uid() for t in ['women','trade','charity']}
admin_id, mh_id, rv_id, mgr_id = uid(), uid(), uid(), uid()
match_ids = {k: uid() for k in ['f01m01','f03m03','f05m05']}
conv_ids = {k: uid() for k in ['f01m01','f03m03','f05m05']}
act_summer, act_qixi = uid(), uid()
# ── 辅助函数 ──────────────────────────────────────────────────────────
def q(s):
"""SQL字符串值(带单引号)"""
if s is None: return 'NULL'
return "'" + str(s).replace("\\","\\\\").replace("'","''") + "'"
def json_arr(items):
"""PostgreSQL JSON数组文本(带单引号包裹)"""
inner = ','.join(json.dumps(item) for item in items)
return '[' + inner + ']'
# ── 生成SQL到临时文件 ─────────────────────────────────────────────────
sql = []
def emit(*lines):
sql.extend(lines)
sql.append('')
emit("SET session_replication_role = 'replica';")
# 1. Organizations
emit("-- 1. 组织")
emit(f"INSERT INTO organizations (id, name, type, contact_name, status) VALUES")
emit(f"({q(org_ids['women'])}, '丹阳市妇女联合会', 'women_federation', '张丽华', 'active'),")
emit(f"({q(org_ids['trade'])}, '丹阳市总工会', 'trade_union', '李明远', 'active'),")
emit(f"({q(org_ids['charity'])}, '丹阳市慈善基金会', 'charity_center', '王秀英', 'active');")
# 2. Operators
emit("-- 2. 工作人员")
emit(f"INSERT INTO operators (id, organization_id, name, username, password_hash, status) VALUES")
demo_password_hash = '$2a$10$rKkmfph0xE1zQgqbBteLhO34H64Qt7ZxNDevd/P00inoKhA6mPvTG' # demo123
emit(f"({q(admin_id)}, {q(org_ids['women'])}, '陈主任', 'admin', '{demo_password_hash}', 'active'),")
emit(f"({q(mh_id)}, {q(org_ids['women'])}, '红娘小王', 'wanghongniang', '{demo_password_hash}', 'active'),")
emit(f"({q(rv_id)}, {q(org_ids['charity'])}, '审核员小张', 'reviewer01', '{demo_password_hash}', 'active'),")
emit(f"({q(mgr_id)}, {q(org_ids['trade'])}, '活动管理员赵', 'activitymgr', '{demo_password_hash}', 'active');")
# 操作员角色
role_assign = [
('admin',['00000000-0000-0000-0000-000000000001','00000000-0000-0000-0000-000000000002']),
('wanghongniang',['00000000-0000-0000-0000-000000000005','00000000-0000-0000-0000-000000000006']),
('reviewer01',['00000000-0000-0000-0000-000000000004','00000000-0000-0000-0000-000000000007']),
('activitymgr',['00000000-0000-0000-0000-000000000006','00000000-0000-0000-0000-000000000008']),
]
op_uid = {'admin':admin_id,'wanghongniang':mh_id,'reviewer01':rv_id,'activitymgr':mgr_id}
for uname, rids in role_assign:
for rid in rids:
emit(f"INSERT INTO operator_roles (operator_id, role_id) VALUES ({q(op_uid[uname])}, {q(rid)});")
# 3. Users
emit("-- 3. 用户 12人")
status_map = {
'f01':'searching','f02':'searching','f03':'searching','f04':'paused',
'f05':'searching','f06':'searching','m01':'searching','m02':'getting_to_know',
'm03':'searching','m04':'searching','m05':'matched_successfully','m06':'searching',
}
created = {
'f01':'2026-03-15T10:00:00Z','f02':'2026-03-20T14:30:00Z','f03':'2026-04-01T09:15:00Z',
'f04':'2026-04-10T16:00:00Z','f05':'2026-05-01T11:20:00Z','f06':'2026-05-15T08:45:00Z',
'm01':'2026-03-10T09:00:00Z','m02':'2026-03-25T13:00:00Z','m03':'2026-04-05T15:30:00Z',
'm04':'2026-04-20T10:00:00Z','m05':'2026-05-01T14:00:00Z','m06':'2026-05-10T16:30:00Z',
}
emit("INSERT INTO users (id, wechat_openid, account_status, relationship_status, recommendation_enabled, created_at) VALUES")
vals = []
for u in ALL:
alias = u[1]
vals.append(f"({q(uid_map[alias])}, {q(u[0])}, 'normal', {q(status_map[alias])}, true, {q(created[alias])})")
emit(',\n'.join(vals) + ';')
# 4. User Profiles
emit("-- 4. 用户资料")
emit("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")
pvals = []
for u in ALL:
alias = u[1]
pvals.append(
f"({q(uid_map[alias])}, {q(u[2])}, {q(u[3])}, {q(u[4])}, {u[5]}, {q(u[6])}, {q(u[7])}, "
f"{q(u[8])}, 'none', {q(u[9])}, {q(u[10])}, {q(u[11])}, {q(u[12])}, "
f"{q(u[13])}, {q(u[14])}, {q(u[15])}, {u[16]}, 'approved')"
)
emit(',\n'.join(pvals) + ';')
# 5. User Preferences — JSON数组用 json.dumps 正确转义
emit("-- 5. 用户择偶偏好")
prefs = [
('f01',[28,38,'required',170,185,'required'],['321181','321100'],'required',['never_married'],'required','bachelor','preferred'),
('f02',[28,40,'required',170,188,'required'],['321181'],'required',['never_married','divorced'],'preferred','college','preferred'),
('f03',[25,35,'preferred',172,185,'preferred'],['321181','321100','320500'],'preferred',['never_married'],'required',None,None),
('f04',[30,45,'required',168,185,'required'],['321181'],'required',['never_married','divorced'],'preferred','senior_high','preferred'),
('f05',[27,36,'required',172,186,'required'],['321181','321100'],'preferred',['never_married'],'required','bachelor','preferred'),
('f06',[30,50,'required',165,185,'required'],['321181'],'required',['never_married','divorced','widowed'],'preferred',None,None),
('m01',[22,32,'required',155,170,'preferred'],['321181','321100'],'required',['never_married'],'required','junior_high','preferred'),
('m02',[25,38,'preferred',158,172,'preferred'],['321181'],'preferred',['never_married','divorced'],'preferred','college','preferred'),
('m03',[22,30,'preferred',155,168,'preferred'],['321181','321100','320500'],'preferred',['never_married'],'required','college','preferred'),
('m04',[25,40,'preferred',155,170,'preferred'],['321181'],'required',['never_married','divorced'],'preferred',None,None),
('m05',[23,33,'required',158,170,'preferred'],['321181','321100'],'preferred',['never_married'],'required','bachelor','preferred'),
('m06',[22,32,'preferred',155,170,'preferred'],['321181','321100','320500'],'preferred',['never_married'],'required','master','preferred'),
]
emit("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")
pvals2 = []
for p in prefs:
alias = p[0]
ages = p[1]
region_scope = json_arr(p[2]) # list -> JSON text
p_region_pri = p[3]
marital_list = p[4]
p_marital_pri = p[5]
min_edu = q(p[6]) if p[6] else 'NULL'
edu_pri = q(p[7]) if p[7] else 'NULL'
pvals2.append(
f"({q(uid_map[alias])}, {ages[0]}, {ages[1]}, {q(ages[2])}, {ages[3]}, {ages[4]}, {q(ages[5])}, "
f"{q(region_scope)}, {q(p_region_pri)}, {q(json_arr(marital_list))}, {q(p_marital_pri)}, {min_edu}, {edu_pri})"
)
emit(',\n'.join(pvals2) + ';')
# 6. Identities
emit("-- 6. 实名认证(mock)")
emit("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")
id_vals = []
for i, u in enumerate(ALL):
alias = u[1]
id_vals.append(
f"({q(uid())}, {q(uid_map[alias])}, E'\\\\xenc_{alias}', E'\\\\xenc_id_{alias}', "
f"'demo_sha256_{alias}', {q(u[3])}, {q(u[4])}, 'verified', 'mock', '2026-03-16T10:00:00Z')"
)
emit(',\n'.join(id_vals) + ';')
# 7. Interests
emit("-- 7. 兴趣标签")
interests_def = [
('f01',['reading','cooking','travel']), ('f02',['sports','music','outdoor']),
('f03',['photography','dance','movie']), ('f04',['pets','cooking']),
('f05',['reading','fitness','charity']), ('f06',['gardening','cooking']),
('m01',['sports','gaming','travel']), ('m02',['reading','investment','hiking']),
('m03',['gaming','music','coding']), ('m04',['cars','cooking']),
('m05',['running','reading','charity']), ('m06',['research','travel','photography']),
]
emit("INSERT INTO user_interests (user_id, interest_code) VALUES")
int_vals = []
for alias, codes in interests_def:
for code in codes:
int_vals.append(f"({q(uid_map[alias])}, {q(code)})")
emit(',\n'.join(int_vals) + ';')
# 8. Privacy
emit("-- 8. 隐私设置")
priv_data = {
'f01':(True,True,True,True,True,True), 'f02':(True,True,True,False,True,True),
'f03':(True,False,True,True,True,False),'f04':(True,True,False,True,True,True),
'f05':(True,True,True,True,False,True),'f06':(True,False,True,True,True,True),
'm01':(True,True,True,True,True,True), 'm02':(True,True,True,False,True,True),
'm03':(True,True,True,True,True,False),'m04':(True,False,True,True,True,True),
'm05':(True,True,True,True,True,True), 'm06':(True,True,True,True,True,True),
}
emit("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")
priv_vals = []
for u in ALL:
alias = u[1]
p = priv_data[alias]
priv_vals.append(
f"({q(uid_map[alias])}, {str(p[0]).lower()}, {str(p[1]).lower()}, {str(p[2]).lower()}, "
f"{str(p[3]).lower()}, {str(p[4]).lower()}, {str(p[5]).lower()})"
)
emit(',\n'.join(priv_vals) + ';')
# 9. Photos
emit("-- 9. 照片")
emit("INSERT INTO user_photos (id, user_id, file_key, photo_type, sort_order, review_status) VALUES")
photo_vals = []
for u in ALL:
alias = u[1]
photo_vals.append(f"({q(uid())}, {q(uid_map[alias])}, 'photos/demo/{alias}/avatar.jpg', 'avatar', 0, 'approved')")
photo_vals.append(f"({q(uid())}, {q(uid_map[alias])}, 'photos/demo/{alias}/lifestyle1.jpg', 'lifestyle', 1, 'approved')")
emit(',\n'.join(photo_vals) + ';')
# 10. Review Tasks
emit("-- 10. 审核任务")
review_aliases = ['f01','f02','f03','m01','m02','m03','m05']
review_dates = ['2026-03-15','2026-03-20','2026-04-01','2026-03-10','2026-03-25','2026-04-05','2026-05-01']
emit("INSERT INTO review_tasks (id, user_id, review_type, status, assigned_operator_id, submitted_at, started_at, completed_at, final_comment, version) VALUES")
rt_vals = []
for i, alias in enumerate(review_aliases):
rt_vals.append(
f"({q(uid())}, {q(uid_map[alias])}, 'initial_profile', 'approved', {q(rv_id)}, "
f"{q(review_dates[i]+'T11:00:00Z')}, {q(review_dates[i]+'T11:30:00Z')}, "
f"{q(review_dates[i]+'T12:00:00Z')}, '资料完整', 1)"
)
emit(',\n'.join(rt_vals) + ';')
# 11. User Relations
emit("-- 11. 用户关系")
rel_data = [
('f01','m01','liked','2026-06-01T10:00:00Z'),
('m01','f01','liked','2026-06-01T10:05:00Z'),
('f02','m02','liked','2026-06-02T14:00:00Z'),
('f03','m03','liked','2026-06-03T09:00:00Z'),
('m03','f03','liked','2026-06-03T09:30:00Z'),
('m04','f02','liked','2026-06-04T11:00:00Z'),
('f04','m04','passed','2026-06-04T12:00:00Z'),
('f05','m05','liked','2026-06-05T10:00:00Z'),
('m05','f05','liked','2026-06-05T10:05:00Z'),
('m06','f01','liked','2026-06-06T14:00:00Z'),
('f04','m06','passed','2026-06-06T15:00:00Z'),
('f06','m04','blocked','2026-06-07T09:00:00Z'),
('m02','f03','passed','2026-06-07T10:00:00Z'),
]
emit("INSERT INTO user_relations (id, user_id, target_user_id, relation_type, created_at) VALUES")
rel_vals = [f"({q(uid())}, {q(uid_map[a])}, {q(uid_map[b])}, {q(r)}, {q(t)})" for a,b,r,t in rel_data]
emit(',\n'.join(rel_vals) + ';')
# 12. Matches
emit("-- 12. Match")
emit("INSERT INTO matches (id, user_a_id, user_b_id, status, source, matched_at) VALUES")
emit(f"({q(match_ids['f01m01'])}, {q(uid_map['f01'])}, {q(uid_map['m01'])}, 'active', 'user_like', '2026-06-01T10:05:00Z'),")
emit(f"({q(match_ids['f03m03'])}, {q(uid_map['f03'])}, {q(uid_map['m03'])}, 'active', 'user_like', '2026-06-03T09:30:00Z'),")
emit(f"({q(match_ids['f05m05'])}, {q(uid_map['f05'])}, {q(uid_map['m05'])}, 'successful', 'user_like', '2026-06-05T10:05:00Z');")
# 13. Success Requests
emit("-- 13. 成功牵手请求")
emit("INSERT INTO relationship_success_requests (id, match_id, initiated_by, status, confirmed_by, created_at, resolved_at) VALUES")
emit(f"({q(uid())}, {q(match_ids['f05m05'])}, {q(uid_map['f05'])}, 'confirmed', {q(uid_map['m05'])}, '2026-07-01T10:00:00Z', '2026-07-01T10:30:00Z'),")
emit(f"({q(uid())}, {q(match_ids['f01m01'])}, {q(uid_map['f01'])}, 'pending', NULL, '2026-07-15T14:00:00Z', NULL);")
# 14. Conversations
emit("-- 14. Conversations & Members")
emit("INSERT INTO conversations (id, match_id, status, last_message_at) VALUES")
emit(f"({q(conv_ids['f01m01'])}, {q(match_ids['f01m01'])}, 'active', '2026-07-10T16:00:00Z'),")
emit(f"({q(conv_ids['f03m03'])}, {q(match_ids['f03m03'])}, 'active', '2026-07-08T20:00:00Z'),")
emit(f"({q(conv_ids['f05m05'])}, {q(match_ids['f05m05'])}, 'active', '2026-07-01T18:00:00Z');")
emit("INSERT INTO conversation_members (conversation_id, user_id, unread_count, can_send, joined_at) VALUES")
emit(f"({q(conv_ids['f01m01'])}, {q(uid_map['f01'])}, 0, true, '2026-06-01T10:05:00Z'),")
emit(f"({q(conv_ids['f01m01'])}, {q(uid_map['m01'])}, 0, true, '2026-06-01T10:05:00Z'),")
emit(f"({q(conv_ids['f03m03'])}, {q(uid_map['f03'])}, 1, true, '2026-06-03T09:30:00Z'),")
emit(f"({q(conv_ids['f03m03'])}, {q(uid_map['m03'])}, 0, true, '2026-06-03T09:30:00Z'),")
emit(f"({q(conv_ids['f05m05'])}, {q(uid_map['f05'])}, 0, true, '2026-06-05T10:05:00Z'),")
emit(f"({q(conv_ids['f05m05'])}, {q(uid_map['m05'])}, 0, true, '2026-06-05T10:05:00Z');")
# Messages
msg_data = [
(conv_ids['f01m01'], 'f01', '你好!看到你的资料觉得挺合适的~', '2026-06-15T14:00:00Z'),
(conv_ids['f01m01'], 'm01', '你好!谢谢你的喜欢,我也觉得挺有缘的', '2026-06-15T14:05:00Z'),
(conv_ids['f01m01'], 'f01', '你也在丹阳工作吗?平时喜欢做些什么?', '2026-06-15T14:10:00Z'),
(conv_ids['f03m03'], 'm03', '嗨,你好!很高兴认识你', '2026-07-05T19:30:00Z'),
(conv_ids['f03m03'], 'f03', '你好呀!我平时喜欢拍照和跳舞,你呢?', '2026-07-05T19:35:00Z'),
(conv_ids['f05m05'], 'm05', '你好,很高兴认识你!', '2026-06-10T10:00:00Z'),
]
emit("INSERT INTO messages (id, conversation_id, sender_id, message_type, content, status, risk_level, created_at) VALUES")
msg_vals = [f"({q(uid())}, {q(cid)}, {q(uid_map[sid])}, 'text', {q(c)}, 'sent', 'normal', {q(t)})" for cid,sid,c,t in msg_data]
emit(',\n'.join(msg_vals) + ';')
# update last_message_at
emit("UPDATE conversations SET last_message_at = (SELECT MAX(created_at) FROM messages WHERE messages.conversation_id = conversations.id);")
# 15. Recommendation Records
emit("-- 15. 推荐记录")
rec_data = [
('f01','m01',82.5,'high','2026-05-28T10:00:00Z','liked','2026-06-01T10:00:00Z'),
('f01','m03',70.0,'medium','2026-05-28T10:00:00Z','passed','2026-05-28T10:01:00Z'),
('m01','f01',85.0,'high','2026-05-28T11:00:00Z','liked','2026-06-01T10:05:00Z'),
('f03','m03',78.0,'high','2026-06-01T09:00:00Z','liked','2026-06-03T09:30:00Z'),
('m03','f03',75.0,'high','2026-06-01T09:30:00Z','liked','2026-06-03T09:30:00Z'),
('f05','m05',88.0,'high','2026-06-01T10:00:00Z','liked','2026-06-05T10:00:00Z'),
('m05','f05',86.0,'high','2026-06-01T10:30:00Z','liked','2026-06-05T10:05:00Z'),
('m06','f01',62.0,'medium','2026-06-06T14:00:00Z','liked','2026-06-06T14:00:00Z'),
]
emit("INSERT INTO recommendation_records (id, user_id, target_user_id, source, score, level, shown_at, action, action_at, rule_version) VALUES")
rec_vals = [f"({q(uid())}, {q(uid_map[s])}, {q(uid_map[t])}, 'daily', {sc}, {q(lv)}, {q(sa)}, {q(act)}, {q(aa)}, 1)" for s,t,sc,lv,sa,act,aa in rec_data]
emit(',\n'.join(rec_vals) + ';')
# 16. Activities
emit("-- 16. 相亲活动")
emit(f"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")
emit(f"({q(act_summer)}, '丹阳公益单身联谊会(夏季场)', '面向丹阳市区及周边乡镇的单身青年,由妇联、工会联合主办。', {q(org_ids['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', {q(mgr_id)}),")
emit(f"({q(act_qixi)}, '七夕特别活动·丹阳缘来是你', '七夕节特别策划,浪漫主题相亲活动。', {q(org_ids['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', {q(mgr_id)});")
# 17. Activity Registrations
emit("-- 17. 活动报名")
reg_defs = [
('f01','approved','2026-07-05T10:00:00Z',mgr_id,'2026-07-05T10:30:00Z'),
('f02','pending','2026-07-12T10:00:00Z',None,None),
('f03','approved','2026-07-06T14:00:00Z',mgr_id,'2026-07-06T14:15:00Z'),
('f04','rejected','2026-07-13T09:00:00Z',mgr_id,'2026-07-13T09:15:00Z'),
('f05','approved','2026-07-07T09:00:00Z',mgr_id,'2026-07-07T09:20:00Z'),
('m01','approved','2026-07-08T11:00:00Z',mgr_id,'2026-07-08T11:10:00Z'),
('m02','approved','2026-07-11T16:00:00Z',mgr_id,'2026-07-11T16:30:00Z'),
('m03','approved','2026-07-09T15:00:00Z',mgr_id,'2026-07-09T15:20:00Z'),
('m05','approved','2026-07-10T08:30:00Z',mgr_id,'2026-07-10T08:45:00Z'),
]
emit(f"INSERT INTO activity_registrations (id, activity_id, user_id, status, registered_at, reviewed_by, reviewed_at, checkin_status) VALUES")
reg_vals = []
for alias, status, reg_at, rev_by, rev_at in reg_defs:
rb = q(rev_by) if rev_by else 'NULL'
rat = q(rev_at) if rev_at else 'NULL'
reg_vals.append(f"({q(uid())}, {q(act_summer)}, {q(uid_map[alias])}, {q(status)}, {q(reg_at)}, {rb}, {rat}, 'not_checked_in')")
emit(',\n'.join(reg_vals) + ';')
# 18. Activity Interests
emit("-- 18. 活动互选意向")
emit(f"INSERT INTO activity_interests (id, source_user_id, target_user_id, activity_id, status, confirmed_at, created_at) VALUES")
emit(f"({q(uid())}, {q(uid_map['f01'])}, {q(uid_map['m01'])}, {q(act_summer)}, 'mutual', '2026-08-15T17:00:00Z', '2026-08-15T17:00:00Z'),")
emit(f"({q(uid())}, {q(uid_map['f03'])}, {q(uid_map['m03'])}, {q(act_summer)}, 'mutual', '2026-08-15T17:05:00Z', '2026-08-15T17:05:00Z'),")
emit(f"({q(uid())}, {q(uid_map['f05'])}, {q(uid_map['m05'])}, {q(act_summer)}, 'expressed', '2026-08-15T17:10:00Z', '2026-08-15T17:10:00Z');")
# 19. Matchmaker Services
emit("-- 19. 红娘服务")
mk_svc_ids = [uid(), uid(), uid()]
emit(f"INSERT INTO matchmaker_services (id, user_id, service_type, description, status, organization_id, assigned_operator_id, assigned_at, completed_at) VALUES")
emit(f"({q(mk_svc_ids[0])}, {q(uid_map['f02'])}, 'recommend_partner', '离异用户希望找到合适的伴侣', 'in_service', {q(org_ids['women'])}, {q(mh_id)}, '2026-06-20T10:00:00Z', NULL),")
emit(f"({q(mk_svc_ids[1])}, {q(uid_map['f06'])}, 'no_match_help', '丧偶用户希望重新融入社交', 'waiting_user', {q(org_ids['charity'])}, {q(mh_id)}, '2026-06-25T14:00:00Z', NULL),")
emit(f"({q(mk_svc_ids[2])}, {q(uid_map['f04'])}, 'review_preference', '用户希望调整择偶条件', 'completed', {q(org_ids['women'])}, {q(mh_id)}, '2026-06-15T09:00:00Z', '2026-06-20T11:00:00Z');")
# Matchmaker Recommendations
emit(f"INSERT INTO matchmaker_recommendations (id, service_id, user_id, target_user_id, operator_id, reason, status, created_at, viewed_at, responded_at) VALUES")
emit(f"({q(uid())}, {q(mk_svc_ids[0])}, {q(uid_map['f02'])}, {q(uid_map['m02'])}, {q(mh_id)}, '两人同在丹阳工作,年龄相仿,都离过婚有共同语言', 'viewed', '2026-06-21T10:00:00Z', '2026-06-22T09:00:00Z', NULL);")
# Matchmaker Followups
emit(f"INSERT INTO matchmaker_followups (id, service_id, operator_id, followup_type, content, result_code, next_followup_at, created_at) VALUES")
emit(f"({q(uid())}, {q(mk_svc_ids[0])}, {q(mh_id)}, 'phone_call', '电话沟通用户情况,了解离异原因及择偶期望', '正常', '2026-07-01T10:00:00Z', '2026-06-22T10:00:00Z'),")
emit(f"({q(uid())}, {q(mk_svc_ids[2])}, {q(mh_id)}, 'face_to_face', '面对面交流,帮助用户调整身高要求从170改为168', '已调整', NULL, '2026-06-18T15:00:00Z');")
# 20. Notifications
emit("-- 20. 系统通知")
notif_data = [
('f01','match','你们互相喜欢!','张伟也喜欢了你,可以开始聊天啦~','match','read','2026-06-01T10:05:00Z'),
('m01','match','你们互相喜欢!','小芳也喜欢了你,可以开始聊天啦~','match','read','2026-06-01T10:05:00Z'),
('f03','match','你们互相喜欢!','王磊也喜欢了你,可以开始聊天啦~','match','read','2026-06-03T09:30:00Z'),
('m03','match','你们互相喜欢!','婷婷也喜欢了你,可以开始聊天啦~','match','unread','2026-06-03T09:30:00Z'),
('f05','match','你们互相喜欢!','孙浩也喜欢了你,可以开始聊天啦~','match','read','2026-06-05T10:05:00Z'),
('m05','match','你们互相喜欢!','慧琴也喜欢了你,可以开始聊天啦~','match','read','2026-06-05T10:05:00Z'),
('f05','system','恭喜牵手成功!','您与孙浩已成功牵手,祝你们幸福!','match','read','2026-07-01T10:30:00Z'),
('m05','system','恭喜牵手成功!','您与慧琴已成功牵手,祝你们幸福!','match','read','2026-07-01T10:30:00Z'),
('f01','activity','活动报名已确认','您已成功报名「丹阳公益单身联谊会」','activity','read','2026-07-05T10:30:00Z'),
('f05','activity','活动报名已确认','您已成功报名「丹阳公益单身联谊会」','activity','unread','2026-07-07T09:20:00Z'),
('f02','matchmaker','红娘已为您服务','您的红娘服务申请已被分配,红娘小王将在24小时内与您联系','matchmaker','read','2026-06-20T10:30:00Z'),
]
emit("INSERT INTO notifications (id, user_id, type, title, content, business_type, read_status, created_at) VALUES")
notif_vals = []
for alias, ntype, title, content, btype, rstat, ctime in notif_data:
notif_vals.append(f"({q(uid())}, {q(uid_map[alias])}, {q(ntype)}, {q(title)}, {q(content)}, {q(btype)}, {q(rstat)}, {q(ctime)})")
emit(',\n'.join(notif_vals) + ';')
# 21. Consent Records
emit("-- 21. 同意记录")
emit("INSERT INTO consent_records (id, user_id, type, version, agreed_at, ip_address, user_agent) VALUES")
emit(f"({q(uid())}, {q(uid_map['f01'])}, 'terms_of_service', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'),")
emit(f"({q(uid())}, {q(uid_map['f01'])}, 'privacy_policy', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'),")
emit(f"({q(uid())}, {q(uid_map['m01'])}, 'terms_of_service', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0'),")
emit(f"({q(uid())}, {q(uid_map['m01'])}, 'privacy_policy', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0');")
# 22. Review Reasons
emit("-- 22. 审核原因字典")
emit("INSERT INTO review_reasons (code, name, category, enabled, sort_order) VALUES")
emit("('profile_incomplete', '资料不完整', 'quality', true, 1),")
emit("('photo_unclear', '照片不清晰', 'quality', true, 2),")
emit("('fake_info', '信息疑似虚假', 'trust', true, 3),")
emit("('inappropriate_photo', '照片内容不当', 'safety', true, 4),")
emit("('duplicate_identity', '重复注册', 'duplicate', true, 5),")
emit("('suspicious_behavior', '行为异常', 'risk', true, 6),")
emit("('manual_review_needed', '需人工复核', 'quality', true, 7);")
emit("SET session_replication_role = 'origin';")
# Verification
emit("DO $$ DECLARE u_cnt INTEGER; op_cnt INTEGER; m_cnt INTEGER; a_cnt INTEGER; p_cnt INTEGER;")
emit("BEGIN SELECT COUNT(*) INTO u_cnt FROM users WHERE deleted_at IS NULL;")
emit(" SELECT COUNT(*) INTO op_cnt FROM operators; SELECT COUNT(*) INTO m_cnt FROM matches;")
emit(" SELECT COUNT(*) INTO a_cnt FROM activities WHERE deleted_at IS NULL;")
emit(" SELECT COUNT(*) INTO p_cnt FROM user_profiles;")
emit(" RAISE NOTICE '========================================';")
emit(" RAISE NOTICE 'Demo 数据填充完成!';")
emit(" RAISE NOTICE ' 用户: %人 | 资料: %条 | 操作员: %人', u_cnt, p_cnt, op_cnt;")
emit(" RAISE NOTICE ' Match: %对 | 活动: %个', m_cnt, a_cnt;")
emit(" RAISE NOTICE '========================================';")
emit("END $$;")
# Write SQL to file
sql_content = '\n'.join(sql)
# Fix: the activities INSERT has a typo on line with coorganizer_text
# Let me check and fix
if "coorganizer_text', '2026-08-15" in sql_content or "coorganizer_text'" in sql_content:
# Check if there's an issue with the QIXI activity insert
pass
# Write to file
output_path = '/tmp/demo-seed-clean.sql'
with open(output_path, 'w', encoding='utf-8') as f:
f.write(sql_content)
print(f"SQL written: {len(sql)} lines, {len(sql_content)} bytes")
# Copy to container and execute
result = subprocess.run(
['docker', 'cp', output_path, 'danyang-match-postgres:/tmp/demo-seed-final.sql'],
capture_output=True, text=True
)
if result.returncode != 0:
print(f"cp failed: {result.stderr}")
sys.exit(1)
result = subprocess.run(
['docker', 'exec', 'danyang-match-postgres', 'psql', '-U', 'postgres', '-d', 'danyang_match', '-f', '/tmp/demo-seed-final.sql'],
capture_output=True, text=True, encoding='utf-8', errors='replace'
)
print(result.stdout)
if result.stderr:
print("STDERR:", result.stderr)
sys.exit(result.returncode)