# 数据流设计
**本文引用的文件**
- [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/command/handlers/start.ts](file://src/command/handlers/start.ts)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts)
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts)
- [src/command/handlers/logout.ts](file://src/command/handlers/logout.ts)
- [src/scheduler/index.ts](file://src/scheduler/index.ts)
- [wrangler.jsonc](file://wrangler.jsonc)
- [package.json](file://package.json)
- [tsconfig.json](file://tsconfig.json)
- [worker-configuration.d.ts](file://worker-configuration.d.ts)
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
## 简介
本设计文档围绕 Cosmoe Bot 的数据流进行系统性梳理,覆盖从 Telegram 用户消息进入 Cloudflare Workers,经由 grammY 框架解析与路由,到各命令处理器执行业务逻辑、调用 Cosmoe API 客户端访问外部服务,并通过 KV 存储完成状态持久化的完整链路。文档同时给出数据流向图、关键数据节点结构定义、缓存策略与一致性保障、异步处理与错误恢复机制等。
## 项目结构
该项目采用按功能模块组织的目录结构,核心入口在 Cloudflare Workers 中,使用 grammY 作为 Telegram Bot 框架,配合 @grammyjs/conversations 实现对话式交互,使用 @grammyjs/storage-cloudflare 将会话状态持久化至 KV。
```mermaid
graph TB
subgraph "Cloudflare Workers"
A["src/index.ts
入口与webhook回调"]
B["src/command/index.ts
命令注册与会话存储"]
C["src/scheduler/index.ts
定时任务"]
end
subgraph "命令处理器"
H1["start.ts"]
H2["login.ts"]
H3["events.ts"]
H4["eventDetails.ts"]
H5["bookEvent.ts"]
H6["history.ts"]
H7["cancel.ts"]
H8["logout.ts"]
end
subgraph "外部服务"
E["Telegram API"]
F["Cosmoe API"]
end
subgraph "KV 存储"
K1["COSMOE_CREDENTIALS
用户凭证"]
K2["COSMOE_STORAGE
通用状态"]
end
A --> B
A --> C
B --> H1
B --> H2
B --> H3
B --> H4
B --> H5
B --> H6
B --> H7
B --> H8
H2 --> K1
H6 --> K1
H8 --> K1
H5 --> F
H6 --> F
H7 --> F
H3 --> F
H4 --> F
C --> F
C --> K2
```
图表来源
- [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)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L1-L75)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L1-L107)
- [src/command/handlers/logout.ts](file://src/command/handlers/logout.ts#L1-L34)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L1-L226)
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L1-L27)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L1-L61)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L1-L503)
章节来源
- [src/index.ts](file://src/index.ts#L1-L47)
- [src/command/index.ts](file://src/command/index.ts#L1-L110)
- [wrangler.jsonc](file://wrangler.jsonc#L1-L31)
## 核心组件
- 入口与 Webhook 回调:初始化 grammY Bot,设置命令菜单,将请求交由 Cloudflare 的 webhookCallback 处理。
- 命令注册与会话存储:安装 conversations 插件,使用 KV 适配器实现会话状态持久化;注册各类命令与回调处理器。
- 命令处理器:按功能拆分,包括启动引导、登录(对话式)、活动列表、活动详情、预约、历史、取消、登出等。
- Cosmoe API 客户端:封装认证、事件查询、个人资料、预约、取消、修改等 API 调用。
- 定时任务:周期性扫描新活动并向已注册用户推送通知。
- KV 存储:COSMOE_CREDENTIALS 保存用户凭证;COSMOE_STORAGE 保存通用状态(如最新活动 ID)。
章节来源
- [src/index.ts](file://src/index.ts#L1-L47)
- [src/command/index.ts](file://src/command/index.ts#L1-L110)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L1-L503)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L1-L88)
- [wrangler.jsonc](file://wrangler.jsonc#L21-L30)
## 架构总览
下图展示从 Telegram 到 Cloudflare Workers、grammY、命令处理器、Cosmoe API 客户端以及 KV 存储的整体数据流。
```mermaid
sequenceDiagram
participant U as "用户"
participant T as "Telegram API"
participant W as "Cloudflare Workers
src/index.ts"
participant G as "grammY 框架"
participant CMD as "命令处理器
src/command/handlers/*"
participant KV as "KV 存储
COSMOE_CREDENTIALS/COSMOE_STORAGE"
participant API as "Cosmoe API"
U->>T : "发送消息/命令"
T-->>W : "HTTP 请求"
W->>G : "webhookCallback 分发"
G->>CMD : "匹配命令/回调并执行"
CMD->>KV : "读取/写入用户凭证/状态"
CMD->>API : "调用 Cosmoe API"
API-->>CMD : "返回业务数据"
CMD-->>G : "构造响应"
G-->>W : "生成 Telegram 响应"
W-->>T : "回传消息"
T-->>U : "显示结果"
```
图表来源
- [src/index.ts](file://src/index.ts#L13-L35)
- [src/command/index.ts](file://src/command/index.ts#L20-L110)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L75)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L4-L107)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L11-L226)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503)
- [wrangler.jsonc](file://wrangler.jsonc#L21-L30)
## 详细组件分析
### 命令注册与会话存储(KV)
- 会话存储:通过 @grammyjs/storage-cloudflare 的 KvAdapter 将会话状态序列化为 JSON 并写入 COSMOE_STORAGE。
- 登录对话:使用 createConversation 定义交互式登录流程,完成后将用户凭证写入 COSMOE_CREDENTIALS。
- 命令路由:注册 /start、/login、/events、/event_{id}、/book_{event}_{slot}、/history、/cancel_{id}、回调等。
```mermaid
flowchart TD
Start(["进入 setupCommands"]) --> KV["创建 KV 适配器
绑定 COSMOE_STORAGE"]
KV --> Conv["安装 conversations 插件
指定 storage=KV"]
Conv --> Login["注册 /login 对话
enter('login')"]
Login --> ReadCreds["读取用户凭证
COSMOE_CREDENTIALS"]
ReadCreds --> ExecCmd["执行命令处理器"]
ExecCmd --> WriteKV["写入 KV 状态/凭证"]
WriteKV --> End(["完成"])
```
图表来源
- [src/command/index.ts](file://src/command/index.ts#L20-L110)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L75)
章节来源
- [src/command/index.ts](file://src/command/index.ts#L20-L110)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L75)
### 登录流程(对话式)
- 用户输入用户名/密码,调用 CosmoeClient.getToken 获取 token。
- 将 user_id、token、timestamp 写入 COSMOE_CREDENTIALS,键为 Telegram 用户 ID。
- 异常处理:输入缺失、认证失败、KV 写入异常均进行友好提示与日志记录。
```mermaid
sequenceDiagram
participant U as "用户"
participant CMD as "handleInteractiveLogin"
participant KV as "COSMOE_CREDENTIALS"
participant API as "CosmoeClient.getToken"
U->>CMD : "/login 进入对话"
CMD->>U : "提示输入用户名"
U-->>CMD : "用户名"
CMD->>U : "提示输入密码"
U-->>CMD : "密码"
CMD->>API : "getToken(username,password)"
API-->>CMD : "返回 {user_id,token}"
CMD->>KV : "put(telegramUserId, JSON)"
CMD-->>U : "登录成功提示"
```
图表来源
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L75)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L124-L140)
章节来源
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L75)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L124-L140)
### 活动列表与详情
- /events:调用 getEvents 获取最新活动列表,拼接 Markdown 链接供用户点击 /event_{id}。
- /event_{id}:调用 getEventDetail 获取活动详情,渲染时间段、价格、剩余容量,并对可预约时间段提供 /book_{event}_{slot} 链接。
```mermaid
flowchart TD
A["/events"] --> B["CosmoeClient.getEvents"]
B --> C["筛选最新N条"]
C --> D["拼装 Markdown 列表"]
D --> E["发送消息"]
F["/event_{id}"] --> G["CosmoeClient.getEventDetail"]
G --> H["排序时间槽"]
H --> I{"是否可预约"}
I --> |是| J["生成 /book_{event}_{slot} 链接"]
I --> |否| K["仅展示信息"]
```
图表来源
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L4-L27)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L4-L61)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L177-L200)
章节来源
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L4-L27)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L4-L61)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L177-L200)
### 预约流程(含优惠券选择)
- 解析 /book_{event}_{slot},校验用户登录态,获取活动详情与时间槽。
- 若存在多个可用优惠券,弹出内联键盘让用户选择;单个则自动使用。
- 调用 bookEvent 提交预约,返回最终价格、预约编号等信息。
```mermaid
sequenceDiagram
participant U as "用户"
participant CMD as "handleBookEvent"
participant KV as "COSMOE_CREDENTIALS"
participant API as "CosmoeClient"
participant CB as "handleCouponSelection"
U->>CMD : "/book_{event}_{slot}"
CMD->>KV : "读取凭证"
CMD->>API : "getEventDetail(eventId)"
CMD->>API : "getAvailableCoupons(eventId)"
alt 多个优惠券
CMD-->>U : "显示内联键盘选择"
U->>CB : "回调 : select_coupon_{...}"
CB->>API : "bookEvent(带coupon)"
else 单个/无优惠券
CMD->>API : "bookEvent(直接提交)"
end
API-->>CMD : "返回预约结果"
CMD-->>U : "发送成功/失败消息"
```
图表来源
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L11-L226)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L247-L270)
章节来源
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L11-L226)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L247-L270)
### 历史与取消
- /history:读取用户凭证,调用 getMyBookings 获取预约历史,格式化 Markdown 并附带可取消链接。
- /cancel_{id}:弹出确认内联键盘,确认后调用 cancelBooking 执行取消。
```mermaid
flowchart TD
H1["/history"] --> H2["读取凭证"]
H2 --> H3["CosmoeClient.getMyBookings"]
H3 --> H4["格式化 Markdown"]
H4 --> H5["发送消息"]
C1["/cancel_{id}"] --> C2["读取凭证"]
C2 --> C3["获取预约详情"]
C3 --> C4["内联键盘确认"]
C4 --> C5["cancelBooking"]
C5 --> C6["编辑消息反馈结果"]
```
图表来源
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L4-L107)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L11-L132)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L226-L239)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L405-L422)
章节来源
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L4-L107)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L11-L132)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L226-L239)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L405-L422)
### 定时任务与通知
- 触发频率:每分钟一次(*/1 * * * *)。
- 逻辑:读取 COSMOE_STORAGE 中的 latestEventId,拉取全部活动,过滤新增活动,遍历 COSMOE_CREDENTIALS 中的用户键,逐个发送通知,并更新 latestEventId。
```mermaid
flowchart TD
S["scheduled 触发"] --> L["读取 latestEventId"]
L --> E["CosmoeClient.getEvents"]
E --> F["过滤新活动"]
F --> K["遍历已注册用户键"]
K --> N["bot.api.sendMessage"]
N --> U["更新 latestEventId"]
```
图表来源
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L12-L88)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L177-L184)
章节来源
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L12-L88)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L177-L184)
### 关键数据节点结构定义
- 通用响应结构
- 字段:code、msg、data
- 用途:统一承载 API 返回状态与数据
- 认证响应
- 字段:user_id、token
- 用途:登录成功后返回,后续请求需携带
- 事件与活动详情
- 字段:id、name、description、event_date、cover_image_url、slots、gallery 等
- 用途:活动列表与详情展示
- 时间槽
- 字段:range、price、capacity、remaining
- 用途:展示时间段、价格与剩余容量
- 用户资料与统计
- 字段:user_info、statistics
- 用途:个人中心与历史记录
- 预约
- 字段:id、status、booking_date、time_slot、final_price、notes_by_user、event_name 等
- 用途:历史记录与取消操作
章节来源
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L9-L105)
### 缓存策略与一致性
- KV 会话存储:使用 @grammyjs/storage-cloudflare 的 KvAdapter 将会话状态持久化至 COSMOE_STORAGE,确保多实例间会话一致性。
- 用户凭证:COSMOE_CREDENTIALS 以 Telegram 用户 ID 为键,存储 user_id、token、timestamp,便于命令处理器快速读取与鉴权。
- 通用状态:COSMOE_STORAGE 用于保存 latestEventId 等全局状态,避免重复推送。
- 一致性保障:KV 写入在登录、历史查询、取消等关键路径均有错误捕获与日志输出,保证异常可追踪;会话读写封装在 KV 适配器中,避免直接 KV 操作分散。
章节来源
- [src/command/index.ts](file://src/command/index.ts#L20-L110)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L49-L63)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L26-L78)
### 异步处理与错误恢复
- 异步模型:grammY 与 Cloudflare Workers 均基于事件循环与 Promise,命令处理器与 API 调用均为异步。
- 错误恢复:
- 命令处理器内部 try/catch 包裹,出现异常时向用户发送“稍后重试”提示并记录日志。
- KV 读写封装在会话存储中,异常时打印错误并继续执行,避免中断对话流程。
- 定时任务对每个用户的发送单独 try/catch,失败不影响其他用户的通知。
- 超时与可观测性:Wrangler 启用 observability,便于监控与排障。
章节来源
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L23-L26)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L103-L106)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L114-L117)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L65-L67)
- [wrangler.jsonc](file://wrangler.jsonc#L10-L12)
## 依赖关系分析
- grammY 生态:grammy、@grammyjs/conversations、@grammyjs/storage-cloudflare。
- 运行时类型:通过 wrangler types 生成的 worker-configuration.d.ts 提供环境变量与运行时类型声明。
- 构建与脚本:使用 TypeScript 与 Vitest,部署与开发通过 Wrangler CLI。
```mermaid
graph LR
P["package.json 依赖"] --> G["grammy"]
P --> C["conversations"]
P --> S["storage-cloudflare"]
W["wrangler.jsonc 配置"] --> T["worker-configuration.d.ts 类型"]
```
图表来源
- [package.json](file://package.json#L18-L22)
- [wrangler.jsonc](file://wrangler.jsonc#L1-L31)
- [worker-configuration.d.ts](file://worker-configuration.d.ts#L1-L10849)
章节来源
- [package.json](file://package.json#L18-L22)
- [wrangler.jsonc](file://wrangler.jsonc#L1-L31)
- [worker-configuration.d.ts](file://worker-configuration.d.ts#L1-L10849)
## 性能考量
- 会话存储:KV 读写为网络 IO,建议减少不必要的频繁写入;对话结束后及时清理临时状态。
- API 调用:批量获取活动与用户历史时注意分页与限流,避免超时。
- Markdown 渲染:历史消息长度限制在 4000 字符以内,防止 Telegram API 报错。
- 定时任务:每分钟触发一次,注意控制通知数量与并发发送,避免触发速率限制。
## 故障排查指南
- 登录失败:检查用户名/密码是否正确,确认 CosmoeClient.getToken 返回 code=200;查看 KV 写入是否成功。
- 无凭证或凭证失效:确认 /login 是否执行成功,COSMOE_CREDENTIALS 中是否存在对应键;必要时执行 /logout 清理后重新登录。
- 预约失败:核对时间槽剩余容量,确认优惠券有效性;查看 bookEvent 返回的 msg 信息。
- 历史为空:确认用户是否有历史记录,或是否超过筛选条数上限。
- 定时通知未送达:检查 COSMOE_STORAGE 中 latestEventId 是否更新,确认 COSMOE_CREDENTIALS 中用户键是否有效;查看定时任务日志。
章节来源
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L67-L73)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L34-L37)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L137-L156)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L59-L64)
## 结论
该系统通过 grammY 与 Cloudflare Workers 实现高可用的 Telegram Bot 数据流:用户消息经由 webhook 进入 Worker,命令处理器负责业务编排,Cosmoe API 客户端承担外部数据交互,KV 存储贯穿凭证与会话状态管理。整体具备清晰的模块边界、完善的错误处理与可观测性配置,适合在生产环境中稳定运行与扩展。