Files
KSP_project/docs/guanghan_topology_adaptation_audit_2026-07-09.md
T

16 KiB
Raw Blame History

广寒基地时态拓扑页面适配审计报告

日期:2026-07-09

测试目标:

http://localhost:8080/guanghan_topology_demo.html?mission=GHC-01

审计范围:

  • 页面初始加载和默认快照;
  • 全部 9 个任务选项;
  • 明确时间查询、任务与时间并存、基地建立前时间点;
  • 无效时间、不存在任务、API 异常呈现;
  • 浏览器回退与 URL 状态一致性;
  • GHC-05 全部 14 个可视节点的详情弹窗;
  • 鼠标、键盘、关闭按钮、遮罩和 Escape 交互;
  • 1440×1000 桌面视图与 390×844 窄屏视图;
  • API 响应、数据库任务事件、布局数据;
  • 既有自动化回归测试;
  • 页面、API、种子数据和近期改动的根因检查。

本轮只检查、截图和出具报告,没有修改页面、API、数据库或测试代码。

1. 总结结论

当前版本不建议确认完成或发布。

它已经具备可工作的基本链路:页面能从 API 取得数据,9 个任务均可查询,GHC-05 最终拓扑的空间骨架基本正确,14 个可视节点均能打开详情弹窗,弹窗在桌面和窄屏下都可用。

但适配仍存在发布阻断问题:

  1. 页面并未真正由数据库拓扑和布局驱动,仍是固定 SVG 加少量显隐逻辑;
  2. 历史任务会显示不存在的悬空连接线,散热器在基地不存在时仍出现;
  3. 5 个任务的“最后一条任务记录时间”与 Timeline 不一致;
  4. GHC-05 图中文字大面积越界,严重影响工程总图可读性;
  5. 页面写死 localhost:5000,部署到真正 Wiki 后,其他访问者会请求自己电脑的 localhost;
  6. 无效时间导致 API 返回 HTML 500,页面显示 JSON 解析错误;
  7. 自动化回归测试 8 项中有 4 项失败;
  8. 后端配置文件包含已提交的明文默认数据库凭据。

2. 测试结果概览

测试项 结果 说明
API 健康检查 通过 /health 返回 200
无参数默认快照 部分通过 页面能显示最新数据,但数据库“最新事件”本身不完整
9 个任务逐项查询 接口通过、呈现部分失败 全部返回数据并截图;早期任务拓扑线和散热器错误
明确时间优先 部分通过 时间生效,但任务上下文从 API 请求和副标题中丢失
基地建立前时间 部分通过 组件和连接为空,但 4 个散热器仍显示
无效时间 失败 API 500 HTML;页面显示 Unexpected token '<'
不存在任务 基本通过 404 能显示,但下拉框丢失请求值,错误文案为英文
浏览器回退 失败 URL 回到 GHC-01,页面仍显示 GHC-05
14 个节点点击弹窗 通过 全部能打开和关闭
Enter / Space 打开弹窗 通过 两种键盘操作均有效
× / 遮罩 / Escape 关闭 通过 三种方式均有效
关闭后焦点恢复 失败 焦点落到 BODY,未返回触发节点
390×844 页面布局 部分通过 页面本身无横向溢出,地图可横向滚动;图中文字仍越界
390×844 弹窗 通过 弹窗完整落在视口内
既有自动化测试 失败 8 项中 4 项失败

3. 全部任务测试

所有任务都通过页面下拉框和“查询”按钮实际执行,并分别截图。

