## ADDED Requirements

### Requirement: 设备停机接口

系统 SHALL 提供设备停机接口，批量停用设备下所有已实名卡，并建立停机保护期。

**API 端点**: `POST /api/admin/assets/device/:device_id/stop`

**执行流程**:
1. 验证设备存在（不存在返回 HTTP 404）
2. 检查设备是否在保护期（`RedisDeviceProtectKey(deviceID, "stop")` 或 `"start"` 存在则返回 HTTP 403）
3. 获取该设备所有已实名（`real_name_status = 1`）的绑定卡
4. 遍历调用网关停机接口（未实名卡跳过，永远是停机状态）
5. 更新成功停机的卡的 `network_status = 0`，`stopped_at = now()`，`stop_reason = "manual"`
6. 在 Redis 中设置停机保护期：`RedisDeviceProtectKey(deviceID, "stop")`，TTL = 1 小时
7. 响应：返回成功，附带失败卡列表（如有）

**保护期说明**:
- 保护期时长：1 小时（常量 `DeviceProtectPeriodDuration = 1 * time.Hour`，定义在 `pkg/constants/`）
- 停机保护期 key：`protect:device:{device_id}:stop`
- 复机保护期 key：`protect:device:{device_id}:start`
- 两个 key 互斥：设置 stop 保护期时删除 start 保护期，反之亦然

**批量部分失败策略**:
- 部分卡调网关失败：**仍设置** Redis 保护期（保护期从发起操作时算起）
- 已成功停机的卡**不回滚**
- 失败的卡记录 Error 日志，响应体中携带失败列表

#### Scenario: 成功执行设备停机

- **WHEN** 管理员调用 `POST /api/admin/assets/device/456/stop`，该设备有 3 张已实名卡
- **THEN** 系统批量调网关停机，更新 3 张卡 network_status=0，设置 1 小时 stop 保护期，返回成功

#### Scenario: 设备存在保护期

- **WHEN** 管理员在设备已有 stop 保护期时再次调用停机接口
- **THEN** 系统返回 HTTP 403，提示"设备处于保护期，不允许操作"

#### Scenario: 设备下无已实名卡

- **WHEN** 管理员对只有未实名卡的设备执行停机
- **THEN** 系统返回成功（0 张卡操作），设置 stop 保护期

#### Scenario: 设备不存在

- **WHEN** 管理员调用不存在的设备 ID
- **THEN** 系统返回 HTTP 404

#### Scenario: 部分卡停机失败

- **WHEN** 设备有 3 张卡，1 张网关调用失败
- **THEN** 2 张成功停机，1 张失败记录日志，**仍设置** stop 保护期，响应中包含失败卡信息

---

### Requirement: 设备复机接口

系统 SHALL 提供设备复机接口，批量恢复设备下所有已实名卡，并建立复机保护期。

**API 端点**: `POST /api/admin/assets/device/:device_id/start`

**执行流程**:
1. 验证设备存在（不存在返回 HTTP 404）
2. 检查设备是否在保护期（stop 或 start 保护期均存在时返回 HTTP 403）
3. 获取该设备所有已实名（`real_name_status = 1`）的绑定卡
4. 遍历调用网关复机接口
5. 更新成功复机的卡的 `network_status = 1`，`resumed_at = now()`
6. 设置复机保护期：`RedisDeviceProtectKey(deviceID, "start")`，TTL = 1 小时
7. 响应：返回成功

#### Scenario: 成功执行设备复机

- **WHEN** 管理员调用 `POST /api/admin/assets/device/456/start`，该设备有 2 张已实名卡
- **THEN** 系统批量复机，更新卡状态，设置 1 小时 start 保护期，返回成功

#### Scenario: 设备在 start 保护期内再次复机

- **WHEN** 设备已有 start 保护期时再次调用复机接口
- **THEN** 系统返回 HTTP 403，提示"设备处于保护期，不允许操作"

---

### Requirement: 卡停机接口

系统 SHALL 提供单卡停机接口，含保护期感知逻辑。

**API 端点**: `POST /api/admin/assets/card/:iccid/stop`

**执行流程**:
1. 通过 ICCID 查找卡（不存在返回 HTTP 404）
2. 检查卡是否已实名（`real_name_status = 0` 时返回 HTTP 403：未实名卡不允许停复机）
3. 若卡绑定了设备，检查该设备的保护期：
   - 设备有 **stop 保护期**：允许停机（本已是停机方向，无冲突）
   - 设备有 **start 保护期**：允许停机（用户可主动停单张卡）
   - 设备无保护期：正常执行
4. 调用网关停机接口
5. 更新卡 `network_status = 0`，`stopped_at = now()`，`stop_reason = "manual"`

#### Scenario: 独立卡（未绑定设备）停机

- **WHEN** 管理员对一张未绑定设备的已实名卡执行停机
- **THEN** 系统正常调网关停机，更新卡状态

#### Scenario: 绑定设备且设备在 start 保护期内停机

- **WHEN** 管理员对绑定了设备且设备有 start 保护期的卡执行停机
- **THEN** 系统允许执行（用户主动停单张卡不违反 start 保护期），正常停机

#### Scenario: 对未实名卡执行停机

- **WHEN** 管理员对 real_name_status=0（未实名）的卡执行停机
- **THEN** 系统返回 HTTP 403，提示"未实名卡不允许停复机操作"

---

### Requirement: 卡复机接口

系统 SHALL 提供单卡复机接口，含保护期感知逻辑。

**API 端点**: `POST /api/admin/assets/card/:iccid/start`

**执行流程**:
1. 通过 ICCID 查找卡（不存在返回 HTTP 404）
2. 检查卡是否已实名（`real_name_status = 0` 时返回 HTTP 403）
3. 若卡绑定了设备，检查该设备的保护期：
   - 设备有 **stop 保护期**：**不允许**手动复机，返回 HTTP 403（设备处于停机保护期）
   - 设备有 **start 保护期**：允许复机（本已是复机方向，无冲突）
   - 设备无保护期：正常执行
4. 调用网关复机接口
5. 更新卡 `network_status = 1`，`resumed_at = now()`，清空 `stop_reason`

#### Scenario: 独立卡（未绑定设备）复机

- **WHEN** 管理员对一张未绑定设备的已实名停机卡执行复机
- **THEN** 系统正常调网关复机，更新卡状态

#### Scenario: 设备处于 stop 保护期时尝试复机

- **WHEN** 管理员对绑定了设备且设备有 stop 保护期的卡执行复机
- **THEN** 系统返回 HTTP 403，提示"设备处于停机保护期，不允许手动复机"

#### Scenario: 设备在 start 保护期内复机

- **WHEN** 管理员对绑定了设备且设备有 start 保护期的卡执行复机
- **THEN** 系统允许执行（本已是复机方向），正常复机

#### Scenario: 对未实名卡执行复机

- **WHEN** 管理员对 real_name_status=0 的卡执行复机
- **THEN** 系统返回 HTTP 403，提示"未实名卡不允许停复机操作"

---

### Requirement: 废弃旧停复机接口

系统 SHALL 删除以下重复的停复机接口，统一使用新的 `/api/admin/assets/` 路径。

**待删除接口**:
- `POST /api/admin/enterprises/:id/cards/:card_id/suspend`
- `POST /api/admin/enterprises/:id/cards/:card_id/resume`
- `POST /h5/devices/:device_id/cards/:card_id/suspend`
- `POST /h5/devices/:device_id/cards/:card_id/resume`
- 旧 Admin 卡停复机接口（`POST /iot-cards/:iccid/suspend|resume`）

#### Scenario: 调用已删除的旧接口

- **WHEN** 前端调用 `POST /api/admin/enterprises/:id/cards/:card_id/suspend`
- **THEN** 系统返回 HTTP 404（路由已不存在）
