18 KiB
18 KiB
Change Log — 2026-08-24
请求
- 新增一个「公共模块」,模块下存放
tools功能模块,tools下再分各种子功能。 - 建立项目上下文记忆体系:记录每次请求与更改,方案对比后落地;要求后续使用其他 CodeBuddy 账号也能无缝衔接。
变更
新增文件:
common/doc.go— 公共模块说明(不依赖 internal、可独立抽取)common/tools/doc.go— tools 模块布局清单与封装规则common/tools/md5/md5.go— MD5 摘要(Md5Hex / Md5Bytes / Md5File)common/tools/cryptox/cryptox.go— AES-128-CBC / DES-ECB 加解密(base64 输出,密钥任意长度自动规范化)common/tools/uuid/uuid.go— 唯一 ID(New 32 位 / Short 短随机码)common/tools/random/random.go— 随机数/随机串(Int / String / Digits / Letters)common/tools/timex/timex.go— 时间工具(Format / Timestamp / StartOfDay / EndOfDay)common/tools/convertx/convertx.go— 类型转换带默认值(ToInt / ToInt64 / ToFloat64 / ToString / ToBool)common/tools/strx/strx.go— 字符串工具(命名转换 SnakeCase/CamelCase + 脱敏 MaskPhone/MaskIDCard/MaskName)common/tools/slicex/slicex.go— 泛型切片工具(Contains / Unique / Chunk / Map / Filter)common/tools/ip/ip.go— IP 工具(IsValid / LocalIP / IsInternal / ToLong / ToString)common/tools/filex/filex.go— 文件工具(Exists / IsDir / ReadString / WriteString)AGENTS.md— 项目智能体说明书(架构、规范、命令、记忆体系索引)docs/change-log/2026-08-24.md— 本文档
修改文件:
.gitignore— 追加.workbuddy/(本机记忆不入库)PROJECT_STRUCTURE.md— 目录树补充common/与docs/change-log/(见后续提交)
验证:go build ./... 与 go vet ./common/... 全部通过。
决策与理由
- 公共模块放顶层
common/而非internal/common/:Go 的 internal 包无法被外部模块引用,放顶层便于未来抽取为独立库/被同仓库其他服务复用。 - tools 一律薄封装 GoFrame 内置组件:v2.10.2 中 AES/DES 已拆为
crypto/gaes、crypto/gdes,UUID 为util/guid,无gslicer(用标准库slices替代);避免重复造轮子,保持与框架一致。 - 记忆体系三层方案(对比见下):
AGENTS.md(根目录)— 长期稳定规范,跨工具标准(Claude Code/CodeBuddy/Codex 等均识别),随 git 走;docs/change-log/YYYY-MM-DD.md— 每次请求变更的结构化记录,随 git 走,这是跨账号衔接的关键;.workbuddy/memory/— WorkBuddy 本机增强,不入库。
- 对比过
CLAUDE.md(Claude Code 专属、已建议统一为 AGENTS.md)、.cursor/rules(Cursor 专属)、.codebuddy/(仅 CodeBuddy 读取)——它们都不是最大公约数,故不采用。
待办与风险
- 后续每次任务完成后:更新
docs/change-log/(当日文件追加)+ 提交 git,确保其他账号 clone 即恢复上下文。 convertx依赖 gconv 的"转换失败返回零值"行为(无法区分"0"与非法输入),需要严格转换的场景应在 service 层先校验。- 本次变更尚未 git 提交,建议尽快 commit。
追加(17:30):方向纠正 — 「公共模块」实为公共接口
请求
用户澄清:要新增的是给前端调用的公共 HTTP 接口(此前误建成 Go 工具包),确认应规划到 api/ 契约层。
变更
新增文件:
api/common/v1/tools.go— 公共接口契约:UUIDReq/Res、MD5Req/Res、RandomReq/Res、TimeReq/Res、IPReq/Res(g.Meta 路由元数据)internal/controller/common/tools.go— 控制器实现,薄适配层,复用common/tools/*Go 包
修改文件:
internal/cmd/cmd.go— 新增公开分组s.Group("/api/common/v1", ...)(Recover+CORS+HandlerResponse,无鉴权)common/tools/timex/timex.go— 修复:Format内部改用Layout()方法(见决策)internal/controller/common/tools.go—Time用now.Layout(...)AGENTS.md— 目录树与新增「公共接口」小节、注意事项补 gtime 与包名差异PROJECT_STRUCTURE.md— 目录树补充api/common/v1
验证:go build ./...、go vet 通过;实际启动服务冒烟测试 5 个端点全部返回正确(含修复后 time 格式化)。
决策与理由
- 路由前缀
/api/common/v1:与/api/v1(user)、/admin/v1(admin) 平级的独立公开前缀,天然不套登录鉴权;前端三个端(mini/h5/app)通用。 - 契约层放
api/common/v1,实现放internal/controller/common:与 user/admin 完全同构;公共接口不需要 service 层(纯工具计算),controller 直接复用common/tools包,避免过度分层。 - 🐛 gtime v2.10.2 大坑(已修复):
Time.Format()参数是 PHP 风格("Y-m-d H:i:s"),传 Go layout("2006-01-02 15:04:05")会原样输出!Go layout 必须用Time.Layout()。common/tools/timex已统一封装为Layout语义,调用方直接timex.Format(t, layout...)即可。 - 冒烟测试教训:
go run会 spawn 子进程,kill %1只杀包装进程,残留的main.exe会继续占用 8000 端口导致后续测试打到旧代码——杀进程需netstat -ano | grep :8000找 PID 后Stop-Process。
待办与风险
- 本次追加变更同样未提交 git,与上文合并为一次 commit。
- 公共接口已开放无鉴权能力(md5/random/uuid 等),后续新增接口时需评审是否应限流/加签名,避免被滥用。
追加(18:05):开放接口命名决策 + API 目录重构
请求
- 变更 API 目录设计:契约层改为
tools/<子功能>/index.go结构(示例/api/common/v1/tools/ocr/index.go)。 - 同步修改所有涉及处(控制器、路由)。
- 把命名规则记入项目记忆。
- 咨询:公共接口一般用 common 命名吗?有没有更好的?
变更
新增文件(契约层按子功能拆目录):
api/open/v1/tools/doc.go— tools 目录结构规则说明api/open/v1/tools/uuid/index.go、md5/index.go、random/index.go、time/index.go、ip/index.go— 每子功能一个目录,index.go 内package <子功能名>,g.Meta tags 改Open/Toolsinternal/controller/open/controller.go— Controller 结构 + New()internal/controller/open/uuid.go、md5.go、random.go、time.go、ip.go— 按子功能拆文件,import 对应契约子包
删除文件:
api/common/v1/tools.go、api/common/目录internal/controller/common/tools.go、internal/controller/common/目录
修改文件:
internal/cmd/cmd.go— importcommonctl→openctl;路由/api/common/v1→/api/open/v1,注释改 Open tools APIAGENTS.md— 目录树更新;「公共接口」小节改为「开放接口(api/open/v1)与命名规则」,记录 open 命名决策与 tools 子功能目录规则PROJECT_STRUCTURE.md— 目录树同步
验证:go build ./...、go vet 通过;冒烟测试:旧路由 /api/common/v1/tools/time 返回 404,新路由 /api/open/v1/tools/* 5 端点全部正确。
决策与理由
- 命名 common → open:用户询问"公共接口一般用 common 吗",对比后选 open(业界开放接口惯例,如支付宝 /open/api;语义强调对外暴露、无鉴权)。
public为并列备选(更强调"公开"),common偏内部通用语义、弃用。命名规则已记入 AGENTS.md「开放接口」小节。 - 契约层目录规则:
api/open/v1/tools/<子功能名>/index.go每子功能一目录(与 GoFrame 惯例「api 下按功能分包」一致,用户示例 ocr 即为后续子功能,如未来加 OCR 识别接口即建tools/ocr/index.go);控制器internal/controller/open/<子功能名>.go对应拆文件(同 package open)。 - 路由绑定不受目录重构影响:GoFrame 通过 controller 方法参数反射定位 g.Meta,契约包拆成多个子包(uuid/md5/random/time/ip)不影响
group.Bind(openctl.New())自动注册,cmd.go 只需改前缀。 - 包名
time(api/open/v1/tools/time)与标准库 time 潜在同名,controller 中统一用 import 别名timeapi规避。
待办与风险
- 前端若已联调旧
/api/common/v1路径需同步改/api/open/v1(当前无线上前端,风险低)。 - 新增子功能记得更新
api/open/v1/tools/doc.go的示例清单。
追加(18:08):契约文件 index.go → <功能名>.go
请求
用户咨询"子功能目录内用 index.go 还是 <功能名>.go 更易扩展维护",确认推荐后执行改动。
变更
git mv重命名 5 个契约文件:tools/{uuid,md5,random,time,ip}/index.go→tools/{uuid,md5,random,time,ip}/{uuid,md5,random,time,ip}.go(包内容不变)api/open/v1/tools/doc.go— 规则说明改为「目录名=包名=文件名三一致」,补充"功能变大后目录内加文件"的扩展指引AGENTS.md/PROJECT_STRUCTURE.md— 同步 index.go 引用为 .go
验证:go build ./...、go vet 通过;冒烟测试 5 端点全部正常。
决策与理由
- 选 <功能名>.go 而非 index.go:① 目录名=包名=文件名三一致,导航直观;② index.go 是"入口"语义,功能膨胀后出现
index.go + idcard.go混排会失去入口意义,而<name>.go + idcard.go自然;③ 符合 Go 生态主流(strings/strings.go)与 GoFrame 官方模板(api/user/v1/user.go)。 - 扩展路径已定型:子功能从 1 个端点到多个端点,只需在目录内加文件(如 ocr 目录
ocr.go → + idcard.go + invoice.go),无需重构文件名。
待办与风险
- 无新增风险;后续新增子功能统一按
tools/<name>/<name>.go建文件。
追加(22:40):后台管理功能开发(后端完成)
请求
使用 goframe-v2 开发登录、菜单、按钮级权限等常规后台管理功能(前端 vben5 对接,backend 动态路由模式);登录后台后开发服务器日志管理功能。
变更(commit 8fdb25e,35 文件)
manifest/sql/003_schema_ext.sql:admin_menu 加icon/component/hidden列manifest/sql/004_seed.sql:初始 admin/admin123、super_admin 角色、22 条菜单(含按钮权限码)、角色/用户绑定manifest/sql/005_menu_paths.sql:按钮行 path 填"METHOD /路径"接口映射({id} 动态段)- auth:
/auth/info、/auth/codes;路由拆分公开(NewAuth)/仅登录(NewProfile)/受保护(New)三组;新增AdminAuthOnly中间件 - menu:
/menu/routes返回 vben backend 动态路由树(按角色过滤+排序) - RBAC:
/admins、/roles、/menus/tree及 CRUD(含角色绑定、重置密码、菜单授权、删除校验子节点) - log:
/log/files、/log/tail(反向块扫描读尾部+关键词过滤+路径穿越防护) - 安全:接口鉴权改为「方法+路径→权限码」自动映射(
PermissionForPath+matchRoute),不再信任前端 X-Permission - 修复:gf v2.10.2
${ENV}不自动替换 → cmd.injectEnv 注入;MySQL driver 需 blank importcontrib/drivers/mysql/v2;gtime Format(PHP) 与 Layout(Go) 区分再次踩坑(CreatedAt 输出 layout 原样) log/加入 .gitignore;config.dev.yaml logger.path=log(日志落盘)
决策与理由
- 接口鉴权用路径映射而非 X-Permission:原实现用户可用自己拥有的任意权限码访问任意受保护接口(越权漏洞);改为后端按 method+path 查 admin_menu 映射,未配置即拒绝。
- 受保护接口分三层:公开 login;AdminAuthOnly(info/codes/routes,登录即可取,vben 登录后立即调用);AdminAuth(RBAC/日志)。
- admin_menu 按钮行 path 存接口映射:与 type=1 菜单行的路由 path 语义区分开,避免冲突。
- gf gen dao 不可用:本机 gf CLI 为公司定制版(生成 com.lib.gf.v2 import),与项目官方 gf 不兼容;本次手动补齐 admin_menu 三字段(entity/do/table),后续换官方 CLI 或脚本化处理。
待办与风险
- 前端对接(vben5):admin.xpcool.com 需配置 accessMode=backend、登录/信息/权限码/动态路由对接、系统管理三页面+日志监控页面、按钮级 v-access:code。
- 冒烟测试已建 opuser/op 测试角色,可清理。
- 菜单管理接口的 assignMenu 权限码暂无独立接口(角色授权在 role update 中完成),保留扩展位。
- 生产环境 JWT_SECRET/DB_DSN 必须通过环境变量提供(${ENV} 不会自动替换)。
追加(23:05):前端 vben 对接(源码完成,本地启动验证受阻)
请求
继续做 vben 前端(admin.xpcool.com,vben 5.7.0 monorepo),对接后端登录/菜单/按钮级权限/RBAC/日志监控。
变更(前端独立仓库 commit 4615e7c)
.env.development:VITE_GLOB_API_URL置空、关闭 mockvite.config.ts:代理/admin、/api→http://localhost:8000preferences.ts:accessMode: 'backend'(动态路由)、关闭 token 自动刷新api/core/auth.ts:登录/权限码路径改/admin/v1/...,codes 解包data.codesapi/core/user.ts:/admin/v1/auth/info字段映射(adminId→userId、nickname→realName、homePath)api/core/menu.ts:/admin/v1/menu/routes解包data.routes- 新增
api/system.ts、api/log.ts - 新增页面:
views/system/admin|role|menu/index.vue(CRUD+按钮级权限)、views/monitor/log/index.vue(文件列表/tail/关键词过滤/自动刷新)
决策与理由
- 后端 component 值
system/admin/index与 vben 映射:vbennormalizeViewPath会去前缀、补前导/、去/views,最终匹配views/**/*.vue,无需.vue后缀。 - 前端请求路径写完整
/admin/v1/...+ apiURL 置空:因 user(/api/v1)、open(/api/open/v1)、admin(/admin/v1) 前缀不同,写全路径最清晰,避免 proxy rewrite 混乱。 - 字段映射在后端/前端约定:后端返回
adminId/nickname,前端映射为 vbenUserInfo(userId/realName)。
待办与风险(本地启动验证受阻)
- node 环境:system node 23.0.0 未编译
node:sqlite(ERR_UNKNOWN_BUILTIN_MODULE),pnpm 11.16.0 依赖它;已用 managed node 22.22.2 + corepack wrapper 绕过。 pnpm install卡住:已配.npmrc(npmmirror 镜像 +node-linker=hoisted+store-dir=E:/.pnpm-store),但 install 在 "added 27→98" 反复循环,疑似某 native 依赖 postinstall 失败重试。dev server 未能启动验证。- 后续步骤:① 定位卡住的依赖(
pnpm install --reporter=append-only看具体包);② 或跳过 postinstall(pnpm install --ignore-scripts后手动补 esbuild 等二进制);③ 完成 install 后pnpm dev:antd启动,浏览器验证登录/菜单/权限/日志。
追加(23:40):API 层 base/system/admin 分组重构
请求
优化 API 层设计:/api/admin/v1/base(基础常规)、/api/admin/v1/system(menu/role/auth 系统管理)、/api/admin/v1/admin(后台管理),并同步 service/controller 层。
变更
api/admin/v1/重组为三子包:base/log.go(日志)、system/{auth,menu,menu_manage,role}.go(认证+菜单+角色)、admin/admin.go(管理员)- 路由前缀变更:
/auth/*→/system/auth/*;/menu/routes→/system/menu/routes;/menus→/system/menu;/roles→/system/role;/admins→/admin;/log/*→/base/log/* internal/controller/admin/*.go改 import 对应子包(basev1/systemv1/adminv1)manifest/sql/006_menu_paths_v2.sql:按钮-接口 path 映射更新;system:role:assignMenu无独立接口,path 清空- 冒烟测试全通过:新路径 8 接口正常,旧路径
/admins返回 Not Found
决策与理由
- 权限码与路由分离:permission 保持
system:admin:list等逻辑标识不变,只改物理路由 path。管理员管理路由在/admin/v1/admin但权限码仍system:admin:*(逻辑归属系统权限体系)。 - service/dao 层不硬拆子包:service 保持
internal/service单包按领域接口组织(GoFrame 惯例),dao 为生成代码按表组织;api/controller 体现 base/system/admin 分组即可。 assignMenu权限码保留(前端按钮),但无独立后端接口(授权合并进 role update),path 置空不映射。
待办与风险
- 前端 API 路径需同步为
/admin/v1/{base,system,admin}前缀(当前前端代码仍是旧路径)。
追加(23:55):前端统一 tdesign UI + 清理无用 app
请求
- 前端 vben5 采用 tdesign UI 库;检查整个前端项目,清理用不到的目录。
- (关联)后端 API 层 base/system/admin 分组重构(见上一条 43fa796)。
变更(前端仓库 commit 6725151)
- 移除
apps/web-antd|web-ele|web-naive|web-antdv-next和backend-mock,仅保留web-tdesign(此前用户已在工作区删除,本次一并提交) web-tdesign重新对接后端:.env.development(apiURL 置空/关 mock)、vite.config.ts(代理 /admin,/api→8000)、preferences.ts(accessMode=backend/关 token 刷新)api/core/{auth,user,menu}.ts+api/{system,log}.ts:路径对齐 base/system/admin 分组- 页面用 tdesign-vue-next 重写:
views/system/{admin,role,menu}/index.vue、views/monitor/log/index.vue
决策与理由
- UI 统一 tdesign:web-tdesign 是 vben 官方 tdesign 应用;页面组件从 ant-design-vue 换成 tdesign-vue-next(t-table/t-dialog/t-tree/MessagePlugin/DialogPlugin)。
- 权限码与路由分离(后端):permission 保持
system:admin:list逻辑标识,路由改/admin/v1/admin;管理员管理在 admin 分组但权限码仍 system:*(逻辑归属系统权限体系)。
待办与风险
pnpm install卡住问题仍未解决(node:sqlite 已绕过,但 install 在 native 依赖 postinstall 反复循环),dev server 未启动验证。- 后端已删测试角色 opuser/op 可清理;前端路径已同步 base/system/admin,待 dev 启动后联调验证。