02 · 历史需求与设计构想
按「主题 + 时间」整理。每条尽量保留原始措辞的关键含义。 标注:✅ 已实现 | 🟡 部分实现/雏形 | ⬜ 已提出未实施 | ❌ 已撤销/被取代 证据:对话摘要(30 个历史阶段摘要)、任务书原文、Git 提交、当前代码。
一、初始需求(2026-10-05)
见 01_项目总览与长期目标.md 第 3 节(五组要求逐条列出,不再重复)。三条关键约束至今有效:
- 不准重构代码结构、不准改 UI 风格;
- 不准一次性甩几百行代码,要拆成可复制粘贴的步骤(手机操作);
- 用户输入与 AI 回复必须原封不动入库。
已确认的技术选型:Worker 统一转发 / 关键词检索 / 页面打开时检查主动消息。
二、UI 与交互:历次明确要求
2.1 第一批(10-05 ~ 10-06,✅)
| 要求 | 结果 |
|---|---|
| 果冻/液态玻璃气泡(blur 8px、半透明白、微高光、圆角 16、宽 75%) | ✅ |
| 头像可自定义上传,不写死任何默认图 | ✅(内置无头像时用文字占位,不写死图片) |
| 猫爪面板:颜文字 / 表情包(本地上传转 Base64 + 粘贴 URL)/ 右侧麦克风占位 | ✅ |
| 长按菜单:复制 / 引用 / 删除单条 / 收藏;引用时上方显示原文 | ✅ |
| 消息状态:发送中 / 成功 / 失败可重试 | ✅(后续加了秒级时间,再后又改回居中时间条) |
动态状态胶囊:按 ai_status 渲染,无则不显示空白框 |
✅ |
| IndexedDB 替代 localStorage 存聊天记录 | ✅ |
| 真实 fetch 替代假回复,错误显示在气泡 | ✅ |
2.2 外观细化(10-14 ~ 10-16,✅ / 一处回滚)
| 日期 | 要求 | 状态 |
|---|---|---|
| 10-14 | 手绘气泡框(猫/云/星星/蝴蝶结装饰,参照截图) | ❌ 上线后中文乱码(atob 字节问题)→ 回滚 |
| 10-14 | 液态玻璃 + 「我的气泡粉白少女心」 | ✅ |
| 10-14 | 阴影范围缩小、颜色加深 | ✅ |
| 10-14 | 状态文字:头像正上方、白字、明显深阴影 | ✅(后修正居中、过长贴边不裁切) |
| 10-14 | 表情包点击直接发送 + 发送前自动压缩 | ✅ |
| 10-14 | 文案「自定义标题 → 备注喵」「自定义状态 → 状态喵」 | ✅ |
| 10-14 | 设置分「头像与聊天背景」「后端与模型」两组折叠 | ✅ |
| 10-14 | 猫爪面板重排 + 照片三入口(上传 / 拍照 / 文件) | ✅ |
| 10-14 | 新增收藏(微信式 UI、双向收藏、显示收藏者) | ✅ |
| 10-14 | 发送状态移到气泡下方 + 成功后秒级时间;行距调大 | ✅(10-17 改为居中时间条) |
| 10-16 | 顶部全屏按钮(Fullscreen API,图标随状态切换) | ✅ |
| 10-16 | PWA:添加到主屏幕无地址栏启动(manifest + 爪印图标 + apple meta) | ✅ |
| 10-16 | 图片全屏灯箱(点击查看、点击关闭) | ✅ |
| 10-16 | showToast 轻提示组件 |
✅ |
2.3 10-17:功能与观感修正(✅)
- 修发送键(点击事件被当成文本,出现
[object PointerEvent]); - 修头像阴影被重复定义覆盖;
- 新状态只跟新消息,不全量改写历史状态;
- 取消气泡下方秒级时间 → 微信式居中时间条
2026.10.15 10:20; - 顶部栏 / 底部输入栏改悬浮圆角玻璃卡片;
- AI 认知纠正:知道自己是 AI;「状态」= 心情/情绪,不是任务或地点;
- 建立《模块索引.md》,以后按区域点单改代码。
2.4 10-17 第二轮(✅)
照片三入口面板 / iOS 高透液态玻璃 / 自定义气泡皮肤(PNG 九宫格 border-image-slice:33%,分「我的/对方」)/ 顶栏、底栏、全局底色可单独调 / 气泡颜色+透明度+磨砂分双方 / 表情包按微信规范压缩(长边 ≤240,透明图存 PNG,显示 ≤150px)/ 状态文字居中贴边 / 一键恢复默认外观(含深色模式)。
2.5 10-22:iOS 全屏与键盘(✅,过程极曲折)
用户原话演进(保留原意):
- 「你格式不是全屏的 是不是?这是新开的初始化」
- 「我每次点进去,然后我下拉的那个状态他不会保存」(滚动位置)
- 「根本不是这个问题,还是你的那个整体的叫什么布局格式有问题,你重新校准……把我底部的那个也给改回去 如图所示」
- 「你设置自适应高度啊行不行咋别人前端不这样 改了几次了烦死了 你搜别人的怎么做啊 自己想什么啊」
- 「我改了那么多次跟你反馈问题你自己不会思考怎么做或者搜索吗??……一个搜索能解决的你给我改了6版」
- 「之前有成功的版本的 这版时好时坏的」
- 「它直接不跟着那个键盘移动了,它直接钉死在那了,你继续搜啊,还有之前不是有成功的版本吗,你参考一下」
- 「不打字的那个状态下面,有的时候它会跳出来一大片那个空格」
- 「取消或者发送完以后,它这个键盘还是会抽搐,你不要再继续改那个代码了,我之前说没问题的那一版,你把这个那部分的那个代码直接套在这里」
- 「我真服了,终于行了。」
最终方案(✅,提交 f02cc07 / 线上 51ac31d3):
100vh → 100dvh渐进增强;.wrapper普通流height:100%(不再整页 fixed);- 键盘高度
kb = innerHeight - visualViewport.height - offsetTop,只写 CSS 变量--kb-inset,不在回调里改布局高度; - iOS 26 已知 bug(键盘收起后
offsetTop残留)用「未聚焦即归零」规避; - 去掉
transition:bottom与 focusout 延迟补测(抽搐根因); - 去掉
--safe-bar双重补偿(iOSinnerHeight已排除工具栏); ResizeObserver实测输入栏高度写--bar-h,面板展开/引用条出现不遮挡消息;- 输入框字号 16px(iOS <16px 聚焦自动缩放整页的根治方案)。
2.6 10-24:输入框与删除(✅,9ed08a6 / 线上 0114d69f)
- 「删除功能出问题了 气泡框也是又出问题了 就修复这两个其他别动 上网搜怎么做」——经确认「气泡框」指输入框。
- 修法:单条删除走服务端(
deleteOneOnServer,两条删除路径统一);输入框 15px→16px;颜文字输入框 13px→16px;--bar-h动态高度。
2.7 10-25:删除语义(✅)
- 「我发现这个云端删除它不能真的云端删除」→ 选 A 根治:物理删除 + 墓碑。
- 「这个云端删除是后端删除的意思吗?」→ 是(云端 KV 记录),并明确 UI 文案「本机和云端都删,不可恢复」。
- 用户随后要求「先做 V2 的,万一跑不通怎么办」→ v2 先行,v1 后行(staged rollout)。
三、安全改造(10-17 第三轮,✅)
用户 7 条要求 → 实现与验证:
| # | 要求 | 实现 |
|---|---|---|
| 1 | 接口身份验证(防未授权/绕过) | X-Cat-Token + 同源校验;所有 POST、/proactive、/backup、/init 必须带令牌 |
| 2 | API Key 保护 | 出站白名单、https+443、禁内网 IP、禁重定向、错误脱敏 |
| 3 | 频率/体积/模型额度 | IP 分钟 20、IP 日 400、全局 1500;body 1MB(导入 8MB);消息 4000 字;图片 800KB;max_tokens 500 |
| 4 | KV/记忆越权 | 全部接口置于鉴权之后;后续再加 profile 隔离 |
| 5 | 提示词注入/输入校验 | <<< >>> 包裹数据 + 最高优先级安全段 + stripMarkers + 控制字符清洗 |
| 6 | SSRF/开放代理/重定向 | 白名单 + 禁 IP 字面量 + redirect:'manual' + 3xx 拒绝 |
| 7 | 日志/轮换/备份/回滚 | rid 追踪、wrangler secret put AUTH_TOKEN 轮换、/backup 导出、wrangler rollback |
测试:后端 46 项断言 + Playwright 前端回归(当时全过)。
遗留:令牌随页面下发(知道地址即可拿令牌),当时已如实记录为「未解决风险」,任务书阶段 7 才计划做独立强认证。
四、《完整系统升级与安全改造任务书 v1.0》阶段 0–9
原文:
/root/uploads/1792388616892580314-文本.txt
| 阶段 | 目标 | 状态 | 说明 |
|---|---|---|---|
| 0 | 最新源码审计(只读,输出 A–E 五份清单) | ✅ | 审计报告 + 修复清单,10-19 完成 |
| 1 | 备份与基础可靠性(只修确认存在的问题) | ✅ | 修 B1 误清空、备份恢复、保存失败反馈、幂等 |
| 2 | 统一数据结构(角色/会话/消息/来源/同步状态) | ✅ | profile_id / message_id / conversation_id / sync_status、msg:<profile>:<mid> |
| 3 | 完整档案与搜索(查询/追溯/导出/恢复/重试) | ✅ | /archive(含 keyword/from/to/speaker/分页)、/export/full、/import/full |
| 4 | 高光与经历记忆(时间线/关联/来源/不确定标注) | ✅ | hl/exp/rel + 记忆库面板 + 候选经历单列 |
| 5 | 人设版本管理(独立保存、版本、对比、回滚) | ⬜ 未开始 | 当前人设只是一段 localStorage 文本 |
| 6 | 批量成长分析(任务队列、证据/反例、待审核) | ⬜ 未开始 | 无任何成长分析代码 |
| 7 | 后台管理(档案/记忆/人设/任务/备份) | 🟡 雏形 | 只有设置面板里的记忆库三标签;无独立后台、无强认证 |
| 8 | 沈屿本体迁移(历史/人设/记忆) | ⬜ 未开始 | 当前是测试角色 owner |
| 9 | 测试环境清理 | ⬜ 未开始 | 测试数据仍在(v1 归档 279 条软删、国内版 307 条导入) |
任务书还规定:每阶段必须交付 11 项内容(目标/文件清单/改动说明/API 变更/迁移风险/测试结果/未解决问题/回归/部署验证/回滚/下阶段建议),未实际运行的测试不得声称通过。
五、记忆系统构想(详见 05)
按代际:
| 代 | 构想 | 状态 |
|---|---|---|
| v0 | 所有消息原封不动存 KV(mem_<ts>_<rand>),关键词检索最近片段 |
✅ 已实现(旧键保留只读) |
| v1 | 按 profile 隔离(mem:<profile>:*),修跨角色泄漏 |
✅ |
| v2 | 结构化档案(msg:<profile>:<mid>)+ 稳定 mid + 幂等归档 |
✅ |
| v3 | 高光原话(必须引用真实消息)+ 经历(active/candidate + source_mids + 确定性)+ 关系(5 种类型) | ✅ |
| v4 | 参考 Mem0/Graphiti/Letta/LangGraph 的四态记忆、双时间戳、版本链、token 预算 | ⬜ 仅调研 + 5 条建议,未实施 |
六、托管与部署构想
| 时间 | 要求 | 状态 |
|---|---|---|
| 10-24 | 「重新建一个后端……不是一个网址」「全部重新部署吧一个全新的」 | ✅ 新建 zhai-v2 + chat_memory_v3(空库),旧环境保留 |
| 10-24 | 「暂时先部署到 WorkBuddy 上面,后端那个记录的先不用」 | ✅ 国内直连测试版(先无 KV,后加 SQLite) |
| 10-25 | 「理论上来说你是不是可以把后端相同的迁移到那个阿里云的云服务器?」→ 给四方案 → 用户选 C(先验证 WorkBuddy 存储持久性) | ✅ 四批完成(SqliteKV / 垫片 / 回归 / 双快照 / 搬迁) |
| 10-25 | 「情况一(v2 搬迁)情况二(导出导入恢复)都考虑,做一个版本」 | ✅ 双快照三层防护 + 手动导出导入 |
| 10-25 | 「你直接做完吧,不用问我了」 | ✅ 第 3、4 批自主推进 |
国内版的硬约束(平台规则,实测):
- 同源请求必须带 ?sharecode=…,否则网关 403「链接不完整」;
- 部署目录会被本地代码同步覆盖 → 数据必须放 /tmp;
- 反向代理改写 Host → 同源基准只能用固定的可信公网地址。
七、明确「不要做什么」(全部仍然有效)
摘自初始需求、任务书与历次纠正:
- 不准重构代码结构、不准改 UI 风格;只改被点名的区域(《模块索引.md》就是为了这个)。
- 不准一次性给几百行;要拆成可复制粘贴的步骤。
- 不准写死默认头像/默认人设;人设只用用户自定义的。
- 不准用假回复(
setTimeout);必须是真实请求,错误要显示在气泡里。 - 不准把界面已显示消息当成云端保存成功(任务书原话)。
- 不准在没备份的情况下覆盖唯一可用版本;不准直接清空 KV/IndexedDB。
- 不准把推测当确定事实;不确定的记忆要标 candidate/unknown。
- 不准把管理密钥/模型 Key 写进公开 HTML。
- 不准只靠隐藏按钮/前端路由保护管理功能。
- 不准跳过阶段验收;未实际运行的测试不得声称通过。
- 不准未经批准扩大修改范围;发现问题先停下说明风险。
- 不准删测试后端/测试数据(阶段 9 之前);删除必须指定 profile 与清单,不能用模糊条件。
八、已提出但未实施(保留,不要丢)
| 构想 | 出处 | 状态 |
|---|---|---|
| 向量检索(Vectorize + embedding) | 初始方案选项 | ⬜ 用户选了关键词检索;任务书也说「不得视为第一阶段必要」 |
| 图片存 R2(云端保留原图) | 交付文档「已知限制 2」 | ⬜ 涉及付费,未授权 |
| 全量导出/导入的前端 UI | 交付文档「待办」 | 🟡 API 已有,前端仅国内版可用 |
| 档案搜索面板 + 跳转原消息 | 交付文档「待办」 | ⬜ 后端 /archive?keyword= 已有 |
| 人设四层 + 版本管理(阶段 5) | 任务书 | ⬜ |
| 成长队列 + 证据/反例/审核(阶段 6) | 任务书 | ⬜ |
| 独立后台 + 强认证(阶段 7) | 任务书 | ⬜ |
| 沈屿本体迁移(阶段 8) | 任务书 | ⬜ |
| 测试环境清理(阶段 9) | 任务书 | ⬜ |
| 流式回复(SSE) | 10-23 基线审查标注【未实现】 | ⬜ 未提出明确需求 |
| 消息全文搜索 UI | 10-23 基线审查标注【未实现】 | ⬜ |
| 多角色切换 UI | 10-23 基线审查标注【未实现】 | 🟡 后端 profile 已支持,前端固定 owner |
| 深色模式 | 10-17 用户要求删除 | ❌ 已移除入口(CSS 仍有变量残留) |
| 手绘气泡装饰 | 10-14 | ❌ 因乱码回滚,未再尝试 |
九、需求冲突与待核实
| 冲突 | 处理 |
|---|---|
| 「云端删除」早期=软删(记录仍在)vs 10-25 用户要求「真的删」 | 10-25 起改为硬删+墓碑;历史 279 条软删记录仍物理存在(见 07),需一次性清理 |
| 「备份要包含记忆」vs 早期导出只含 messages/favorites/settings | 已补 /export/full(含 mem/hl/exp/rel);但 v1/v2 的前端导出仍走本机数据(见 07 P1-4) |
| 「v2 空=搬迁失败」(我的错误结论)vs 用户「v2 是全新部署」 | 以用户为准:v2 空是设计;606 条搬进的是国内版(见 06 D-08) |