# 设计文档：IoT 模型位置重构

## 问题陈述 (Problem Statement)

当前 IoT 模块的数据模型被放置在 `internal/iot/model/` 目录下，这与项目的架构约定不一致。根据 `openspec/project.md` 的架构规范，项目采用严格的四层架构：

```
Handler 层 → Service 层 → Store 层 → Model 层
```

其中 **Model 层** 应该是全局统一的，所有模型都应该放在 `internal/model/` 目录下。当前的 IoT 模型位置违反了这一约定。

## 当前架构问题分析

### 1. 目录结构不一致

**当前状态：**
```
internal/
├── model/                    # 大部分模型在这里
│   ├── account.go
│   ├── shop.go
│   ├── enterprise.go
│   ├── personal_customer.go
│   ├── role.go
│   ├── permission.go
│   └── ...
├── iot/
│   └── model/                # IoT 模型单独在这里 ❌
│       ├── carrier.go
│       ├── commission.go
│       ├── iot_card.go
│       └── ...
```

**存在的问题：**
- 模型分散在两个位置，违反了单一数据模型层的设计原则
- 导入路径不一致：`internal/model` vs `internal/iot/model`
- 新开发者容易困惑，不知道应该把新模型放在哪里

### 2. 违反项目架构约定

根据项目架构规范，四层架构应该是 **横向分层**，而不是 **纵向按模块分层**：

**正确的架构（横向分层）：**
```
internal/
├── handler/              # 所有 Handler
│   ├── user_handler.go
│   ├── shop_handler.go
│   └── iot_handler.go    # IoT 的 Handler
├── service/              # 所有 Service
│   ├── user_service.go
│   ├── shop_service.go
│   └── iot_service.go    # IoT 的 Service
├── store/                # 所有 Store
│   ├── user_store.go
│   ├── shop_store.go
│   └── iot_store.go      # IoT 的 Store
└── model/                # 所有 Model ✅
    ├── user.go
    ├── shop.go
    └── iot_card.go       # IoT 的 Model
```

**错误的架构（纵向按模块分层）：**
```
internal/
├── user/                 # 用户模块（纵向）
│   ├── handler.go
│   ├── service.go
│   ├── store.go
│   └── model.go
├── shop/                 # 店铺模块（纵向）
│   ├── handler.go
│   ├── service.go
│   ├── store.go
│   └── model.go
└── iot/                  # IoT 模块（纵向）❌
    ├── handler.go
    ├── service.go
    ├── store.go
    └── model/            # 违反横向分层原则
        └── iot_card.go
```

### 3. Go 语言惯用设计原则

根据 Go 语言的包组织最佳实践：

- **包应该扁平化**：避免深层嵌套（最多 2-3 层）
- **包应该按功能组织**：`model` 包应该包含所有数据模型，不是按业务模块分散
- **包名应该描述功能**：`model` 表示数据模型，而不是 `iot/model`（冗余）

当前 `internal/iot/model` 的包名虽然是 `package model`，但实际导入路径是 `internal/iot/model`，这是不必要的复杂性。

## 设计决策 (Design Decision)

**决策：** 将所有 IoT 模型迁移到 `internal/model/` 目录，与项目的其他模型保持一致。

### 为什么选择统一的 Model 层？

1. **符合项目架构约定**：遵循严格的横向四层架构（Handler → Service → Store → Model）
2. **简化导入路径**：所有模型统一使用 `internal/model` 导入
3. **提高代码可维护性**：开发者只需要在一个地方查找所有数据模型
4. **符合 Go 语言惯用设计**：扁平化包结构，按功能组织
5. **降低认知负担**：新开发者不需要猜测模型应该放在哪里

### 为什么不保留 `internal/iot/model`？

**反驳方案 1：按业务模块组织（纵向分层）**

```
internal/
├── iot/
│   ├── model/        # IoT 模型
│   ├── service/      # IoT 服务
│   └── store/        # IoT 存储
```

**缺点：**
- 违反项目架构约定（横向分层）
- 导致模型分散，难以统一管理
- 跨模块调用时需要引用不同的 model 包（如 `iot/model` 和 `internal/model`）
- 不符合当前项目已有的架构实践

