feat(t14-s1s2): 数据迁移基础设施 + 用户迁移

T14 数据迁移工具 S1/S2 阶段:

S1 基础设施:
- source_app/migrate_task 建表 + 实体 + Mapper
- TencentImClient 双密钥 callApiAs(老应用拉取,不走主应用限流,审计记 migrate)
- 后台「老应用配置」页(CRUD + 测试连通)

S2 用户迁移:
- batchImport(multiaccount_import,每批≤100)
- MigrateService.migrateUsers(前缀转换+导入+映射+校验,幂等)
- 后台「数据迁移」页(上传清单文件/粘贴列表 + 任务记录)

联调通过:3用户清单→加sa前缀→腾讯导入OK→user_mapping→校验3/3/3。

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
yixiong
2026-07-09 11:12:25 +08:00
co-authored by Claude
parent b4c6652f66
commit 7b1385e160
14 changed files with 754 additions and 11 deletions
+32
View File
@@ -211,3 +211,35 @@ CREATE TABLE IF NOT EXISTS admin_user (
CONSTRAINT uk_admin_username UNIQUE (username)
);
-- 默认管理员账号由应用首次启动时按 app.yml imutil.admin 配置初始化(不在此写死密码hash)
-- ===== 14. 老应用配置(数据迁移源:每个老应用对应主应用一个租户前缀) =====
CREATE TABLE IF NOT EXISTS source_app (
id bigint GENERATED BY DEFAULT AS IDENTITY,
app_name varchar(64) NOT NULL, -- 老应用名称
sdk_app_id varchar(32) NOT NULL, -- 老应用 SDKAppID
secret_key varchar(128) NOT NULL, -- 老应用密钥(仅本工具持有,迁移拉取用)
tenant_id varchar(32) NOT NULL, -- 对应主应用租户(决定 UserID 前缀),关联 tenant.tenant_id
status smallint NOT NULL DEFAULT 1,-- 1=启用 0=停用
remark text,
created_at timestamptz NOT NULL DEFAULT now(),
CONSTRAINT pk_source_app PRIMARY KEY (id)
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_source_app_sdk ON source_app(sdk_app_id);
-- ===== 15. 迁移任务记录(支持断点续传与校验) =====
CREATE TABLE IF NOT EXISTS migrate_task (
id bigint GENERATED BY DEFAULT AS IDENTITY,
source_app_id bigint NOT NULL, -- 关联 source_app.id
object_type varchar(16) NOT NULL, -- USER/GROUP/MSG/ROSTER
status smallint NOT NULL DEFAULT 0, -- 0=pending 1=running 2=paused 3=done 4=failed
total_count bigint NOT NULL DEFAULT 0, -- 应处理总数
processed_count bigint NOT NULL DEFAULT 0, -- 已处理数
pos_cursor varchar(256), -- 断点游标(时间戳/会话+seq,按对象类型语义不同)
verify_result text, -- 校验结果 JSON(老 vs 新 条数对比)
error_msg text, -- 失败原因
started_at timestamptz,
finished_at timestamptz,
created_at timestamptz NOT NULL DEFAULT now(),
CONSTRAINT pk_migrate_task PRIMARY KEY (id)
);
CREATE INDEX IF NOT EXISTS idx_migrate_task_app ON migrate_task(source_app_id, object_type, status);