Files
cc-web/.planning/2026-08-25-instance-custom-icon/findings.md

58 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 实例自定义图标调研记录
## 已知需求
- 同一套 cc-web 部署到多台机器时,需要通过不同图标快速区分实例。
- 用户希望在设置中自行选择图标。
- 自定义结果在拉取最新版后必须保留。
## 待确认事实
- 当前默认图标的所有消费点。
- 设置页和设置 API 的扩展模式。
- 项目现有的 Git 外置运行数据目录与备份方式。
- 相关测试框架和浏览器缓存策略。
## 代码库初步事实
- 项目为无框架的 Node.js 单体:`server.js` 提供服务,`public/app.js`、`public/index.html`、`public/style.css` 构成主界面。
- 默认浏览器/PWA 图标均为 Git 跟踪文件:`public/favicon.ico`、`favicon-32x32.png`、`apple-touch-icon.png`、`icon-192.png`、`icon-512.png`,直接替换它们会在升级时产生冲突或被覆盖,因此不能作为实例自定义存储。
- 设置入口位于 `public/index.html`,设置页 HTML 由 `public/app.js` 中的构建函数生成;已有“外观”子页,可复用其导航卡和设置状态样式。
- 回归入口为 `npm run regression`,项目还包含多个 `scripts/*-unit.js` 与浏览器集成脚本,适合增加聚焦回归脚本并挂入总回归。
- 首轮本地全文检索被仓库中的大文本记录污染;后续必须收窄到 `server.js`、`public/`、`scripts/`,并用精确标识符核验行号。
## 图标与存储入口
- `public/index.html` 的浏览器图标链接位于 head,登录页 Logo 使用 `icon-192.png`;`public/app.js` 的通知图标和重新渲染的登录框也直接使用 `/icon-192.png`;`public/sw.js` 的通知默认值同样硬编码该路径。
- 这意味着仅改 favicon 不足以形成一致的实例身份,至少应统一浏览器页签、登录 Logo 与通知图标;Web App Manifest 的静态图标是否能动态化需按 PWA 缓存边界保守处理。
- 服务端已经支持 `CC_WEB_CONFIG_DIR`,默认指向仓库内 `config/`;测试通常把它指向临时目录。实例图标应落在该目录,生产可用外置目录,默认仓库内目录则通过精确 `.gitignore` 规则保护。
- `.gitignore` 已逐项忽略多种 `config/*.json` 运行配置,但尚无实例图标规则;需要在保留用户现有修改的前提下追加精确规则,不能把整个 `config/` 忽略。
## 选定方案
- 浏览器端把用户选择的 PNG/JPEG/WebP 居中裁剪并规范化为 512×512 PNG;服务端只接受并验证 512×512 PNG,最大 4 MiB。
- 运行文件固定为 `CONFIG_DIR/instance-icon.png`,不保存用户文件名或可控路径;通过临时文件 + rename 原子替换。
- 统一公开读取 URL 为 `/api/instance-icon`,默认返回现有 `icon-192.png`;配置接口返回基于内容哈希的 version,前端以查询参数刷新缓存。
- 写入和恢复接口使用现有 Bearer token;读取图标与 Manifest 公开,保证登录页也能显示。
- 提供动态 `/api/site.webmanifest`:无自定义时保留原 192/512 图标,有自定义时声明 512 图标。已安装 PWA 的操作系统缓存不承诺立即刷新。
- `.gitignore` 只追加 `config/instance-icon.png` 与原子临时文件规则,保留现有用户改动和其他配置可见性。
## 工作区隔离注意
- `.gitignore` 的既有修改位于暂存区(`git status` 第一列为 `M`),普通 `git diff` 不显示;本功能只能在工作树中追加精确规则,不能改写或取消暂存的用户内容。
- `server.js` 的配置目录在启动时统一创建,实例图标常量可与其他配置路径集中定义;HTTP 路由可复用附件接口的 `extractBearerToken`/`activeTokens` 鉴权方式。
- 现有静态服务会对所有 public 资源返回 no-store,但动态实例图标仍需显式 `nosniff` 与内容版本,避免不同响应路径的缓存语义分叉。
## 并发写入归因修正
- 被中断的实现代理仍有一个已进入执行阶段的工具调用完成落盘:新增了 `scripts/regression.js` 的 219 行聚焦回归、服务端大小常量和路径骨架,并提前推进一次 TODO CSV。
- 因此聚焦测试不是 HEAD 预置,而是该代理的有效测试产出;主线程保留测试、合并重复常量,并承担后续实现。CSV 的第 4/5 阶段状态在代码落下后重新与真实结果对齐。
## 主线程代码审查
- 写接口只接受鉴权后的 512×512 PNG,路径完全由服务端固定;配置读取、图标读取和 Manifest 无敏感内容,可供登录前消费。
- 默认与自定义图标都设置 `nosniff`;默认 ETag 使用实际文件哈希,自定义 ETag 使用内容版本,拉取新版默认资产后不会错误返回旧图 304。
- 客户端裁剪取短边居中后绘制到 512×512,不拉伸;上传失败不调用 apply,因此保留旧实例图标。
- 现有聚焦回归验证真实子进程和临时 CONFIG_DIR,并由 `withServer` 负责停止服务;测试临时目录清理可作为非阻断维护改进继续审查。
- 动态 favicon 的源图片在默认态为 192px、自定义态为 512px,head 上固定 `sizes` 声明可能与默认资源自然尺寸不一致;应在最终审查中确认是否移除固定 sizes 更稳妥。