MVP 保存个人词义与状态,并在其他章节同步显示 #7

Closed
opened 2026-09-10 17:09:08 +08:00 by ila · 4 comments
Owner

来源与目标

2026-09-10 用户确认 F01–F12、原型通过,并要求按四阶段建议推进。原型验收:#1 评论 7498。阶段 3;覆盖 F07、F05 高亮、B02。

阅读者编辑词语释义、例句与学习状态,保存后当前和其他章节显示一致;另一用户不受影响。

验收标准

  • 明确用户/语言/规范词条身份与原词形关系;保存幂等,同一词不产生多份冲突记录。
  • 新词、学习中、已知、忽略的含义及等级映射明确;高亮与返回页面后的状态一致。
  • 个人释义与共享词典分离;篡改 ID、用户和语言不能越权读写;跨账号退出后清理前端缓存。
  • 保存失败保留输入,成功有简短反馈;状态边界、跨章一致性和两账号互不影响测试通过。

依赖与执行

前置:#6。状态:已完成(2026-09-11 用户验收通过,功能提交 8c0946a,PR #26 已合入 main,验收记录见最新评论)。前置尚未通过时不得标进行中;每单完成停在待验收,由用户验收后关闭。技术验证可与不依赖其结论的工作分工,但不提前冻结未验证契约。

参考模块与设计证据

参考 go-admin DTO 校验、事务与迁移;领域保存/高亮定制,不能仅套 CRUD。

沿用已验收词语面板,后端先记录词条唯一性和状态转换。

后端不为建表/API 单独画页面原型;先写数据、接口、状态、隔离与幂等契约。学习端采用 #1 已验收 v1,未做的 LinguaCafe 对照不标完成。

工作量、范围与风险

预计 4~6 人日(8 小时/人日),包含本单设计、前后端实现、相关测试、修正和文档;是规划估算,不是交付日期或 AI 运行时间。仅 F 范围,X 系列不纳入。数据变更先在隔离测试库验证迁移/回退,保留既有数据和原型。

文档与证据

实施时按影响更新 Architecture-and-Code-Map、Business-Rules-and-Glossary、Local-Development-and-Verification;需求变化更新 Product-Requirements-Overview,交付单补实际部署恢复文档。Wiki 先写再回读同步;结束评论记录测试、未验证内容、提交及 revision。工单正文保留基线,重要变化追加评论。

Gitea MCP 指向其他站点,沿用目标 git.ilapage.cn API 回退;凭据仅进入进程。

## 来源与目标 2026-09-10 用户确认 F01–F12、原型通过,并要求按四阶段建议推进。原型验收:#1 评论 7498。阶段 3;覆盖 F07、F05 高亮、B02。 阅读者编辑词语释义、例句与学习状态,保存后当前和其他章节显示一致;另一用户不受影响。 ## 验收标准 - [ ] 明确用户/语言/规范词条身份与原词形关系;保存幂等,同一词不产生多份冲突记录。 - [ ] 新词、学习中、已知、忽略的含义及等级映射明确;高亮与返回页面后的状态一致。 - [ ] 个人释义与共享词典分离;篡改 ID、用户和语言不能越权读写;跨账号退出后清理前端缓存。 - [ ] 保存失败保留输入,成功有简短反馈;状态边界、跨章一致性和两账号互不影响测试通过。 ## 依赖与执行 前置:#6。状态:已完成(2026-09-11 用户验收通过,功能提交 8c0946a,PR #26 已合入 main,验收记录见最新评论)。前置尚未通过时不得标进行中;每单完成停在待验收,由用户验收后关闭。技术验证可与不依赖其结论的工作分工,但不提前冻结未验证契约。 ## 参考模块与设计证据 参考 go-admin DTO 校验、事务与迁移;领域保存/高亮定制,不能仅套 CRUD。 沿用已验收词语面板,后端先记录词条唯一性和状态转换。 后端不为建表/API 单独画页面原型;先写数据、接口、状态、隔离与幂等契约。学习端采用 #1 已验收 v1,未做的 LinguaCafe 对照不标完成。 ## 工作量、范围与风险 预计 4~6 人日(8 小时/人日),包含本单设计、前后端实现、相关测试、修正和文档;是规划估算,不是交付日期或 AI 运行时间。仅 F 范围,X 系列不纳入。数据变更先在隔离测试库验证迁移/回退,保留既有数据和原型。 ## 文档与证据 实施时按影响更新 Architecture-and-Code-Map、Business-Rules-and-Glossary、Local-Development-and-Verification;需求变化更新 Product-Requirements-Overview,交付单补实际部署恢复文档。Wiki 先写再回读同步;结束评论记录测试、未验证内容、提交及 revision。工单正文保留基线,重要变化追加评论。 Gitea MCP 指向其他站点,沿用目标 git.ilapage.cn API 回退;凭据仅进入进程。
Author
Owner

