Files
banban/mini-program/design.md
HycJack a22fcafea9 新增小程序后端代码,包括数据库、路由、服务层等。
小程序前后端打通,包括登录、注册、绑定设备、查询绑定信息,修改小朋友名称等功能。
2026-04-13 01:54:57 +08:00

380 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Banban 统一数据与接口设计文档Mini Program + talkingq-urlV3
## 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. 小程序可查看小孩最新位置与历史轨迹。