# 数据库表结构设计

基于 `软件系统说明.docx` 整理。本文档用于把已知数据实体推进到表级字段草案，便于后续直接转成 DDL。

本文档仍然遵循一个原则：不把文档未确认的业务规则写成既定事实。以下字段草案中，凡是来源仅为"推导"而非"文档原文确认"的，会标明"待确认"。所有表名、字段名均为设计阶段讨论名，不代表最终数据库列名。

## 全局设计约定

以下约定建议在所有表统一采用：

- 主键：统一使用自增 `id`，类型 `BIGINT UNSIGNED`，具体方案待确认
- 时间字段：`created_at`、`updated_at`，类型 `DATETIME`，时区统一为待确认
- 软删：建议统一使用 `deleted_at`，值为 `NULL` 表示未删除，具体策略待确认
- 字符集：建议统一 `utf8mb4`
- 审计：建议所有表至少保留 `created_at` 和 `updated_at`

## 已确认逻辑表

- `users`
- `devices`
- `bindings`
- `subscriptions`
- `sessions`
- `treatment_records`
- `pd_data`
- `operation_logs`

## 表级字段草案

### `users`

承载用户身份与账号信息。

| 字段名 | 建议类型 | 是否必填 | 默认值 | 来源 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `id` | `BIGINT UNSIGNED` | 是 | 自增 | 约定 | 主键 |
| `openid` | `VARCHAR(128)` | 是 | 无 | 推导 | 微信用户唯一标识，待确认字段名 |
| `union_id` | `VARCHAR(128)` | 否 | `NULL` | 推导 | 微信开放平台跨应用标识，待确认是否需要 |
| `nickname` | `VARCHAR(64)` | 否 | `NULL` | 推导 | 用户昵称，待确认是否存储 |
| `avatar_url` | `VARCHAR(512)` | 否 | `NULL` | 推导 | 用户头像地址，待确认是否存储 |
| `phone` | `VARCHAR(32)` | 否 | `NULL` | 推导 | 手机号，待确认是否需要 |
| `status` | `TINYINT UNSIGNED` | 是 | `1` | 推导 | 用户状态枚举，待确认 |
| `created_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP` | 约定 | 创建时间 |
| `updated_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP ON UPDATE` | 约定 | 更新时间 |
| `deleted_at` | `DATETIME` | 否 | `NULL` | 约定 | 软删时间 |

建议唯一索引：`openid`

建议状态枚举（待确认）：

| 值 | 含义 |
| --- | --- |
| `1` | 正常 |
| `2` | 禁用 |
| `3` | 注销 |

### `devices`

承载设备主数据。

| 字段名 | 建议类型 | 是否必填 | 默认值 | 来源 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `id` | `BIGINT UNSIGNED` | 是 | 自增 | 约定 | 主键 |
| `device_sn` | `VARCHAR(64)` | 是 | 无 | 推导 | 设备序列号，作为设备唯一业务标识，待确认字段名和格式 |
| `product_id` | `VARCHAR(64)` | 是 | 无 | 文档确认 | IoT 平台产品 ID |
| `device_name` | `VARCHAR(128)` | 是 | 无 | 文档确认 | IoT 平台设备名称 |
| `firmware_version` | `VARCHAR(32)` | 否 | `NULL` | 推导 | 当前固件版本 |
| `hardware_version` | `VARCHAR(32)` | 否 | `NULL` | 推导 | 硬件版本 |
| `status` | `TINYINT UNSIGNED` | 是 | `1` | 推导 | 设备状态枚举，待确认 |
| `activated_at` | `DATETIME` | 否 | `NULL` | 推导 | 首次激活时间 |
| `created_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP` | 约定 | 创建时间 |
| `updated_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP ON UPDATE` | 约定 | 更新时间 |
| `deleted_at` | `DATETIME` | 否 | `NULL` | 约定 | 软删时间 |

建议唯一索引：`device_sn`

建议状态枚举（待确认）：

| 值 | 含义 |
| --- | --- |
| `1` | 未激活 |
| `2` | 已激活 |
| `3` | 禁用 |
| `4` | 故障 |

### `bindings`

承载用户与设备的绑定关系。

| 字段名 | 建议类型 | 是否必填 | 默认值 | 来源 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `id` | `BIGINT UNSIGNED` | 是 | 自增 | 约定 | 主键 |
| `user_id` | `BIGINT UNSIGNED` | 是 | 无 | 推导 | 关联 `users.id` |
| `device_id` | `BIGINT UNSIGNED` | 是 | 无 | 推导 | 关联 `devices.id` |
| `status` | `TINYINT UNSIGNED` | 是 | `1` | 推导 | 绑定状态枚举，待确认 |
| `bound_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP` | 推导 | 绑定时间 |
| `unbound_at` | `DATETIME` | 否 | `NULL` | 推导 | 解绑时间 |
| `created_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP` | 约定 | 创建时间 |
| `updated_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP ON UPDATE` | 约定 | 更新时间 |

