222 lines
15 KiB
Go
222 lines
15 KiB
Go
# Change Log — 2026-08-24
|
||
|
||
## 请求
|
||
|
||
1. 新增一个「公共模块」,模块下存放 `tools` 功能模块,`tools` 下再分各种子功能。
|
||
2. 建立项目上下文记忆体系:记录每次请求与更改,方案对比后落地;要求后续使用其他 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` 替代);避免重复造轮子,保持与框架一致。
|
||
- **记忆体系三层方案**(对比见下):
|
||
1. `AGENTS.md`(根目录)— 长期稳定规范,跨工具标准(Claude Code/CodeBuddy/Codex 等均识别),随 git 走;
|
||
2. `docs/change-log/YYYY-MM-DD.md` — 每次请求变更的结构化记录,随 git 走,**这是跨账号衔接的关键**;
|
||
3. `.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 目录重构
|
||
|
||
### 请求
|
||
|
||
1. 变更 API 目录设计:契约层改为 `tools/<子功能>/index.go` 结构(示例 `/api/common/v1/tools/ocr/index.go`)。
|
||
2. 同步修改所有涉及处(控制器、路由)。
|
||
3. 把命名规则记入项目记忆。
|
||
4. 咨询:公共接口一般用 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/Tools`
|
||
- `internal/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` — import `commonctl`→`openctl`;路由 `/api/common/v1`→`/api/open/v1`,注释改 Open tools API
|
||
- `AGENTS.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 引用为 <name>.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 import `contrib/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` 置空、关闭 mock
|
||
- `vite.config.ts`:代理 `/admin`、`/api` → `http://localhost:8000`
|
||
- `preferences.ts`:`accessMode: 'backend'`(动态路由)、关闭 token 自动刷新
|
||
- `api/core/auth.ts`:登录/权限码路径改 `/admin/v1/...`,codes 解包 `data.codes`
|
||
- `api/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 映射**:vben `normalizeViewPath` 会去前缀、补前导 `/`、去 `/views`,最终匹配 `views/**/*.vue`,无需 `.vue` 后缀。
|
||
- **前端请求路径写完整 `/admin/v1/...` + apiURL 置空**:因 user(`/api/v1`)、open(`/api/open/v1`)、admin(`/admin/v1`) 前缀不同,写全路径最清晰,避免 proxy rewrite 混乱。
|
||
- **字段映射在后端/前端约定**:后端返回 `adminId/nickname`,前端映射为 vben `UserInfo(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` 启动,浏览器验证登录/菜单/权限/日志。
|