#7 方案确认与实施启动(2026-09-11)

用户在当前会话确认并授权实施:身份口径「赞同」,其余三个决策点由 Agent 判断后定案。前置 #6 已由用户验收关闭,PR #25 已合入 main;本单分支 feat/7-personal-terms 从 main 33182e5 创建。本单实施期间工单状态进入「进行中」,完成测试后停在「待验收」。

已确认决策

决策 结论 理由
词条身份 (owner_id, language, normalizeWord(原词形));Dog/dog 合并,dog/dogs 不合并 无上下文词性时 lemma 候选不可信,与 #6 已验收的「不按候选合并个人学习状态」一致;原词形单独保存供显示
首次保存默认状态 new(新词) 与生词本列表「curiosity / 好奇心 · 新词」这条权威状态显示一致;若默认学习中会在用户只点保存时凭空产生等级和复习进度
等级选择器 #7 面板不提供 1~7 选择器;等级在契约层持久化,POST /terms 接受可选 level 并按状态校验 原型 v1 面板无等级控件,等级是 #8 的调度概念;F07「修改学习等级」由接口与 #8/#12 编辑页承接
例句 只保存用户手输例句(按行,≤5 条),不自动关联原文句子 全 Go 分词没有句子切分规则,自动关联会静默贴错句子;原型 mock 文案「原文例句已关联」不作为契约,差异记录在下方遗留项

数据结构(schema v5,纯新增表)

