# 数据管理 **本文引用的文件** - [src/index.ts](file://src/index.ts) - [src/command/index.ts](file://src/command/index.ts) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts) - [src/scheduler/index.ts](file://src/scheduler/index.ts) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts) - [src/command/handlers/history.ts](file://src/command/handlers/history.ts) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts) - [wrangler.jsonc](file://wrangler.jsonc) - [worker-configuration.d.ts](file://worker-configuration.d.ts) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [组件详解](#组件详解) 6. [依赖关系分析](#依赖关系分析) 7. [性能考量](#性能考量) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本文件面向 Cosmoe Bot 的数据管理系统,聚焦于 Cloudflare KV 的配置与使用、会话状态管理、数据模型设计、数据访问模式最佳实践、迁移与备份恢复策略、性能优化以及与 Cosmoe 服务端 API 的数据同步与冲突解决策略。文档基于仓库中实际代码进行分析,帮助开发者快速理解并维护该系统。 ## 项目结构 - 入口与运行时:Worker 入口负责初始化 Bot、注册命令、设置 Webhook 和定时任务。 - 命令层:通过 @grammyjs/conversations 提供交互式对话能力,使用 Cloudflare KV 作为会话存储。 - 客户端层:封装 Cosmoe 服务端 API,统一认证、事件查询、预约、历史等接口。 - 调度层:基于 Cron 定时任务,向已注册用户推送新活动通知,并持久化最新活动 ID。 ```mermaid graph TB A["入口: src/index.ts"] --> B["命令注册: src/command/index.ts"] B --> C["会话存储: Cloudflare KV(COSMOE_STORAGE)"] B --> D["命令处理器
login/history/bookEvent/cancel"] D --> E["客户端: src/client/cosmoe.ts"] A --> F["调度器: src/scheduler/index.ts"] F --> G["KV(COSMOE_STORAGE) 最新活动ID"] F --> H["KV(COSMOE_CREDENTIALS) 注册用户列表"] ``` 图表来源 - [src/index.ts](file://src/index.ts#L13-L46) - [src/command/index.ts](file://src/command/index.ts#L20-L52) - [src/scheduler/index.ts](file://src/scheduler/index.ts#L12-L87) 章节来源 - [src/index.ts](file://src/index.ts#L1-L47) - [src/command/index.ts](file://src/command/index.ts#L1-L110) - [src/scheduler/index.ts](file://src/scheduler/index.ts#L1-L88) ## 核心组件 - Worker 入口与环境绑定 - 绑定 KV 命名空间:COSMOE_CREDENTIALS(用户凭证)、COSMOE_STORAGE(通用存储)。 - 初始化 Bot 并注册命令菜单;Webhook 回调适配 Cloudflare 运行时。 - 会话状态管理 - 使用 @grammyjs/storage-cloudflare 将对话状态持久化到 COSMOE_STORAGE。 - 对话读写采用 JSON 序列化/反序列化。 - Cosmoe 客户端 - 统一封装认证、事件、个人资料、预约、优惠券、取消等 API。 - 支持手动设置凭证或通过交互式登录获取并保存至 COSMOE_CREDENTIALS。 - 调度任务 - 每分钟扫描新活动,向已注册用户发送通知,并更新最新活动 ID。 章节来源 - [src/index.ts](file://src/index.ts#L6-L11) - [src/command/index.ts](file://src/command/index.ts#L20-L52) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503) - [src/scheduler/index.ts](file://src/scheduler/index.ts#L12-L87) ## 架构总览 下图展示从用户交互到服务端 API 与 KV 存储的整体流程。 ```mermaid sequenceDiagram participant U as "用户" participant B as "Bot(grammy)" participant CMD as "命令处理器" participant KV as "Cloudflare KV" participant API as "Cosmoe API 客户端" participant S as "Cosmoe 服务端" U->>B : "/login" 或 "/events" 等命令 B->>CMD : 分发到对应处理器 CMD->>KV : 读取/写入会话/凭证/配置 CMD->>API : 调用认证/查询/预约/取消等接口 API->>S : 发起 HTTP 请求 S-->>API : 返回 JSON 结果 API-->>CMD : 返回业务结果 CMD-->>B : 组织消息回复 B-->>U : 发送消息/内联键盘 ``` 图表来源 - [src/command/index.ts](file://src/command/index.ts#L20-L52) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L74) - [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L4-L106) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L11-L225) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L11-L131) ## 组件详解 ### Cloudflare KV 配置与使用 - 命名空间绑定 - COSMOE_CREDENTIALS:存储用户凭证(Telegram 用户 ID -> 用户信息与令牌)。 - COSMOE_STORAGE:存储会话状态与通用配置(如最新活动 ID)。 - 访问模式 - 会话存储:通过 @grammyjs/storage-cloudflare 的 KvAdapter,将对话状态以 JSON 字符串形式写入 KV。 - 业务数据:直接使用 env.COSMOE_CREDENTIALS.get/put 与 env.COSMOE_STORAGE.get/put。 - 序列化与反序列化 - 会话读写:统一使用 JSON.stringify(JSON.parse(...))。 - 凭证与配置:统一使用 JSON.stringify(JSON.parse(...))。 - 错误处理 - 读写异常均捕获并记录日志,避免中断对话流程。 ```mermaid flowchart TD Start(["进入命令"]) --> GetCreds["从 KV(COSMOE_CREDENTIALS) 获取用户凭证"] GetCreds --> HasCreds{"是否存在凭证?"} HasCreds -- 否 --> PromptLogin["提示先执行 /login"] HasCreds -- 是 --> UseClient["初始化 CosmoeClient 并 setCredentials"] UseClient --> CallAPI["调用 Cosmoe API 接口"] CallAPI --> UpdateKV["必要时更新 KV(COSMOE_STORAGE/COSMOE_CREDENTIALS)"] UpdateKV --> Reply["构造并发送回复"] PromptLogin --> Reply ``` 图表来源 - [src/command/index.ts](file://src/command/index.ts#L20-L52) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L49-L63) - [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L13-L29) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L22-L39) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L21-L43) 章节来源 - [wrangler.jsonc](file://wrangler.jsonc#L21-L30) - [worker-configuration.d.ts](file://worker-configuration.d.ts#L1809-L1850) - [src/command/index.ts](file://src/command/index.ts#L20-L52) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L49-L63) ### 会话状态管理 - 设计原则 - 以 Telegram 用户 ID 为键,KV 中存储对话上下文对象(JSON)。 - 会话生命周期由 @grammyjs/conversations 控制,KV 仅作为持久化介质。 - 创建与更新 - 登录对话结束后,将凭证写入 COSMOE_CREDENTIALS。 - 历史、预约、取消等命令在执行前读取凭证,确保认证有效。 - 销毁 - 会话结束自动清理;注销命令可结合业务逻辑删除相关 KV 条目(当前实现未显式删除,建议在 logout 中扩展)。 ```mermaid sequenceDiagram participant U as "用户" participant Conv as "对话(Conversation)" participant KV as "KV(COSMOE_STORAGE)" participant Login as "登录处理器" U->>Conv : 触发 /login Conv->>Login : 进入登录对话 Login->>KV : 写入凭证(JSON) KV-->>Login : 成功 Login-->>Conv : 登录成功 Conv-->>U : 返回结果 ``` 图表来源 - [src/command/index.ts](file://src/command/index.ts#L54-L57) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L49-L63) 章节来源 - [src/command/index.ts](file://src/command/index.ts#L20-L52) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L74) ### 数据模型设计 - 用户信息 - 结构:包含用户标识、用户名、邮箱、角色、是否激活、创建时间等字段。 - 存储:KV(COSMOE_CREDENTIALS) 以 Telegram 用户 ID 为键,值为包含 user_id、token、timestamp 的对象。 - 活动数据 - 结构:活动基本信息、描述、封面图、时间片数组等。 - 查询:通过 CosmoeClient.getEvents/getEventDetail 获取。 - 预约记录 - 结构:包含预约 ID、状态、预约日期、时间段、最终价格、支付订单号、用户备注、创建时间、活动名称等。 - 查询:通过 CosmoeClient.getMyBookings 获取。 ```mermaid classDiagram class UserInfo { +number id +string username +string email +string user_identity +string role +number is_active +string created_at } class Event { +string id +string name +string description +string event_date +string cover_image_url +string description_brief } class TimeSlot { +string range +string price +number capacity +number remaining } class EventDetail { +number id +string name +string description +string event_date +string time_slots_with_prices +string cover_image_url +string detail_image_urls +number is_listed +number login_required +number allow_coupons +string created_at +TimeSlot[] slots +string[] gallery } class Booking { +number id +string status +string booking_date +string time_slot +string final_price +string payment_order_id +string notes_by_user +string created_at +string event_name } class Credentials { +number user_id +string token +number timestamp } EventDetail --> TimeSlot : "包含多个" Credentials <.. UserInfo : "关联用户" Booking <.. UserInfo : "关联用户" ``` 图表来源 - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L52-L105) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L57-L61) 章节来源 - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L20-L105) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L57-L61) ### 数据访问模式最佳实践 - 缓存策略 - 会话状态:KV 作为持久化存储,对话结束即释放;建议为高频读取的用户资料设置 TTL(当前未使用)。 - 通用配置:如最新活动 ID,按需读取并更新,避免频繁写入。 - 并发控制 - KV 写入为原子操作;对话写入通过 @grammyjs/storage-cloudflare 的 Adapter 实现,建议避免在同一会话中并发写入。 - 事务处理 - KV 不支持跨键事务;对于需要一致性的操作(如“先检查余量再下单”),可在应用层通过幂等设计与重试策略保证一致性。 - 序列化与反序列化 - 统一使用 JSON.stringify/JSON.parse;对可能为 null 的值进行判空处理,避免解析异常。 章节来源 - [src/command/index.ts](file://src/command/index.ts#L25-L49) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L65-L74) ### 数据迁移方案 - 凭证迁移 - 将旧 KV 中的凭证结构转换为新的 {user_id, token, timestamp} 形式;迁移后验证登录有效性。 - 会话迁移 - 若更换 KV 命名空间或键规则,需编写迁移脚本读取旧键,转换为新键并写入新命名空间。 - 历史数据 - 预约历史为只读查询,无需迁移;若需导出,可按需拉取并落库到外部存储。 章节来源 - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L57-L61) ### 备份与恢复策略 - 备份 - 定期导出 KV 中的关键键集(如最新活动 ID、用户凭证键列表)。 - 恢复 - 在新环境中重建 KV 命名空间后,导入备份数据;验证登录与会话功能正常。 章节来源 - [src/scheduler/index.ts](file://src/scheduler/index.ts#L26-L28) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L63) ### 性能优化技巧 - 减少 KV 读写次数:合并多次写入,批量读取常用键。 - 合理使用 TTL:对临时数据设置 TTL,降低冷数据占用。 - 限流与退避:对外部 API 调用增加指数退避与限流,避免触发限频。 - 消息长度控制:历史消息过长时截断,避免 Telegram API 限制。 章节来源 - [src/scheduler/index.ts](file://src/scheduler/index.ts#L76-L78) - [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L94-L97) ### 与 Cosmoe 服务端 API 的数据同步与冲突解决 - 同步机制 - 定时任务每分钟轮询最新活动,对比本地存储的最新活动 ID,推送新增活动给已注册用户。 - 用户侧通过命令实时查询活动与预约,保持本地状态与服务端一致。 - 冲突解决 - 预约冲突:在客户端层检查剩余容量与状态,避免重复提交;服务端返回错误时提示用户重试。 - 取消与变更:通过回调确认与服务端接口完成,失败时保留本地状态并提示用户重试。 ```mermaid sequenceDiagram participant Cron as "定时任务" participant KV as "KV(COSMOE_STORAGE)" participant API as "Cosmoe API" participant Users as "已注册用户" Cron->>KV : 读取 latestEventId Cron->>API : 获取所有活动 API-->>Cron : 返回活动列表 Cron->>KV : 更新 latestEventId(最大ID) loop 遍历新活动 Cron->>Users : 发送通知 end ``` 图表来源 - [src/scheduler/index.ts](file://src/scheduler/index.ts#L24-L84) 章节来源 - [src/scheduler/index.ts](file://src/scheduler/index.ts#L12-L87) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L177-L184) ## 依赖关系分析 - 运行时依赖 - @grammyjs/conversations:提供对话与会话状态管理。 - @grammyjs/storage-cloudflare:KV 适配器,用于会话持久化。 - grammy:Telegram Bot SDK。 - 配置依赖 - Wrangler 将 KV 命名空间绑定到环境变量,供运行时访问。 ```mermaid graph LR Pkg["package.json 依赖"] --> G["@grammyjs/conversations"] Pkg --> GC["@grammyjs/storage-cloudflare"] Pkg --> GM["grammy"] W["wrangler.jsonc"] --> KVC["COSMOE_CREDENTIALS"] W --> KVS["COSMOE_STORAGE"] ``` 图表来源 - [package.json](file://package.json#L18-L22) - [wrangler.jsonc](file://wrangler.jsonc#L21-L30) 章节来源 - [package.json](file://package.json#L1-L24) - [wrangler.jsonc](file://wrangler.jsonc#L1-L31) ## 性能考量 - KV 读写延迟:尽量减少不必要的 KV 操作,合并读写。 - API 调用频率:对频繁查询的接口增加本地缓存(如活动列表),并设置合理 TTL。 - 并发与锁:避免同一用户并发写入 KV;必要时引入分布式锁或队列。 - 日志与可观测性:开启 Wrangler 可观测性,监控 KV 读写与 API 调用成功率。 章节来源 - [src/command/index.ts](file://src/command/index.ts#L25-L49) - [src/scheduler/index.ts](file://src/scheduler/index.ts#L13-L17) ## 故障排查指南 - 会话读写失败 - 检查 KV 命名空间绑定与权限;确认 JSON 解析异常(空值或格式错误)。 - 登录失败 - 核对用户名/密码;检查 Cosmoe API 返回码与消息;确认凭证写入 KV 成功。 - 预约失败 - 检查活动详情与时间片剩余容量;确认优惠券可用性;查看 API 返回错误。 - 取消失败 - 确认预约状态允许取消;检查回调处理逻辑与 API 返回。 - 定时任务未推送通知 - 检查 Cron 配置与 latestEventId 更新逻辑;确认已注册用户列表存在。 章节来源 - [src/command/index.ts](file://src/command/index.ts#L25-L49) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L67-L69) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L137-L156) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L117-L124) - [src/scheduler/index.ts](file://src/scheduler/index.ts#L24-L84) ## 结论 本系统通过 Cloudflare KV 实现会话状态与业务数据的持久化,结合 @grammyjs/conversations 与 Cosmoe API 客户端,提供了完整的用户交互与数据同步能力。建议在现有基础上进一步完善凭证与会话的生命周期管理、KV TTL 与缓存策略、以及对外部 API 的重试与限流机制,以提升稳定性与性能。 ## 附录 - KV 类型与方法参考 - get/put/list 等方法签名与选项(如 TTL、metadata)可参考类型声明文件。 - 部署与开发 - 使用 Wrangler 进行本地开发与部署;配置 Cron 触发器以启用定时任务。 章节来源 - [worker-configuration.d.ts](file://worker-configuration.d.ts#L1809-L1850) - [wrangler.jsonc](file://wrangler.jsonc#L13-L17)