From 22c7c4e7d9c5bf3bd0faac60e6b78803f77e74ba Mon Sep 17 00:00:00 2001 From: zetaloop Date: Sun, 3 May 2026 07:24:20 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=94=A8=20per-domain=20fixture=20?= =?UTF-8?q?=E6=9B=BF=E4=BB=A3=20seed.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/dev/docker-compose.yml | 11 + deploy/dev/fixture/community.sql | 59 +++++ deploy/dev/fixture/game.sql | 9 + deploy/dev/fixture/order.sql | 34 +++ deploy/dev/fixture/player.sql | 17 ++ deploy/dev/fixture/search.sql | 5 + deploy/dev/fixture/shop.sql | 13 ++ deploy/dev/fixture/users.sql | 68 ++++++ deploy/dev/fixture/wallet.sql | 18 ++ deploy/dev/init-domain.sh | 6 + deploy/dev/seed.py | 387 ------------------------------- 11 files changed, 240 insertions(+), 387 deletions(-) create mode 100644 deploy/dev/fixture/community.sql create mode 100644 deploy/dev/fixture/game.sql create mode 100644 deploy/dev/fixture/order.sql create mode 100644 deploy/dev/fixture/player.sql create mode 100644 deploy/dev/fixture/search.sql create mode 100644 deploy/dev/fixture/shop.sql create mode 100644 deploy/dev/fixture/users.sql create mode 100644 deploy/dev/fixture/wallet.sql delete mode 100644 deploy/dev/seed.py diff --git a/deploy/dev/docker-compose.yml b/deploy/dev/docker-compose.yml index 9c881bf..8fbd4b2 100644 --- a/deploy/dev/docker-compose.yml +++ b/deploy/dev/docker-compose.yml @@ -24,6 +24,7 @@ services: - users-pgdata:/var/lib/postgresql/data - ./init-domain.sh:/docker-entrypoint-initdb.d/00-init-domain.sh:ro - ../../desc/sql:/docker-entrypoint-initdb.d/sql:ro + - ./fixture:/docker-entrypoint-initdb.d/fixture:ro game-db: <<: *postgres-base @@ -35,6 +36,7 @@ services: - game-pgdata:/var/lib/postgresql/data - ./init-domain.sh:/docker-entrypoint-initdb.d/00-init-domain.sh:ro - ../../desc/sql:/docker-entrypoint-initdb.d/sql:ro + - ./fixture:/docker-entrypoint-initdb.d/fixture:ro player-db: <<: *postgres-base @@ -46,6 +48,7 @@ services: - player-pgdata:/var/lib/postgresql/data - ./init-domain.sh:/docker-entrypoint-initdb.d/00-init-domain.sh:ro - ../../desc/sql:/docker-entrypoint-initdb.d/sql:ro + - ./fixture:/docker-entrypoint-initdb.d/fixture:ro shop-db: <<: *postgres-base @@ -57,6 +60,7 @@ services: - shop-pgdata:/var/lib/postgresql/data - ./init-domain.sh:/docker-entrypoint-initdb.d/00-init-domain.sh:ro - ../../desc/sql:/docker-entrypoint-initdb.d/sql:ro + - ./fixture:/docker-entrypoint-initdb.d/fixture:ro order-db: <<: *postgres-base @@ -68,6 +72,7 @@ services: - order-pgdata:/var/lib/postgresql/data - ./init-domain.sh:/docker-entrypoint-initdb.d/00-init-domain.sh:ro - ../../desc/sql:/docker-entrypoint-initdb.d/sql:ro + - ./fixture:/docker-entrypoint-initdb.d/fixture:ro wallet-db: <<: *postgres-base @@ -79,6 +84,7 @@ services: - wallet-pgdata:/var/lib/postgresql/data - ./init-domain.sh:/docker-entrypoint-initdb.d/00-init-domain.sh:ro - ../../desc/sql:/docker-entrypoint-initdb.d/sql:ro + - ./fixture:/docker-entrypoint-initdb.d/fixture:ro community-db: <<: *postgres-base @@ -90,6 +96,7 @@ services: - community-pgdata:/var/lib/postgresql/data - ./init-domain.sh:/docker-entrypoint-initdb.d/00-init-domain.sh:ro - ../../desc/sql:/docker-entrypoint-initdb.d/sql:ro + - ./fixture:/docker-entrypoint-initdb.d/fixture:ro review-db: <<: *postgres-base @@ -101,6 +108,7 @@ services: - review-pgdata:/var/lib/postgresql/data - ./init-domain.sh:/docker-entrypoint-initdb.d/00-init-domain.sh:ro - ../../desc/sql:/docker-entrypoint-initdb.d/sql:ro + - ./fixture:/docker-entrypoint-initdb.d/fixture:ro dispute-db: <<: *postgres-base @@ -112,6 +120,7 @@ services: - dispute-pgdata:/var/lib/postgresql/data - ./init-domain.sh:/docker-entrypoint-initdb.d/00-init-domain.sh:ro - ../../desc/sql:/docker-entrypoint-initdb.d/sql:ro + - ./fixture:/docker-entrypoint-initdb.d/fixture:ro notification-db: <<: *postgres-base @@ -123,6 +132,7 @@ services: - notification-pgdata:/var/lib/postgresql/data - ./init-domain.sh:/docker-entrypoint-initdb.d/00-init-domain.sh:ro - ../../desc/sql:/docker-entrypoint-initdb.d/sql:ro + - ./fixture:/docker-entrypoint-initdb.d/fixture:ro search-db: <<: *postgres-base @@ -134,6 +144,7 @@ services: - search-pgdata:/var/lib/postgresql/data - ./init-domain.sh:/docker-entrypoint-initdb.d/00-init-domain.sh:ro - ../../desc/sql:/docker-entrypoint-initdb.d/sql:ro + - ./fixture:/docker-entrypoint-initdb.d/fixture:ro redis: image: redis:8-alpine diff --git a/deploy/dev/fixture/community.sql b/deploy/dev/fixture/community.sql new file mode 100644 index 0000000..ba02551 --- /dev/null +++ b/deploy/dev/fixture/community.sql @@ -0,0 +1,59 @@ +INSERT INTO posts (id, author_id, author_role, title, content, tags, like_count, comment_count) VALUES + (100001, 100001, 'player', '新赛季中单法师强度排行', + '新赛季中单法师的强度有了不少变化,这里给大家分析一下当前版本的T0-T2梯队。 + +T0: 阿狸、辛德拉 +T1: 维克托、泽丽 +T2: 佐伊、妮蔻 + +大家觉得还有哪些英雄被低估了?', + ARRAY['英雄联盟','攻略','中单'], 12, 3), + (100002, 100003, 'player', 'VALORANT 新地图攻略分享', + '新地图的几个关键烟点和架枪位分享给大家。决斗位在这张图上优势很大,特别是A点的peek角度。', + ARRAY['VALORANT','攻略','地图'], 8, 1), + (100003, 100004, 'owner', '星辰工作室招募公告', + '星辰代练工作室现招募以下段位打手: +- LOL 大师及以上 +- 王者荣耀 王者50星以上 + +待遇优厚,佣金比例可谈。有意者私信联系。', + ARRAY['招募','工作室'], 5, 2), + (100004, 100006, 'consumer', '求推荐靠谱的LOL代练', + '钻石卡了好久上不去,想找个靠谱的代练帮忙上大师。有推荐的吗?最好是有保障的工作室。', + ARRAY['英雄联盟','求推荐'], 3, 2), + (100005, 100002, 'player', '上分心得:如何从钻石到大师', + '很多人卡在钻石上不去,其实关键在于几个点: +1. 英雄池不要太广,精通2-3个就够 +2. 对线期不要浪,稳住发育 +3. 多看小地图,把握团战时机 + +希望对大家有帮助!', + ARRAY['英雄联盟','心得','上分'], 15, 4); + +INSERT INTO comments (id, post_id, author_id, content, like_count) VALUES + (100001, 100001, 100002, '阿狸确实强,ban率太高了', 3), + (100002, 100001, 100006, '维克托感觉也是T0级别的', 1), + (100003, 100001, 100003, '法师版本确实舒服', 2), + (100004, 100002, 100001, '新地图确实好玩,决斗位优势大', 1), + (100005, 100003, 100001, '有兴趣,已私信', 0), + (100006, 100003, 100002, '星辰工作室不错,之前合作过', 2), + (100007, 100004, 100001, '可以看看我的主页,钻石到大师是我的强项', 1), + (100008, 100004, 100004, '欢迎来星辰工作室了解,我们有专业的代练团队', 0), + (100009, 100005, 100006, '写得好,学到了', 2), + (100010, 100005, 100007, '确实,英雄池精了比广好', 1), + (100011, 100005, 100001, '补充一点:心态也很重要,连跪就休息', 3), + (100012, 100005, 100003, '赞同,我也是靠精通少数英雄上的不朽', 1); + +INSERT INTO post_likes (id, post_id, user_id) VALUES + (109101, 100001, 100002),(109102, 100001, 100003),(109103, 100001, 100006),(109104, 100001, 100007), + (109105, 100002, 100001),(109106, 100002, 100006), + (109107, 100003, 100001),(109108, 100003, 100002), + (109109, 100004, 100001),(109110, 100004, 100004), + (109111, 100005, 100001),(109112, 100005, 100003),(109113, 100005, 100006),(109114, 100005, 100007); + +INSERT INTO comment_likes (id, comment_id, user_id) VALUES + (109201, 100001, 100001),(109202, 100001, 100006),(109203, 100001, 100007), + (109204, 100003, 100001),(109205, 100003, 100006), + (109206, 100006, 100001),(109207, 100006, 100004), + (109208, 100009, 100001),(109209, 100009, 100007), + (109210, 100011, 100002),(109211, 100011, 100006),(109212, 100011, 100007); diff --git a/deploy/dev/fixture/game.sql b/deploy/dev/fixture/game.sql new file mode 100644 index 0000000..32a8ec9 --- /dev/null +++ b/deploy/dev/fixture/game.sql @@ -0,0 +1,9 @@ +INSERT INTO games (id, name, icon, category, sort_order) VALUES + (100001, '英雄联盟', '🎮', 'MOBA', 1), + (100002, '王者荣耀', '👑', 'MOBA', 2), + (100003, 'VALORANT', '🔫', 'FPS', 3), + (100004, '永劫无间', '⚔️', 'ACT', 4), + (100005, '原神', '🌟', 'RPG', 5), + (100006, 'CS2', '💣', 'FPS', 6), + (100007, '绝地求生', '🪖', 'FPS', 7), + (100008, '和平精英', '🎯', 'FPS', 8); diff --git a/deploy/dev/fixture/order.sql b/deploy/dev/fixture/order.sql new file mode 100644 index 0000000..7374e8f --- /dev/null +++ b/deploy/dev/fixture/order.sql @@ -0,0 +1,34 @@ +INSERT INTO orders (id, consumer_id, player_id, shop_id, service_snapshot, status, total_price, note) VALUES + (100001, 100006, 100001, 100001, + '{"serviceId":100001,"title":"LOL 钻石上分","price":99.00,"unit":"段","gameName":"英雄联盟"}'::jsonb, + 'completed', 99.00, '希望快点上分'), + (100002, 100006, 100002, 100001, + '{"serviceId":100004,"title":"LOL 大师冲击","price":199.00,"unit":"段","gameName":"英雄联盟"}'::jsonb, + 'in_progress', 199.00, '大师冲宗师'), + (100003, 100007, 100003, 100002, + '{"serviceId":100006,"title":"VALORANT 不朽上分","price":150.00,"unit":"段","gameName":"VALORANT"}'::jsonb, + 'pending_accept', 150.00, null), + (100004, 100007, 100001, 100001, + '{"serviceId":100002,"title":"LOL 排位陪玩","price":30.00,"unit":"局","gameName":"英雄联盟"}'::jsonb, + 'completed', 30.00, '陪玩两局'), + (100005, 100006, 100004, 100003, + '{"serviceId":100010,"title":"原神深渊代打","price":80.00,"unit":"次","gameName":"原神"}'::jsonb, + 'pending_payment', 80.00, '深渊满星'); + +INSERT INTO order_state_logs (id, order_id, from_status, to_status, action, actor_id, actor_role) VALUES + (100001, 100001, null, 'pending_payment', 'create', 100006, 'consumer'), + (100002, 100001, 'pending_payment', 'pending_accept', 'pay', 100006, 'consumer'), + (100003, 100001, 'pending_accept', 'in_progress', 'accept', 100001, 'player'), + (100004, 100001, 'in_progress', 'pending_close', 'finish', 100001, 'player'), + (100005, 100001, 'pending_close', 'completed', 'confirm', 100006, 'consumer'), + (100006, 100002, null, 'pending_payment', 'create', 100006, 'consumer'), + (100007, 100002, 'pending_payment', 'pending_accept', 'pay', 100006, 'consumer'), + (100008, 100002, 'pending_accept', 'in_progress', 'accept', 100002, 'player'), + (100009, 100003, null, 'pending_payment', 'create', 100007, 'consumer'), + (100010, 100003, 'pending_payment', 'pending_accept', 'pay', 100007, 'consumer'), + (100011, 100004, null, 'pending_payment', 'create', 100007, 'consumer'), + (100012, 100004, 'pending_payment', 'pending_accept', 'pay', 100007, 'consumer'), + (100013, 100004, 'pending_accept', 'in_progress', 'accept', 100001, 'player'), + (100014, 100004, 'in_progress', 'pending_close', 'finish', 100001, 'player'), + (100015, 100004, 'pending_close', 'completed', 'confirm', 100007, 'consumer'), + (100016, 100005, null, 'pending_payment', 'create', 100006, 'consumer'); diff --git a/deploy/dev/fixture/player.sql b/deploy/dev/fixture/player.sql new file mode 100644 index 0000000..f921208 --- /dev/null +++ b/deploy/dev/fixture/player.sql @@ -0,0 +1,17 @@ +INSERT INTO players (id, user_id, status, rating, total_orders, completed_orders, gender, tags, games, shop_id) VALUES + (100001, 100001, 'available', 4.85, 128, 120, false, ARRAY['中单','法师','上分快'], ARRAY[100001,100002]::bigint[], 100001), + (100002, 100002, 'available', 4.72, 95, 88, true, ARRAY['上单','刺客','高端局'], ARRAY[100001]::bigint[], 100001), + (100003, 100003, 'busy', 4.90, 67, 65, false, ARRAY['决斗','不朽段位'], ARRAY[100003]::bigint[], 100002), + (100004, 100008, 'available', 4.60, 42, 38, true, ARRAY['全能','多游戏'], ARRAY[100001,100003,100005]::bigint[], 100003); + +INSERT INTO player_services (id, player_id, game_id, title, description, price, unit, rank_range, availability) VALUES + (100001, 100001, 100001, 'LOL 钻石上分', '钻石到大师,稳定上分', 99.00, '段', '钻石→大师', ARRAY['周一至周五','晚间']), + (100002, 100001, 100001, 'LOL 排位陪玩', '钻石段位陪玩,轻松愉快', 30.00, '局', '钻石', ARRAY['全天']), + (100003, 100001, 100002, '王者荣耀 星耀上分', '星耀到王者,快速安全', 68.00, '段', '星耀→王者', ARRAY['全天']), + (100004, 100002, 100001, 'LOL 大师冲击', '大师到宗师,高端局专精', 199.00, '段', '大师→宗师', ARRAY['周末','晚间']), + (100005, 100002, 100001, 'LOL 定位赛代打', '10局定位赛,保底铂金', 50.00, '10局','定位赛', ARRAY['全天']), + (100006, 100003, 100003, 'VALORANT 不朽上分', '永恒到不朽,决斗位专精', 150.00, '段', '永恒→不朽', ARRAY['晚间','周末']), + (100007, 100003, 100003, 'VALORANT 陪玩', '不朽段位陪玩,教学向', 40.00, '局', '不朽', ARRAY['全天']), + (100008, 100004, 100001, 'LOL 黄金上分', '黄金到铂金,新手友好', 39.00, '段', '黄金→铂金', ARRAY['全天']), + (100009, 100004, 100003, 'VALORANT 白银上分', '白银到黄金,基础教学', 45.00, '段', '白银→黄金', ARRAY['全天']), + (100010, 100004, 100005, '原神深渊代打', '深渊12层满星', 80.00, '次', '深渊12层', ARRAY['全天']); diff --git a/deploy/dev/fixture/search.sql b/deploy/dev/fixture/search.sql new file mode 100644 index 0000000..f6eb79b --- /dev/null +++ b/deploy/dev/fixture/search.sql @@ -0,0 +1,5 @@ +INSERT INTO favorites (id, user_id, target_type, target_id) VALUES + (100001, 100006, 'player', 100001), + (100002, 100006, 'shop', 100001), + (100003, 100007, 'player', 100003), + (100004, 100007, 'shop', 100002); diff --git a/deploy/dev/fixture/shop.sql b/deploy/dev/fixture/shop.sql new file mode 100644 index 0000000..3f1f9cb --- /dev/null +++ b/deploy/dev/fixture/shop.sql @@ -0,0 +1,13 @@ +INSERT INTO shops (id, owner_id, name, description, rating, total_orders, player_count, commission_type, commission_value, dispatch_mode, announcements) VALUES + (100001, 100004, '星辰代练工作室', '专业LOL/王者代练,7天无理由退款', 4.80, 256, 2, 'percentage', 15.00, 'manual', + ARRAY['新店开业,首单九折!','招募高端局打手,待遇从优']), + (100002, 100005, '狼群电竞俱乐部', '高端局代练团队,大师以上段位保证', 4.65, 180, 1, 'percentage', 12.00, 'auto', + ARRAY['本周特惠:钻石到大师只需199']), + (100003, 100008, '全能工作室', '多游戏代练,总有一款适合你', 4.50, 80, 1, 'fixed', 10.00, 'manual', + ARRAY['支持LOL/VALORANT/原神']); + +INSERT INTO shop_players (id, shop_id, player_id, is_primary) VALUES + (109001, 100001, 100001, true), + (109002, 100001, 100002, false), + (109003, 100002, 100003, true), + (109004, 100003, 100004, true); diff --git a/deploy/dev/fixture/users.sql b/deploy/dev/fixture/users.sql new file mode 100644 index 0000000..dc27758 --- /dev/null +++ b/deploy/dev/fixture/users.sql @@ -0,0 +1,68 @@ +INSERT INTO users (id, username, password_hash, email, nickname, avatar, bio, "current_role", verified_roles, verification_status) VALUES + (100001, 'player_lux', + crypt('test1234', gen_salt('bf')), + 'lux@test.local', '光辉女郎', '', '王者段位代练,擅长中单法师', + 'player', ARRAY['consumer','player'], + '{"consumer":"approved","player":"approved"}'::jsonb), + + (100002, 'player_yasuo', + crypt('test1234', gen_salt('bf')), + 'yasuo@test.local', '疾风剑豪', '', '国服亚索,上分快准狠', + 'player', ARRAY['consumer','player'], + '{"consumer":"approved","player":"approved"}'::jsonb), + + (100003, 'player_jett', + crypt('test1234', gen_salt('bf')), + 'jett@test.local', '飞刀小姐', '', 'VALORANT 不朽段位', + 'player', ARRAY['consumer','player'], + '{"consumer":"approved","player":"approved"}'::jsonb), + + (100004, 'owner_star', + crypt('test1234', gen_salt('bf')), + 'star@test.local', '星辰工作室', '', '专业代练工作室,诚信经营', + 'owner', ARRAY['consumer','owner'], + '{"consumer":"approved","owner":"approved"}'::jsonb), + + (100005, 'owner_wolf', + crypt('test1234', gen_salt('bf')), + 'wolf@test.local', '狼群电竞', '', '高端局代练团队', + 'owner', ARRAY['consumer','owner'], + '{"consumer":"approved","owner":"approved"}'::jsonb), + + (100006, 'consumer_test', + crypt('test1234', gen_salt('bf')), + 'consumer@test.local', '普通玩家小明', '', '想上钻石', + 'consumer', ARRAY['consumer'], + '{"consumer":"approved"}'::jsonb), + + (100007, 'consumer_test2', + crypt('test1234', gen_salt('bf')), + 'consumer2@test.local', '快乐玩家小红', '', '想找人带上分', + 'consumer', ARRAY['consumer'], + '{"consumer":"approved"}'::jsonb), + + (100008, 'player_owner_duo', + crypt('test1234', gen_salt('bf')), + 'duo@test.local', '全能选手', '', '既是打手也是店主', + 'player', ARRAY['consumer','player','owner'], + '{"consumer":"approved","player":"approved","owner":"approved"}'::jsonb); + +INSERT INTO user_preferences (user_id) VALUES + (100001),(100002),(100003),(100004),(100005),(100006),(100007),(100008); + +INSERT INTO user_verifications (id, user_id, role, status, materials, reviewed_by, reviewed_at) VALUES + (100001, 100001, 'player', 'approved', '{"id_card":"mock://id1.jpg","rank_screenshot":"mock://rank1.jpg"}'::jsonb, 702627789228081152, NOW()), + (100002, 100002, 'player', 'approved', '{"id_card":"mock://id2.jpg","rank_screenshot":"mock://rank2.jpg"}'::jsonb, 702627789228081152, NOW()), + (100003, 100003, 'player', 'approved', '{"id_card":"mock://id3.jpg","rank_screenshot":"mock://rank3.jpg"}'::jsonb, 702627789228081152, NOW()), + (100004, 100004, 'owner', 'approved', '{"business_license":"mock://biz1.jpg"}'::jsonb, 702627789228081152, NOW()), + (100005, 100005, 'owner', 'approved', '{"business_license":"mock://biz2.jpg"}'::jsonb, 702627789228081152, NOW()), + (100006, 100008, 'player', 'approved', '{"id_card":"mock://id8.jpg","rank_screenshot":"mock://rank8.jpg"}'::jsonb, 702627789228081152, NOW()), + (100007, 100008, 'owner', 'approved', '{"business_license":"mock://biz8.jpg"}'::jsonb, 702627789228081152, NOW()); + +INSERT INTO user_follows (id, follower_id, followee_id) VALUES + (100001, 100006, 100001), + (100002, 100006, 100002), + (100003, 100007, 100003), + (100004, 100007, 100001), + (100005, 100001, 100002), + (100006, 100002, 100001); diff --git a/deploy/dev/fixture/wallet.sql b/deploy/dev/fixture/wallet.sql new file mode 100644 index 0000000..af40261 --- /dev/null +++ b/deploy/dev/fixture/wallet.sql @@ -0,0 +1,18 @@ +INSERT INTO wallets (user_id, balance, frozen_balance) VALUES + (100001, 2580.00, 0.00), + (100002, 1890.00, 0.00), + (100003, 3200.00, 0.00), + (100004, 5600.00, 0.00), + (100005, 4200.00, 0.00), + (100006, 500.00, 0.00), + (100007, 300.00, 0.00), + (100008, 1500.00, 0.00); + +INSERT INTO wallet_transactions (id, user_id, type, amount, balance_after, description, order_id) VALUES + (100001, 100006, 'topup', 500.00, 500.00, '充值', null), + (100002, 100006, 'payment', -99.00, 401.00, 'LOL 钻石上分', 100001), + (100003, 100001, 'income', 84.15, 2580.00, 'LOL 钻石上分(扣佣)', 100001), + (100004, 100006, 'payment', -199.00, 202.00, 'LOL 大师冲击', 100002), + (100005, 100007, 'topup', 300.00, 300.00, '充值', null), + (100006, 100007, 'payment', -30.00, 270.00, 'LOL 排位陪玩', 100004), + (100007, 100001, 'income', 25.50, 2605.50, 'LOL 排位陪玩(扣佣)', 100004); diff --git a/deploy/dev/init-domain.sh b/deploy/dev/init-domain.sh index 9ada658..1d1590d 100755 --- a/deploy/dev/init-domain.sh +++ b/deploy/dev/init-domain.sh @@ -2,6 +2,7 @@ set -e SQL_DIR="/docker-entrypoint-initdb.d/sql" +FIXTURE_DIR="/docker-entrypoint-initdb.d/fixture" DOMAIN="${POSTGRES_DOMAIN:?POSTGRES_DOMAIN env required}" psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" \ @@ -11,3 +12,8 @@ for f in "$SQL_DIR/$DOMAIN"/*.sql; do [ -f "$f" ] || continue psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" -f "$f" done + +if [ -f "$FIXTURE_DIR/$DOMAIN.sql" ]; then + psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" \ + -f "$FIXTURE_DIR/$DOMAIN.sql" +fi diff --git a/deploy/dev/seed.py b/deploy/dev/seed.py deleted file mode 100644 index fde778f..0000000 --- a/deploy/dev/seed.py +++ /dev/null @@ -1,387 +0,0 @@ -#!/usr/bin/env python3 -""" -Dev seed script — populates the local database with test data. - -Usage: - python seed.py # insert seed data (skips if already seeded) - python seed.py --reset # delete seed data first, then re-insert - -Requires: docker CLI accessible, juwan-postgres container running. -All IDs use a fixed range (100_001 – 109_999) to avoid collision with -snowflake-generated production IDs. -""" - -import json -import subprocess -import sys - -CONTAINER = "juwan-postgres" -DB_USER = "postgres" -DB_NAME = "app" - -# All seed users share this password: test1234 -# bcrypt hash generated via pgcrypto crypt() -PASSWORD = "test1234" - - -def psql(sql: str) -> str: - r = subprocess.run( - [ - "docker", - "exec", - "-i", - CONTAINER, - "psql", - "-U", - DB_USER, - "-d", - DB_NAME, - "-v", - "ON_ERROR_STOP=1", - "--no-psqlrc", - "-t", - "-A", - ], - input=sql, - capture_output=True, - text=True, - timeout=30, - ) - if r.returncode != 0: - print(f"psql error:\n{r.stderr}", file=sys.stderr) - sys.exit(1) - return r.stdout.strip() - - -def already_seeded() -> bool: - cnt = psql("SELECT count(*) FROM games WHERE id BETWEEN 100001 AND 109999;") - return int(cnt) > 0 - - -def reset(): - print("Resetting seed data …") - psql(""" -DELETE FROM wallet_transactions WHERE user_id BETWEEN 100001 AND 109999; -DELETE FROM wallets WHERE user_id BETWEEN 100001 AND 109999; -DELETE FROM comment_likes WHERE id BETWEEN 100001 AND 109999; -DELETE FROM post_likes WHERE id BETWEEN 100001 AND 109999; -DELETE FROM comments WHERE id BETWEEN 100001 AND 109999; -DELETE FROM posts WHERE id BETWEEN 100001 AND 109999; -DELETE FROM order_state_logs WHERE id BETWEEN 100001 AND 109999; -DELETE FROM orders WHERE id BETWEEN 100001 AND 109999; -DELETE FROM shop_invitations WHERE id BETWEEN 100001 AND 109999; -DELETE FROM shop_players WHERE id BETWEEN 100001 AND 109999; -DELETE FROM player_services WHERE id BETWEEN 100001 AND 109999; -DELETE FROM shops WHERE id BETWEEN 100001 AND 109999; -DELETE FROM players WHERE id BETWEEN 100001 AND 109999; -DELETE FROM favorites WHERE id BETWEEN 100001 AND 109999; -DELETE FROM user_follows WHERE id BETWEEN 100001 AND 109999; -DELETE FROM user_verifications WHERE id BETWEEN 100001 AND 109999; -DELETE FROM user_preferences WHERE user_id BETWEEN 100001 AND 109999; -DELETE FROM users WHERE id BETWEEN 100001 AND 109999; -DELETE FROM games WHERE id BETWEEN 100001 AND 109999; -""") - - -def seed(): - print("Seeding …") - - # ── Games ────────────────────────────────────────────────────── - psql(""" -INSERT INTO games (id, name, icon, category, sort_order) VALUES - (100001, '英雄联盟', '🎮', 'MOBA', 1), - (100002, '王者荣耀', '👑', 'MOBA', 2), - (100003, 'VALORANT', '🔫', 'FPS', 3), - (100004, '永劫无间', '⚔️', 'ACT', 4), - (100005, '原神', '🌟', 'RPG', 5), - (100006, 'CS2', '💣', 'FPS', 6), - (100007, '绝地求生', '🪖', 'FPS', 7), - (100008, '和平精英', '🎯', 'FPS', 8); -""") - - # ── Users ────────────────────────────────────────────────────── - # password_hash via pgcrypto: crypt('test1234', gen_salt('bf')) - psql(f""" -INSERT INTO users (id, username, password_hash, email, nickname, avatar, bio, "current_role", verified_roles, verification_status) VALUES - (100001, 'player_lux', - crypt('{PASSWORD}', gen_salt('bf')), - 'lux@test.local', '光辉女郎', '', '王者段位代练,擅长中单法师', - 'player', ARRAY['consumer','player'], - '{{"consumer":"approved","player":"approved"}}'::jsonb), - - (100002, 'player_yasuo', - crypt('{PASSWORD}', gen_salt('bf')), - 'yasuo@test.local', '疾风剑豪', '', '国服亚索,上分快准狠', - 'player', ARRAY['consumer','player'], - '{{"consumer":"approved","player":"approved"}}'::jsonb), - - (100003, 'player_jett', - crypt('{PASSWORD}', gen_salt('bf')), - 'jett@test.local', '飞刀小姐', '', 'VALORANT 不朽段位', - 'player', ARRAY['consumer','player'], - '{{"consumer":"approved","player":"approved"}}'::jsonb), - - (100004, 'owner_star', - crypt('{PASSWORD}', gen_salt('bf')), - 'star@test.local', '星辰工作室', '', '专业代练工作室,诚信经营', - 'owner', ARRAY['consumer','owner'], - '{{"consumer":"approved","owner":"approved"}}'::jsonb), - - (100005, 'owner_wolf', - crypt('{PASSWORD}', gen_salt('bf')), - 'wolf@test.local', '狼群电竞', '', '高端局代练团队', - 'owner', ARRAY['consumer','owner'], - '{{"consumer":"approved","owner":"approved"}}'::jsonb), - - (100006, 'consumer_test', - crypt('{PASSWORD}', gen_salt('bf')), - 'consumer@test.local', '普通玩家小明', '', '想上钻石', - 'consumer', ARRAY['consumer'], - '{{"consumer":"approved"}}'::jsonb), - - (100007, 'consumer_test2', - crypt('{PASSWORD}', gen_salt('bf')), - 'consumer2@test.local', '快乐玩家小红', '', '想找人带上分', - 'consumer', ARRAY['consumer'], - '{{"consumer":"approved"}}'::jsonb), - - (100008, 'player_owner_duo', - crypt('{PASSWORD}', gen_salt('bf')), - 'duo@test.local', '全能选手', '', '既是打手也是店主', - 'player', ARRAY['consumer','player','owner'], - '{{"consumer":"approved","player":"approved","owner":"approved"}}'::jsonb); -""") - - # ── User preferences ─────────────────────────────────────────── - psql(""" -INSERT INTO user_preferences (user_id) VALUES - (100001),(100002),(100003),(100004),(100005),(100006),(100007),(100008); -""") - - # ── User verifications ───────────────────────────────────────── - psql(""" -INSERT INTO user_verifications (id, user_id, role, status, materials, reviewed_by, reviewed_at) VALUES - (100001, 100001, 'player', 'approved', '{"id_card":"mock://id1.jpg","rank_screenshot":"mock://rank1.jpg"}'::jsonb, 702627789228081152, NOW()), - (100002, 100002, 'player', 'approved', '{"id_card":"mock://id2.jpg","rank_screenshot":"mock://rank2.jpg"}'::jsonb, 702627789228081152, NOW()), - (100003, 100003, 'player', 'approved', '{"id_card":"mock://id3.jpg","rank_screenshot":"mock://rank3.jpg"}'::jsonb, 702627789228081152, NOW()), - (100004, 100004, 'owner', 'approved', '{"business_license":"mock://biz1.jpg"}'::jsonb, 702627789228081152, NOW()), - (100005, 100005, 'owner', 'approved', '{"business_license":"mock://biz2.jpg"}'::jsonb, 702627789228081152, NOW()), - (100006, 100008, 'player', 'approved', '{"id_card":"mock://id8.jpg","rank_screenshot":"mock://rank8.jpg"}'::jsonb, 702627789228081152, NOW()), - (100007, 100008, 'owner', 'approved', '{"business_license":"mock://biz8.jpg"}'::jsonb, 702627789228081152, NOW()); -""") - - # ── Players ──────────────────────────────────────────────────── - psql(""" -INSERT INTO players (id, user_id, status, rating, total_orders, completed_orders, gender, tags, games) VALUES - (100001, 100001, 'available', 4.85, 128, 120, false, ARRAY['中单','法师','上分快'], ARRAY[100001,100002]::bigint[]), - (100002, 100002, 'available', 4.72, 95, 88, true, ARRAY['上单','刺客','高端局'], ARRAY[100001]::bigint[]), - (100003, 100003, 'busy', 4.90, 67, 65, false, ARRAY['决斗','不朽段位'], ARRAY[100003]::bigint[]), - (100004, 100008, 'available', 4.60, 42, 38, true, ARRAY['全能','多游戏'], ARRAY[100001,100003,100005]::bigint[]); -""") - - # ── Shops ────────────────────────────────────────────────────── - psql(""" -INSERT INTO shops (id, owner_id, name, description, rating, total_orders, player_count, commission_type, commission_value, dispatch_mode, announcements) VALUES - (100001, 100004, '星辰代练工作室', '专业LOL/王者代练,7天无理由退款', 4.80, 256, 2, 'percentage', 15.00, 'manual', - ARRAY['新店开业,首单九折!','招募高端局打手,待遇从优']), - (100002, 100005, '狼群电竞俱乐部', '高端局代练团队,大师以上段位保证', 4.65, 180, 1, 'percentage', 12.00, 'auto', - ARRAY['本周特惠:钻石到大师只需199']), - (100003, 100008, '全能工作室', '多游戏代练,总有一款适合你', 4.50, 80, 1, 'fixed', 10.00, 'manual', - ARRAY['支持LOL/VALORANT/原神']); -""") - - # ── Shop players ─────────────────────────────────────────────── - psql(""" -INSERT INTO shop_players (id, shop_id, player_id, is_primary) VALUES - (109001, 100001, 100001, true), - (109002, 100001, 100002, false), - (109003, 100002, 100003, true), - (109004, 100003, 100004, true); -""") - - # Update players.shop_id cache - psql(""" -UPDATE players SET shop_id = 100001 WHERE id = 100001; -UPDATE players SET shop_id = 100001 WHERE id = 100002; -UPDATE players SET shop_id = 100002 WHERE id = 100003; -UPDATE players SET shop_id = 100003 WHERE id = 100004; -""") - - # ── Player services ──────────────────────────────────────────── - psql(""" -INSERT INTO player_services (id, player_id, game_id, title, description, price, unit, rank_range, availability) VALUES - (100001, 100001, 100001, 'LOL 钻石上分', '钻石到大师,稳定上分', 99.00, '段', '钻石→大师', ARRAY['周一至周五','晚间']), - (100002, 100001, 100001, 'LOL 排位陪玩', '钻石段位陪玩,轻松愉快', 30.00, '局', '钻石', ARRAY['全天']), - (100003, 100001, 100002, '王者荣耀 星耀上分', '星耀到王者,快速安全', 68.00, '段', '星耀→王者', ARRAY['全天']), - (100004, 100002, 100001, 'LOL 大师冲击', '大师到宗师,高端局专精', 199.00, '段', '大师→宗师', ARRAY['周末','晚间']), - (100005, 100002, 100001, 'LOL 定位赛代打', '10局定位赛,保底铂金', 50.00, '10局','定位赛', ARRAY['全天']), - (100006, 100003, 100003, 'VALORANT 不朽上分', '永恒到不朽,决斗位专精', 150.00, '段', '永恒→不朽', ARRAY['晚间','周末']), - (100007, 100003, 100003, 'VALORANT 陪玩', '不朽段位陪玩,教学向', 40.00, '局', '不朽', ARRAY['全天']), - (100008, 100004, 100001, 'LOL 黄金上分', '黄金到铂金,新手友好', 39.00, '段', '黄金→铂金', ARRAY['全天']), - (100009, 100004, 100003, 'VALORANT 白银上分', '白银到黄金,基础教学', 45.00, '段', '白银→黄金', ARRAY['全天']), - (100010, 100004, 100005, '原神深渊代打', '深渊12层满星', 80.00, '次', '深渊12层', ARRAY['全天']); -""") - - # ── Wallets ──────────────────────────────────────────────────── - psql(""" -INSERT INTO wallets (user_id, balance, frozen_balance) VALUES - (100001, 2580.00, 0.00), - (100002, 1890.00, 0.00), - (100003, 3200.00, 0.00), - (100004, 5600.00, 0.00), - (100005, 4200.00, 0.00), - (100006, 500.00, 0.00), - (100007, 300.00, 0.00), - (100008, 1500.00, 0.00); -""") - - # ── Orders ───────────────────────────────────────────────────── - psql(""" -INSERT INTO orders (id, consumer_id, player_id, shop_id, service_snapshot, status, total_price, note) VALUES - (100001, 100006, 100001, 100001, - '{"serviceId":100001,"title":"LOL 钻石上分","price":99.00,"unit":"段","gameName":"英雄联盟"}'::jsonb, - 'completed', 99.00, '希望快点上分'), - (100002, 100006, 100002, 100001, - '{"serviceId":100004,"title":"LOL 大师冲击","price":199.00,"unit":"段","gameName":"英雄联盟"}'::jsonb, - 'in_progress', 199.00, '大师冲宗师'), - (100003, 100007, 100003, 100002, - '{"serviceId":100006,"title":"VALORANT 不朽上分","price":150.00,"unit":"段","gameName":"VALORANT"}'::jsonb, - 'pending_accept', 150.00, null), - (100004, 100007, 100001, 100001, - '{"serviceId":100002,"title":"LOL 排位陪玩","price":30.00,"unit":"局","gameName":"英雄联盟"}'::jsonb, - 'completed', 30.00, '陪玩两局'), - (100005, 100006, 100004, 100003, - '{"serviceId":100010,"title":"原神深渊代打","price":80.00,"unit":"次","gameName":"原神"}'::jsonb, - 'pending_payment', 80.00, '深渊满星'); -""") - - # ── Order state logs ─────────────────────────────────────────── - psql(""" -INSERT INTO order_state_logs (id, order_id, from_status, to_status, action, actor_id, actor_role) VALUES - (100001, 100001, null, 'pending_payment', 'create', 100006, 'consumer'), - (100002, 100001, 'pending_payment', 'pending_accept', 'pay', 100006, 'consumer'), - (100003, 100001, 'pending_accept', 'in_progress', 'accept', 100001, 'player'), - (100004, 100001, 'in_progress', 'pending_close', 'finish', 100001, 'player'), - (100005, 100001, 'pending_close', 'completed', 'confirm', 100006, 'consumer'), - (100006, 100002, null, 'pending_payment', 'create', 100006, 'consumer'), - (100007, 100002, 'pending_payment', 'pending_accept', 'pay', 100006, 'consumer'), - (100008, 100002, 'pending_accept', 'in_progress', 'accept', 100002, 'player'), - (100009, 100003, null, 'pending_payment', 'create', 100007, 'consumer'), - (100010, 100003, 'pending_payment', 'pending_accept', 'pay', 100007, 'consumer'), - (100011, 100004, null, 'pending_payment', 'create', 100007, 'consumer'), - (100012, 100004, 'pending_payment', 'pending_accept', 'pay', 100007, 'consumer'), - (100013, 100004, 'pending_accept', 'in_progress', 'accept', 100001, 'player'), - (100014, 100004, 'in_progress', 'pending_close', 'finish', 100001, 'player'), - (100015, 100004, 'pending_close', 'completed', 'confirm', 100007, 'consumer'), - (100016, 100005, null, 'pending_payment', 'create', 100006, 'consumer'); -""") - - # ── Wallet transactions ──────────────────────────────────────── - psql(""" -INSERT INTO wallet_transactions (id, user_id, type, amount, balance_after, description, order_id) VALUES - (100001, 100006, 'topup', 500.00, 500.00, '充值', null), - (100002, 100006, 'payment', -99.00, 401.00, 'LOL 钻石上分', 100001), - (100003, 100001, 'income', 84.15, 2580.00, 'LOL 钻石上分(扣佣)', 100001), - (100004, 100006, 'payment', -199.00, 202.00, 'LOL 大师冲击', 100002), - (100005, 100007, 'topup', 300.00, 300.00, '充值', null), - (100006, 100007, 'payment', -30.00, 270.00, 'LOL 排位陪玩', 100004), - (100007, 100001, 'income', 25.50, 2605.50, 'LOL 排位陪玩(扣佣)', 100004); -""") - - # ── Community posts ──────────────────────────────────────────── - psql(""" -INSERT INTO posts (id, author_id, author_role, title, content, tags, like_count, comment_count) VALUES - (100001, 100001, 'player', '新赛季中单法师强度排行', - '新赛季中单法师的强度有了不少变化,这里给大家分析一下当前版本的T0-T2梯队。\n\nT0: 阿狸、辛德拉\nT1: 维克托、泽丽\nT2: 佐伊、妮蔻\n\n大家觉得还有哪些英雄被低估了?', - ARRAY['英雄联盟','攻略','中单'], 12, 3), - (100002, 100003, 'player', 'VALORANT 新地图攻略分享', - '新地图的几个关键烟点和架枪位分享给大家。决斗位在这张图上优势很大,特别是A点的peek角度。', - ARRAY['VALORANT','攻略','地图'], 8, 1), - (100003, 100004, 'owner', '星辰工作室招募公告', - '星辰代练工作室现招募以下段位打手:\n- LOL 大师及以上\n- 王者荣耀 王者50星以上\n\n待遇优厚,佣金比例可谈。有意者私信联系。', - ARRAY['招募','工作室'], 5, 2), - (100004, 100006, 'consumer', '求推荐靠谱的LOL代练', - '钻石卡了好久上不去,想找个靠谱的代练帮忙上大师。有推荐的吗?最好是有保障的工作室。', - ARRAY['英雄联盟','求推荐'], 3, 2), - (100005, 100002, 'player', '上分心得:如何从钻石到大师', - '很多人卡在钻石上不去,其实关键在于几个点:\n1. 英雄池不要太广,精通2-3个就够\n2. 对线期不要浪,稳住发育\n3. 多看小地图,把握团战时机\n\n希望对大家有帮助!', - ARRAY['英雄联盟','心得','上分'], 15, 4); -""") - - # ── Comments ─────────────────────────────────────────────────── - psql(""" -INSERT INTO comments (id, post_id, author_id, content, like_count) VALUES - (100001, 100001, 100002, '阿狸确实强,ban率太高了', 3), - (100002, 100001, 100006, '维克托感觉也是T0级别的', 1), - (100003, 100001, 100003, '法师版本确实舒服', 2), - (100004, 100002, 100001, '新地图确实好玩,决斗位优势大', 1), - (100005, 100003, 100001, '有兴趣,已私信', 0), - (100006, 100003, 100002, '星辰工作室不错,之前合作过', 2), - (100007, 100004, 100001, '可以看看我的主页,钻石到大师是我的强项', 1), - (100008, 100004, 100004, '欢迎来星辰工作室了解,我们有专业的代练团队', 0), - (100009, 100005, 100006, '写得好,学到了', 2), - (100010, 100005, 100007, '确实,英雄池精了比广好', 1), - (100011, 100005, 100001, '补充一点:心态也很重要,连跪就休息', 3), - (100012, 100005, 100003, '赞同,我也是靠精通少数英雄上的不朽', 1); -""") - - # ── Post likes ───────────────────────────────────────────────── - psql(""" -INSERT INTO post_likes (id, post_id, user_id) VALUES - (109101, 100001, 100002),(109102, 100001, 100003),(109103, 100001, 100006),(109104, 100001, 100007), - (109105, 100002, 100001),(109106, 100002, 100006), - (109107, 100003, 100001),(109108, 100003, 100002), - (109109, 100004, 100001),(109110, 100004, 100004), - (109111, 100005, 100001),(109112, 100005, 100003),(109113, 100005, 100006),(109114, 100005, 100007); -""") - - # ── Comment likes ────────────────────────────────────────────── - psql(""" -INSERT INTO comment_likes (id, comment_id, user_id) VALUES - (109201, 100001, 100001),(109202, 100001, 100006),(109203, 100001, 100007), - (109204, 100003, 100001),(109205, 100003, 100006), - (109206, 100006, 100001),(109207, 100006, 100004), - (109208, 100009, 100001),(109209, 100009, 100007), - (109210, 100011, 100002),(109211, 100011, 100006),(109212, 100011, 100007); -""") - - # ── User follows ─────────────────────────────────────────────── - psql(""" -INSERT INTO user_follows (id, follower_id, followee_id) VALUES - (100001, 100006, 100001), - (100002, 100006, 100002), - (100003, 100007, 100003), - (100004, 100007, 100001), - (100005, 100001, 100002), - (100006, 100002, 100001); -""") - - # ── Favorites ────────────────────────────────────────────────── - psql(""" -INSERT INTO favorites (id, user_id, target_type, target_id) VALUES - (100001, 100006, 'player', 100001), - (100002, 100006, 'shop', 100001), - (100003, 100007, 'player', 100003), - (100004, 100007, 'shop', 100002); -""") - - print("Done! Seed data inserted.") - print() - print("Test accounts (password: test1234):") - print(" player_lux — 打手,LOL/王者,星辰工作室成员") - print(" player_yasuo — 打手,LOL高端局,星辰工作室成员") - print(" player_jett — 打手,VALORANT,狼群俱乐部成员") - print(" owner_star — 店主,星辰代练工作室") - print(" owner_wolf — 店主,狼群电竞俱乐部") - print(" consumer_test — 普通消费者") - print(" consumer_test2 — 普通消费者") - print(" player_owner_duo — 打手+店主,全能工作室") - - -if __name__ == "__main__": - if "--reset" in sys.argv: - reset() - elif already_seeded(): - print("Seed data already exists. Use --reset to re-seed.") - sys.exit(0) - seed()