release: v1.2.0 版本号提升 + 脚手架对齐 + 文档核验

- 版本号 1.1.1 → 1.2.0:app.go Version 常量;脚手架 GoMod 模板经 xlgo.Version 自动跟随;GUIDE 文档版本同步
- CHANGELOG/README 新增 v1.2.0 破坏性版本条目(包级全局 atomic.Pointer 治理、jwt.DefaultJWT 删除、FindWhereOrdered 签名变更、response 去 omitempty、cache.ErrRedisNotReady、config.Clone 深拷贝等)
- 脚手架对齐:RepositoryMake 模板 FindByName 改用 FindOne(走 readConn 读写分离,避免 M-35 GetDB 不路由 footgun)
- 文档核验修复(README/GUIDE 逐行对照源码 6595e94):
  - README DB 示例 users := ...Find(&users) 自引用声明编译错误
  - GUIDE xlgo.StartServer(engine,8080) 不存在 → engine.Run(":8080")
  - GUIDE app.token_expire 死键(v1.1.0 已移除 AppConfig.TokenExpire)
  - GUIDE jwt.expire: 86400 类型错(time.Duration 需字符串 "24h")
  - GUIDE storage.Init(&cfg.Storage) 吞错误 → 显式 err 处理
  - GUIDE 登录示例 token,_:=jwt.GenerateToken 吞错误 + time.Duration(cfg.JWT.Expire)*time.Second 双重转换
  - GUIDE 验证规则表补 phone_strict / username
- .gitignore 忽略 8 个评审报告文件(仅本地保留,不入库;已从未推送提交中 filter-branch 清除)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
杭州明婳科技
2026-07-04 11:46:59 +08:00
parent 6595e94677
commit 86e126c42b
7 changed files with 58 additions and 21 deletions
+8
View File
@@ -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
+8 -3
View File
@@ -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
+16 -8
View File
@@ -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_
+18 -1
View File
@@ -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 过时/错误描述(含会致启动失败的配置示例)。
+1 -1
View File
@@ -28,7 +28,7 @@ import (
// Version 框架版本号。发版时只改这一处,避免版本字面量散落各处。
// CLIxlgo version)、脚手架生成的 go.mod 等均引用此常量。
const Version = "1.1.1"
const Version = "1.2.0"
// HealthCheckFunc 健康检查函数
type HealthCheckFunc func(context.Context) error
+1 -1
View File
@@ -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)
+6 -7
View File
@@ -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)
}
`,