# Model Organization

## Purpose

定义项目中数据模型（Model）的组织规范，确保所有模型遵循统一的目录结构和命名约定。

本规范支持：
- 统一的模型目录结构（`internal/model/`）
- 横向分层架构（Handler → Service → Store → Model）
- 扁平化包组织（符合 Go 语言最佳实践）
- 跨模块的模型共享和引用

## ADDED 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_case）：`user_account.go`、`iot_card.go`、`shop_order.go`
- 文件名应该清晰描述模型的业务含义，不使用缩写（除非是广泛认可的缩写如 `iot`、`http`）
- 一个文件可以包含一个或多个相关模型（如 `iot_card.go` 可以包含 `IotCard` 和 `IotCardDTO`）
- DTO 模型应该与主模型放在同一个文件中（如 `IotCard` 和 `IotCardDTO` 都在 `iot_card.go` 中）

**文件内容结构：**

```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.go` 或 `deviceBinding.go`

#### Scenario: DTO 模型放置位置

- **WHEN** 开发者为 `IotCard` 模型创建 DTO（`IotCardDTO`）
- **THEN** 系统要求 DTO 定义在同一个文件 `iot_card.go` 中，而不是创建新文件 `iot_card_dto.go`

---

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

系统 SHALL 禁止按业务模块（如 `iot`、`user`、`order`）创建独立的模型子目录，所有模型必须扁平化组织在 `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/` 目录

