## Context

当前系统的企业卡授权功能存在权限控制不当的问题。现有实现使用 `asset_allocation_record` 表记录授权关系，但该表设计用于资产分配而非授权管理。此外，授权逻辑未正确实现单卡授权限制，权限控制不够精细。

**现状问题**：
- 授权记录存储位置不当（使用了资产分配表）
- 缺少对已绑定设备的卡的授权限制
- 企业可以看到不应该看到的商业敏感信息
- 权限控制逻辑分散，没有统一的授权管理

**技术约束**：
- 必须保持向后兼容，不能影响现有的卡分配功能
- 需要遵循项目的 GORM 数据权限自动过滤机制
- 不使用外键约束，关联通过代码层维护

## Goals / Non-Goals

**Goals:**
- 实现真正的单卡授权，授权不转移所有权
- 建立专用的授权记录表 `enterprise_card_authorization`
- 实现细粒度的权限控制，保护商业敏感数据
- 支持授权的创建、查询、回收全生命周期管理
- 与现有的 GORM 数据权限过滤机制无缝集成

**Non-Goals:**
- 不改变现有的卡分配（allocation）功能
- 不支持设备级授权（已绑定设备的卡不能单独授权）
- 不支持授权转移（必须先回收再重新授权）
- 不实现授权审批流程（直接授权生效）

## Decisions

### 1. 新建专用授权表

**决策**：创建 `enterprise_card_authorization` 表专门管理授权关系

**理由**：
- 授权和分配是两个不同的业务概念，应该分离存储
- 专用表可以更好地记录授权历史（包括回收记录）
- 避免污染现有的 `asset_allocation_record` 表结构

**备选方案**：
- 复用 `asset_allocation_record` 表：会混淆授权和分配的概念，且表结构不完全匹配
- 在 `iot_cards` 表添加授权字段：无法记录授权历史，且一张卡可能被多次授权/回收

### 2. 数据权限过滤集成

**决策**：通过修改现有的 IoT 卡查询逻辑，在 Store 层集成授权检查

**实现方式**：
```go
// 企业用户查询时的过滤逻辑
if userType == UserTypeEnterprise {
    db = db.Where("owner_type = ? AND owner_id = ?", "enterprise", enterpriseID).
        Or(db.Where("id IN (?)", 
            db.Table("enterprise_card_authorization").
            Select("card_id").
            Where("enterprise_id = ? AND revoked_at IS NULL", enterpriseID)))
}
```

**理由**：
- 利用现有的 GORM Callback 机制，自动应用权限过滤
- 保持查询接口不变，上层代码无需修改
- 统一的权限控制点，易于维护

### 3. 敏感信息过滤

**决策**：在 Handler 层对响应数据进行后处理，移除敏感字段

**实现方式**：
- Service 层返回完整数据
- Handler 层检查用户类型，如果是企业用户则清空敏感字段
- 敏感字段：`cost_price`、`distribute_price`、`supplier`

**理由**：
- 保持 Service 层的通用性，不同场景可能需要不同的字段过滤
- Handler 层更接近展示层，适合做展示相关的数据处理
- 便于未来扩展不同用户类型的字段过滤规则

### 4. 批量授权接口设计

**决策**：提供单一的批量授权接口，不单独提供预检接口

**接口结构**：
```go
// 请求
POST /api/admin/enterprises/{enterpriseId}/authorize-cards
{
    "card_ids": [1, 2, 3]
}

// 响应
{
    "success": [
        {"card_id": 1, "iccid": "8986..."}
    ],
    "failed": [
        {"card_id": 2, "iccid": "8986...", "reason": "卡已绑定设备"},
        {"card_id": 3, "iccid": "8986...", "reason": "卡状态不是已分销"}
    ]
}
```

**理由**：
- 减少网络往返，提高性能
- 简化前端实现，一次调用获得所有结果
- 支持部分成功的场景，提高容错性

## Risks / Trade-offs

### 性能风险

**风险**：企业用户查询卡列表时需要 JOIN 授权表，可能影响查询性能

**缓解措施**：
- 在 `enterprise_card_authorization` 表的 `enterprise_id` 和 `revoked_at` 字段建立联合索引
- 在 `card_id` 字段建立索引支持反向查询
- 考虑未来使用 Redis 缓存授权关系

### 数据一致性

**风险**：授权记录和卡状态可能不一致（如卡被删除但授权记录还在）

**缓解措施**：
- 使用软删除，保留历史数据
- 定期运行数据一致性检查任务
- 在查询时过滤已删除的卡

### 权限泄露风险

**风险**：敏感信息过滤不完整可能导致商业数据泄露

**缓解措施**：
- 在 Handler 层统一处理，确保所有接口都经过过滤
- 添加单元测试验证敏感字段确实被过滤
- 考虑使用 DTO 模式，为不同用户类型定义不同的响应结构

## Migration Plan

### 部署步骤

1. **数据库迁移**
   - 创建 `enterprise_card_authorization` 表
   - 添加必要的索引

2. **代码部署**
   - 部署新的授权管理代码
   - 保持旧的分配接口正常工作

3. **数据迁移**（如需要）
   - 如果有历史授权数据在 `asset_allocation_record` 表，编写迁移脚本
   - 迁移完成后可以清理旧数据

### 回滚策略

- 代码支持功能开关，可通过配置禁用新的授权功能
- 数据库表独立，不影响现有功能，可保留表结构
- 如需完全回滚，删除新表并恢复旧代码

## Open Questions

1. **授权有效期**：是否需要支持授权有效期？目前设计是永久授权直到主动回收
2. **授权数量限制**：是否需要限制一个企业可以被授权的卡数量？
3. **通知机制**：授权/回收时是否需要通知企业？
4. **审计日志**：是否需要更详细的授权操作日志？