CREATE TABLE IF NOT EXISTS lexgo_terms (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  owner_id BIGINT NOT NULL, language VARCHAR(16) NOT NULL DEFAULT 'en',
  term VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  original_form VARCHAR(191) NOT NULL,
  definition TEXT NOT NULL, examples TEXT NOT NULL,
  status VARCHAR(16) NOT NULL, level TINYINT NOT NULL DEFAULT 0,
  created_at DATETIME(3) NOT NULL, updated_at DATETIME(3) NOT NULL,
  UNIQUE KEY uq_term_identity (owner_id, language, term),
  CHECK (status IN ('new','learning','known','ignored')), CHECK (level BETWEEN 0 AND 7),
  FOREIGN KEY (owner_id) REFERENCES sys_user(user_id) ON DELETE CASCADE
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

term 使用 utf8mb4_bin:归一化由 Go 完成,避免 _ai_ci 把 resume/résumé 折成同一身份。v5 不修改任何既有表或既有数据。

状态与等级映射

业务状态 level 含义 进入到期复习 原版 stage
new 新词 0 已保存、尚未开始学习;首次保存默认 是(由 #8 决定) 2
learning 学习中 1~7 正在复习,越接近 7 越熟 是 -1~-7
known 已知 0 已掌握,不再进入到期复习 否 0
ignored 忽略 0 明确忽略,不计入已知 否 1

服务端强校验:非 learning 时 level 必须为 0;learning 且缺省时置 1。#7 不实现复习推进、到期时间与计数(归 #8/#13)。

接口契约

接口 权限与输入/输出
POST /api/v1/terms 本人;{chapterId,start,end,definition,examples[],status,level?};服务端按 #6 同一套 token 范围校验反推身份,owner/language/term 一律不接受客户端输入;唯一键 upsert,重复保存只产生一条记录;首次 201、更新 200,返回完整 term
GET /api/v1/terms/:id 本人;他人编号与不存在编号统一 404,不泄露存在性
GET /api/v1/chapters/:id/tokens 在原响应上为 word 片段增加可选 term:{id,status,level};服务端按本章全部词形一次性查本人词条,其他章节保存的同形词同样命中(跨章节一致与 F05 高亮)

约束:definition ≤2000 字符可为空;examples ≤5 条、每条 ≤500 字符、不允许换行;start/end 必须是本人 ready 章节内的完整单词且 ≤128 码点;跨账号章节 404,非 ready 409,未知字段 400。

隔离与幂等

  • owner 只来自会话,language 只来自 lexgo_spaces,term 只来自服务端分词结果:篡改 ID、用户、语言都不能越权读写,也不能伪造身份。
  • 幂等由唯一键承担,重复提交同一词形不产生第二条记录,也不产生「冲突记录」。同一账号多端同时保存采用最后写入生效;本单不引入版本冲突拒绝,并在文档中记录该边界。
  • 前端 terms 状态跟随 session.user 变化重置,退出登录或切换账号后不保留任何前一账号的词条数据与高亮。

前端

沿用已验收词语面板:释义与例句输入、四个状态选择、保存与关闭;成功后显示简短反馈并立即更新正文高亮,失败保留已输入内容与面板。沿用同一套 seq/generation 防竞态与 stale 响应。管理端无改动。

测试计划

  • Go 单测:归一化身份、状态/等级矩阵与边界、字段上限、幂等 upsert、鉴权矩阵。
  • MySQL 集成(专用库 lexgo_test_issue7,不借用其他库):v4→v5 迁移保留既有表计数;两账号互不影响;篡改 id/user/language 被拒绝;重复保存仅一条;跨章节同形词状态一致;非 ready 章节与非法范围拒绝。
  • 学习端单测与类型检查/构建;管理端回归;治理检查。
  • 真实 API + MySQL + 浏览器两账号联调,证据与截图按 #6 惯例处理;真实手机不作为本单验收,缺口保留。

回退

v5 只新增表:停止 API → 恢复 .local/lexgo-pre-issue7.exe → 将 lexgo_schema 标记回 4 → 重启;保留 lexgo_terms 与全部既有学习数据,不删除数据、不重新 bootstrap。迁移先在 lexgo_test_issue7 验证。

文档影响

实施后更新 Architecture-and-Code-Map、Business-Rules-and-Glossary、Local-Development-and-Verification;F07 需求文本未变,Product-Requirements-Overview 仅在需求实质变化时更新。Wiki 先改后回读,再同步镜像。

遗留项

原型 v1 的「原文例句已关联到词条」需要句子切分规则,本单不实现,若用户需要则另立范围;等级编辑 UI 归 #8/#12;#7 不实现词汇库列表、短语、复习与进度。

回退说明:本会话 pi 无可用 Gitea MCP 工具,沿用本单既定回退,使用目标 git.ilapage.cn API;凭据仅从既有安全配置读入进程,不进入仓库、日志或工单正文。

## #7 方案确认与实施启动(2026-09-11) 用户在当前会话确认并授权实施:身份口径「赞同」,其余三个决策点由 Agent 判断后定案。前置 #6 已由用户验收关闭,PR #25 已合入 main;本单分支 `feat/7-personal-terms` 从 main `33182e5` 创建。本单实施期间工单状态进入「进行中」,完成测试后停在「待验收」。 ### 已确认决策 | 决策 | 结论 | 理由 | |---|---|---| | 词条身份 | `(owner_id, language, normalizeWord(原词形))`;`Dog`/`dog` 合并,`dog`/`dogs` 不合并 | 无上下文词性时 lemma 候选不可信,与 #6 已验收的「不按候选合并个人学习状态」一致;原词形单独保存供显示 | | 首次保存默认状态 | `new`(新词) | 与生词本列表「curiosity / 好奇心 · 新词」这条权威状态显示一致;若默认学习中会在用户只点保存时凭空产生等级和复习进度 | | 等级选择器 | #7 面板不提供 1~7 选择器;等级在契约层持久化,`POST /terms` 接受可选 `level` 并按状态校验 | 原型 v1 面板无等级控件,等级是 #8 的调度概念;F07「修改学习等级」由接口与 #8/#12 编辑页承接 | | 例句 | 只保存用户手输例句(按行,≤5 条),不自动关联原文句子 | 全 Go 分词没有句子切分规则,自动关联会静默贴错句子;原型 mock 文案「原文例句已关联」不作为契约,差异记录在下方遗留项 | ### 数据结构(schema v5,纯新增表) ```sql CREATE TABLE IF NOT EXISTS lexgo_terms ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, owner_id BIGINT NOT NULL, language VARCHAR(16) NOT NULL DEFAULT 'en', term VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, original_form VARCHAR(191) NOT NULL, definition TEXT NOT NULL, examples TEXT NOT NULL, status VARCHAR(16) NOT NULL, level TINYINT NOT NULL DEFAULT 0, created_at DATETIME(3) NOT NULL, updated_at DATETIME(3) NOT NULL, UNIQUE KEY uq_term_identity (owner_id, language, term), CHECK (status IN ('new','learning','known','ignored')), CHECK (level BETWEEN 0 AND 7), FOREIGN KEY (owner_id) REFERENCES sys_user(user_id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ``` `term` 使用 `utf8mb4_bin`:归一化由 Go 完成,避免 `_ai_ci` 把 `resume`/`résumé` 折成同一身份。v5 不修改任何既有表或既有数据。 ### 状态与等级映射 | 业务状态 | level | 含义 | 进入到期复习 | 原版 stage | |---|---|---|---|---| | `new` 新词 | 0 | 已保存、尚未开始学习;首次保存默认 | 是(由 #8 决定) | 2 | | `learning` 学习中 | 1~7 | 正在复习,越接近 7 越熟 | 是 | -1~-7 | | `known` 已知 | 0 | 已掌握,不再进入到期复习 | 否 | 0 | | `ignored` 忽略 | 0 | 明确忽略,不计入已知 | 否 | 1 | 服务端强校验:非 `learning` 时 `level` 必须为 0;`learning` 且缺省时置 1。`#7` 不实现复习推进、到期时间与计数(归 #8/#13)。 ### 接口契约 | 接口 | 权限与输入/输出 | |---|---| | `POST /api/v1/terms` | 本人;`{chapterId,start,end,definition,examples[],status,level?}`;服务端按 #6 同一套 token 范围校验反推身份,`owner/language/term` 一律不接受客户端输入;唯一键 upsert,重复保存只产生一条记录;首次 201、更新 200,返回完整 term | | `GET /api/v1/terms/:id` | 本人;他人编号与不存在编号统一 404,不泄露存在性 | | `GET /api/v1/chapters/:id/tokens` | 在原响应上为 word 片段增加可选 `term:{id,status,level}`;服务端按本章全部词形一次性查本人词条,其他章节保存的同形词同样命中(跨章节一致与 F05 高亮) | 约束:`definition` ≤2000 字符可为空;`examples` ≤5 条、每条 ≤500 字符、不允许换行;`start/end` 必须是本人 ready 章节内的完整单词且 ≤128 码点;跨账号章节 404,非 ready 409,未知字段 400。 ### 隔离与幂等 - owner 只来自会话,language 只来自 `lexgo_spaces`,term 只来自服务端分词结果:篡改 ID、用户、语言都不能越权读写,也不能伪造身份。 - 幂等由唯一键承担,重复提交同一词形不产生第二条记录,也不产生「冲突记录」。同一账号多端同时保存采用最后写入生效;本单不引入版本冲突拒绝,并在文档中记录该边界。 - 前端 `terms` 状态跟随 `session.user` 变化重置,退出登录或切换账号后不保留任何前一账号的词条数据与高亮。 ### 前端 沿用已验收词语面板:释义与例句输入、四个状态选择、保存与关闭;成功后显示简短反馈并立即更新正文高亮,失败保留已输入内容与面板。沿用同一套 seq/generation 防竞态与 stale 响应。管理端无改动。 ### 测试计划 - Go 单测:归一化身份、状态/等级矩阵与边界、字段上限、幂等 upsert、鉴权矩阵。 - MySQL 集成(专用库 `lexgo_test_issue7`,不借用其他库):v4→v5 迁移保留既有表计数;两账号互不影响;篡改 id/user/language 被拒绝;重复保存仅一条;跨章节同形词状态一致;非 ready 章节与非法范围拒绝。 - 学习端单测与类型检查/构建;管理端回归;治理检查。 - 真实 API + MySQL + 浏览器两账号联调,证据与截图按 #6 惯例处理;真实手机不作为本单验收,缺口保留。 ### 回退 v5 只新增表:停止 API → 恢复 `.local/lexgo-pre-issue7.exe` → 将 `lexgo_schema` 标记回 4 → 重启;保留 `lexgo_terms` 与全部既有学习数据,不删除数据、不重新 bootstrap。迁移先在 `lexgo_test_issue7` 验证。 ### 文档影响 实施后更新 Architecture-and-Code-Map、Business-Rules-and-Glossary、Local-Development-and-Verification;F07 需求文本未变,Product-Requirements-Overview 仅在需求实质变化时更新。Wiki 先改后回读,再同步镜像。 ### 遗留项 原型 v1 的「原文例句已关联到词条」需要句子切分规则,本单不实现,若用户需要则另立范围;等级编辑 UI 归 #8/#12;#7 不实现词汇库列表、短语、复习与进度。 回退说明:本会话 pi 无可用 Gitea MCP 工具,沿用本单既定回退,使用目标 `git.ilapage.cn` API;凭据仅从既有安全配置读入进程,不进入仓库、日志或工单正文。
Author
Owner

#7 实施完成,待用户验收(2026-09-11)

用户确认的方案与决策见评论 7737。分支 feat/7-personal-terms 从 main 33182e5 创建,实现提交 8c0946af9f1b69cd14e474b3b0178adc92438cb6,已推送。PR #26 未合并,工单不关闭,停在待用户验收。

决策落定

决策 结果
词条身份 学习者+语言+规范化词形;Dog/dog 同一条记录,dog/dogs 两条
首次保存默认状态 new 新词
等级 契约层持久化并按状态校验,阅读器面板只提供四个状态;选择器归 #8/#12
例句 只保存手输内容,不自动关联原文句子

实现与差异

  • schema v5 新增 lexgo_terms(server/app/lexgo/database.go):身份唯一键 (owner_id,language,term),term 列用 utf8mb4_bin 避免折叠 resume/résumé,original_form 保存最近一次的原词形;检查约束只允许 learning 带 1~7 级。未修改任何既有表和既有数据。
  • server/app/lexgo/terms.go:身份推导、状态/等级边界、文本上限、INSERT … ON DUPLICATE KEY UPDATE 幂等保存、跨章节状态匹配。个人词条不写审计日志(私人学习内容不入审计)。
  • 接口:POST /api/v1/terms(首次 201、重复 200,返回 {term,created})、GET /api/v1/terms/:id(他人与不存在统一 404)、GET /api/v1/chapters/:id/tokens 为 word 片段增加 term:{id,status,level}。lookup 与 terms 共用 wordAtRange,保存与查询必须落在同一完整单词范围。
  • 学习端:useReaderLookup.ts 增加释义/例句/状态、预填与保存(打开已保存词先读原内容,读取失败即禁用保存,避免空表单覆盖);LookupPanel.vue 提供状态单选、释义与例句输入、保存与「已保存 · 状态」反馈;ReaderTokens.vue 按状态高亮;style.css 增加四种状态样式。换词/换章/离页/退出/切账号清空表单、状态与高亮。管理端无改动。

实际验证

验证 结果
go vet ./... 通过
LEXGO_TEST_DB_NAME=lexgo_test_issue7 python scripts/server.py test-integration 34 个顶层用例全部通过、0 跳过(原 26,新增 3 个 MySQL 词条用例、4 个单元用例、1 个 v4→v5 迁移用例)
learner npx vitest --run / vue-tsc --build / pnpm run build / playwright test 58 项单测、类型检查、构建、3 项默认 E2E 通过
admin pnpm test / pnpm lint 31 项与 lint 通过;管理端本单无代码改动
python -m unittest discover -s tests / harness.py check --strict 56 项与严格检查通过
Wiki sync --check 一致,5 个页面先写后回读

覆盖:非法状态与等级边界、文本上限、大小写合并与词形不合并、完全相同的重复保存幂等、跨章节同形词状态一致、两账号互不影响、篡改 owner/language/term 与未知字段被拒、非本人章节 404、未登录 401、未就绪章节 409、冷启动读取。

本机开发库 lexgo_dev 已显式 v4→v5:升级前后 sys_user 6、lexgo_spaces 6、lexgo_sessions 8、lexgo_books 4、lexgo_chapters 9、lexgo_ingest_jobs 9、lexgo_dictionaries 1 全部不变,新增空的 lexgo_terms;旧二进制备份在忽略的 .local/lexgo-pre-issue7.exe,仅重启 lexgo-api,其余 11 个实例 PID 与状态未变化,8000 与两端入口均 200。

真实链路:真实 Go API+真实 MySQL 共 30 项检查通过,使用 #6 已建的虚构测试账号 issue5_a/issue5_b 与其虚构章节 1/2/8/9(凭据只从本机安全配置读入进程)。随后用临时 Playwright 用例在真实学习端+真实 API 上复核:保存释义/例句/状态 → 「已保存 · 学习中」与正文高亮 → 重新加载后高亮与预填一致 → 390×844 窄屏底部面板 → 退出并以另一账号登录,同文本章节显示该账号自己的状态、未保存的词无状态。临时用例运行后删除,截图作为附件上传。

未验证与边界

  • 真实手机触屏详细证据与完整备份恢复演练仍属既有缺口(#14/#15);本单只用桌面浏览器窄屏检查,不当作真机结果。
  • 同一账号多端同时编辑为最后写入生效,本版不引入版本冲突拒绝;单实例部署,未做并发压测。
  • #7 不实现词汇库列表/搜索(#12)、短语(#11)、复习推进与到期时间(#8)、进度(#13);等级编辑 UI 未实现。
  • 原型 v1 的「原文例句已关联到词条」需要句子切分规则,本单按决策不实现。

文档

Wiki 先写后回读,再同步镜像(镜像随本次提交):

  • Architecture-and-Code-Map: cb6d420632527a436f8b9a7a6a18413a0773f93d
  • Business-Rules-and-Glossary: 71389f97df86e17699f4af930022251fa354631b
  • Local-Development-and-Verification: 919545b0d716180a49ac7dd2fe96bbeccdba0880
  • Product-Requirements-Overview: b5eaaf1d0664e1e3c564079c857ccb5042540022
  • Home: 6fd4c754e3bb6ab215edb6077974fbd401f24103

未提交凭据、账号密码、测试数据库数据或截图;.local/ 保持忽略。

回退

停止 lexgo-api,恢复 .local/lexgo-pre-issue7.exe,把 lexgo_schema 标记改回 4 后启动;保留 lexgo_terms 与全部既有学习数据,不删除数据、不重新 bootstrap。

Gitea MCP 仍指向其他站点,沿用已记录的目标站点 API 回退;凭据仅从既有安全配置读入进程。推送使用同一 API 令牌经进程环境注入,未写入命令文本、.git/config 或日志。

附件:issue7-reader-desktop.png、issue7-reader-mobile-390.png、issue7-account-b.png(本会话模型不能读取图片,截图未经 Agent 目视检查,功能断言来自程序化检查)。

## #7 实施完成,待用户验收(2026-09-11) 用户确认的方案与决策见评论 7737。分支 `feat/7-personal-terms` 从 main `33182e5` 创建,实现提交 `8c0946af9f1b69cd14e474b3b0178adc92438cb6`,已推送。PR [#26](https://git.ilapage.cn/OPC/lexgo/pulls/26) 未合并,工单不关闭,停在待用户验收。 ### 决策落定 | 决策 | 结果 | |---|---| | 词条身份 | 学习者+语言+规范化词形;`Dog`/`dog` 同一条记录,`dog`/`dogs` 两条 | | 首次保存默认状态 | `new` 新词 | | 等级 | 契约层持久化并按状态校验,阅读器面板只提供四个状态;选择器归 #8/#12 | | 例句 | 只保存手输内容,不自动关联原文句子 | ### 实现与差异 - schema v5 新增 `lexgo_terms`(`server/app/lexgo/database.go`):身份唯一键 `(owner_id,language,term)`,`term` 列用 `utf8mb4_bin` 避免折叠 `resume`/`résumé`,`original_form` 保存最近一次的原词形;检查约束只允许 `learning` 带 1~7 级。未修改任何既有表和既有数据。 - `server/app/lexgo/terms.go`:身份推导、状态/等级边界、文本上限、`INSERT … ON DUPLICATE KEY UPDATE` 幂等保存、跨章节状态匹配。个人词条不写审计日志(私人学习内容不入审计)。 - 接口:`POST /api/v1/terms`(首次 201、重复 200,返回 `{term,created}`)、`GET /api/v1/terms/:id`(他人与不存在统一 404)、`GET /api/v1/chapters/:id/tokens` 为 word 片段增加 `term:{id,status,level}`。`lookup` 与 `terms` 共用 `wordAtRange`,保存与查询必须落在同一完整单词范围。 - 学习端:`useReaderLookup.ts` 增加释义/例句/状态、预填与保存(打开已保存词先读原内容,读取失败即禁用保存,避免空表单覆盖);`LookupPanel.vue` 提供状态单选、释义与例句输入、保存与「已保存 · 状态」反馈;`ReaderTokens.vue` 按状态高亮;`style.css` 增加四种状态样式。换词/换章/离页/退出/切账号清空表单、状态与高亮。管理端无改动。 ### 实际验证 | 验证 | 结果 | |---|---| | `go vet ./...` | 通过 | | `LEXGO_TEST_DB_NAME=lexgo_test_issue7 python scripts/server.py test-integration` | 34 个顶层用例全部通过、0 跳过(原 26,新增 3 个 MySQL 词条用例、4 个单元用例、1 个 v4→v5 迁移用例) | | learner `npx vitest --run` / `vue-tsc --build` / `pnpm run build` / `playwright test` | 58 项单测、类型检查、构建、3 项默认 E2E 通过 | | admin `pnpm test` / `pnpm lint` | 31 项与 lint 通过;管理端本单无代码改动 | | `python -m unittest discover -s tests` / `harness.py check --strict` | 56 项与严格检查通过 | | Wiki `sync --check` | 一致,5 个页面先写后回读 | 覆盖:非法状态与等级边界、文本上限、大小写合并与词形不合并、完全相同的重复保存幂等、跨章节同形词状态一致、两账号互不影响、篡改 owner/language/term 与未知字段被拒、非本人章节 404、未登录 401、未就绪章节 409、冷启动读取。 本机开发库 `lexgo_dev` 已显式 v4→v5:升级前后 sys_user 6、lexgo_spaces 6、lexgo_sessions 8、lexgo_books 4、lexgo_chapters 9、lexgo_ingest_jobs 9、lexgo_dictionaries 1 全部不变,新增空的 `lexgo_terms`;旧二进制备份在忽略的 `.local/lexgo-pre-issue7.exe`,仅重启 lexgo-api,其余 11 个实例 PID 与状态未变化,8000 与两端入口均 200。 真实链路:真实 Go API+真实 MySQL 共 30 项检查通过,使用 #6 已建的虚构测试账号 issue5_a/issue5_b 与其虚构章节 1/2/8/9(凭据只从本机安全配置读入进程)。随后用临时 Playwright 用例在真实学习端+真实 API 上复核:保存释义/例句/状态 → 「已保存 · 学习中」与正文高亮 → 重新加载后高亮与预填一致 → 390×844 窄屏底部面板 → 退出并以另一账号登录,同文本章节显示该账号自己的状态、未保存的词无状态。临时用例运行后删除,截图作为附件上传。 ### 未验证与边界 - 真实手机触屏详细证据与完整备份恢复演练仍属既有缺口(#14/#15);本单只用桌面浏览器窄屏检查,不当作真机结果。 - 同一账号多端同时编辑为最后写入生效,本版不引入版本冲突拒绝;单实例部署,未做并发压测。 - #7 不实现词汇库列表/搜索(#12)、短语(#11)、复习推进与到期时间(#8)、进度(#13);等级编辑 UI 未实现。 - 原型 v1 的「原文例句已关联到词条」需要句子切分规则,本单按决策不实现。 ### 文档 Wiki 先写后回读,再同步镜像(镜像随本次提交): - Architecture-and-Code-Map: `cb6d420632527a436f8b9a7a6a18413a0773f93d` - Business-Rules-and-Glossary: `71389f97df86e17699f4af930022251fa354631b` - Local-Development-and-Verification: `919545b0d716180a49ac7dd2fe96bbeccdba0880` - Product-Requirements-Overview: `b5eaaf1d0664e1e3c564079c857ccb5042540022` - Home: `6fd4c754e3bb6ab215edb6077974fbd401f24103` 未提交凭据、账号密码、测试数据库数据或截图;`.local/` 保持忽略。 ### 回退 停止 lexgo-api,恢复 `.local/lexgo-pre-issue7.exe`,把 `lexgo_schema` 标记改回 4 后启动;保留 `lexgo_terms` 与全部既有学习数据,不删除数据、不重新 bootstrap。 Gitea MCP 仍指向其他站点,沿用已记录的目标站点 API 回退;凭据仅从既有安全配置读入进程。推送使用同一 API 令牌经进程环境注入,未写入命令文本、`.git/config` 或日志。 附件:issue7-reader-desktop.png、issue7-reader-mobile-390.png、issue7-account-b.png(本会话模型不能读取图片,截图未经 Agent 目视检查,功能断言来自程序化检查)。
Author
Owner

补充提交 a5a8c3c(docs: 记录 #7 已确认的个人词条决策):按本项目既有惯例,把用户本轮确认的个人词条口径写入仓库根 AGENTS.md 的项目决策清单——身份为「学习者+语言+规范化词形」且不按 lemma 合并、首次保存默认新词、四状态与 1~7 级映射及原版 stage 对照、例句不自动关联原文句子。仅新增一行文档,未改动代码、数据或契约;前期提交 8c0946a 保持不变,分支 feat/7-personal-terms 已同步推送。

补充提交 `a5a8c3c`(docs: 记录 #7 已确认的个人词条决策):按本项目既有惯例,把用户本轮确认的个人词条口径写入仓库根 `AGENTS.md` 的项目决策清单——身份为「学习者+语言+规范化词形」且不按 lemma 合并、首次保存默认新词、四状态与 1~7 级映射及原版 stage 对照、例句不自动关联原文句子。仅新增一行文档,未改动代码、数据或契约;前期提交 `8c0946a` 保持不变,分支 feat/7-personal-terms 已同步推送。
Author
Owner

用户验收与合并收尾

验收时间:2026-09-11 20:25 +0800(Asia/Shanghai,与 PR 合入时刻一致)。用户在当前会话明确确认「#7 通过验收」。结论:#7 验收通过,关闭工单;PR #26 已 fast-forward-only 合入 main。

合入方式为 fast-forward-only,main 直接前进到分支提交,功能提交仍为 8c0946af9f1b69cd14e474b3b0178adc92438cb6,与用户验收版本逐字节一致,没有产生合并提交、没有改写历史。分支 feat/7-personal-terms 保留;需要撤销时可在新工单中使用 revert。

验收状态文档提交 527d8af(Home、Project-Profile、Architecture-and-Code-Map、Product-Requirements-Overview)与决策记录提交 a5a8c3c(AGENTS.md)已推送。合并后复核:harness.py check --strict 通过、sync --verify 通过、治理测试 56 项通过,工作区干净,先前完整交付证据见评论 7744,不重复覆盖。

长期文档 Wiki revisions:

  • Project-Profile: 91a2eb47ca73e41a329bccd6ceeb7498c691529c
  • Architecture-and-Code-Map: 02b7fc12b222c0050652443ca1368730f35f5652
  • Product-Requirements-Overview: c9dcc7a0e9739fe17c148751662acceaed41982f
  • Home: d355012d0f773ab5becb8c966cecfac71e39fabe
  • Business-Rules-and-Glossary / Local-Development-and-Verification 本单验收未变化,仍为 71389f97df86e17699f4af930022251fa354631b / 919545b0d716180a49ac7dd2fe96bbeccdba0880

未增加产品范围或数据库变更;schema 保持 v5,本机开发库已完成 v4→v5 迁移与 lexgo-api 重启。真机触屏详细证据与完整备份恢复演练缺口保留,后续由 #14/#15 承接;短语 #11、到期复习 #8、词汇库 #12、进度 #13、附件 #21 与列表优化 #24 仍待实施。

Gitea MCP 仍指向其他站点,沿用已记录的目标 git.ilapage.cn API 回退,凭据仅在进程环境中使用。

## 用户验收与合并收尾 验收时间:2026-09-11 20:25 +0800(Asia/Shanghai,与 PR 合入时刻一致)。用户在当前会话明确确认「#7 通过验收」。结论:#7 验收通过,关闭工单;PR [#26](https://git.ilapage.cn/OPC/lexgo/pulls/26) 已 fast-forward-only 合入 main。 合入方式为 fast-forward-only,main 直接前进到分支提交,功能提交仍为 `8c0946af9f1b69cd14e474b3b0178adc92438cb6`,与用户验收版本逐字节一致,没有产生合并提交、没有改写历史。分支 `feat/7-personal-terms` 保留;需要撤销时可在新工单中使用 revert。 验收状态文档提交 `527d8af`(Home、Project-Profile、Architecture-and-Code-Map、Product-Requirements-Overview)与决策记录提交 `a5a8c3c`(AGENTS.md)已推送。合并后复核:`harness.py check --strict` 通过、`sync --verify` 通过、治理测试 56 项通过,工作区干净,先前完整交付证据见评论 [7744](https://git.ilapage.cn/OPC/lexgo/issues/7#issuecomment-7744),不重复覆盖。 长期文档 Wiki revisions: - Project-Profile: `91a2eb47ca73e41a329bccd6ceeb7498c691529c` - Architecture-and-Code-Map: `02b7fc12b222c0050652443ca1368730f35f5652` - Product-Requirements-Overview: `c9dcc7a0e9739fe17c148751662acceaed41982f` - Home: `d355012d0f773ab5becb8c966cecfac71e39fabe` - Business-Rules-and-Glossary / Local-Development-and-Verification 本单验收未变化,仍为 `71389f97df86e17699f4af930022251fa354631b` / `919545b0d716180a49ac7dd2fe96bbeccdba0880` 未增加产品范围或数据库变更;schema 保持 v5,本机开发库已完成 v4→v5 迁移与 lexgo-api 重启。真机触屏详细证据与完整备份恢复演练缺口保留,后续由 #14/#15 承接;短语 #11、到期复习 #8、词汇库 #12、进度 #13、附件 #21 与列表优化 #24 仍待实施。 Gitea MCP 仍指向其他站点,沿用已记录的目标 git.ilapage.cn API 回退,凭据仅在进程环境中使用。
ila closed this issue 2026-09-11 20:30:08 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/lexgo#7