建议索引：`user_id` + `status`，`device_id` + `status`

建议状态枚举（待确认）：

| 值 | 含义 |
| --- | --- |
| `1` | 有效 |
| `2` | 已解绑 |

待确认关系约束：

- 同一时刻一个用户是否只能绑定一台设备
- 同一时刻一台设备是否只能绑定一个用户
- 解绑后是否保留历史记录

### `subscriptions`

承载试用与正式订阅信息。

| 字段名 | 建议类型 | 是否必填 | 默认值 | 来源 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `id` | `BIGINT UNSIGNED` | 是 | 自增 | 约定 | 主键 |
| `user_id` | `BIGINT UNSIGNED` | 是 | 无 | 推导 | 关联 `users.id`，待确认是否同时关联设备 |
| `device_id` | `BIGINT UNSIGNED` | 否 | `NULL` | 推导 | 关联 `devices.id`，待确认是否需要 |
| `type` | `TINYINT UNSIGNED` | 是 | 无 | 推导 | 订阅类型枚举 |
| `status` | `TINYINT UNSIGNED` | 是 | `1` | 推导 | 订阅状态枚举 |
| `started_at` | `DATETIME` | 是 | 无 | 推导 | 生效时间 |
| `expired_at` | `DATETIME` | 是 | 无 | 推导 | 到期时间 |
| `source` | `VARCHAR(32)` | 否 | `NULL` | 推导 | 来源说明，如 `trial_grant`、`manual_create`、`purchase`，待确认 |
| `source_id` | `VARCHAR(64)` | 否 | `NULL` | 推导 | 来源关联 ID，如订单号，待确认是否有订单概念 |
| `created_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP` | 约定 | 创建时间 |
| `updated_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP ON UPDATE` | 约定 | 更新时间 |

建议索引：`user_id` + `status`，`user_id` + `type`

建议类型枚举（待确认）：

| 值 | 含义 |
| --- | --- |
| `1` | 试用 |
| `2` | 正式 |
| `3` | 赠送 |

建议状态枚举（待确认）：

| 值 | 含义 |
| --- | --- |
| `1` | 有效 |
| `2` | 已过期 |
| `3` | 已停用 |

### `sessions`

承载一次治疗会话的过程态。

| 字段名 | 建议类型 | 是否必填 | 默认值 | 来源 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `id` | `BIGINT UNSIGNED` | 是 | 自增 | 约定 | 主键 |
| `user_id` | `BIGINT UNSIGNED` | 是 | 无 | 推导 | 关联 `users.id` |
| `device_id` | `BIGINT UNSIGNED` | 是 | 无 | 推导 | 关联 `devices.id` |
| `status` | `TINYINT UNSIGNED` | 是 | `1` | 推导 | 会话状态枚举 |
| `started_at` | `DATETIME` | 否 | `NULL` | 推导 | 会话开始时间 |
| `ended_at` | `DATETIME` | 否 | `NULL` | 推导 | 会话结束时间 |
| `created_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP` | 约定 | 创建时间 |
| `updated_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP ON UPDATE` | 约定 | 更新时间 |

建议索引：`user_id` + `status`，`device_id`

建议状态枚举（待确认）：

| 值 | 含义 |
| --- | --- |
| `1` | 进行中 |
| `2` | 已完成 |
| `3` | 已中断 |
| `4` | 失败 |

待确认边界：`sessions` 与 `treatment_records` 是否一对一。

### `treatment_records`

承载治疗结果记录。

| 字段名 | 建议类型 | 是否必填 | 默认值 | 来源 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `id` | `BIGINT UNSIGNED` | 是 | 自增 | 约定 | 主键 |
| `session_id` | `BIGINT UNSIGNED` | 是 | 无 | 推导 | 关联 `sessions.id`，待确认一对一还是一对多 |
| `user_id` | `BIGINT UNSIGNED` | 是 | 无 | 推导 | 关联 `users.id`，冗余查询用 |
| `device_id` | `BIGINT UNSIGNED` | 是 | 无 | 推导 | 关联 `devices.id`，冗余查询用 |
| `duration_seconds` | `INT UNSIGNED` | 否 | `NULL` | 推导 | 治疗时长秒数，待确认字段名和单位 |
| `mode` | `TINYINT UNSIGNED` | 否 | `NULL` | 推导 | 治疗模式，待确认枚举 |
| `result_summary` | `VARCHAR(512)` | 否 | `NULL` | 推导 | 结果摘要，待确认格式 |
| `sync_status` | `TINYINT UNSIGNED` | 是 | `1` | 推导 | 同步状态，用于追踪异步写入 |
| `synced_at` | `DATETIME` | 否 | `NULL` | 推导 | 同步完成时间 |
| `started_at` | `DATETIME` | 否 | `NULL` | 推导 | 治疗开始时间 |
| `ended_at` | `DATETIME` | 否 | `NULL` | 推导 | 治疗结束时间 |
| `created_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP` | 约定 | 创建时间 |
| `updated_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP ON UPDATE` | 约定 | 更新时间 |