任务 API 快照时间(页面显示,UTC+8) 组件数 API 连接数 页面结果 截图
BL-01 2024-04-20 06:58 1 0 失败:仍显示一条供电/燃料线;4 个散热器始终存在 截图
GHC-01 2024-06-16 15:23 2 0 失败:核心舱四条结构线悬空,冰轮线悬空 截图
JC-01 2024-06-17 16:19 2 0 失败:与 GHC-01 相同 截图
BL-02 2024-06-23 13:23 3 0 失败:显示 6 条并不存在的固定线 截图
GHC-02 2024-07-01 18:37 3 1 失败:页面固定线不能表达 API 中实际的冰轮连接 截图
GHC-03 2024-08-19 08:00 9 7 失败:显示核心舱未来安装口悬空线和不存在的电力东侧线 截图
BL-03 2024-09-24 03:20 10 7 失败:固定线仍多于该时刻实际拓扑 截图
GHC-04 2024-11-08 08:00 12 14 部分通过:主要电力拓扑可见,但固定图不能忠实反映连接记录 截图
GHC-05 2025-01-02 08:00 17 19 空间骨架基本正确;文字越界、信息缺失和时间锚点错误 截图

说明:17 个数据库组件被合并成 14 个可视节点,电力模块东、西两组分别使用组合节点。这种组合可以保留,但组合关系目前硬编码在页面中。

4. 发布阻断问题

P0-1 页面没有真正使用数据库拓扑和布局

表现:

  • API 返回 layout,页面没有读取 currentData.layout
  • SVG 节点、连接线和散热器全部写死在 HTML 中;
  • 任务列表也由 loadMissions() 返回固定数组;
  • 数据库新增模块、连接或未来十字结构后,页面不会自动出现;
  • 数据库 17 个组件只能依赖页面中的 GROUP_MEMBERS 硬编码压成 14 个节点。

证据:

  • data/wiki/guanghan_topology_demo.html:258 写死 API 地址;
  • data/wiki/guanghan_topology_demo.html:282 写死任务列表;
  • data/wiki/guanghan_topology_demo.html:301 仅对固定节点执行显隐;
  • 页面没有任何 currentData.layout 使用点;
  • topology_api/queries/snapshot_queries.py 已返回布局,但前端丢弃。

根因:

这次改动保留了原始静态 SVG,只将部分文字和显隐状态接到了 API。它不是“从数据库渲染拓扑”,而是“数据库数据覆盖固定模板”。

影响:

  • 无法满足未来扩建;
  • 无法保证任意历史快照准确;
  • 数据库和页面会持续形成两套事实来源。

P0-2 正式 Wiki 部署后 API 地址不可用

页面写死:

const API_BASE = 'http://localhost:5000';

在当前开发机上可以工作,但真正的 Wiki 访问者打开页面后,浏览器会请求访问者自己电脑的 localhost:5000,而不是服务器。

根因:

缺少同源反向代理路径或部署时可注入的 API 基址。

影响:

除开发机外,页面大概率完全无法加载。

P0-3 后端源码包含明文默认数据库凭据

topology_api/config.py 在环境变量缺失时使用硬编码用户名和密码,并已进入 Git 历史。

报告中不重复凭据内容。

影响:

  • 凭据泄露;
  • 环境变量遗漏时会静默连接真实数据库;
  • 后续即使删除源码中的字符串,Git 历史仍保留旧值。

需要在修复阶段先轮换凭据,再移除默认密码并检查 Git 历史处置方案。

5. 高优先级功能问题

P1-1 历史拓扑连接线不可信

页面没有根据 currentData.connections 画线,而是给固定线配置粗粒度的组件依赖:

const connTypes = {
  'core-structural': ['core_cabin'],
  ...
};

随后使用“任意一个依赖组件存在即可显示”:

needed.some(k => existing.has(k))

因此:

  • GHC-01 只有核心舱和冰轮一号、API 连接数为 0,但页面显示核心舱四条悬空线和冰轮线;
  • 基地建立前 0 组件时,4 个散热器仍显示;
  • GHC-03 电力东部模块尚不存在,东侧结构线仍显示。

相关截图:

P1-2 任务默认时间不符合已确认规则

已确认规则是:仅传任务编号时,采用该任务最后一条记录的时间。

数据库目前只录入少量拓扑变化事件,导致 5 个任务的最大事件时间早于 Timeline 中最后一条任务记录。

