# Banban 统一数据与接口设计文档(Mini Program + talkingq-url,V3) ## 1. 目标与边界 本设计用于统一 `mini-program` 与 `talkingq-url` 的数据库模型与接口语义,目标是: 1. 两个服务使用同一套设备身份(`device_id`)。 2. 保留 `talkingq-url/mysql/init/01-init.sql` 现有表结构不变。 3. 在不改动基础表的前提下,补齐家长/小孩/绑定/聊天/定位能力。 硬性边界: 1. `01-init.sql` 中现有表不改表名、不改字段、不改约束。 2. 所有新增表仅做增量扩展。 3. 新增表字段命名风格对齐现有风格:`snake_case`、`*_id`、`is_active`、`status`、`created_at`、`updated_at`。 ## 2. 现有冻结表(来自 01-init.sql) 以下表为设备能力基础层,保持不变: 1. `device_auth`:设备身份白名单(`device_id + serial_number`)。 2. `device_configs`:设备角色与基础配置(含 `volume`)。 3. `conversation_histories`:设备与角色会话头。 4. `conversation_messages`:设备与角色会话消息。 5. `roles` / `role_languages`:角色与多语言配置。 6. `device_firmware_update`:设备固件升级状态。 7. `system_config`:系统配置项。 职责说明: 1. `conversation_histories/conversation_messages` 继续只服务“设备 <-> AI 角色”的对话,不承担家长-小孩 IM。 2. 设备鉴权统一走 `device_auth`,`device_id` 为全局设备业务标识。 ## 3. 新增主体模型 ### 3.1 家长主体表 `parents` 建议字段: 1. `user_id` BIGINT UNSIGNED PK AUTO_INCREMENT 2. `openid` VARCHAR(64) UNIQUE NOT NULL 3. `unionid` VARCHAR(64) NULL 4. `nickname` VARCHAR(64) NULL 5. `avatar_url` VARCHAR(255) NULL 6. `phone` VARCHAR(20) NULL 7. `status` TINYINT NOT NULL DEFAULT 1 8. `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP 9. `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 索引建议: 1. `uk_openid(openid)` 2. `idx_unionid(unionid)` 3. `idx_phone(phone)` ### 3.2 小孩主体表 `children` 建议字段: 1. `child_id` BIGINT UNSIGNED PK AUTO_INCREMENT 2. `child_name` VARCHAR(32) NOT NULL 3. `child_gender` TINYINT NOT NULL DEFAULT 2 4. `child_birthday` DATE NULL 5. `status` TINYINT NOT NULL DEFAULT 1 6. `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP 7. `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 说明: 1. 不在库内存储 `child_age` 计算列,年龄由查询层按时间实时计算,避免跨年缓存误差。 ### 3.3 家长-小孩关系表 `parent_child_relations` 建议字段: 1. `id` BIGINT UNSIGNED PK AUTO_INCREMENT 2. `user_id` BIGINT UNSIGNED NOT NULL 3. `child_id` BIGINT UNSIGNED NOT NULL 4. `relation_type` TINYINT NOT NULL DEFAULT 9 5. `is_primary` TINYINT(1) NOT NULL DEFAULT 0 6. `status` TINYINT NOT NULL DEFAULT 1 7. `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP 8. `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 约束建议: 1. `UNIQUE(user_id, child_id)` 2. `FOREIGN KEY (user_id) REFERENCES parents(user_id)` 3. `FOREIGN KEY (child_id) REFERENCES children(child_id)` ### 3.4 设备归属表 `device_bindings` 用途:表达“当前哪块设备绑定到哪个小孩”,并与 `device_auth` 对齐。 建议字段: 1. `id` BIGINT UNSIGNED PK AUTO_INCREMENT 2. `device_id` VARCHAR(64) NOT NULL 3. `child_id` BIGINT UNSIGNED NOT NULL 4. `status` TINYINT NOT NULL DEFAULT 1 5. `bound_at` DATETIME NOT NULL 6. `unbound_at` DATETIME NULL 7. `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP 8. `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 约束建议: 1. `UNIQUE(device_id)` 2. `UNIQUE(child_id)` 3. `FOREIGN KEY (device_id) REFERENCES device_auth(device_id)` 4. `FOREIGN KEY (child_id) REFERENCES children(child_id)` ### 3.5 绑定会话表 `device_bind_sessions` 建议字段: 1. `id` BIGINT UNSIGNED PK AUTO_INCREMENT 2. `bind_token` CHAR(36) UNIQUE NOT NULL 3. `device_id` VARCHAR(64) NOT NULL 4. `initiator_user_id` BIGINT UNSIGNED NOT NULL 5. `target_child_id` BIGINT UNSIGNED NULL 6. `challenge_code_hash` CHAR(64) NULL 7. `challenge_set_at` DATETIME NULL 8. `expires_at` DATETIME NOT NULL 9. `max_attempt_count` TINYINT UNSIGNED NOT NULL DEFAULT 5 10. `attempt_count` TINYINT UNSIGNED NOT NULL DEFAULT 0 11. `status` TINYINT NOT NULL DEFAULT 1 12. `confirmed_at` DATETIME NULL 13. `consumed_at` DATETIME NULL 14. `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP 15. `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 约束建议: 1. `FOREIGN KEY (device_id) REFERENCES device_auth(device_id)` 2. `FOREIGN KEY (initiator_user_id) REFERENCES parents(user_id)` 3. `FOREIGN KEY (target_child_id) REFERENCES children(child_id)` ### 3.6 绑定历史表 `device_bind_history` 建议字段: 1. `id` BIGINT UNSIGNED PK AUTO_INCREMENT 2. `device_id` VARCHAR(64) NOT NULL 3. `child_id` BIGINT UNSIGNED NOT NULL 4. `bound_by_user_id` BIGINT UNSIGNED NOT NULL 5. `unbound_by_user_id` BIGINT UNSIGNED NULL 6. `bind_source` TINYINT NOT NULL DEFAULT 1 7. `bound_at` DATETIME NOT NULL 8. `unbound_at` DATETIME NULL 9. `unbind_reason` VARCHAR(191) NULL 10. `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP 约束建议: 1. `FOREIGN KEY (device_id) REFERENCES device_auth(device_id)` 2. `FOREIGN KEY (child_id) REFERENCES children(child_id)` 3. `FOREIGN KEY (bound_by_user_id) REFERENCES parents(user_id)` 4. `FOREIGN KEY (unbound_by_user_id) REFERENCES parents(user_id)` ### 3.7 卡片表 `cards` 建议字段: 1. `card_id` BIGINT UNSIGNED PK AUTO_INCREMENT 2. `card_uuid` VARCHAR(64) UNIQUE NOT NULL 3. `device_id` VARCHAR(64) UNIQUE NULL 4. `card_name` VARCHAR(64) NULL 5. `status` TINYINT NOT NULL DEFAULT 0 6. `total_swaps` INT NOT NULL DEFAULT 0 7. `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP 8. `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 约束建议: 1. `FOREIGN KEY (device_id) REFERENCES device_auth(device_id)` ### 3.8 设备设置表 `device_settings` 建议字段: 1. `setting_id` BIGINT UNSIGNED PK AUTO_INCREMENT 2. `device_id` VARCHAR(64) NOT NULL UNIQUE 3. `sleep_mode` TINYINT NOT NULL DEFAULT 0 4. `disable_time_start` TIME NULL 5. `disable_time_end` TIME NULL 6. `timezone` VARCHAR(32) NOT NULL DEFAULT 'Asia/Shanghai' 7. `volume` TINYINT UNSIGNED NULL 8. `brightness` TINYINT UNSIGNED NULL 9. `disable_weekdays` VARCHAR(32) NULL 10. `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP 11. `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 兼容规则: 1. `volume` 同步写入 `device_configs.volume`,防止两服务读到不同值。 2. 若只允许单一音量来源,则以 `device_configs.volume` 为准,`device_settings.volume` 可后续下线。 3. `disable_time_start/disable_time_end` 与历史命名 `sleep_start/sleep_end` 一一映射。 4. 禁用时段按 `timezone` 解释;跨天时段(如 22:00-07:00)按“跨日窗口”处理。 ## 4. 聊天与定位模型(新增,不改 01 现有会话表) ### 4.1 IM 会话表 `im_conversations` 用途:仅服务家长-小孩、小孩-小孩 1v1,不与 `conversation_histories` 混用。 建议字段: 1. `id` BIGINT UNSIGNED PK AUTO_INCREMENT 2. `conversation_type` TINYINT UNSIGNED NOT NULL 3. `participant_a_type` TINYINT UNSIGNED NOT NULL 4. `participant_a_id` VARCHAR(64) NOT NULL 5. `participant_b_type` TINYINT UNSIGNED NOT NULL 6. `participant_b_id` VARCHAR(64) NOT NULL 7. `pair_key` VARCHAR(191) NOT NULL 8. `status` TINYINT NOT NULL DEFAULT 1 9. `last_seq` BIGINT UNSIGNED NOT NULL DEFAULT 0 10. `message_count` BIGINT UNSIGNED NOT NULL DEFAULT 0 11. `last_message_preview` VARCHAR(255) NULL 12. `last_message_at` DATETIME NULL 13. `ext_json` JSON NULL 14. `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP 15. `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 说明: 1. 会话核心字段保持通用,不使用 `child_low_id/child_high_id` 这类场景耦合命名。 2. `conversation_type` 使用类型码,可扩展;新增会话类型优先通过“类型码 + 业务校验 + `ext_json`”扩展,无需改核心表。 3. 当前建议启用类型:`1-child_peer`、`2-parent_child`。 约束建议: 1. `UNIQUE(conversation_type, pair_key)` 2. `INDEX idx_participant_a (participant_a_type, participant_a_id)` 3. `INDEX idx_participant_b (participant_b_type, participant_b_id)` 4. `INDEX idx_last_message_at (last_message_at)` ### 4.2 IM 消息表 `im_messages` 建议字段: 1. `id` BIGINT UNSIGNED PK AUTO_INCREMENT 2. `conversation_id` BIGINT UNSIGNED NOT NULL 3. `seq` BIGINT UNSIGNED NOT NULL 4. `sender_type` TINYINT UNSIGNED NOT NULL 5. `sender_id` VARCHAR(64) NOT NULL 6. `receiver_type` TINYINT UNSIGNED NOT NULL 7. `receiver_id` VARCHAR(64) NOT NULL 8. `content_type` TINYINT UNSIGNED NOT NULL 9. `content_text` MEDIUMTEXT NULL 10. `content_json` JSON NULL 11. `media_file_key` VARCHAR(255) NULL 12. `media_duration_ms` INT UNSIGNED NULL 13. `media_mime_type` VARCHAR(64) NULL 14. `media_size_bytes` BIGINT UNSIGNED NULL 15. `media_transcript_text` TEXT NULL 16. `client_msg_id` VARCHAR(64) NULL 17. `sender_name_snapshot` VARCHAR(64) NULL 18. `sender_avatar_snapshot` VARCHAR(255) NULL 19. `receiver_name_snapshot` VARCHAR(64) NULL 20. `receiver_avatar_snapshot` VARCHAR(255) NULL 21. `ext_json` JSON NULL 22. `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP 23. `deleted_at` DATETIME NULL 约束建议: 1. `UNIQUE(conversation_id, seq)` 2. `UNIQUE(conversation_id, client_msg_id)` 3. `FOREIGN KEY (conversation_id) REFERENCES im_conversations(id) ON DELETE CASCADE` 4. `INDEX idx_sender (sender_type, sender_id, created_at)` 5. `INDEX idx_receiver (receiver_type, receiver_id, created_at)` #### 4.2.1 文本与语音消息规则 1. `content_type=1(text)`:`content_text` 必填。 2. `content_type=2(audio)`:`media_file_key` 必填,建议同时写入 `media_duration_ms`、`media_mime_type`、`media_size_bytes`。 3. `content_type=3(image)`:`media_file_key` 必填。 4. `content_type=4(json)`:`content_json` 必填。 5. 语音转写内容可写入 `media_transcript_text`,用于检索与展示。 6. 展示层优先使用 `sender_name_snapshot/sender_avatar_snapshot` 与 `receiver_*_snapshot`,减少联表查询。 ### 4.3 位置表 `child_location_current`: 1. `child_id` BIGINT UNSIGNED PK 2. `device_id` VARCHAR(64) NOT NULL 3. `coord_type` VARCHAR(16) NOT NULL DEFAULT 'gcj02' 4. `lat` DECIMAL(10,7) NOT NULL 5. `lng` DECIMAL(10,7) NOT NULL 6. `accuracy_m` INT UNSIGNED NULL 7. `altitude_m` DECIMAL(8,2) NULL 8. `speed_mps` DECIMAL(8,2) NULL 9. `heading_deg` SMALLINT UNSIGNED NULL 10. `source` TINYINT UNSIGNED NOT NULL 11. `battery_pct` TINYINT UNSIGNED NULL 12. `device_time` DATETIME NOT NULL 13. `server_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP 14. `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP `child_location_history`: 1. `id` BIGINT UNSIGNED PK AUTO_INCREMENT 2. `child_id` BIGINT UNSIGNED NOT NULL 3. `device_id` VARCHAR(64) NOT NULL 4. `coord_type` VARCHAR(16) NOT NULL DEFAULT 'gcj02' 5. 其余定位字段与 `child_location_current` 对齐 6. `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP #### 4.3.1 位置上报协议(统一格式) 1. 上报字段:`device_id`、`child_id`、`coord_type`、`lat`、`lng`、`accuracy_m`、`source`、`device_time`、`battery_pct`。 2. 坐标系标准:统一使用 `gcj02`。 3. 坐标格式:统一按 `lat,lng`(纬度在前,经度在后)传输和存储。 4. 若设备侧提供 `wgs84`,服务端需先转换到 `gcj02` 后再入库;原始坐标可选写入 `ext_json` 备查。 5. 写入规则:同事务写 `child_location_history` 并覆盖 `child_location_current`。 ## 5. 核心业务流程 ### 5.1 设备注册与鉴权 1. 生产或后台调用 `talkingq-url` 现有注册接口,写入 `device_auth`。 2. 手表请求携带 `X-Device-ID` 与 `X-Device-Serial`。 3. 后端基于 `device_auth` 鉴权通过后继续处理聊天/定位/绑定。 ### 5.2 绑定流程(扫码 + 确认码) 1. 家长登录后发起 `bind/start`,创建 `device_bind_sessions`。 2. 手表上报确认码,更新会话挑战信息。 3. 家长提交确认码。 4. 后端校验通过后开启事务。 5. upsert `parent_child_relations`。 6. upsert `device_bindings`(保证一设备一行、一小孩一行)。 7. 追加 `device_bind_history`。 8. 更新会话状态为 `confirmed/consumed` 并提交事务。 ### 5.3 聊天流程 1. 设备 AI 对话仍走 `conversation_histories + conversation_messages`。 2. 家长-小孩、小孩-小孩消息走 `im_conversations + im_messages`。 3. IM 消息统一使用 `sender_type/sender_id + receiver_type/receiver_id`,不按场景拆专用发送者字段。 4. 发送接口必须使用 `client_msg_id` 幂等。 5. 查询前必须校验 `parent_child_relations` 权限。 6. 列表展示优先读取消息快照字段,降低跨表查询成本。 ### 5.4 位置流程 1. 手表上报定位写入 `child_location_history`。 2. 同事务更新 `child_location_current`。 3. 小程序查询当前定位读 `child_location_current`,轨迹读 `child_location_history`。 4. 地址解析使用腾讯位置服务;若解析失败,前端降级展示经纬度。 ## 6. 统一约束与实现规则 1. 所有设备引用字段统一使用 `device_id VARCHAR(64)`,不再新增 `watch_device_id BIGINT`。 2. 设备主身份只认 `device_auth.device_id`。 3. 跨主体通用 ID 字段统一采用字符串(如 `participant_*_id`、`sender_id`、`receiver_id`)。 4. 所有业务表统一包含 `created_at/updated_at`(历史流水类可无 `updated_at`)。 5. `status` 用于业务态,`is_active` 用于启停态;两者不混用。 6. 关键写路径(绑定确认、发消息、位置写入)必须事务化。 7. 腾讯位置服务启用前提:必须配置合法 `key`,并完成域名/来源白名单与配额设置。 8. 地图相关接口统一使用 `gcj02` 和 `lat,lng`;禁止混用 `wgs84/bd09` 直接入库。 ## 7. 分阶段落地 1. 第一阶段:落地 `parents/children/parent_child_relations/device_bind_*`,打通绑定链路。 2. 第二阶段:落地 `im_conversations/im_messages`,打通家长与小孩 IM。 3. 第三阶段:落地 `child_location_current/history`,打通定位链路。 4. 第四阶段:补充审计、告警、实时推送和运营能力。 ## 8. 验收标准 1. 不修改 `01-init.sql` 任一现有表,服务可正常启动。 2. 设备鉴权、角色配置、OTA能力保持可用。 3. 家长可完成扫码绑定、解绑、重绑,且历史保留。 4. 家长可查看自己小孩与其他小孩完整双向消息。 5. 小程序可查看小孩最新位置与历史轨迹。