Răsfoiți Sursa

chore: document blocked site configuration migration

彭峰 1 lună în urmă
părinte
comite
9aee6540a8

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

@@ -53,9 +53,11 @@
 - 旧聊天后台的用户消息数、个人/群聊历史、好友、群组、群成员和管理员操作全部依赖 `ChatMsg/ChatGroup/ChatGroupUser/User_Friend`,目标 Schema 与数据库文档均未迁入这些类和历史关系。`UserFriendGroup` 仅保留好友分组,不是好友关系;旧 `RoomConfig` 的 TRTC AppID/SecretKey 与消费它的聊天运行时也不存在。因此 9 个数据动作和 2 个配置动作分别登记为数据/基础设施阻塞,`legacyChatBlocker` 返回逐项原因。
 - 旧可视化模板分类 `Design/Class` 的 4 个动作依赖 `DesignTlpClass/Design_TlpClass`,但线上两个候选 Schema 都不存在。现有 `DesignTlp` 确有 2 条历史模板且均引用 `classId=6`,分类 6 的名称、父级、排序和说明却已丢失。不擅自新建分类伪造语义,也不执行可能使模板引用悬空的删除;`legacyDesignClassBlocker` 会返回逐项数据阻塞原因。
 - 旧 `Com` 通用控制器中,`Logout` 已迁为管理云函数销毁当前 Parse `_Session`,Angular 再清除本地会话并返回登录页;`BootLayout` 已完整迁为 Angular Bootstrap 栅格工具,保留 `.container/.container-fluid`、2–8 列、5 类设备断点、6 组预设、预览和复制 HTML。`SPwdCheck` 依赖旧 `Manager.RandNumber` 二级密码 Session 及业务消费者;6 个 Excel 导入动作依赖已缺失的 `/Config/Import/{mode}.xml`、NPOI、动态模型附表和 `ZL_Commodities`,由 `legacyComBlocker` 返回基础设施原因。`Sort/Sort_API` 中的 `ModelField` 帐套安全排序已由 `modelFieldOrder` 覆盖,内容、商品、栏目和贴吧分类分支仍按部分迁移登记。
