Kaynağa Gözat

chore: document blocked chart and chat migration

彭峰 1 ay önce
ebeveyn
işleme
4cd45e462d

+ 3 - 1
docs/migration/admin-migration-status.md

@@ -49,9 +49,11 @@
 - 旧用户附加功能中,`PointGroup/PointGroupAdd/PointGroup_API/PointGroup_Submit` 已映射到 `UserLevel`:提供帐套隔离列表、关键词搜索、现有等级别名/积分阈值/图片/备注编辑和批量删除;旧 `id` 与 Parse 保留字段冲突,因此新增等级明确 501。`VMoneyLog` 已由只读 `UserMoneyLog` 虚拟资源统一聚合 `UserExpDomP/UserSIcon/UserExpHis/UserUserPoint/UserDummyPoint/UserCredit` 六类规范化账本,支持余额/银币/经验/积分/虚拟币/信用分类型、日期、用户名与摘要筛选,不允许篡改历史流水。旧 `ThirdInfo.config` 六个提供商和密钥未迁入,现有 `ThirdPlatInfo` 是不同业务平台且没有旧 OAuth/XML 消费者;`PrizeTaskLog(Global.SignIn)` 用户签到日志与 `UserRealNameAuth` 实名申请/奖励链也全部缺失。这 6 个动作由 `legacyUserAddonBlocker` 逐项返回数或基础设施阻塞,未把 `MisSign` 工作签到或 `Profile` 零散身份字段伪装成旧审批历史。
 - 旧问答后台 11 个动作无法从目标数据库等价重建:线上 Schema 没有 `Ask/GuestAnswer`、`ZL_Ask/ZL_GuestAnswer` 历史记录或 `QueId` 问题—回答关系。`Baike` 是百科词条,`Guestbook` 是留言/回复,`GuestBar` 是论坛帖子,`DesignQuestion/DesignAnswer` 是问卷题目/答卷,都不能伪冒问答主从表。`Default/AskInfo/AskAdd/AskAdd_Submit/Ask_API/AnswerList/AnswerAdd/AnswerAdd_Submit/Answer_API` 已按数据阻塞登记;`Config/Config_Submit` 依赖已丢失的 `GuestConfig.WDOption` 问答运行时、用户组权限与积分消费者,按基础设施阻塞登记。`legacyAskBlocker` 会对每个请求返回具体原因。
 - 旧裱件计算后台 5 个动作全部依赖未迁入的 `BiaoCalcModel/BiaoCalcUserFiles`:目标 Schema 与签约数据库文档都没有裱件主记录、用户文件授权、等级或 `ExpireTime` 历史数据。现有账户会员到期时间控制整个账户权益,不等价于指定裱件用户文件授权,因此不用它伪实现到期/续期。`legacyBiaoCalcBlocker` 已对 `Default/BiaoDetail/Biao_API/UserFiles/UserFiles_API` 返回逐项数据阻塞原因。
+- 旧 `Office/Chart.Index` 控制器只执行 `View()`,但反编译交付包和 Zoomla 官方 `cms2` 源码树都不包含对应 `Areas/Admin/Views/Office/Chart/Index.cshtml`,也没有任何参数、数据源或交互合约可供推导。该动作按缺失旧视图资产的基础设施阻塞登记,不把无关的问卷统计或 `ECharts` 编辑器冒充为 1:1 页面。
+- 旧聊天后台的用户消息数、个人/群聊历史、好友、群组、群成员和管理员操作全部依赖 `ChatMsg/ChatGroup/ChatGroupUser/User_Friend`,目标 Schema 与数据库文档均未迁入这些类和历史关系。`UserFriendGroup` 仅保留好友分组,不是好友关系;旧 `RoomConfig` 的 TRTC AppID/SecretKey 与消费它的聊天运行时也不存在。因此 9 个数据动作和 2 个配置动作分别登记为数据/基础设施阻塞,`legacyChatBlocker` 返回逐项原因。
 - 旧百科后台的主词条审查已映射到 `Baike`:`baikeEntries` 提供帐套、关键词、审核/未审核和推荐/未推荐筛选,`baikeBatch` 支持审核、取消审核、推荐和取消推荐,Angular 新增百科审核入口和只读详情。线上仅保留 1 条 `Baike` 主记录,完全没有旧 `BaikeEdit` 版本表,因此 `BKVersionList/Version_API/BKList` 及 `BK_API` 的版本删除/应用部分明确数据阻塞。`GuestConfig.BKOption` 百科创建/编辑/推荐权限与积分奖励消费者也缺失,`Config/Config_Submit` 按基础设施阻塞登记;推荐操作不伪造已发放奖励。
 - `_User`、`CommonModel`、`Node` 与 `Special` 表格已补齐当前页全选和批量工具栏,可直接批量停用/解锁/移动用户组,审核、回收、恢复、移动内容节点,回收、恢复、移动栏目,以及移动专题;翻页或重新查询会清空选择,避免误操作隐藏页记录。