下表均以 Timeline 原始时间(UTC)比较:

任务 数据库最后事件 Timeline 最后记录 结果
BL-01 2024-04-19 22:58 2024-05-17 23:01 错误
GHC-01 2024-06-16 07:23 2024-06-16 07:23 正确
JC-01 2024-06-17 08:19 2024-06-17 08:19 正确
BL-02 2024-06-23 05:23 2024-06-23 05:23 正确
GHC-02 2024-07-01 10:37 2024-07-15 03:16 错误
GHC-03 2024-08-19 00:00 2024-08-30 12:45 错误
BL-03 2024-09-23 19:20 2024-09-23 19:20 正确
GHC-04 2024-11-08 00:00 2024-11-20 13:57 错误
GHC-05 2025-01-02 00:00 2025-01-22 10:52 错误

根因:

种子数据将 mission_events 当成“拓扑变化事件”,但查询规则将其当成“完整任务时间线”。两种语义冲突。

P1-3 GHC-05 图中文字严重越界

updateNodeLabels() 将数据库中的长摘要直接写入固定大小 SVG <text>,没有截断、换行或 foreignObject 布局。

同时它把原本的安装位置说明替换成泛化类型,如“舱段模块”“设备模块”,使工程图信息反而减少。

核心舱和北部模块仍残留“加载中...”占位文本。

截图:

P1-4 同时提供任务和时间时,页面丢失任务上下文

页面 URL 正确保留:

?mission=GHC-01&at=2025-01-02T08:00:00+08:00

fetchSnapshot() 使用:

if (at) ...
else if (mission) ...

所以 API 请求只携带 at,没有携带 mission。最终副标题显示“(最新)”,而不是保留 GHC-01 上下文。

API 本身在同时收到两个参数时行为正确,缺陷位于页面请求组装。

截图:任务与时间并存

P1-5 浏览器回退后 URL 与页面状态不一致

页面查询时调用 history.pushState(),但没有监听 popstate

复现:

  1. 查询 GHC-01
  2. 查询 GHC-05
  3. 浏览器后退;
  4. URL 已回到 mission=GHC-01
  5. 下拉框、副标题和拓扑仍是 GHC-05。

截图:浏览器回退错位

P1-6 无效时间产生 500 和技术性错误文案

输入 not-a-time 后:

  • API 将原字符串直接送入 PostgreSQL timestamptz 强制转换;
  • PostgreSQL 抛错;
  • Flask 返回 HTML 500
  • 页面对错误响应强制执行 res.json()
  • 用户看到 Unexpected token '<'
  • 旧副标题仍保留,形成新旧状态混杂。

截图:无效时间错误

P1-7 “任务节点”字段并不是任务信息

弹窗中的“任务节点”实际显示 detailUrl

详见 Wiki: /home/Spacecraft/...

没有链接时显示“资料未记录”。

API 没有返回组件引入任务、最后状态任务或生效事件,因此页面无法正确展示任务节点。

P1-8 模块尺寸和详情数据不完整

GHC-05 的 17 个组件中:

  • 只有居住舱一号、居住舱二号、温室舱和实验舱具有完整几何尺寸;
  • 核心舱只有质量,没有长宽高;
  • 其余 12 个组件的 dimensions 为空;
  • 多个电力设备只有一句摘要,没有描述和规格;
  • 电力东、西组合弹窗以第一个成员作为标题、位置和状态,其他成员只被拼进“关键参数”。

全部 14 个可视节点的弹窗操作都成功,但信息完整性未达到“模块状态、模块信息等均从数据库读取并完整呈现”的目标。

代表截图:

P1-9 冰轮连接端口数据与空间位置冲突

视觉图将冰轮一号、二号、三号分别放在电力模块西、南、东。

但数据库中的 6 条燃料/供电连接全部指向:

power_module_hub.west

这使弹窗连接数据与工程图位置矛盾。至少冰轮二号、三号应分别核对南、东端口语义。

6. 中优先级问题

