# 数据库表结构设计 基于 `软件系统说明.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` 的关系。