**反驳方案 2：IoT 模型使用子包（`internal/model/iot`）**

```
internal/
├── model/
│   ├── user.go
│   ├── shop.go
│   └── iot/          # IoT 子包
│       └── iot_card.go
```

**缺点：**
- 引入不必要的层级嵌套
- 导入路径变为 `internal/model/iot`，不符合项目惯例
- 其他模型（User、Shop）没有子包，为什么 IoT 要特殊对待？
- 增加认知负担：需要记住哪些模型有子包，哪些没有

### 最终方案：扁平化模型目录

```
internal/
└── model/
    ├── account.go
    ├── shop.go
    ├── enterprise.go
    ├── personal_customer.go
    ├── role.go
    ├── permission.go
    ├── carrier.go          # IoT 相关模型
    ├── commission.go       # IoT 相关模型
    ├── data_usage.go       # IoT 相关模型
    ├── device.go           # IoT 相关模型
    ├── financial.go        # IoT 相关模型
    ├── iot_card.go         # IoT 相关模型
    ├── number_card.go      # IoT 相关模型
    ├── order.go            # IoT 相关模型
    ├── package.go          # IoT 相关模型
    ├── polling.go          # IoT 相关模型
    └── system.go           # IoT 相关模型
```

**优点：**
- 符合项目架构约定（横向分层）
- 所有模型统一管理，易于查找和维护
- 导入路径统一（`internal/model`）
- 符合 Go 语言扁平化包结构的最佳实践
- 与项目现有架构保持一致

## 实施风险评估

### 风险等级：低

**理由：**
1. **无代码引用**：经过搜索，当前项目中没有任何代码引用 `internal/iot/model`（因为 IoT 模块尚未完全实现）
2. **纯文件移动**：只需要移动文件，不需要修改文件内容（包名已经是 `package model`）
3. **无数据库影响**：模型位置变更不影响数据库表结构或迁移脚本
4. **无 API 影响**：模型位置变更不影响 API 接口定义

### 潜在风险

**风险 1：并发开发冲突**
- **描述**：如果在重构期间有其他开发者新增了对 `internal/iot/model` 的引用
- **缓解措施**：在重构前和重构后都执行全局搜索，确保无遗漏引用
- **恢复方案**：如果发现遗漏引用，只需要更新导入路径即可（从 `internal/iot/model` 改为 `internal/model`）

**风险 2：Git 历史追踪**
- **描述**：Git 的 `git log` 或 `git blame` 可能无法自动追踪文件移动历史
- **缓解措施**：使用 `git mv` 命令移动文件（或确保提交信息清晰说明文件移动）
- **影响评估**：低（可以通过 `git log --follow` 追踪文件历史）

## 验收标准 (Acceptance Criteria)

1. **目录结构正确**：
   - [ ] `internal/iot/model/` 目录不存在
   - [ ] 所有 11 个 IoT 模型文件都在 `internal/model/` 目录下

2. **包名一致性**：
   - [ ] 所有模型文件的包名都是 `package model`

3. **无遗漏引用**：
   - [ ] 项目中不存在 `internal/iot/model` 的引用

4. **编译成功**：
   - [ ] 执行 `go build` 成功，无错误

5. **测试通过**：
   - [ ] 执行 `go test ./...` 成功（如果存在测试）

## 后续改进建议

虽然本次重构只涉及模型位置，但建议后续也考虑其他架构一致性改进：

1. **完善 IoT Handler 层**：创建 `internal/handler/iot/` 或 `internal/handler/iot_handler.go`
2. **完善 IoT Service 层**：创建 `internal/service/iot/` 或 `internal/service/iot_service.go`
3. **完善 IoT Store 层**：创建 `internal/store/postgres/iot_store.go`
4. **删除空的 `internal/iot/` 目录**（如果迁移后为空）

## 参考资料

- **项目架构规范**：`openspec/project.md`
- **Go 包组织最佳实践**：[Effective Go - Package names](https://go.dev/doc/effective_go#package-names)
- **Go Code Review Comments**：[Go Wiki - Package names](https://go.dev/wiki/CodeReviewComments#package-names)
- **现有模型目录**：`internal/model/`
- **IoT 规格文档**：`openspec/specs/iot-card/spec.md`