建议索引：`user_id` + `started_at`，`session_id`，`sync_status`

建议同步状态枚举（待确认）：

| 值 | 含义 |
| --- | --- |
| `1` | 待同步 |
| `2` | 已同步 |
| `3` | 同步失败 |

### `pd_data`

承载与 `PD` 相关的数据。

当前只知道该表存在，字段无法推导。

| 字段名 | 建议类型 | 是否必填 | 默认值 | 来源 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `id` | `BIGINT UNSIGNED` | 是 | 自增 | 约定 | 主键 |
| `session_id` | `BIGINT UNSIGNED` | 否 | `NULL` | 推导 | 关联 `sessions.id`，待确认 |
| `device_id` | `BIGINT UNSIGNED` | 否 | `NULL` | 推导 | 关联 `devices.id`，待确认 |
| `data_payload` | 待定义 | 待定义 | 待定义 | 待定义 | 数据内容，格式和结构完全未确认 |
| `recorded_at` | `DATETIME` | 否 | `NULL` | 推导 | 采集时间 |
| `created_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP` | 约定 | 创建时间 |

待确认：

- `PD` 的含义和数据来源
- 是否为高频时序数据
- 是否需要单独存储引擎
- 是否按会话切片

### `operation_logs`

承载操作日志。

| 字段名 | 建议类型 | 是否必填 | 默认值 | 来源 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `id` | `BIGINT UNSIGNED` | 是 | 自增 | 约定 | 主键 |
| `operator_type` | `TINYINT UNSIGNED` | 是 | 无 | 推导 | 操作者类型，区分管理员和系统 |
| `operator_id` | `BIGINT UNSIGNED` | 否 | `NULL` | 推导 | 操作者 ID，关联 `users` 或后台管理员表 |
| `target_type` | `VARCHAR(32)` | 是 | 无 | 推导 | 操作对象类型，如 `user`、`device`、`subscription`、`binding` |
| `target_id` | `BIGINT UNSIGNED` | 否 | `NULL` | 推导 | 操作对象 ID |
| `action` | `VARCHAR(32)` | 是 | 无 | 推导 | 操作类型，如 `create`、`update`、`delete`、`bind`、`unbind` |
| `before_snapshot` | `TEXT` | 否 | `NULL` | 推导 | 操作前数据快照，待确认格式 |
| `after_snapshot` | `TEXT` | 否 | `NULL` | 推导 | 操作后数据快照，待确认格式 |
| `ip_address` | `VARCHAR(64)` | 否 | `NULL` | 推导 | 操作来源 IP |
| `user_agent` | `VARCHAR(256)` | 否 | `NULL` | 推导 | 操作来源客户端标识 |
| `remark` | `VARCHAR(256)` | 否 | `NULL` | 推导 | 备注说明 |
| `created_at` | `DATETIME` | 是 | `CURRENT_TIMESTAMP` | 约定 | 创建时间 |

建议索引：`target_type` + `target_id`，`operator_type` + `operator_id`，`created_at`

建议操作者类型枚举（待确认）：

| 值 | 含义 |
| --- | --- |
| `1` | 管理员 |
| `2` | 系统自动 |

## 实体关系总结

| 关系 | 左侧 | 右侧 | 类型 | 待确认 |
| --- | --- | --- | --- | --- |
| 用户绑定设备 | `users` | `devices` | 通过 `bindings` 多对多 | 是，实际可能接近一对一 |
| 用户拥有订阅 | `users` | `subscriptions` | 一对多 | 否 |
| 设备关联订阅 | `devices` | `subscriptions` | 待确认 | 是，是否需要关联 |
| 用户发起会话 | `users` | `sessions` | 一对多 | 否 |
| 设备执行会话 | `devices` | `sessions` | 一对多 | 否 |
| 会话产生记录 | `sessions` | `treatment_records` | 待确认 | 是，一对一还是一对多 |
| 会话产生 PD 数据 | `sessions` | `pd_data` | 待确认 | 是 |
| 操作日志记录对象 | `operation_logs` | 各业务表 | 多态关联 | 否 |

## 每张表仍需补齐的设计项

后续推进到 DDL 时，每张表至少还需要：

- 确认主键方案
- 确认字段类型和长度
- 确认枚举值
- 确认时区约定
- 确认软删策略
- 补充 DDL
- 补充索引设计
- 补充迁移脚本

## 当前结论

当前说明已经足够把数据库推进到"字段草案"层。所有标为"推导"的字段都需要在下一步被确认或修正。最优先要确认的是 `users` 与 `devices` 的绑定约束、`subscriptions` 的归属模型、`sessions` 与 `treatment_records` 的关系。
