Files
junhong_cmp_fiber/openspec/specs/model-organization/spec.md
huang 867e97af11 重构:统一 IoT 模型到 internal/model/ 目录
将所有 IoT 相关的数据模型从 internal/iot/model/ 迁移到 internal/model/,
实现全局统一的模型层架构,符合项目横向分层设计原则。

变更内容:
- 迁移 11 个 IoT 模型文件(carrier, iot_card, device, order, package 等)
- 删除 internal/iot/model/ 目录
- 更新文档中的模型路径引用(25 处)
- 创建重构总结文档
- 归档 OpenSpec 变更为 2026-01-12-refactor-iot-model-location
- 创建 model-organization 规格文档

验证结果:
- 编译通过(go build 成功)
- 静态分析通过(go vet 无错误)
- 代码格式通过(go fmt 无变更)
- 无 Go 代码引用旧路径

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-12 16:01:53 +08:00

6.2 KiB
Raw Blame History

model-organization Specification

Purpose

TBD - created by archiving change refactor-iot-model-location. Update Purpose after archive.

Requirements

Requirement: 统一的模型目录

系统 SHALL 将所有数据模型GORM 模型、DTO统一放置在 internal/model/ 目录下,不按业务模块分散。

核心原则:

  • 横向分层模型层Model是全局统一的不按业务模块纵向分割
  • 扁平化组织:所有模型文件直接放在 internal/model/ 目录下,不创建子目录(除非文件数量超过 50 个)
  • 统一导入路径:所有代码引用模型时统一使用 internal/model 导入路径
  • 统一包名:所有模型文件的包名统一为 package model

目录结构:

internal/
├── model/                    # 所有数据模型统一在这里
│   ├── account.go            # 账户模型
│   ├── shop.go               # 店铺模型
│   ├── enterprise.go         # 企业模型
│   ├── personal_customer.go  # 个人客户模型
│   ├── role.go               # 角色模型
│   ├── permission.go         # 权限模型
│   ├── carrier.go            # 运营商模型IoT 相关)
│   ├── iot_card.go           # IoT 卡模型IoT 相关)
│   ├── device.go             # 设备模型IoT 相关)
│   ├── order.go              # 订单模型IoT 相关)
│   ├── package.go            # 套餐模型IoT 相关)
│   └── ...                   # 其他模型
├── handler/                  # Handler 层(按功能分包)
├── service/                  # Service 层(按功能分包)
└── store/                    # Store 层(按功能分包)

Scenario: 创建新的 IoT 相关模型

  • WHEN 开发者需要创建新的 IoT 相关数据模型(如 SIMCard
  • THEN 系统要求开发者在 internal/model/sim_card.go 创建模型,而不是在 internal/iot/model/sim_card.go

Scenario: 引用 IoT 模型

  • WHEN Service 层或 Store 层需要引用 IoT 卡模型
  • THEN 系统使用统一的导入路径 internal/model,而不是 internal/iot/model

Scenario: 跨模块引用模型

  • WHEN 用户模块User需要引用 IoT 卡模型IotCard进行关联查询
  • THEN 系统允许直接从 internal/model 导入 IotCard,因为所有模型都在同一个包中

Requirement: 模型文件命名规范

系统 SHALL 遵循统一的模型文件命名规范,确保文件名清晰、一致、易于查找。

命名规则:

  • 文件名使用小写下划线命名法snake_caseuser_account.goiot_card.goshop_order.go
  • 文件名应该清晰描述模型的业务含义,不使用缩写(除非是广泛认可的缩写如 iothttp
  • 一个文件可以包含一个或多个相关模型(如 iot_card.go 可以包含 IotCardIotCardDTO
  • DTO 模型应该与主模型放在同一个文件中(如 IotCardIotCardDTO 都在 iot_card.go 中)

文件内容结构:

package model

// IotCard IoT 卡模型GORM 模型)
type IotCard struct {
    ID        uint   `gorm:"column:id;primaryKey" json:"id"`
    ICCID     string `gorm:"column:iccid;uniqueIndex" json:"iccid"`
    // ... 其他字段
}

// TableName 指定表名
func (IotCard) TableName() string {
    return "iot_cards"
}

// IotCardDTO IoT 卡 DTO数据传输对象
type IotCardDTO struct {
    ID        uint   `json:"id"`
    ICCID     string `json:"iccid"`
    // ... 其他字段
}

Scenario: 创建新模型时命名文件

  • WHEN 开发者创建新的数据模型 DeviceBinding
  • THEN 系统要求文件名为 device_binding.go,而不是 DeviceBinding.godeviceBinding.go

Scenario: DTO 模型放置位置

  • WHEN 开发者为 IotCard 模型创建 DTOIotCardDTO
  • THEN 系统要求 DTO 定义在同一个文件 iot_card.go 中,而不是创建新文件 iot_card_dto.go

Requirement: 禁止按业务模块分割模型

系统 SHALL 禁止按业务模块(如 iotuserorder)创建独立的模型子目录,所有模型必须扁平化组织在 internal/model/ 下。

禁止的目录结构:

internal/
├── model/
│   ├── user/           # ❌ 禁止按业务模块分子目录
│   │   └── user.go
│   ├── iot/            # ❌ 禁止按业务模块分子目录
│   │   └── iot_card.go
│   └── order/          # ❌ 禁止按业务模块分子目录
│       └── order.go
internal/
├── user/               # ❌ 禁止按业务模块纵向分层
│   ├── model.go
│   ├── handler.go
│   ├── service.go
│   └── store.go
├── iot/                # ❌ 禁止按业务模块纵向分层
│   ├── model/
│   │   └── iot_card.go
│   ├── handler.go
│   ├── service.go
│   └── store.go

正确的目录结构(扁平化):

internal/
├── model/              # ✅ 所有模型扁平化在一个目录
│   ├── user.go
│   ├── iot_card.go
│   └── order.go
├── handler/            # ✅ 横向分层
├── service/            # ✅ 横向分层
└── store/              # ✅ 横向分层

设计理由:

  1. 符合横向分层架构Handler → Service → Store → Model 是全局分层,不是模块分层
  2. 简化导入路径:所有模型统一使用 internal/model,不需要记忆不同模块的路径
  3. 便于跨模块引用:用户模块可以直接引用 IoT 模型,不需要跨包引用
  4. 符合 Go 语言惯用设计包应该按功能组织model而不是按业务模块组织user/model, iot/model

Scenario: 代码审查拒绝纵向分层

  • WHEN 开发者提交 PR创建了 internal/iot/model/ 目录
  • THEN 系统要求代码审查拒绝该 PR并要求开发者将模型移动到 internal/model/

Scenario: 重构现有纵向分层的模型

  • WHEN 项目中存在 internal/iot/model/ 目录
  • THEN 系统要求重构,将所有模型迁移到 internal/model/,删除 internal/iot/model/ 目录