P2-1 任务下拉框不是数据库数据

loadMissions() 返回固定任务数组。数据库新增任务后页面不会出现,删除或更名也不会同步。

需要任务列表 API,或在快照 API 中返回可选任务。

P2-2 自动化测试与适配代码不同步

执行:

python -m unittest tests.test_guanghan_topology_demo tests.test_guanghan_topology_e2e -v

结果:

Ran 8 tests
FAILED (failures=4)

失败项:

  1. 加压走道连接契约;
  2. 每个可点击模块的尺寸字段契约;
  3. 未来扩展锚点注释;
  4. 渲染和弹窗 E2E。

部分失败是适配后没有同步测试,部分对应真实回归:

  • 原来要求保留的 FUTURE_EXPANSION_ANCHOR:north/east/west 注释已被删除;
  • 新 E2E 没有启动或模拟拓扑 API;
  • 测试仍检查旧 data-connection 契约。

此外,当前没有 API 查询、时间优先级、数据库约束和 9 个任务快照的自动化测试。

P2-3 详情弹窗关闭后不恢复焦点

Enter 和 Space 可以打开弹窗,Escape 可以关闭;但关闭后焦点落在 BODY,没有返回原节点。

这会影响键盘连续浏览和无障碍体验。

窄屏证据:

P2-4 时间显示依赖访问者本地时区

页面使用 toLocaleString('zh-CN'),没有固定时区或显示 UTC 偏移。不同地区的访问者可能看到不同日期和时间。

P2-5 页面显示内部枚举值

页面直接显示:

mission_latest_event
latest_recorded_state
explicit_time

这些是 API 内部值,不适合作为最终 Wiki 文案。

P2-6 数据库内容进入 innerHTML 时未转义

尺寸、关键参数和连接关系通过模板字符串写入 innerHTML。当前种子数据可信,但未来如果后台编辑内容含 HTML,会形成存储型脚本注入风险。

7. 已确认通过的部分

以下部分不应在修复时无故推翻:

  • GHC-05 核心舱十字结构与电力模块十字结构的整体空间关系;
  • 两条加压走道为绿色实线;
  • 四组散热器的视觉样式和文字标注;
  • 14 个可视节点均可点击;
  • 弹窗 ×、遮罩和 Escape 关闭;
  • 节点 Enter / Space 键打开弹窗;
  • 窄屏弹窗尺寸和内部信息布局;
  • API 的明确时间优先规则;
  • API 的未知基地 404 和未知任务 404;
  • 无参数查询采用数据库内已发生任务的最大事件时间这一查询逻辑。

最后一项的查询代码逻辑正确,但种子事件不完整,所以实际得到的“最新时间”仍错误。

8. 建议修复边界

如果本报告获确认,建议按以下顺序实施:

  1. 先处理凭据轮换与部署 API 地址;
  2. 为页面/API/数据库补充失败测试,固定已确认语义;
  3. 补齐任务末条事件或拆分“拓扑事件”和“任务时间锚点”;
  4. 用 API 的组件、连接和布局数据真正生成图,不再维护固定拓扑事实;
  5. 修复历史快照连接、散热器和组合节点;
  6. 修复图中文字布局和残留占位符;
  7. 修复时间校验、任务上下文、回退导航和错误状态;
  8. 补齐任务列表、模块引入任务、尺寸与详情数据;
  9. 完成 9 个任务、明确时间、异常输入、桌面和窄屏全量回归并重新截图。

修复过程中应保留目前已通过的 GHC-05 空间骨架、绿色加压走道、散热器样式和弹窗视觉风格。

9. 截图目录

全部测试截图位于:

demo/topology_audit/

其中包括:

  • 9 个任务各 1 张完整页面截图;
  • GHC-05 上、中、下三段人工视觉检查;
  • 3 个代表性详情弹窗;
  • 明确时间、无效时间、基地建立前、不存在任务和浏览器回退;
  • 390×844 页面和弹窗。

其他异常截图: