tech-debt-tracker.md 7.4 KB

技术债

记在这里的债都是有意欠的,不是忘了。每条写清:是什么、为什么先欠着、 什么条件下该还。

未还

1. 公司候选提交的是文本而非序号(协议标注的做法)

  • 是什么:接口文档写的是"选择第 1 家公司提交 question="1"API 由序号映射到原候选", 而当前前端提交的是选项全部内容拼接的文本(公司名 + 信用代码 + 状态 + 负责人)。
  • 为什么先欠着:这是产品明确要求的形态。文本在语义上无法表达"我选这一个", 后端可能把它当成"换关键词"走 refine 路径重新检索。
  • 欠着会怎样可能出现"选一次又弹回同一批候选"的死循环。
  • 该还的条件:上游公司数据服务恢复后必须补测 —— 走一遍有候选(status: found)的流程, 选中一家,确认返回的是选定公司后的结果而不是又弹候选列表。 若循环,两条路:①改回提交序号(序号取自当前显示顺序);②后端扩语义识别全字段文本。
  • 当前状态:上游持续 provider_failurestatus: found 一次都没出现过,因此从未验证。

2. answer.textsummary.text 首句重复

  • 是什么:后端把同一段话既放进 answer.text(渲染在消息正文)又放进 summary.text 的开头, 实测两者首句逐字相同,用户会看到同一段话出现两次。
  • 为什么先欠着:已确认是后端内容重复,不是前端渲染问题(前端对两个字段各渲染一次)。
  • 欠着会怎样:回答开头重复一段,观感差。
  • 该还的条件:后端修(推荐,最干净),或前端加去重(权宜:比对首句并剥离, 但属启发式判断,可能误删)。需用户拍板走哪条。

3. 文件上传功能待定

  • 是什么:旧协议的文件/图片上传(按钮、拖拽、粘贴三条入口)当前入口已隐藏, 发送逻辑被注释保留。
  • 为什么先欠着:接口请求体只接受 {thread_id, question} 两个字段,多一个返回 422, 旧协议的 transmission.files / file_pos 发不出去
  • 该还的条件:先定后端方案 —— ①后端扩展请求体接受 files/file_pos; ②前端把 OSS 地址拼进 question 文本;③后端提供文件登记接口返回 file_id。
  • 参考:原实现的完整参数见 harness/docs/reference/legacy/API.md(旧协议快照,仅供理解原实现)

4. 部门筛选在新数据下筛不出结果

  • 是什么:政策「更多」面板的部门下拉是固定的最初 15 个部门, 按字面相等匹配;而接口返回的部门是全称(如"青浦区科学技术委员会"),字面不相等。
  • 为什么先欠着用户明确要求保持最初的实现,暂时不做匹配。
  • ⚠️ 不要当 bug 修:曾试过①按接口数据动态生成选项、②保留固定选项但加关键词归一化匹配, 两个方案都被否掉。
  • 该还的条件:用户明确要求时再动。

5. Question.message 字段未被渲染

  • 是什么QuestionCardQuestion 接口里定义了 message 字段, 但模板从未渲染它 —— 适配层写的提示文案一直不可见。
  • 为什么先欠着:只影响观感,不影响功能;改模板会扩大改动面。
  • 该还的条件:需要展示这类提示时。

6. 语音识别仍跑在厂商(metamaker)的服务上

  • 是什么:语音输入走 wss://qingpu-data-api.metamaker.cn/common/asr_hub (引擎 aliyun_dashscope),且鉴权 token 与 appKey 都硬编码在源码里src/three-libs/asr/index.ts 的 token:iss: human-large-screenexp 2034-12-29,入库可见)。
  • 为什么先欠着用户 2026-09-18 明确「先不动,先用原来的语音识别功能」—— 现在能用、无成本、前端零维护;独立的成本主要在「要有人长期维护一个 ASR 网关 + 引擎账号」。
  • 欠着会怎样:⚠️ 厂商若失效那条 token、或停掉那个网关,语音功能会突然不可用,且没有任何预警; 另外用户语音音频流经厂商服务器(政务场景下涉及数据合规评估)。
  • 该还的条件:出现以下任一情况就该动 —— ①厂商停服/改价/要求换凭据;②合规要求音频不出自己的服务器; ③要换引擎。退路已经准备好:协议契约已存档在 ../reference/current-api-call-sites.md 的「ASR 协议契约」, 实现方照着就能写自建网关,前端一行都不用改(只把 VITE_ASR 指向新地址)。
  • 一个低成本的前置动作(尚未做):把 index.html 里写死的 globalThis.isXF = false 改成环境变量开关 —— 这样万一厂商出问题,改配置就能切到讯飞分支,不必改代码重新发版。

7. 移动端真机样式问题:没有兼容基线,且布局依赖 JS 测量

  • 是什么:用户反馈真机上(F12 模拟正常)①首页展示不全 ②思考过程文案超出屏幕 ③不同浏览器问题还不一样。排查后确认三个相互独立的根因:
    1. height: 100dvh 没有 100vh 兜底BusinessAssistantMobile.vue)—— dvh 是较新的单位(Chrome 108+ / Safari 15.4+),国产浏览器内核多基于更老的版本 → 该声明被整条丢弃 → 容器高度塌陷,而外层是 overflow: hidden内容被裁掉
    2. 没有 text-size-adjust: 100% —— 移动端浏览器会按各自策略自动放大文字, 各家不同 → 同一份文案在不同手机上长度不同(也是"不同浏览器不一样"的直接来源)
    3. 思考过程卡片的样式靠 JS 测量 + width: max-content 决定「单行省略 vs 换行」: updateMaxWidthReached()getBoundingClientRect() 比卡片与父容器宽度。 而字体首选 "HarmonyOS Sans SC"手机多无此字体 → 回退到系统字体)→ 字宽不同 → 测量结果不同 → 该换行时判成"没撑满" → 单行 nowrap 撑出屏幕
  • 为什么先欠着需用户提供信息/确认改法(见下),且其中一条会改变观感
  • 欠着会怎样:移动端(本项目的主要使用场景)体验不稳定,且换台手机就可能变样
  • 该还的条件
    1. 用户提供具体浏览器与版本、以及能否真机远程调试(Android 用 chrome://inspect 最省事)—— 没有这个只能猜
    2. 方案 A(低风险、可立刻做):dvhvh 兜底、全局 text-size-adjust: 100%、 给 flex 链补 min-width: 0
    3. 方案 B(建议做,但要用户确认观感变化):去掉「按宽度切样式」这套测量, 改为纯 CSS —— 标题恒定单行省略、正文恒定可换行,删掉 is-max-width-reachedwidth: max-content。现在这套先天不稳定(字体/时机/内核都会影响测量)
    4. 方案 C(机制):定浏览器兼容基线 + 加 browserslist; 项目当前没有任何 browserslist / postcss 降级配置,而代码里用了 dvh(4) / gap(151) / inset(22) / backdrop-filter(24) 等较新特性

已还

(还清后从上面移到此处,保留一行说明怎么还的,便于追溯)