+- 旧 `Common/UserBaseField` 依赖 `B_UserBaseField + ZL_UserBase` 动态用户扩展字段,目标 `Profile` 不是这套任意动态表单的等价数据;`ContentField` 依赖根据 `CommonModel.TableName/ModelID` 实时解析任意动态内容附表,目标只保留部分签约副表。两者按数据阻塞登记。`SelUploadFiles` 视图在交付包和官方源码均缺失,当前 PostgreSQL Parse 文件适配器又无法完成上传,按基础设施阻塞登记;`legacyCommonBlocker` 会返回逐项原因。
+- 旧 `Config` 中除已迁移的节假日与另行审计的 API/快捷键/奖励页外,本批 18 个站点配置动作均依赖 ASP.NET `SiteConfig/OrderConfig/SMSConfig/WaterModuleConfig`、XML/单例文件、`web.config` 与宿主重启。目标没有签约的统一配置模型,也没有能同时消费站点、上传、SMTP、注册奖励、订单文案、短信、水印缩略图、MIME/错误页与重新安装设置的云运行时。不把值单纯塞入 Parse Config 伪装成“已生效”;`legacySiteConfigBlocker` 对每个页面/提交动作返回具体基础设施原因。
 - 旧百科后台的主词条审查已映射到 `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、原因与状态搜索筛选;当前保守登记为 97 项已实现、65 项部分实现、174 项数据阻塞、218 项基础设施阻塞、488 项待逐项核验。生成器和 `admin-coverage:check` 会阻止台账与源码基线漂移。
+- 迁移状态页已接入从反编译基线自动生成的 1,042 项旧后台动作台账,可按模块、action、原因与状态搜索筛选;当前保守登记为 97 项已实现、65 项部分实现、176 项数据阻塞、237 项基础设施阻塞、467 项待逐项核验。生成器和 `admin-coverage:check` 会阻止台账与源码基线漂移。
 - Parse 登录只在浏览器保存当前 `sessionToken`;`masterKey` 只在部署进程中使用。
 - 云函数网关强制校验管理员身份、`company` 帐套、类白名单、字段白名单和敏感字段过滤。
 - `_Session` 不开放,`Function` 源码不开放通用查询或编辑;用户密码只允许专用重置操作。

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

@@ -1315,6 +1315,35 @@ async function handler(request, response) {
         ImportForContent_Submit: '目标缺少动态模型附表批量写入流程,商品分支还缺少 ZL_Commodities 主表'
       }; if (!Object.prototype.hasOwnProperty.call(blockers, action)) fail(400, '不支持的旧通用后台动作'); fail(501, 'migration_blocked: ' + blockers[action]);
     }
+    if (operation === 'legacyCommonBlocker') {
+      const action = String(input.action || ''); const blockers = {
+        UserBaseField: '目标缺少旧 B_UserBaseField 动态字段定义与 ZL_UserBase 原始扩展行;Profile 不是等价的动态字段模型',
+        ContentField: '目标只保留 CommonModel 主记录与部分规范化副表,缺少按 TableName/ModelID 动态解析任意旧内容附表的数据与渲染层',
+        SelUploadFiles: '旧交付包与官方源码均缺少 SelUploadFiles 视图,且当前 PostgreSQL Parse 文件适配器无法完成上传/选择流程'
+      }; if (!Object.prototype.hasOwnProperty.call(blockers, action)) fail(400, '不支持的旧公共动作'); fail(501, 'migration_blocked: ' + blockers[action]);
+    }
+    if (operation === 'legacySiteConfigBlocker') {
+      const action = String(input.action || ''); const blockers = {
+        Index: '旧配置首页只跳转 SiteInfo,目标没有签约的统一站点配置模型与运行时',
+        SiteInfo: '目标缺少 SiteConfig.SiteInfo/SiteOption 站名、Logo、站长、版权、全站 JS 与后台目录配置模型',
+        SiteInfo_Submit: '云函数无法更名 ASP.NET 后台路径或通过 web.config 重启宿主,也没有统一站点配置消费者',
+        SiteOption: '目标没有旧 SiteOption/ShopConfig/UserConfig 的域名、模板、上传、审核、积分与安全策略聚合模型',
+        SiteOption_Submit: '现有云函数未消费旧 SiteOption 的数十项站点/商城/互动规则,不能伪造保存生效',
+        MailConfig: '目标缺少 SiteConfig.MailConfig SMTP 服务器、端口、帐号和收件列表配置模型',
+        MailConfig_Submit: '目标无统一 SMTP 邮件发送运行时消费旧密码配置,MailTemp 只是模板而非邮件通道',
+        UserConfig: '目标缺少 SiteConfig.UserConfig 注册、审核、验证码、必填字段、奖励与提现规则模型',
+        UserConfig_Submit: '当前注册/登录云函数未实现旧 UserConfig 规则消费层,仅存储配置不会生效',
+        SetOrderStatus: '目标缺少 OrderConfig 订单/配送/支付状态文案配置,且 ZL_Commodities/订单主链未迁入',
+        SetOrderStatus_Submit: '目标无订单运行时消费 21 类旧状态文案,不能伪造保存',
+        SMSCfg: '目标缺少 SMSConfig 多供应商帐号、密钥、签名、模板与频率限制模型',
+        SMSConfig_Submit: '当前云函数没有可消费旧 SMSConfig 的短信网关,密码重置也因缺短信验证明确阻塞',
+        ThumbConfig: '目标缺少 WaterModuleConfig/ThumbsConfig 水印、文字样式、尺寸与缩略图规则模型',
+        ThumbConfig_Submit: '当前 PostgreSQL Parse 文件适配器配置错误,也没有图片上传后执行旧水印/缩略图规则的处理器',
+        AppConfig: '目标云函数宿主没有 ASP.NET defaultDocument、customErrors、MIME 和扩展名配置界面',
+        AppConfig_Submit: '云函数无法改写/重启旧 web.config 宿主,目标部署运行时也不消费这些 ASP.NET 选项',
+        APPConfig_ReInstall: '目标没有旧 IsInstalled 状态与 /Install/Index 重新安装流程,云函数不应破坏现有生产库'
+      }; 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) } });
     }

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

@@ -213,6 +213,27 @@ const explicit = new Map([
   ['Com/ImportForContent_Submit', ['blocked-infrastructure', '缺少动态附表批量写入流程,商品分支还缺少 ZL_Commodities']],
   ['Com/Sort', ['partial', '模型字段顺序已由 modelFieldOrder 迁移;内容、商品、栏目和贴吧分类的旧统一排序页尚未完整迁移']],
   ['Com/Sort_API', ['partial', 'modelFieldOrder 已覆盖 ModelField 白名单帐套排序;其余 4 类旧表名分支未提供等价云函数']],
+  ['Common/UserBaseField', ['blocked-data', '目标缺少 B_UserBaseField 动态字段定义与 ZL_UserBase 原始扩展行']],
+  ['Common/ContentField', ['blocked-data', '目标缺少按 CommonModel.TableName/ModelID 动态解析任意旧内容附表的数据与渲染层']],
+  ['Common/SelUploadFiles', ['blocked-infrastructure', '旧交付包/官方源码缺少视图,当前 PostgreSQL Parse 文件适配器也无法上传']],
+  ['Config/Index', ['blocked-infrastructure', '旧配置首页只跳转 SiteInfo,目标无签约的统一站点配置模型和运行时']],
+  ['Config/SiteInfo', ['blocked-infrastructure', '目标缺少 SiteInfo/SiteOption 站点、Logo、版权、全站 JS 与后台目录配置']],
+  ['Config/SiteInfo_Submit', ['blocked-infrastructure', '云函数无法更名 ASP.NET 后台路径、改写 web.config 或重启旧宿主']],
+  ['Config/SiteOption', ['blocked-infrastructure', '目标无 SiteOption/ShopConfig/UserConfig 的域名、模板、上传、审核、积分和安全策略模型']],
+  ['Config/SiteOption_Submit', ['blocked-infrastructure', '现有云函数未消费旧 SiteOption 的数十项站点/商城/互动规则']],
+  ['Config/MailConfig', ['blocked-infrastructure', '目标缺少 SMTP 服务器、端口、帐号和收件列表配置模型']],
+  ['Config/MailConfig_Submit', ['blocked-infrastructure', '目标无统一 SMTP 发送运行时;MailTemp 仅是模板而非邮件通道']],
+  ['Config/UserConfig', ['blocked-infrastructure', '目标缺少注册、审核、验证码、必填字段、奖励与提现规则模型']],
+  ['Config/UserConfig_Submit', ['blocked-infrastructure', '当前注册/登录云函数未实现旧 UserConfig 规则消费层']],
+  ['Config/SetOrderStatus', ['blocked-infrastructure', '目标缺少 OrderConfig 状态文案与订单/商品主运行链']],
+  ['Config/SetOrderStatus_Submit', ['blocked-infrastructure', '目标无订单运行时消费 21 类旧订单/配送/支付状态文案']],
+  ['Config/SMSCfg', ['blocked-infrastructure', '目标缺少 SMSConfig 多供应商帐号、密钥、签名、模板和频控模型']],
+  ['Config/SMSConfig_Submit', ['blocked-infrastructure', '当前云函数无短信网关,密码重置也因缺短信验证而阻塞']],
+  ['Config/ThumbConfig', ['blocked-infrastructure', '目标缺少 WaterModuleConfig/ThumbsConfig 水印、文字样式、尺寸和缩略图规则']],
+  ['Config/ThumbConfig_Submit', ['blocked-infrastructure', '当前 Parse 文件适配器错误,也无上传后执行水印/缩略图规则的处理器']],
+  ['Config/AppConfig', ['blocked-infrastructure', '目标云函数宿主无 ASP.NET defaultDocument、customErrors、MIME 和扩展名配置']],
+  ['Config/AppConfig_Submit', ['blocked-infrastructure', '云函数无法改写/重启旧 web.config,目标运行时也不消费这些选项']],
+  ['Config/APPConfig_ReInstall', ['blocked-infrastructure', '目标没有 IsInstalled 状态与 /Install/Index 重新安装流程']],
   ['Content / Baike/Default', ['partial', '已由 Angular 百科审核入口替代;旧默认跳转的 BaikeEdit 版本列表因数据缺失而阻塞']],
   ['Content / Baike/BKVersionList', ['blocked-data', '目标 Schema 缺少旧 BaikeEdit 版本表、待审版本内容与历史版本数据']],
   ['Content / Baike/Version_API', ['blocked-data', '目标无 BaikeEdit 版本记录,无法审核并 Apply、取消审核、驳回或删除']],

Fișier diff suprimat deoarece este prea mare
+ 2 - 0
scripts/smoke-admin-functions.mjs


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

@@ -123,6 +123,17 @@ describe('legacy admin coverage inventory', () => {
     expect(byKey.get('Com/ImportForContent_Submit')?.status).toBe('blocked-infrastructure');
     expect(byKey.get('Com/Sort')?.status).toBe('partial');
     expect(byKey.get('Com/Sort_API')?.status).toBe('partial');
+    expect(byKey.get('Common/UserBaseField')?.status).toBe('blocked-data');
+    expect(byKey.get('Common/ContentField')?.status).toBe('blocked-data');
+    expect(byKey.get('Common/SelUploadFiles')?.status).toBe('blocked-infrastructure');
+    expect(byKey.get('Config/Index')?.status).toBe('blocked-infrastructure');
+    expect(byKey.get('Config/SiteInfo_Submit')?.status).toBe('blocked-infrastructure');
+    expect(byKey.get('Config/MailConfig_Submit')?.status).toBe('blocked-infrastructure');
+    expect(byKey.get('Config/UserConfig_Submit')?.status).toBe('blocked-infrastructure');
+    expect(byKey.get('Config/SetOrderStatus_Submit')?.status).toBe('blocked-infrastructure');
+    expect(byKey.get('Config/SMSConfig_Submit')?.status).toBe('blocked-infrastructure');
+    expect(byKey.get('Config/ThumbConfig_Submit')?.status).toBe('blocked-infrastructure');
+    expect(byKey.get('Config/APPConfig_ReInstall')?.status).toBe('blocked-infrastructure');
     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');

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

@@ -685,148 +685,148 @@ export const LEGACY_ADMIN_COVERAGE: readonly LegacyAdminCoverageEntry[] = [
     "module": "Common",
     "action": "UserBaseField",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-data",
+    "reason": "目标缺少 B_UserBaseField 动态字段定义与 ZL_UserBase 原始扩展行"
   },
   {
     "module": "Common",
     "action": "ContentField",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-data",
+    "reason": "目标缺少按 CommonModel.TableName/ModelID 动态解析任意旧内容附表的数据与渲染层"
   },
   {
     "module": "Common",
     "action": "SelUploadFiles",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "旧交付包/官方源码缺少视图,当前 PostgreSQL Parse 文件适配器也无法上传"
   },
   {
     "module": "Config",
     "action": "Index",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "旧配置首页只跳转 SiteInfo,目标无签约的统一站点配置模型和运行时"
   },
   {
     "module": "Config",
     "action": "SiteInfo",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "目标缺少 SiteInfo/SiteOption 站点、Logo、版权、全站 JS 与后台目录配置"
   },
   {
     "module": "Config",
     "action": "SiteInfo_Submit",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "云函数无法更名 ASP.NET 后台路径、改写 web.config 或重启旧宿主"
   },
   {
     "module": "Config",
     "action": "SiteOption",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "目标无 SiteOption/ShopConfig/UserConfig 的域名、模板、上传、审核、积分和安全策略模型"
   },
   {
     "module": "Config",
     "action": "SiteOption_Submit",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "现有云函数未消费旧 SiteOption 的数十项站点/商城/互动规则"
   },
   {
     "module": "Config",
     "action": "MailConfig",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "目标缺少 SMTP 服务器、端口、帐号和收件列表配置模型"
   },
   {
     "module": "Config",
     "action": "MailConfig_Submit",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "目标无统一 SMTP 发送运行时;MailTemp 仅是模板而非邮件通道"
   },
   {
     "module": "Config",
     "action": "UserConfig",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "目标缺少注册、审核、验证码、必填字段、奖励与提现规则模型"
   },
   {
     "module": "Config",
     "action": "UserConfig_Submit",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "当前注册/登录云函数未实现旧 UserConfig 规则消费层"
   },
   {
     "module": "Config",
     "action": "SetOrderStatus",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "目标缺少 OrderConfig 状态文案与订单/商品主运行链"
   },
   {
     "module": "Config",
     "action": "SetOrderStatus_Submit",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "目标无订单运行时消费 21 类旧订单/配送/支付状态文案"
   },
   {
     "module": "Config",
     "action": "SMSCfg",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "目标缺少 SMSConfig 多供应商帐号、密钥、签名、模板和频控模型"
   },
   {
     "module": "Config",
     "action": "SMSConfig_Submit",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "当前云函数无短信网关,密码重置也因缺短信验证而阻塞"
   },
   {
     "module": "Config",
     "action": "ThumbConfig",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "目标缺少 WaterModuleConfig/ThumbsConfig 水印、文字样式、尺寸和缩略图规则"
   },
   {
     "module": "Config",
     "action": "ThumbConfig_Submit",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "当前 Parse 文件适配器错误,也无上传后执行水印/缩略图规则的处理器"
   },
   {
     "module": "Config",
     "action": "AppConfig",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "目标云函数宿主无 ASP.NET defaultDocument、customErrors、MIME 和扩展名配置"
   },
   {
     "module": "Config",
     "action": "AppConfig_Submit",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "云函数无法改写/重启旧 web.config,目标运行时也不消费这些选项"
   },
   {
     "module": "Config",
     "action": "APPConfig_ReInstall",
     "occurrence": 1,
-    "status": "pending",
-    "reason": "尚未逐项迁移或完成等价性核验"
+    "status": "blocked-infrastructure",
+    "reason": "目标没有 IsInstalled 状态与 /Install/Index 重新安装流程"
   },
   {
     "module": "Config",

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff