diff --git a/.gitignore b/.gitignore index 3613b7a..aab50ff 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,11 @@ gitHub_release_*.md # 构建产物 *.exe bin/ +claude_check_report_framework.md +claude_check_report_module.md +cross_review_assessment.md +deepseek_check_report_framework.md +deepseek_check_report_module.md +glm_check_report_framework.md +glm_check_report_modelue.md +last_report.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 869cc9d..c2a2aa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,8 +16,12 @@ xlgo 框架更新日志。本文档遵循 [Keep a Changelog](https://keepachange ## [Unreleased] -> 框架整体评估后的结构性修复,包含 2 CRITICAL + 12 HIGH + 6 MEDIUM 问题的修复。 -> 项目处于初级阶段,无下游用户,放心引入破坏性变更。 +_暂无未发布变更。_ + +## [1.2.0] - 2026-07-04 + +> 框架整体评估后的结构性修复:4 轮对抗性评审(deepseek / GLM / Claude / 终审)收口的全部 CRITICAL/HIGH/MEDIUM 问题 + 主线A 包级可变全局并发治理统一。 +> 项目处于初级阶段,无下游用户,放心引入破坏性变更。`go vet` + `go build` + `go test -race ./...` 全绿。 ### Breaking ⚠️ @@ -964,7 +968,8 @@ v1.0.2 引入可插拔方言注册表后,`gorm.io/driver/postgres` 成为直 - 基础框架功能 - 完整示例代码 -[Unreleased]: https://github.com/EthanCodeCraft/xlgo-core/compare/v1.1.1...HEAD +[Unreleased]: https://github.com/EthanCodeCraft/xlgo-core/compare/v1.2.0...HEAD +[1.2.0]: https://github.com/EthanCodeCraft/xlgo-core/compare/v1.1.1...v1.2.0 [1.1.1]: https://github.com/EthanCodeCraft/xlgo-core/releases/tag/v1.1.1 [1.1.0]: https://github.com/EthanCodeCraft/xlgo-core/releases/tag/v1.1.0 [1.0.4]: https://github.com/EthanCodeCraft/xlgo-core/releases/tag/v1.0.4 diff --git a/GUIDE.md b/GUIDE.md index 3e6d75a..94c68a6 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -111,7 +111,6 @@ app: env: "dev" # dev/test/prod debug: true base_url: "http://localhost:8080" - token_expire: 86400 # Token过期时间(秒) server: port: 8080 @@ -134,7 +133,7 @@ redis: jwt: secret: your_jwt_secret_key - expire: 86400 + expire: "24h" # time.Duration,如 "24h"/"30m" log: dir: ./logs @@ -701,7 +700,9 @@ if !ok { | `max=20` | 最大长度 | | `email` | 邮箱格式 | | `phone` | 手机号格式 | +| `phone_strict` | 手机号严格校验(验证运营商号段) | | `password` | 密码强度(8-72 字节,需含大写+小写+数字) | +| `username` | 字母开头,3-20 位字母/数字/下划线 | | `url` | URL 格式 | | `ip` | IP 地址格式 | @@ -1070,7 +1071,8 @@ router.RegisterVersion(router.NewVersion("v1", "/api/v1")) // 应用路由 router.Apply() -xlgo.StartServer(engine, 8080) +// 启动服务(如需优雅关闭与生命周期管理,改用 app := xlgo.New(...); app.Run()) +engine.Run(":8080") ``` #### 8.4.7 默认路由 @@ -1199,7 +1201,9 @@ storage: import "github.com/EthanCodeCraft/xlgo-core/storage" // 初始化 -storage.Init(&cfg.Storage) +if err := storage.Init(&cfg.Storage); err != nil { + return err +} // 上传文件(从请求中获取) file, _ := c.FormFile("file") @@ -1799,13 +1803,17 @@ func Login(c *gin.Context) { } // 生成Token - token, _ := jwt.GenerateToken(user.ID, user.Username, "admin", "admin") + token, err := jwt.GenerateToken(user.ID, user.Username, "admin", "admin") + if err != nil { + response.FailWithError(c, response.ErrServerError) + return + } // 缓存用户信息 cache.GetCache().Set(c.Request.Context(), cache.KSession(token), user, - time.Duration(cfg.JWT.Expire)*time.Second) + cfg.JWT.Expire) response.Success(c, gin.H{ "token": token, @@ -1817,5 +1825,5 @@ func Login(c *gin.Context) { --- -_文档版本: v1.1.1_ -_最后更新: 2026-07-03_ +_文档版本: v1.2.0_ +_最后更新: 2026-07-04_ diff --git a/README.md b/README.md index e1757c6..dc6765a 100644 --- a/README.md +++ b/README.md @@ -246,7 +246,8 @@ database.InitDBWithReplicas(cfg, []string{ }) // 读操作自动路由到从库 -users := database.GetReadDB().Find(&users) +var users []model.User +database.GetReadDB().Find(&users) // 强制使用主库 ctx := database.UseMaster(context.Background()) @@ -819,6 +820,22 @@ docker run -d -p 8080:8080 xlgo-app:latest > 完整变更历史见 [CHANGELOG.md](./CHANGELOG.md)。 +### v1.2.0 (2026-07-04) + +> **破坏性版本**:4 轮对抗性评审(deepseek / GLM / Claude / 终审)收口的全部 CRITICAL/HIGH/MEDIUM 修复 + 主线A 包级可变全局并发治理统一。`go vet` + `go build` + `go test -race ./...` 全绿。完整变更见 [CHANGELOG.md](./CHANGELOG.md)。 + +主要破坏性变更(升级前必读): + +- **包级可变全局一律 `atomic.Pointer`**(主线A):`database.DefaultRedis`/`database.DefaultManager`/`storage.DefaultStorage`/`validation.Validator` 由裸指针改为 `atomic.Pointer[T]`。直接读字段调方法需改用 facade(`InitRedis`/`GetDB`/`ValidateStruct` 等)或 `.Load()`;`database.DefaultManager = x` 改 `database.SetDefaultManager(x)`。 +- **`jwt.DefaultJWT` 包级变量删除** → `GetDefaultJWT()` / `SetDefaultJWTManager()`。 +- **`repository.FindWhereOrdered`/`FindPageWhereOrdered` 签名**:`args []any` → `args ...any`,`order` 前置于 `query`。 +- **`response.Response` 的 `Data`/`RequestID` 去 `omitempty`**:两字段在所有响应中恒存在。 +- **`cache.IsLocked`/`GetLockTTL`/`ForceUnlock`** Redis 不可用改返 `ErrRedisNotReady`(锁操作正确性相关)。 +- **`config.Load()` 返回深拷贝**:新增 `(*Config).Clone()`;`Get()` 仍返只读指针(热路径零分配)。 +- **`handler.GetPage` 加 `page` 上限 10000**;`utils.EqualsIgnoreCase` 改 `strings.EqualFold`;`utils.ReadFile` 去 TOCTOU 前置检查(错误改 `errors.Is(err, os.ErrNotExist)`)。 + +升级:`go get github.com/EthanCodeCraft/xlgo-core@v1.2.0`(⚠️ 含破坏性变更,详见 CHANGELOG 迁移说明) + ### v1.1.1 (2026-06-23) > v1.1.0 的补丁发布:补 `ServerConfig.Host` 绑定地址、面向用户文案统一中文、修正 README 过时/错误描述(含会致启动失败的配置示例)。 diff --git a/app.go b/app.go index 61880e7..a19449d 100644 --- a/app.go +++ b/app.go @@ -28,7 +28,7 @@ import ( // Version 框架版本号。发版时只改这一处,避免版本字面量散落各处。 // CLI(xlgo version)、脚手架生成的 go.mod 等均引用此常量。 -const Version = "1.1.1" +const Version = "1.2.0" // HealthCheckFunc 健康检查函数 type HealthCheckFunc func(context.Context) error diff --git a/cmd/xlgo/commands.go b/cmd/xlgo/commands.go index df3b820..fbd91d8 100644 --- a/cmd/xlgo/commands.go +++ b/cmd/xlgo/commands.go @@ -281,7 +281,7 @@ func createRepository(name, nameTitle string) error { content := fmt.Sprintf(templates.RepositoryMake, nameTitle, name, nameTitle, nameTitle, nameTitle, name, nameTitle, nameTitle, nameTitle, nameTitle, - nameTitle, nameTitle, nameTitle, + nameTitle, nameTitle, ) content = replaceModuleImports(content) diff --git a/cmd/xlgo/templates.go b/cmd/xlgo/templates.go index 2cfe10e..77cc370 100644 --- a/cmd/xlgo/templates.go +++ b/cmd/xlgo/templates.go @@ -491,14 +491,13 @@ func New%sRepository() *%sRepository { } } -// FindByName 根据名称查询 +// FindByName 根据名称查询。 +// +// 走 BaseRepo.FindOne → readConn 读连接:默认路由到从库(读写分离,H6c), +// 需读主库用 database.UseMaster(ctx),事务内自动 join 外层事务。 +// 不要用 r.GetDB() 自行查询——它返回注入的主库且不参与路由(M-35 footgun)。 func (r *%sRepository) FindByName(ctx context.Context, name string) (*model.%s, error) { - var m model.%s - err := r.GetDB().WithContext(ctx).Where("name = ?", name).First(&m).Error - if err != nil { - return nil, err - } - return &m, nil + return r.FindOne(ctx, "name = ?", name) } `,