docs(constitution): 新增数据库设计原则(v2.4.0)

在项目宪章中新增第九条原则"数据库设计原则",明确禁止使用数据库外键约束和ORM关联标签。

主要变更:
- 新增原则IX:数据库设计原则(Database Design Principles)
- 强制要求:数据库表不得使用外键约束
- 强制要求:GORM模型不得使用ORM关联标签(foreignKey、hasMany等)
- 强制要求:表关系必须通过ID字段手动维护
- 强制要求:关联数据查询必须显式编写,避免ORM魔法
- 强制要求:时间字段由GORM处理,不使用数据库触发器

设计理念:
- 提升业务逻辑灵活性(无数据库约束限制)
- 优化高并发性能(无外键检查开销)
- 增强代码可读性(显式查询,无隐式预加载)
- 简化数据库架构和迁移流程
- 支持分布式和微服务场景

版本升级:2.3.0 → 2.4.0(MINOR)
This commit is contained in:
2025-11-13 13:40:19 +08:00
parent ea0c6a8b16
commit 984ccccc63
63 changed files with 12099 additions and 83 deletions

View File

@@ -0,0 +1,169 @@
package integration
import (
"context"
"net/http/httptest"
"testing"
"github.com/break/junhong_cmp_fiber/internal/handler"
"github.com/gofiber/fiber/v2"
"github.com/redis/go-redis/v9"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
// TestHealthCheckNormal 测试健康检查 - 正常状态
func TestHealthCheckNormal(t *testing.T) {
// 初始化日志
logger, _ := zap.NewDevelopment()
// 初始化内存数据库
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
require.NoError(t, err)
// 初始化 Redis 客户端(使用本地 Redis
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
DB: 0,
})
defer rdb.Close()
// 创建 Fiber 应用
app := fiber.New()
// 创建健康检查处理器
healthHandler := handler.NewHealthHandler(db, rdb, logger)
app.Get("/health", healthHandler.Check)
// 发送测试请求
req := httptest.NewRequest("GET", "/health", nil)
resp, err := app.Test(req)
require.NoError(t, err)
defer resp.Body.Close()
// 验证响应状态码
assert.Equal(t, 200, resp.StatusCode)
// 验证响应内容
// 注意:这里可以进一步解析 JSON 响应体验证详细信息
}
// TestHealthCheckDatabaseDown 测试健康检查 - 数据库异常
func TestHealthCheckDatabaseDown(t *testing.T) {
t.Skip("需要模拟数据库连接失败的场景")
// 初始化日志
logger, _ := zap.NewDevelopment()
// 初始化一个会失败的数据库连接
db, err := gorm.Open(sqlite.Open("/invalid/path/test.db"), &gorm.Config{})
if err != nil {
// 预期会失败
t.Log("数据库连接失败(预期行为)")
}
// 初始化 Redis 客户端
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
DB: 0,
})
defer rdb.Close()
// 创建 Fiber 应用
app := fiber.New()
// 创建健康检查处理器
healthHandler := handler.NewHealthHandler(db, rdb, logger)
app.Get("/health", healthHandler.Check)
// 发送测试请求
req := httptest.NewRequest("GET", "/health", nil)
resp, err := app.Test(req)
require.NoError(t, err)
defer resp.Body.Close()
// 验证响应状态码应该是 503 (Service Unavailable)
assert.Equal(t, 503, resp.StatusCode)
}
// TestHealthCheckRedisDown 测试健康检查 - Redis 异常
func TestHealthCheckRedisDown(t *testing.T) {
// 初始化日志
logger, _ := zap.NewDevelopment()
// 初始化内存数据库
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
require.NoError(t, err)
// 初始化一个连接到无效地址的 Redis 客户端
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:9999", // 无效端口
DB: 0,
})
defer rdb.Close()
// 创建 Fiber 应用
app := fiber.New()
// 创建健康检查处理器
healthHandler := handler.NewHealthHandler(db, rdb, logger)
app.Get("/health", healthHandler.Check)
// 发送测试请求
req := httptest.NewRequest("GET", "/health", nil)
resp, err := app.Test(req)
require.NoError(t, err)
defer resp.Body.Close()
// 验证响应状态码应该是 503 (Service Unavailable)
assert.Equal(t, 503, resp.StatusCode)
}
// TestHealthCheckDetailed 测试健康检查 - 验证详细信息
func TestHealthCheckDetailed(t *testing.T) {
// 初始化日志
logger, _ := zap.NewDevelopment()
// 初始化内存数据库
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
require.NoError(t, err)
// 初始化 Redis 客户端
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
DB: 0,
})
defer rdb.Close()
// 测试 Redis 连接
ctx := context.Background()
_, err = rdb.Ping(ctx).Result()
if err != nil {
t.Skip("Redis 未运行,跳过测试")
}
// 创建 Fiber 应用
app := fiber.New()
// 创建健康检查处理器
healthHandler := handler.NewHealthHandler(db, rdb, logger)
app.Get("/health", healthHandler.Check)
// 发送测试请求
req := httptest.NewRequest("GET", "/health", nil)
resp, err := app.Test(req)
require.NoError(t, err)
defer resp.Body.Close()
// 验证响应状态码
assert.Equal(t, 200, resp.StatusCode)
// TODO: 解析 JSON 响应并验证包含以下字段:
// - status: "healthy"
// - postgres: "up"
// - redis: "up"
// - timestamp
}