# 80 · 架构与功能优化评估(**保留现有功能**前提下的重构方向 + 去平台痕迹) - 日期:2026-09-13 - 状态:📋 **评估中(待用户定范围与优先级)**|**P0(去平台痕迹)已落地并上线** - 触发(用户原话): 1. 「看看能否彻底抛弃 dshs 的架构 以及跳转 portal.html,不要在本项目中体现 dshs 任何内容,把 admin 的门户管理都放到设置选项中 弹窗展示」 2. 「看看如何优化架构和功能,在保留现有功能的基础上 优化重构后有更好的效果」 > **TL;DR**|**不推倒重来** —— 平台本体(账号 / 审批 / 实例生命周期 / 反代 / 配额 / DB)就是要保留的那部分,重写 = 把已验证的东西再赌一次、且**零收益**。 > 真正该做的是**收口与显式化**:本档列 **9 项优化**,按"**今天真实事故暴露的痛点**"排序;其中 **2 项零重启、5 项合一次重启窗口、2 项长期**。 > 另:用户另外两个诉求(不跳 `portal.html`、admin 管理进设置弹窗)**已并入第 4 项**,并给出 R5 下的可行形态。 --- ## 一、为什么不是"抛弃架构"(判断依据) 1. **平台本体就是要保留的功能**:账号与审批、实例生命周期(spawn/reap/配额)、反代与子域、DB、插件候选池 —— 这些是"现有功能"的实体。 2. **今天(09-13)的几次事故,根因全是"层层补丁叠加",不是架构本身**: | 事故 | 直接根因 | 性质 | |---|---|---| | 注入脚本整段不执行(浮层/自愈/助手面板全废) | 模板字面量转义被求值(`.join('\n')`) | **补丁缺校验** | | 浮层视觉升级把脚本写崩 | 同上 | 同上 | | guest 实例被 OOM 杀(exitCode 137) | 实例上限 384MB < univer gateway 390MB | **配额与插件集合脱钩** | | 页面"恢复→起来→又被杀"循环 | 恢复逻辑正常,但实例起不来 | **缺"有界恢复"** | | 自愈链路 5 代补丁(档案 50→51→72→77→78) | 每代只解决当期症状 | **策略未收口** | ⇒ **结论:优化方向 = 收口 + 显式化 + 构建期校验**,而不是换架构。 3. **R5**:任何"把管理能力搬进实例"的动作都属**扩大可见面** ⇒ 必须单独评估(见第 4 项)。 --- ## 二、痛点 → 优化项(9 项,按今天事故排序) | # | 优化项 | 现状痛点(证据) | 手段 | 收益 | 代价 | 重启 | 优先级 | |---|---|---|---|---|---|---|---| | 1 | **注入脚本外置 + 构建期硬校验** | `SESSION_*_JS` 是 TS **模板字面量**,转义被求值 ⇒ 今天两次写崩、且旧校验是假绿 | 把脚本挪到 `assets/inject/*.js` 独立文件,构建时内联;`verify-inject`(已建)纳入 `npm run build` 强制 | 彻底消灭该类事故(今天已出 2 次) | 小 | 需一次 | **P0** | | 2 | **`npm run verify` 统一校验入口** | 今天临时补了 `verify-inject`;静默页/配额/内存联动仍无校验 | 汇成一条命令:tsc + 单测 + 注入脚本**运行时**校验 + 静态页一致性 + 关键页 curl 冒烟 | 假绿无处藏身 | 小 | 否 | **P0** | | 3 | **实例配额与插件集合联动(自适应内存)** | guest 上限 384 < univer gateway 390 ⇒ **必被 OOM 杀**(10:03 实测 exitCode 137) | 按已启用插件的**内存预估**(档案 67 已有 UI 预估)自动定 `MemoryMax`;`maxIdleInstances` 与宿主余量联动;V8 堆跟随上限(不再硬编码 160) | 不再"装不下就死";探针仍有意义 | 中 | 需一次 | **P0/P1** | | 4 | **门户管理就地化(不跳 `portal.html`)** | 现在整页跳门户;`desktop/plugins/skills.html` 是三个跳转桩 | 实例内「设置 → **平台管理**」→ **弹窗 iframe** 嵌 `portal.html?embed=1`(隐去平台头/导航);原跳转降级为兜底新窗口 | 不离开工作区、体验连续 | 小-中 | 需一次 | **P1**(**先 R5 评估**) | | 5 | **自愈策略收口成一份状态机** | 探活/熔断/恢复/告警分散在 proxy 注入脚本 + orchestrator(5 代补丁) | 一张状态图(探活→判据→恢复→冷却→告警)+ 单测覆盖;前端只留"探针 + 呈现" | 以后只改一处;今天这类事故不再复现 | 中 | 需一次 | **P1** | | 6 | **有界恢复(放弃无限重试)** | guest 今天"恢复→被杀→再恢复"循环 ~35s/次 | 连续 N 次失败即停在明确失败态 + 手动重试(复用档案 78 熔断信号) | 用户看得懂"为什么不行" | 小 | 需一次 | **P1** | | 7 | **门户页面结构** | `portal.html` 单页 50KB + 3 个跳转桩页 | 保留单页但去掉桩页;或按分区路由化 | 可维护性 | 中 | 否(静态) | P2 | | 8 | **可观测性统一** | 崩溃只有 stderr、熔断只有日志、内存只有采样文件 | 统一 `/opt/dsh/state/*.json` 快照 + `/api/dsh/status` 汇总(今天已加 `breaker`) | 排障从"翻 journal"变"读一个接口" | 中 | 需一次 | P2 | | 9 | **文档/代码双库桥接** | 今天多次"对账/推送/幽灵文件"仪式 | 可选:文档与代码同仓同 PR(或明确只保留单向导出) | 少一半同步仪式 | 大 | 否 | P3 | ### 4 项的补充说明(这两条最像"用户真正想要的") **第 4 项(门户管理就地化)在 R5 下的可行形态** —— 与档案 05 PoC-2 ① 的既有结论对账: | 做法 | 权限性质 | 判定 | |---|---|---| | 实例前端直调平台 admin API(能力下沉) | **真·扩大** | ❌ 与 05 PoC-2 ① + R5 冲突 | | **弹窗 iframe 嵌平台页**(推荐) | 代码与数据**仍全在平台域**;跨子域被**同源策略**隔开 ⇒ 实例内 agent **读不到 iframe 内容** | ⚠️ 仍需 R5 确认"实例内出现管理入口"这一可见面扩大;缓解:**仅 admin 可见** + 先只读 | | 维持整页跳转 | 无变化 | ✅ 最保守 | **技术可行性实测**:`curl -I https://alotbuy.com/portal.html` ⇒ **无 `X-Frame-Options`、无 CSP `frame-ancestors`** ⇒ 同站子域 iframe 内嵌**可直接做**,无需改安全头。 **第 3 项的证据(今天)**:`RSS=390.4MB`(univer gateway,uid 100002) vs 实例上限 **384MB**;10:00 采样 `当前 384/峰值 384/上限 384(100%)`;10:03:11 崩溃 `exitCode=137`(SIGKILL=OOM)。⇒ **配额必须能跟着插件集合走**,否则"启用某插件"就等于"必然被杀"。 --- ## 三、分期路线图(建议) | 期 | 内容 | 重启 | 备注 | |---|---|---|---| | **P0** ✅ 部分已做 | **去平台痕迹**(6 个 title + 门户副标题 + design.css,已上线);第 1 项注入脚本外置、第 2 项 `npm run verify` | 第 1 项需一次 | 都可独立做,风险低 | | **P1**(建议**合一次窗口**做完) | 第 3 项内存自适应 + 第 4 项门户弹窗 + 第 5 项自愈收口 + 第 6 项有界恢复 | **一次重启**(断在线用户 2–5 s) | 第 4 项**先出 R5 评估** | | **P2** | 第 7 项页面结构、第 8 项可观测性 | 第 8 项需一次 | 体验/排障向 | | **P3** | 第 9 项文档/代码同仓 | 否 | 工程仪式向 | --- ## 四、明确"不做"(与既有决策/R 线一致) - ❌ **重写平台 / 换架构**(平台本体即"现有功能",重写零收益高风险) - ❌ **把管理 API 下沉进实例**(档案 05 PoC-2 ① 结论 + R5) - ❌ **改内部命名**(systemd 单元 / 路径 / DB 名):收益仅"看不见",代价是牵动 hooks 绝对路径、同步脚本、文档、自动化、备份脚本 - ❌ **给 univer 加内存上限或禁用**:用户明示它是**内存压力探针**(2026-09-13 原话) --- ## 五、待用户拍板 1. **先做哪几项**?我的建议:**P0 两项先做(1、2)**,P1 四项**合一次重启窗口**做完。 2. 是否要我把其中任一项**落成交接单**(8 段式)交执行会话?(遵循本库"规划与执行分离") --- ## 六、附:P0(去平台痕迹)已落地记录 | 文件 | 改动 | |---|---| | `web/index.html` | title → `工作台` | | `web/login.html` / `register.html` | → `登录` / `注册` | | `web/portal.html` | → `管理门户`;副标题 `dshs 平台管理` → `平台管理` | | `web/admin.html` | → `管理台` | | `web/wake.html` | → `正在启动工作区` | | `web/design.css` | 首行注释去掉平台名 | - 部署:7 文件 scp(**静态页免重启**);线上逐个取回 `` 已验证;`portal.html` 渲染串只剩「平台管理」。 - 回滚:`git checkout -- web/<file>`(未 commit)。**仅动文案层,未动服务端、未重启、未改权限。**