-- 迁移状态页已接入从反编译基线自动生成的 1,042 项旧后台动作台账,可按模块、action、原因与状态搜索筛选;当前保守登记为 95 项已实现、63 项部分实现、161 项数据阻塞、208 项基础设施阻塞、515 项待逐项核验。生成器和 `admin-coverage:check` 会阻止台账与源码基线漂移。
+- 迁移状态页已接入从反编译基线自动生成的 1,042 项旧后台动作台账,可按模块、action、原因与状态搜索筛选;当前保守登记为 95 项已实现、63 项部分实现、170 项数据阻塞、211 项基础设施阻塞、503 项待逐项核验。生成器和 `admin-coverage:check` 会阻止台账与源码基线漂移。
 - Parse 登录只在浏览器保存当前 `sessionToken`;`masterKey` 只在部署进程中使用。
 - 云函数网关强制校验管理员身份、`company` 帐套、类白名单、字段白名单和敏感字段过滤。
 - `_Session` 不开放,`Function` 源码不开放通用查询或编辑;用户密码只允许专用重置操作。

+ 19 - 0
scripts/deploy-admin-functions.mjs

@@ -1269,6 +1269,25 @@ async function handler(request, response) {
         UserFiles_API: '目标无 BiaoCalcUserFiles.ExpireTime 可安全执行到期或按年月日续期;账户会员到期时间语义不等价'
       }; if (!Object.prototype.hasOwnProperty.call(blockers, action)) fail(400, '不支持的旧裱件计算动作'); fail(501, 'migration_blocked: ' + blockers[action]);
     }
+    if (operation === 'legacyOfficeChartBlocker') {
+      if (String(input.action || '') !== 'Index') fail(400, '不支持的旧 Office 图表动作');
+      fail(501, 'migration_blocked: 旧 Office/Chart.Index 只保留了返回视图的空壳控制器,交付包与官方源码均缺少对应 Index.cshtml 视图、数据源和交互定义,无法 1:1 复原');
+    }
+    if (operation === 'legacyChatBlocker') {
+      const action = String(input.action || ''); const blockers = {
+        Default: '目标 Schema 缺少 ChatMsg 消息表,无法还原用户消息数列表',
+        UserChatHistory: '目标缺少 ChatMsg、ChatGroup 与个人/群组会话关系,无法聚合聊天对象',
+        UserFriend: '目标缺少旧 User_Friend 好友关系与历史数据;UserFriendGroup 只是好友分组,不是好友关系',
+        Group: '目标 Schema 缺少 ChatGroup 群组主表与历史群组',
+        GroupAdd: '目标无可定位和编辑的 ChatGroup 群组记录',
+        GroupAdd_Submit: '目标缺少 ChatGroup/ChatGroupUser 群主、管理员与成员关系,无法保持旧更换群主逻辑',
+        GroupUser: '目标 Schema 缺少 ChatGroupUser 群成员和管理员记录',
+        MessageHistory: '目标缺少 ChatMsg 个人/群组消息、发送者与接收者关系',
+        Config: '目标没有旧 RoomConfig TRTC AppID/SecretKey 配置持久层和聊天运行时',
+        Config_Submit: '目标没有消费 TRTC 密钥的聊天服务,保存配置不会生效且会伪造迁移完成',
+        Chat_API: '目标缺少 ChatMsg/ChatGroup/ChatGroupUser 可删除、启停或授权的旧聊天记录'
+      }; if (!Object.prototype.hasOwnProperty.call(blockers, action)) fail(400, '不支持的旧聊天动作'); fail(501, 'migration_blocked: ' + blockers[action]);
+    }
     if (operation === 'baikeEntries') {
       const page = Math.max(1, Number(input.page) || 1); const pageSize = Math.min(100, Math.max(1, Number(input.pageSize) || 20)); const search = String(input.search || '').trim().toLowerCase(); const status = Number(input.status == null ? -100 : input.status); const elite = Number(input.elite == null ? -100 : input.elite); if (search.length > 100 || ![-100,0,1].includes(status) || ![-100,0,1].includes(elite)) fail(400, '百科搜索或状态筛选无效'); const fields = await schemaFor('Baike'); const query = new Parse.Query('Baike'); applyTenant(query, fields, context, input.companyId); query.limit(1000); let results = await query.find({ useMasterKey: true }); results = results.filter((entry) => (status === -100 || Number(entry.get('status')) === status) && (elite === -100 || Number(entry.get('elite')) === elite) && (!search || [entry.get('tittle'),entry.get('brief'),entry.get('contents'),entry.get('userName'),entry.get('classification')].some((value) => String(value || '').toLowerCase().includes(search)))); results.sort((left,right) => Number(right.get('id') || 0) - Number(left.get('id') || 0)); const total = results.length; results = results.slice((page - 1) * pageSize, page * pageSize); return response.json({ success: true, data: { className: 'Baike', page, pageSize, total, results: results.map(serializeObject) } });
     }

