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

@@ -1,5 +1,90 @@
Version Change: 2.2.0 → 2.3.0
Date: 2025-11-11
NEW PRINCIPLES ADDED:
- VIII. Access Logging Standards (访问日志规范) - NEW principle for comprehensive request/response logging
MODIFIED SECTIONS:
- Added new Principle VIII with mandatory access logging requirements
- Rule: ALL requests MUST be logged to access.log without exception
- Rule: Request parameters (query + body) MUST be logged (limited to 50KB)
- Rule: Response parameters (body) MUST be logged (limited to 50KB)
- Rule: Logging MUST happen via centralized Logger middleware
- Rule: No middleware can bypass access logging (including auth failures)
- Rule: Body truncation MUST indicate "... (truncated)" when over limit
- Rationale for comprehensive logging: debugging, audit trails, compliance
TEMPLATES REQUIRING UPDATES:
✅ .specify/templates/plan-template.md - Added access logging check in Constitution Check
✅ .specify/templates/tasks-template.md - Added access logging verification in Quality Gates
FOLLOW-UP ACTIONS:
- None required - logging implementation already completed
RATIONALE:
MINOR version bump (2.3.0) - New principle added for access logging standards.
This establishes a mandatory governance rule that ALL HTTP requests must be logged
with complete request and response data, regardless of middleware short-circuiting
(auth failures, rate limits, etc.). This ensures:
1. Complete audit trail for all API interactions
2. Debugging capability for all failure scenarios
3. Compliance with logging requirements
4. No special cases or exceptions in logging
This is a MINOR bump (not PATCH) because it adds a new mandatory principle that
affects the development workflow and quality gates, requiring verification that
all middleware respects the logging standard.
-->
<!--
SYNC IMPACT REPORT - Constitution Amendment
Version Change: 2.3.0 → 2.4.0
Date: 2025-11-13
NEW PRINCIPLES ADDED:
- IX. Database Design Principles (数据库设计原则) - NEW principle for database schema and ORM relationship management
MODIFIED SECTIONS:
- Added new Principle IX with mandatory database design requirements
- Rule: Database tables MUST NOT have foreign key constraints
- Rule: GORM models MUST NOT use ORM association tags (foreignKey, hasMany, belongsTo, etc.)
- Rule: Table relationships MUST be maintained manually via ID fields
- Rule: Associated data queries MUST be explicit in code, not ORM magic
- Rule: Model structs MUST ONLY contain simple fields
- Rule: Migration scripts MUST NOT include foreign key constraints
- Rule: Migration scripts MUST NOT include triggers for relationship maintenance
- Rule: Time fields (created_at, updated_at) MUST be handled by GORM, not database triggers
- Rationale: Flexibility, performance, simplicity, maintainability, distributed-friendly
TEMPLATES REQUIRING UPDATES:
⚠️ .specify/templates/plan-template.md - Should add database design principle check
⚠️ .specify/templates/tasks-template.md - Should add migration script validation
FOLLOW-UP ACTIONS:
- Migration scripts updated (removed foreign keys and triggers)
- User and Order models updated (removed GORM associations)
- OrderService.ListOrdersByUserID added for manual relationship queries
RATIONALE:
MINOR version bump (2.4.0) - New principle added for database design standards.
This establishes a mandatory governance rule that database relationships must NOT
be enforced at the database or ORM level, but rather managed explicitly in code.
This ensures:
1. Business logic flexibility (no database constraints limiting deletion, updates)
2. Performance (no foreign key check overhead in high-concurrency scenarios)
3. Code clarity (explicit queries, no ORM magic like N+1 queries or unexpected preloading)
4. Developer control (decide when and how to query associated data)
5. Maintainability (simpler schema, easier migrations, no complex FK dependencies)
6. Distributed-friendly (manual relationships work across databases/microservices)
7. GORM value retention (keep core features: auto timestamps, soft delete, query builder)
This is a MINOR bump (not PATCH) because it adds a new mandatory principle that
fundamentally changes how we design database schemas and model relationships,
affecting all future database-related development.
PREVIOUS AMENDMENTS:
- 2.3.0 (2025-11-11): Added Principle VIII - Access Logging Standards
- 2.2.0 (Previous): Added comprehensive code quality and Go idiomatic principles
-->
============================================
Version Change: 2.2.0 → 2.3.0
Date: 2025-11-11
@@ -53,7 +138,7 @@ all middleware respects the logging standard.
- 所有数据库操作 **MUST** 通过 GORM 进行
- 所有配置管理 **MUST** 使用 Viper
- 所有日志记录 **MUST** 使用 Zap + Lumberjack.v2
- 所有 JSON 序列化 **MUST** 使用 sonic
- 所有 JSON 序列化 **SHOULD** 优先使用 sonic,仅在必须使用标准库的场景(如某些第三方库要求)才使用 `encoding/json`
- 所有异步任务 **MUST** 使用 Asynq
- **MUST** 使用 Go 官方工具链:`go fmt``go vet``golangci-lint`
- **MUST** 使用 Go Modules 进行依赖管理
@@ -277,10 +362,28 @@ logger.Error("数据库连接失败",
zap.Error(err))
```
**函数复杂度和职责分离 (Function Complexity and Responsibility Separation):**
- 函数长度 **MUST NOT** 超过合理范围(通常 50-100 行,核心逻辑建议 ≤ 50 行)
- 超过 100 行的函数 **MUST** 拆分为多个小函数,每个函数只负责一件事
- `main()` 函数 **MUST** 只做编排orchestration不包含具体实现逻辑
- `main()` 函数中的每个初始化步骤 **SHOULD** 提取为独立的辅助函数
- 编排函数orchestrator**MUST** 清晰表达流程,避免嵌套的实现细节
- **MUST** 遵循单一职责原则Single Responsibility Principle
- 虽然 **MUST NOT** 过度封装,但 **MUST** 在职责边界清晰的地方进行适度分离
**理由 (RATIONALE):**
清晰的分层架构和代码组织使代码易于理解、测试和维护。统一的错误处理和响应格式提升 API 一致性和客户端集成体验。依赖注入模式便于单元测试和模块替换。集中管理常量和 Redis key 避免拼写错误、重复定义和命名不一致提升代码可维护性和重构安全性。Redis key 统一管理便于监控、调试和缓存策略调整。遵循 Go 官方代码风格确保代码一致性和可读性。
函数复杂度控制和职责分离的理由:
1. **可读性**: 小函数易于阅读和理解,特别是 main 函数清晰表达程序流程
2. **可测试性**: 小函数易于编写单元测试,提高测试覆盖率
3. **可维护性**: 职责单一的函数修改风险低,不易引入 bug
4. **可复用性**: 提取的辅助函数可以在其他地方复用
5. **减少认知负担**: 阅读者不需要同时理解过多细节
6. **便于重构**: 小函数更容易安全地重构和优化
避免硬编码和强制使用常量的规则能够:
1. **提高可维护性**:修改常量值只需改一处,不需要搜索所有硬编码位置
2. **减少错误**:避免手动输入错误(拼写错误、大小写错误)
@@ -1061,6 +1164,139 @@ accessLogger.Info("",
---
### IX. Database Design Principles (数据库设计原则)
**规则 (RULES):**
- 数据库表之间 **MUST NOT** 建立外键约束Foreign Key Constraints
- GORM 模型之间 **MUST NOT** 使用 ORM 关联关系(`foreignKey`、`references`、`hasMany`、`belongsTo` 等标签)
- 表之间的关联 **MUST** 通过存储关联 ID 字段手动维护
- 关联数据查询 **MUST** 在代码层面显式执行,不依赖 ORM 的自动加载Lazy Loading或预加载Eager Loading
- 模型结构体 **MUST ONLY** 包含简单字段,不应包含其他模型的嵌套引用
- 数据库迁移脚本 **MUST NOT** 包含外键约束定义
- 数据库迁移脚本 **MUST NOT** 包含触发器用于维护关联数据
- 时间字段(`created_at`、`updated_at`)的更新 **MUST** 由 GORM 自动处理,不使用数据库触发器
**正确的关联设计:**
```go
// ✅ User 模型 - 完全独立
type User struct {
BaseModel
Username string `gorm:"uniqueIndex;not null;size:50"`
Email string `gorm:"uniqueIndex;not null;size:100"`
Password string `gorm:"not null;size:255"`
Status string `gorm:"not null;size:20;default:'active'"`
}
// ✅ Order 模型 - 仅存储 UserID
type Order struct {
BaseModel
OrderID string `gorm:"uniqueIndex;not null;size:50"`
UserID uint `gorm:"not null;index"` // 仅存储 ID无 ORM 关联
Amount int64 `gorm:"not null"`
Status string `gorm:"not null;size:20;default:'pending'"`
}
// ✅ 手动查询关联数据
func (s *OrderService) GetOrderWithUser(ctx context.Context, orderID uint) (*OrderDetail, error) {
// 查询订单
order, err := s.store.Order.GetByID(ctx, orderID)
if err != nil {
return nil, err
}
// 手动查询关联的用户
user, err := s.store.User.GetByID(ctx, order.UserID)
if err != nil {
return nil, err
}
// 组装返回数据
return &OrderDetail{
Order: order,
User: user,
}, nil
}
```
**错误的关联设计(禁止):**
```go
// ❌ 使用 GORM 外键关联
type Order struct {
BaseModel
OrderID string
UserID uint
User *User `gorm:"foreignKey:UserID"` // ❌ 禁止
Amount int64
}
// ❌ 使用 GORM hasMany 关联
type User struct {
BaseModel
Username string
Orders []Order `gorm:"foreignKey:UserID"` // ❌ 禁止
}
// ❌ 在迁移脚本中定义外键约束
CREATE TABLE tb_order (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
CONSTRAINT fk_order_user FOREIGN KEY (user_id)
REFERENCES tb_user(id) ON DELETE RESTRICT -- ❌ 禁止
);
// ❌ 使用数据库触发器更新时间
CREATE TRIGGER update_order_updated_at
BEFORE UPDATE ON tb_order
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column(); -- ❌ 禁止
// ❌ 依赖 GORM 预加载
orders, err := db.Preload("User").Find(&orders) // ❌ 禁止
```
**GORM BaseModel 自动时间管理:**
```go
// ✅ GORM 自动处理时间字段
type BaseModel struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time // GORM 自动填充创建时间
UpdatedAt time.Time // GORM 自动更新修改时间
DeletedAt gorm.DeletedAt `gorm:"index"` // 软删除支持
}
// 创建记录时GORM 自动设置 CreatedAt 和 UpdatedAt
db.Create(&user)
// 更新记录时GORM 自动更新 UpdatedAt
db.Save(&user)
```
**理由 (RATIONALE):**
移除数据库外键约束和 ORM 关联关系的理由:
1. **灵活性**:业务逻辑完全在代码中控制,不受数据库约束限制。例如删除用户时可以根据业务需求决定是级联删除订单、保留订单还是转移订单,而不是被 `ON DELETE CASCADE/RESTRICT` 强制约束。
2. **性能**:无外键约束意味着无数据库层面的引用完整性检查开销。在高并发场景下,外键检查和锁竞争会成为性能瓶颈。
3. **简单直接**:显式的关联数据查询使数据流向清晰可见,代码行为明确。避免了 ORM 的"魔法"行为N+1 查询问题、意外的预加载、Lazy Loading 陷阱)。
4. **可控性**:开发者完全掌控何时查询关联数据、查询哪些关联数据。可以根据场景优化查询(批量查询、缓存等),而不是依赖 ORM 的自动行为。
5. **可维护性**:数据库 schema 更简单,迁移更容易。修改表结构不需要处理复杂的外键依赖关系。代码重构时不会被数据库约束限制。
6. **分布式友好**:在微服务和分布式数据库场景下,外键约束往往无法跨数据库工作。手动维护关联从设计上就支持未来的服务拆分。
7. **GORM 基础功能**:保留 GORM 的核心价值(自动时间管理、软删除、查询构建、事务支持),去除复杂的关联功能,达到简单性和功能性的平衡。
这种设计哲学符合"明确优于隐式"的原则,代码的行为一目了然,没有隐藏的数据库操作和 ORM 魔法。
---
## Development Workflow (开发工作流程)
### 分支管理
@@ -1171,4 +1407,4 @@ accessLogger.Info("",
---
**Version**: 2.3.0 | **Ratified**: 2025-11-10 | **Last Amended**: 2025-11-11
**Version**: 2.4.0 | **Ratified**: 2025-11-10 | **Last Amended**: 2025-11-13