+ 12 - 0
scripts/generate-admin-coverage.mjs

@@ -186,6 +186,18 @@ const explicit = new Map([
   ['BiaoCalc/Biao_API', ['blocked-data', '目标缺少可启用、停用或删除的 BiaoCalcModel 记录']],
   ['BiaoCalc/UserFiles', ['blocked-data', '目标 Schema 缺少 BiaoCalcUserFiles 文件授权、等级与到期时间数据']],
   ['BiaoCalc/UserFiles_API', ['blocked-data', '目标无 BiaoCalcUserFiles.ExpireTime 可到期或续期;账户会员到期字段语义不等价']],
+  ['Office / Chart/Index', ['blocked-infrastructure', '旧交付包与官方源码只保留空壳控制器,缺少 Index.cshtml、数据源和交互定义']],
+  ['Extend / Chat/Default', ['blocked-data', '目标 Schema 缺少 ChatMsg 消息表,无法还原用户消息数']],
+  ['Extend / Chat/UserChatHistory', ['blocked-data', '目标缺少 ChatMsg/ChatGroup 个人与群会话关系']],
+  ['Extend / Chat/UserFriend', ['blocked-data', '目标缺少 User_Friend 好友关系;UserFriendGroup 只是分组,语义不等价']],
+  ['Extend / Chat/Group', ['blocked-data', '目标 Schema 缺少 ChatGroup 群组主表与历史数据']],
+  ['Extend / Chat/GroupAdd', ['blocked-data', '目标无可定位和编辑的 ChatGroup 群组记录']],
+  ['Extend / Chat/GroupAdd_Submit', ['blocked-data', '目标缺少 ChatGroup/ChatGroupUser 群主、管理员与成员关系']],
+  ['Extend / Chat/GroupUser', ['blocked-data', '目标 Schema 缺少 ChatGroupUser 群成员和管理员记录']],
+  ['Extend / Chat/MessageHistory', ['blocked-data', '目标缺少 ChatMsg 个人/群组消息和收发关系']],
+  ['Extend / Chat/Config', ['blocked-infrastructure', '目标没有 RoomConfig TRTC 配置持久层和聊天运行时']],
+  ['Extend / Chat/Config_Submit', ['blocked-infrastructure', '目标没有消费 TRTC AppID/SecretKey 的聊天服务']],
+  ['Extend / Chat/Chat_API', ['blocked-data', '目标缺少 ChatMsg/ChatGroup/ChatGroupUser 可删除、启停或授权记录']],
   ['Content / Baike/Default', ['partial', '已由 Angular 百科审核入口替代;旧默认跳转的 BaikeEdit 版本列表因数据缺失而阻塞']],
   ['Content / Baike/BKVersionList', ['blocked-data', '目标 Schema 缺少旧 BaikeEdit 版本表、待审版本内容与历史版本数据']],
   ['Content / Baike/Version_API', ['blocked-data', '目标无 BaikeEdit 版本记录,无法审核并 Apply、取消审核、驳回或删除']],

Dosya farkı çok büyük olduğundan ihmal edildi
+ 2 - 0
scripts/smoke-admin-functions.mjs


+ 8 - 0
src/app/admin/legacy-admin-coverage.generated.spec.ts

@@ -105,6 +105,14 @@ describe('legacy admin coverage inventory', () => {
     expect(byKey.get('BiaoCalc/Biao_API')?.status).toBe('blocked-data');
     expect(byKey.get('BiaoCalc/UserFiles')?.status).toBe('blocked-data');
     expect(byKey.get('BiaoCalc/UserFiles_API')?.status).toBe('blocked-data');
+    expect(byKey.get('Office / Chart/Index')?.status).toBe('blocked-infrastructure');
+    expect(byKey.get('Extend / Chat/Default')?.status).toBe('blocked-data');
+    expect(byKey.get('Extend / Chat/UserFriend')?.status).toBe('blocked-data');
+    expect(byKey.get('Extend / Chat/GroupAdd_Submit')?.status).toBe('blocked-data');
+    expect(byKey.get('Extend / Chat/MessageHistory')?.status).toBe('blocked-data');
+    expect(byKey.get('Extend / Chat/Config')?.status).toBe('blocked-infrastructure');
+    expect(byKey.get('Extend / Chat/Config_Submit')?.status).toBe('blocked-infrastructure');
+    expect(byKey.get('Extend / Chat/Chat_API')?.status).toBe('blocked-data');
     expect(byKey.get('Content / Baike/Default')?.status).toBe('partial');
     expect(byKey.get('Content / Baike/BKVersionList')?.status).toBe('blocked-data');
     expect(byKey.get('Content / Baike/Version_API')?.status).toBe('blocked-data');

+ 24 - 24
src/app/admin/legacy-admin-coverage.generated.ts

@@ -496,85 +496,85 @@ export const LEGACY_ADMIN_COVERAGE: readonly LegacyAdminCoverageEntry[] = [
     "module": "Office / Chart",
     "action": "Index",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "旧交付包与官方源码只保留空壳控制器,缺少 Index.cshtml、数据源和交互定义"
   },
   {
     "module": "Extend / Chat",
     "action": "Default",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-data",
+    "reason": "目标 Schema 缺少 ChatMsg 消息表,无法还原用户消息数"
   },
   {
     "module": "Extend / Chat",
     "action": "UserChatHistory",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-data",
+    "reason": "目标缺少 ChatMsg/ChatGroup 个人与群会话关系"
   },
   {
     "module": "Extend / Chat",
     "action": "UserFriend",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-data",
+    "reason": "目标缺少 User_Friend 好友关系;UserFriendGroup 只是分组,语义不等价"
   },
   {
     "module": "Extend / Chat",
     "action": "Group",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-data",
+    "reason": "目标 Schema 缺少 ChatGroup 群组主表与历史数据"
   },
   {
     "module": "Extend / Chat",
     "action": "GroupAdd",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-data",
+    "reason": "目标无可定位和编辑的 ChatGroup 群组记录"
   },
   {
     "module": "Extend / Chat",
     "action": "GroupAdd_Submit",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-data",
+    "reason": "目标缺少 ChatGroup/ChatGroupUser 群主、管理员与成员关系"
   },
   {
     "module": "Extend / Chat",
     "action": "GroupUser",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-data",
+    "reason": "目标 Schema 缺少 ChatGroupUser 群成员和管理员记录"
   },
   {
     "module": "Extend / Chat",
     "action": "MessageHistory",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-data",
+    "reason": "目标缺少 ChatMsg 个人/群组消息和收发关系"
   },
   {
     "module": "Extend / Chat",
     "action": "Config",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "目标没有 RoomConfig TRTC 配置持久层和聊天运行时"
   },
   {
     "module": "Extend / Chat",
     "action": "Config_Submit",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "目标没有消费 TRTC AppID/SecretKey 的聊天服务"
   },
   {
     "module": "Extend / Chat",
     "action": "Chat_API",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-data",
+    "reason": "目标缺少 ChatMsg/ChatGroup/ChatGroupUser 可删除、启停或授权记录"
   },
   {
     "module": "Design / Class",

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor