Web 前端技术参考¶
Web 前端是 TTD 的用户交互入口,提供会话式自然语言查询、实时流式结果展示、多维数据可视化及管理台 (Admin Panel) 能力。
定位
本文档为 Web 前端的技术参考手册,涵盖架构设计、核心模块、开发规范。 面向前端开发者和全栈工程师。
相关设计规范
本文档聚焦前端架构、模块职责与工程实现。
若需查看统一 UI 设计语言与实现约束,请同时参考 Handbook 中新增的 Web Design System 分组:
- Web UI 设计语言总览
- Design Tokens 规范
- 组件规范
- 页面模板规范
- 代码治理与评审约束
1. 技术栈 (Technology Stack)¶
1.1 核心框架¶
| 分类 | 技术 | 版本 | 职责 |
|---|---|---|---|
| Framework | Next.js | 16.2.0 | App Router + Turbopack |
| UI Library | React | 19.2.4 | 组件渲染引擎 |
| Language | TypeScript | 5.x | 类型安全 |
| Client State | Zustand | 5.0.12 | 轻量客户端状态管理 |
| Server State | TanStack React Query | 5.91.2 | 异步数据缓存与同步 |
| Form | react-hook-form | 7.72.1 | 表单状态与验证 |
| Validation | Zod | 4.3.6 | Schema 验证(SSE + 表单) |
1.2 UI 组件与样式¶
| 分类 | 技术 | 说明 |
|---|---|---|
| Primitive | Radix UI | 30+ 无样式可访问性原语 |
| Component System | shadcn/ui | 54 个预构建组件(见 components/ui/) |
| Styling | Tailwind CSS 4 | Utility-first CSS |
| Animation | Framer Motion 12.38 | 声明式动画 |
| Icons | Lucide React 0.577 | 一致性图标集 |
| Theme | next-themes 0.4.6 | Dark/Light 主题切换 |
| Toast | Sonner 2.0.7 | 通知提示 |
| Panels | react-resizable-panels 4.9 | 可拖拽面板分割 |
1.3 数据可视化¶
| 库 | 版本 | 用途 |
|---|---|---|
| ECharts | 6.0.0 | 主力图表渲染(bar, line, pie, scatter, heatmap 等) |
| echarts-for-react | 3.0.6 | React 封装层 |
| Recharts | 3.8.0 | 辅助图表(简单场景) |
| @antv/g6 | 5.0.51 | 知识图谱可视化 |
| D3 | 7.9.0 | 底层数据变换 |
| force-graph | 1.51.2 | 力导向图 |
1.4 工具链¶
| 工具 | 用途 |
|---|---|
| Turbopack | 开发态构建(Next.js 内置) |
| Biome 2.2 | 格式化 + Lint(替代 ESLint + Prettier) |
| @hey-api/openapi-ts 0.94 | OpenAPI 代码生成 |
| bun | 包管理与脚本执行 |
1.5 认证 (Authentication)¶
| 技术 | 版本 | 职责 |
|---|---|---|
| Better Auth | latest | 统一身份源 (Email/Password, GitHub OAuth) |
| better-auth/react | — | React 客户端 SDK (hooks + session) |
| better-auth/plugins (jwt, admin) | — | JWT 签发 + Admin 角色管理 |
| pg | 8.x | Better Auth 数据库适配器 (PostgreSQL) |
2. 路由与页面结构 (Routes & Pages)¶
2.1 目录结构¶
app/
├── layout.tsx # Root layout (providers, fonts, theme)
├── globals.css # Tailwind 入口
├── page.tsx # Landing page (hero + features + CTA)
├── api/auth/[...all]/route.ts # Better Auth API route handler
├── health/
│ └── page.tsx # Backend 健康检查面板
├── results/
│ └── page.tsx # Query results workspace (legacy)
├── (auth)/ # Auth route group (无认证保护)
│ ├── layout.tsx # Auth shell (双栏:左侧品牌 + 右侧表单)
│ ├── auth-left-panel.tsx # 左栏:网格背景、光晕、统计卡片、testimonial
│ ├── login/page.tsx # 登录页 (Email/Password + GitHub)
│ └── signup/page.tsx # 注册页
├── (chat)/ # Chat feature route group (需认证)
│ ├── layout.tsx # Chat shell (sidebar + main) + auth guard
│ ├── page.tsx # → /chat redirect
│ ├── chat/
│ │ └── page.tsx # Chat home (示例问题 + Composer)
│ │ └── c/[id]/page.tsx # 单条对话详情页
│ └── admin/ # Admin Panel (需 admin 角色)
│ ├── layout.tsx # Admin shell + role gate
│ ├── page.tsx # Dashboard (统计概览)
│ ├── knowledge-bases/ # 知识库管理 (CRUD)
│ ├── chat-engines/ # Chat Engine 配置
│ ├── models/ # LLM / Embedding / Reranker 模型管理
│ ├── evaluation/ # 评测任务管理
│ ├── conversations/ # 历史对话浏览
│ ├── feedbacks/ # 用户反馈审核
│ ├── few-shots/ # 动态 Few-Shot 质量审核
│ └── settings/ # 站点设置
└── sessions/ # Legacy query workspace
├── page.tsx # Sessions 列表
└── [sessionId]/page.tsx # Session 详情与 replay
2.2 路由分组说明¶
graph LR
A["/"] --> B["Landing Page"]
A --> C["/health"]
A --> D["/results"]
A --> AUTH["/(auth)"]
AUTH --> AUTH_LOGIN["/login"]
AUTH --> AUTH_SIGNUP["/signup"]
A --> E["/(chat)"]
E --> F["/chat"]
F --> G["/chat/c/:id"]
E --> H["/admin"]
H --> I["/admin/knowledge-bases"]
H --> J["/admin/chat-engines"]
H --> K["/admin/models"]
H --> L["/admin/evaluation"]
H --> M["/admin/conversations"]
H --> N["/admin/feedbacks"]
H --> O["/admin/few-shots"]
H --> P["/admin/settings"]
A --> Q["/sessions"]
Q --> R["/sessions/:sessionId"]
A --> API_AUTH["/api/auth/*"]
Route Group (auth)
认证页面使用独立的 Route Group (auth),共享 Auth Shell 布局(左侧品牌面板 + 右侧表单区)。
该组不做认证保护,允许未登录用户访问。
Route Group (chat) — 需认证
使用 Next.js Route Group 机制,(chat) 目录不体现在 URL 中,但共享统一的 Chat Layout(含侧边栏和导航)。
该布局内置认证守卫,未登录用户会被重定向到 /login。
2.3 Admin Panel 功能页面¶
| 路由 | 功能 | 说明 |
|---|---|---|
/admin |
Dashboard | 系统统计概览 |
/admin/knowledge-bases |
知识库管理 | CRUD,关联数据源与文档 |
/admin/chat-engines |
Chat Engine 配置 | 关联 LLM + 知识库 |
/admin/models |
模型管理 | LLM / Embedding / Reranker |
/admin/evaluation |
评测任务 | 批量评估任务管理 |
/admin/conversations |
历史对话 | 对话浏览与重放 |
/admin/feedbacks |
反馈审核 | 用户 👍/👎 反馈管理 |
/admin/few-shots |
Few-Shot 审核 | 动态 few-shot 质量审核(见下) |
/admin/settings |
站点设置 | 品牌、示例问题、全局配置 |
/admin/few-shots — 动态 Few-Shot 质量审核¶
页面文件:app/(chat)/admin/few-shots/page.tsx
Hook:hooks/use-few-shots.ts(useFewShots, useFewShotStats, reviewFewShot, exportSingleYaml, exportBulkYaml)
功能:
- 统计看板 — Pending / Approved / Rejected 三卡片,实时展示各状态数量
- 分 Tab 列表 — 按
pending_review/approved/rejected筛选,每页 20 条 - 审批操作(仅 Pending Tab):
- ✅ Approve — 条目状态改为
approved,下次 RAG 查询时若 similarity ≥ 0.95 即被注入 - ❌ Reject — 条目状态改为
rejected,永久排除出 RAG - YAML 导出(仅 Approved Tab):
- 单条导出(下载
.yaml文件) - Export All Approved as YAML — 批量导出全部已审批条目,格式与
semantic-plane/few_shots/完全一致,可直接提交 PR 晋升为正式资产 - 信息横幅 — Pending Tab 明确提示"pending 条目不参与 SQL 生成";Approved Tab 说明注入条件(admin approval + sim ≥ 95%)
SQL 预览 — 每条记录的 SQL 字段支持折叠/展开,超过 120 字符时默认截断显示。
3. 认证与会话 (Authentication & Session)¶
3.1 架构概览¶
Web 前端托管 Better Auth 作为统一身份源,管理用户注册、登录、会话和 JWT 签发。
flowchart TB
subgraph "Next.js (Web)"
AUTH_API["api/auth/[...all]/route.ts<br/>Better Auth Handler"]
AUTH_LIB["lib/auth.ts<br/>Server Config"]
AUTH_CLI["lib/auth-client.ts<br/>Client SDK"]
PROV["providers.tsx<br/>AuthProvider + useAuth()"]
end
subgraph "Browser"
LOGIN["login/page.tsx"]
SIGNUP["signup/page.tsx"]
GUARD["(chat)/layout.tsx<br/>Auth Guard"]
end
subgraph "PostgreSQL"
DB[(auth tables:<br/>user, session, account,<br/>verification, jwks)]
end
LOGIN -->|"signIn.email / signIn.social"| AUTH_CLI
AUTH_CLI -->|"HTTP"| AUTH_API
AUTH_API --> AUTH_LIB
AUTH_LIB --> DB
GUARD -->|"useAuth() → session check"| PROV
PROV --> AUTH_CLI
3.2 关键文件¶
| 文件 | 职责 |
|---|---|
lib/auth.ts |
Better Auth 服务端配置(plugins, DB pool, providers) |
lib/auth-client.ts |
客户端 auth 实例(jwtClient + adminClient plugins) |
app/api/auth/[...all]/route.ts |
Next.js App Router catch-all handler,暴露 /api/auth/* |
app/(auth)/layout.tsx |
Auth Shell 布局(双栏:品牌面板 + 表单区) |
app/(auth)/auth-left-panel.tsx |
左侧品牌面板(网格背景、光晕、统计、testimonial) |
app/(auth)/login/page.tsx |
登录页(Email/Password + 条件 GitHub) |
app/(auth)/signup/page.tsx |
注册页(同上表单模式) |
components/ui/providers.tsx |
AuthProvider + useAuth() hook |
3.3 会话管理¶
| 概念 | 实现 | 说明 |
|---|---|---|
| Browser Session | Better Auth cookie (better-auth.session_token) |
7 天有效,自动刷新 (updateAge: 1 天) |
| API Token | authClient.token() → RS256 JWT |
1 小时有效,用于发往 FastAPI 的请求 |
| Session Provider | AuthProvider in providers.tsx |
包装 authClient.useSession(),提供 useAuth() hook |
3.4 页面保护策略¶
// app/(chat)/layout.tsx — 认证守卫
const { data: session, isPending } = useAuth();
if (!isPending && !session) {
redirect("/login");
}
// app/(chat)/admin/layout.tsx — 角色守卫
if (session?.user?.role !== "admin") {
redirect("/chat");
}
| 路由组 | 保护级别 | 未通过时行为 |
|---|---|---|
(auth) |
无保护 | — |
(chat) |
需要登录 | → /login |
(chat)/admin |
需要 admin 角色 | → /chat |
3.5 Token Bridge(API 认证注入)¶
所有发往 FastAPI 的请求通过 client-config.ts 的 request interceptor 自动注入 JWT:
// lib/api/client-config.ts
interceptors: {
request: [async (request) => {
const { data: token } = await authClient.token();
if (token) request.headers.set("Authorization", `Bearer ${token}`);
return request;
}],
response: [async (response) => {
if (response.status === 401) window.location.href = "/login";
return response;
}],
}
- Token 获取:调用
authClient.token(),Better Auth JWT plugin 签发 RS256 JWT - 401 处理:统一重定向到登录页(会话过期或 Token 无效)
- SSE 流:
chat-stream.ts同样注入 Bearer Token
3.6 条件 GitHub OAuth¶
GitHub 登录为可选功能,通过环境变量控制:
- 服务端(
lib/auth.ts):仅当GITHUB_CLIENT_ID+GITHUB_CLIENT_SECRET都存在时启用 - 客户端(login/signup):根据
NEXT_PUBLIC_GITHUB_AUTH_ENABLED=true显示 GitHub 按钮
未配置 GitHub 时,登录页仅显示 Email/Password 表单,不影响核心功能。
4. 状态管理架构 (State Management)¶
4.1 整体数据流¶
flowchart TB
subgraph Browser
UI[React Components]
ZS[Zustand Stores]
RQ[React Query Cache]
end
subgraph Backend
API[REST API]
SSE[SSE Stream]
end
UI -->|dispatch actions| ZS
UI -->|useQuery / useMutation| RQ
RQ -->|fetch / mutate| API
SSE -->|onEvent callback| ZS
ZS -->|selector subscriptions| UI
RQ -->|cache data| UI
4.2 Zustand Stores 详解¶
chat-store.ts — Chat 核心状态¶
| 状态字段 | 类型 | 说明 |
|---|---|---|
currentChatId |
string \| null |
当前活跃对话 ID |
messages |
MessageResponse[] |
当前对话完整消息列表 |
streamStatus |
StreamStatus |
idle / connecting / streaming / clarification / viz_checkpoint / done / error |
streaming |
StreamingAssistant |
SSE 流式过程中累积的结构化数据 |
chats |
ChatSummary[] |
侧边栏对话列表 |
chatsTotal |
number |
对话总数(分页) |
StreamingAssistant 结构(SSE 流式累积):
type StreamingAssistant = {
sql: string | null; // 生成的 SQL
intent: Record<string, unknown> | null; // 意图解析结果
validationResult: Record<string, unknown> | null; // SQL 校验
executionResult: { // 执行结果
columns: string[];
rows: unknown[][];
row_count: number;
has_more: boolean;
execution_time_ms: number;
} | null;
visualization: { // 可视化决策包
chart_type: string | null;
echarts_option: Record<string, unknown> | null;
templateRef: TemplateRef | null; // 模板引用(前端 hydration 用,类型来自 chart-templates/types.ts)
candidates: VizCandidateData[] | null; // Top-k 候选图表列表
confidence: number | null; // 推荐置信度 (0-1)
checkpointStatus: "auto_pass" | "needs_review" | "blocked" | null;
} | null;
insights: string[]; // 数据洞察
sqlBusinessContext: {...} | null; // 业务上下文
pipelineNodes: PipelineNodeEntry[]; // Pipeline 节点状态
pipelineSteps: Array<{...}>; // Pipeline 步骤详情
retrievalSteps: Array<{...}>; // 检索步骤
graphResult: {...} | null; // 知识图谱结果
knowledge: { answer: string; sources: string[] } | null;
routeDecision: string | null; // 路由决策
evaluators: Array<{...}>; // 评估器结果
mlResults: unknown[]; // ML 分析结果
suggestedFollowups: Array<{...}>; // 推荐追问
errors: string[]; // 错误信息
clarification: {...} | null; // 澄清请求
};
query-workspace-store.ts — Query 工作区状态¶
| 状态字段 | 类型 | 说明 |
|---|---|---|
streamStatus |
StreamStatus |
流状态 |
sessionId |
string \| null |
当前 Session ID |
resultData |
ResultData \| null |
查询结果(columns + rows) |
currentSql |
string \| null |
当前生成的 SQL |
visualization |
VisualizationData \| null |
可视化决策包:ECharts 配置 + 模板引用 + 候选列表 + 置信度 + checkpoint 状态 |
vizCheckpoint |
VizCheckpointData \| null |
HITL checkpoint 数据(低置信度时展示候选选择 UI) |
insights |
string[] |
数据洞察 |
pipelineSteps |
PipelineStepData[] |
Pipeline 步骤 |
drilldownPath |
DrilldownData[] |
下钻路径 |
linkedSelection |
LinkedSelectionData \| null |
图表-表格联动选中 |
session-detail-store.ts — Session 详情状态¶
用于 /sessions/[sessionId] 页面,管理历史 Turn 的回放和展示。
ui-preferences-store.ts — UI 偏好(持久化)¶
type UiPreferencesState = {
activeResultTab: "table" | "sql" | "chart" | "insights"
| "context" | "graph" | "knowledge" | "ml";
sidebarOpen: boolean;
};
持久化策略
ui-preferences-store 使用 Zustand persist 中间件,状态保存到 localStorage(key: ttd-ui-prefs)。
4.3 React Query 管理的服务端状态¶
| Hook | 数据 | 缓存策略 |
|---|---|---|
useChatEngines() |
Chat Engine 列表 | staleTime: 5min |
useKnowledgeBases() |
知识库列表 | staleTime: 5min |
useModels() |
LLM/Embedding/Reranker 模型 | staleTime: 5min |
useSiteSettings() |
站点配置(示例问题、品牌) | staleTime: 10min |
useSessionsQuery() |
Session 列表 | staleTime: 30s |
useSessionQuery(id) |
单个 Session 详情 | staleTime: 0 (always fresh) |
useHealthQuery() |
后端健康状态 | refetchInterval: 30s |
useStats() |
Admin Dashboard 统计 | staleTime: 1min |
useFeedbacks() |
用户反馈列表 | staleTime: 1min |
useFewShots() |
Few-Shot 条目列表(按状态) | staleTime: 30s |
useFewShotStats() |
Few-Shot 各状态统计 | staleTime: 30s |
5. API 集成层 (API Integration Layer)¶
5.1 架构概览¶
flowchart LR
subgraph Frontend
C[Components]
H[Hooks]
LIB[lib/api/index.ts]
GEN[lib/api/generated/]
SSE_LIB[lib/api/chat-stream.ts]
end
subgraph Backend
REST[REST API]
STREAM[SSE Endpoint]
end
C --> H
H --> LIB
H --> SSE_LIB
LIB --> GEN
GEN -->|@hey-api/client-fetch| REST
SSE_LIB -->|POST + ReadableStream| STREAM
5.2 OpenAPI 代码生成¶
// openapi-ts.config.ts
import { defineConfig } from "@hey-api/openapi-ts";
export default defineConfig({
input: process.env.OPENAPI_TS_INPUT ?? "http://localhost:8000/openapi.json",
output: "lib/api/generated",
plugins: [
{ name: "@hey-api/client-fetch", runtimeConfigPath: "../client-config.ts" },
{ name: "@hey-api/sdk", operations: { nesting: "operationId" } },
],
});
生成产物:
| 文件 | 说明 |
|---|---|
lib/api/generated/client.gen.ts |
HTTP 客户端实例 |
lib/api/generated/sdk.gen.ts |
按 operationId 组织的 SDK 函数 |
lib/api/generated/types.gen.ts |
TypeScript 类型定义 |
5.3 SSE 流式实现¶
非 EventSource
本项目使用 POST-based SSE(非浏览器原生 EventSource),因为需要在 SSE 请求中携带 JSON body。
实现基于 fetch + ReadableStream + TextDecoder 手动解析 SSE 协议。
核心流程:
// lib/api/chat-stream.ts
export async function streamChatMessage({
chatId, content, language, signal, onEvent, onError, onDone
}: StreamChatMessageParams): Promise<void> {
const response = await fetch(
`${baseUrl}/api/v1/chats/${chatId}/messages/stream`,
{ method: "POST", headers: {...}, body: JSON.stringify({ content, language }), signal }
);
const reader = response.body?.getReader();
// 手动 SSE line protocol 解析:event: / data: / 空行分隔
// ...解析后调用 onEvent(parsedEvent)
}
5.4 SSE Event Types(完整列表)¶
| Event Name | Schema | 说明 |
|---|---|---|
chat |
chatEventSchema |
对话创建确认 |
message |
messageEventSchema |
消息 ID 与序号 |
turn |
turnEventSchema |
Turn 标识 |
session |
sessionEventSchema |
Session ID 关联 |
pipeline_plan |
pipelinePlanEventSchema |
Pipeline 计划节点列表 |
node_start |
nodeStartEventSchema |
节点开始执行 |
node_complete |
nodeCompleteEventSchema |
节点执行完成 |
step_detail |
stepDetailEventSchema |
步骤详情(label-value 对) |
retrieval_step |
retrievalStepEventSchema |
检索步骤结果 |
route_decision |
routeDecisionEventSchema |
路由决策 |
intent |
intentEventSchema |
意图解析 |
sql |
sqlEventSchema |
生成的 SQL |
validation |
validationEventSchema |
SQL 校验结果 |
data |
dataEventSchema |
查询执行结果 |
visualization |
visualizationEventSchema |
可视化决策包 (echarts_option, template_ref, candidates, confidence, checkpoint_status) |
checkpoint |
checkpointEventSchema |
可视化 HITL checkpoint(低置信度时触发前端候选确认 UI) |
insights |
insightsEventSchema |
数据洞察 |
sql_business_context |
sqlBusinessContextEventSchema |
业务上下文 |
context |
sqlBusinessContextEventSchema |
同上(别名) |
graph |
graphEventSchema |
知识图谱结果 |
knowledge |
knowledgeEventSchema |
知识问答结果 |
evaluator |
evaluatorEventSchema |
评估器结果 |
clarification |
clarificationEventSchema |
澄清请求 |
errors |
errorsEventSchema |
错误(可能含修复尝试) |
error |
errorEventSchema |
单条错误 |
ml_result |
mlResultEventSchema |
ML 分析结果 |
ml_chart |
mlChartEventSchema |
ML 图表配置 |
ml_summary |
mlSummaryEventSchema |
ML 摘要 |
suggested_followups |
suggestedFollowupsEventSchema |
推荐追问 |
done |
doneEventSchema |
流结束标记 |
5.5 SSE Schema 验证¶
所有 SSE 事件使用 Zod v4 进行运行时 Schema 验证:
// lib/api/sse-schema.ts
export function parseStreamEvent(eventName: string, rawData: string): ParsedStreamEvent | null {
const schema = schemaMap[eventName];
if (!schema) return null;
const result = schema.safeParse(JSON.parse(rawData));
if (!result.success) {
console.warn(`[SSE] Validation failed for "${eventName}":`, result.error);
return null;
}
return { event: eventName, data: result.data } as ParsedStreamEvent;
}
容错策略
Schema 验证失败时返回 null(跳过),不中断流。同时在 console 打印警告以辅助调试。
6. 核心 Hooks (Core Hooks)¶
6.1 Hooks 列表¶
| Hook | 文件 | 职责 |
|---|---|---|
useChatStream() |
hooks/use-chat-stream.ts |
完整 Chat 生命周期(创建 → 流式 → 构建消息) |
useQueryStream() |
hooks/use-query-stream.ts |
Query Workspace 流式查询 |
useChatEngines() |
hooks/use-chat-engines.ts |
Chat Engine 列表 |
useKnowledgeBases() |
hooks/use-knowledge-bases.ts |
知识库列表 |
useModels() |
hooks/use-models.ts |
模型列表(LLM / Embedding / Reranker) |
useSiteSettings() |
hooks/use-site-settings.ts |
站点设置(示例问题、品牌) |
useSessionsQuery() |
hooks/use-sessions-query.ts |
Session 列表(分页) |
useSessionQuery() |
hooks/use-session-query.ts |
单 Session 详情 |
useSessionsListQuery() |
hooks/use-sessions-list-query.ts |
Session 列表(列表形式) |
useFeedbackMutation() |
hooks/use-feedback-mutation.ts |
提交消息反馈 |
useMessageFeedback() |
hooks/use-message-feedback.ts |
消息级别反馈 |
useFeedbacks() |
hooks/use-feedbacks.ts |
反馈列表查询 |
useFewShots() |
hooks/use-few-shots.ts |
动态 Few-Shot 列表(按状态分页) |
useFewShotStats() |
hooks/use-few-shots.ts |
Few-Shot 各状态数量统计 |
useHealthQuery() |
hooks/use-health-query.ts |
后端健康检查(轮询) |
useStats() |
hooks/use-stats.ts |
Admin 统计数据 |
useEvaluation() |
hooks/use-evaluation.ts |
评测任务管理 |
useGraph() |
hooks/use-graph.ts |
图谱数据查询 |
useGraph() |
hooks/use-graph.ts |
图谱数据查询 |
useDatasources() |
hooks/use-datasources.ts |
数据源列表 |
useDocuments() |
hooks/use-documents.ts |
文档管理 |
useMobile() |
hooks/use-mobile.tsx |
移动端检测 |
6.2 useChatStream() 详解¶
sequenceDiagram
participant User
participant Hook as useChatStream
participant Store as ChatStore
participant API as Backend SSE
User->>Hook: submit(question)
Hook->>API: POST /api/v1/chats (if no chatId)
API-->>Hook: { id: chatId }
Hook->>Store: setCurrentChat(chatId)
Hook->>Store: addMessages(userMsg)
Hook->>Store: startStream()
Hook->>API: POST /api/v1/chats/{id}/messages/stream
loop SSE Events
API-->>Hook: event: node_start, sql, data, ...
Hook->>Store: handleStreamEvent(event)
end
API-->>Hook: event: done
Hook->>Store: finishStream(assistantMsg)
关键行为:
- 自动创建 Chat — 若
currentChatId为null,先调用POST /api/v1/chats创建 - 乐观更新 — 用户消息立即添加到 Store,无需等待服务端确认
- AbortController — 支持取消正在进行的流
- 路由跳转 — 创建新 Chat 后自动
router.replace(/chat/c/${chatId})
6.3 useQueryStream() 详解¶
export function useQueryStream() {
const submit = useCallback((question: string, existingSessionId?: string | null) => {
// 1. 取消旧流
// 2. 调用 startStream() 重置 Store
// 3. streamQuery() → POST /api/v1/query/stream
// 4. onEvent → handleStreamEvent() 分发到 Store
}, []);
const cancel = useCallback(() => { abortRef.current?.abort(); }, []);
return { submit, cancel, sessionId };
}
7. 组件体系 (Component Architecture)¶
7.1 目录结构¶
components/
├── chat/ # Chat 相关组件
├── results/ # 结果展示组件
├── admin/ # Admin Panel 组件
├── landing/ # Landing Page 区块
├── charts/ # 图表组件(chart-panel, visualization-checkpoint, echarts-renderer)
├── feedback/ # 反馈组件
├── markdown/ # Markdown 渲染
├── query/ # Query Workspace 组件(含 clarification-dialog)
├── session/ # Session 组件
├── ui/ # 基础 UI 组件 (shadcn/ui)
└── site-sidebar.tsx # 全局侧边栏
7.2 Chat 组件群¶
| 组件 | 职责 |
|---|---|
message-composer.tsx |
消息输入框(自动 resize、快捷键、发送) |
chat-conversation.tsx |
对话消息列表(虚拟滚动、自动滚底) |
streaming-message.tsx |
流式消息渲染(实时更新 Pipeline 进度) |
assistant-message.tsx |
完成态助手消息(8 个结果 Tab) |
assistant-result-block.tsx |
结果区块包裹器 |
thinking-steps.tsx |
Pipeline 思考步骤动画 |
user-message.tsx |
用户消息气泡 |
chat-empty-state.tsx |
空状态(示例问题引导) |
chat-export-button.tsx |
对话导出 |
message-feedback.tsx |
消息级别反馈(👍/👎) |
Assistant Message 8 个结果 Tab:
| Tab | 内容 |
|---|---|
| Table | 数据表格(排序、筛选、固定列、密度调节、下钻) |
| SQL | SQL 代码块(语法高亮、复制、格式化) |
| Chart | ECharts 可视化 |
| Insights | 数据洞察(Markdown 渲染) |
| Context | 业务上下文(关联表、列、指标、规则、术语) |
| Graph | 知识图谱可视化(@antv/g6) |
| Knowledge | 知识问答结果 |
| ML | ML 分析结果与图表 |
7.3 Results 组件群¶
| 组件 | 职责 |
|---|---|
result-table.tsx |
核心数据表格(@tanstack/react-table) |
result-table-toolbar.tsx |
工具栏(搜索、筛选、列可见性、密度切换) |
result-table-footer.tsx |
表格底部(分页、行数统计) |
result-table-utils.ts |
表格工具函数 |
result-tabs.tsx |
结果标签页容器 |
sql-panel.tsx |
SQL 展示面板 |
graph-result-panel.tsx |
图谱结果面板 |
knowledge-panel.tsx |
知识回答面板 |
ml-result-panel.tsx |
ML 结果面板 |
business-context-panel.tsx |
业务上下文面板 |
suggested-followups.tsx |
推荐追问卡片 |
drilldown-breadcrumb.tsx |
下钻面包屑导航 |
advanced-filter-dropdown.tsx |
高级筛选下拉 |
column-visibility-dropdown.tsx |
列可见性控制 |
7.4 Landing Page 组件群¶
| 组件 | 职责 |
|---|---|
hero-section.tsx |
首页主视觉区 |
metrics-bar.tsx |
关键指标展示条 |
governance-section.tsx |
三层治理模型介绍 |
triple-engine-section.tsx |
三引擎架构介绍 |
agent-section.tsx |
Agent 编排能力介绍 |
security-section.tsx |
安全特性介绍 |
features-grid.tsx |
功能特性网格 |
cta-section.tsx |
Call-to-Action 区 |
footer.tsx |
页脚 |
nav.tsx |
导航栏 |
7.5 基础 UI 组件(54 个)¶
基于 Radix UI + shadcn/ui 的完整组件库,包括:
完整列表
accordion · alert-dialog · alert · aspect-ratio · avatar · badge ·
breadcrumb · button · calendar · card · checkbox · collapsible ·
command · confirm-dialog · context-menu · data-table · date-picker ·
dialog · dot-pattern · drawer · dropdown-menu · form · health-badge ·
hover-card · input-otp · input · label · menubar · navigation-menu ·
popover · progress · providers · radio-group · resizable · scroll-area ·
select · separator · sheet · sidebar · skeleton · slider · sonner ·
sql-code-block · stream-status-badge · switch · table · tabs ·
textarea · theme-toggle · toggle-group · toggle · tooltip ·
workspace-composer-bar · workspace-empty-state · workspace-header ·
workspace-sidebar
8. 数据可视化 (Data Visualization)¶
8.1 ECharts 集成¶
ECharts 6.0 是主力图表引擎,通过 echarts-for-react 封装为 React 组件。
配置来源: Backend 采用 推荐决策引擎(top-k recommendation + adapter render),95%+ 的请求无需 LLM。
响应中包含 echarts_option(完整配置)、template_ref(模板引用)以及 candidates/confidence/checkpoint_status(决策元数据)。
flowchart LR
BE["Backend Recommendation Engine<br/>(35 templates, top-k scoring)"] -->|"SSE: visualization event<br/>{echarts_option, template_ref,<br/>candidates, confidence,<br/>checkpoint_status}"| FE[Frontend]
FE -->|"High confidence<br/>(auto_pass)"| EC[ECharts Component]
FE -->|"Low confidence<br/>(needs_review)"| CP[Checkpoint Dialog]
CP -->|"User selects"| HY[Client Hydration]
FE -->|"Fallback: hydrateChart(template_ref, data)"| HY
HY --> EC
EC --> R[Rendered Chart]
推荐决策架构(Backend):
Query Result (columns, rows, row_count, intent_type)
│
▼
┌─────────────────────────────────────┐
│ DataShapeAnalyzer (pure Python) │ ← 列分类、结构检测
└──────────────────┬──────────────────┘
▼
┌─────────────────────────────────────┐
│ ChartMatcher.recommend(top_k=3) │ ← 候选评分、置信度计算、checkpoint 判定
└──────────────────┬──────────────────┘
▼
┌─────────────────────────────────────┐
│ EChartsAdapter (RendererAdapter) │ ← 数据绑定 + 主题覆盖
│ (35 templates × 4 themes) │ ← Output: echarts_option
└─────────────────────────────────────┘
HITL Checkpoint(低置信度人工确认):
当推荐置信度低于阈值(0.50)或 top-1/top-2 分差过小(< 0.05)时,前端展示候选确认 UI:
streamStatus变为"viz_checkpoint",暂停后续流处理VisualizationCheckpointDialog展示 2-3 个候选图表的迷你预览(通过hydrateChart()渲染)- 用户可选择:接受推荐 / 选择其他候选 / 回退为表格视图
- 选择后
resolveVizCheckpoint()更新 store,流恢复为"done"状态
前端 ECharts Adapter(lib/chart-templates/):
该模块是前端 ECharts 渲染适配器,不负责可视化决策。当 backend 仅发送 template_ref 时提供客户端渲染:
import { canHydrate, hydrateChart } from "@/lib/chart-templates";
// template_ref from SSE visualization event
if (canHydrate(templateRef)) {
const option = hydrateChart(templateRef, { columns, rows, rowCount });
// option is a complete ECharts config, ready to render
}
主题系统: 支持 default、light、dark、brand 四种主题,通过 rehydrateWithTheme() 可实时切换:
import { rehydrateWithTheme } from "@/lib/chart-templates";
const darkOption = rehydrateWithTheme(templateRef, data, "dark");
支持的图表类型(35 模板):
| 类型 | 模板数 | 变体 |
|---|---|---|
| Bar / Column | 6 | vertical, horizontal, grouped, stacked, waterfall, percentage |
| Line / Area | 7 | basic, smooth, area, stacked area, step, multi, dual axis |
| Pie / Donut | 5 | basic, donut, rose, nested donut, semi donut |
| Trend | 3 | trend line, trend area, multi-trend |
| Ranking | 2 | ranking bar, top-N highlight |
| Combo | 2 | dual axis (bar+line), overlay |
| KPI | 3 | gauge, card, multi-KPI |
| Specialized | 7 | heatmap, distribution, funnel, scatter, radar, treemap, progress gauge |
8.2 图表-表格联动 (Linked Selection)¶
sequenceDiagram
participant Chart
participant Store as QueryWorkspaceStore
participant Table as ResultTable
Chart->>Store: setLinkedSelection({ column, value, source: "chart" })
Store-->>Table: linkedSelection 变更
Table->>Table: 高亮匹配行
Note right of Table: 反向联动:表格点击行 → 图表高亮对应数据点
8.3 @antv/g6 知识图谱¶
用于展示图谱查询结果(graph 事件),支持:
- 力导向布局(Force-directed layout)
- 节点按类型着色(Table / Column / Term / Metric)
- 边标签(关系类型)
- 交互缩放与拖拽
- 节点点击跳转详情
8.4 Recharts 辅助图表¶
用于简单的统计图表场景(如 Admin Dashboard 中的趋势图),提供声明式 API。
9. 交互设计模式 (Interaction Patterns)¶
9.1 流式渐进披露 (Progressive Disclosure)¶
SSE 流式响应按以下顺序逐步展示:
flowchart TB
A[pipeline_plan] --> B[node_start: 意图解析]
B --> C[intent + route_decision]
C --> D[node_start: SQL 生成]
D --> E[sql]
E --> F[validation]
F --> G[node_start: 执行]
G --> H[data]
H --> I[visualization]
I -->|"auto_pass"| J[insights]
I -->|"needs_review"| CP[checkpoint — HITL 候选确认]
CP -->|"user resolves"| J
J --> K[suggested_followups]
K --> L[done]
视觉效果:
thinking-steps.tsx组件负责 Pipeline 步骤的动画展示- 每个节点完成后展示对应结果 Tab
- 使用 Framer Motion 实现平滑入场动画
9.2 键盘快捷键¶
| 快捷键 | 功能 |
|---|---|
Enter |
发送消息(Composer 焦点时) |
Shift + Enter |
换行(Composer 焦点时) |
Ctrl + Shift + O |
新建对话 |
Escape |
取消当前流式请求 |
9.3 主题切换¶
基于 next-themes,支持 Light / Dark / System 三种模式:
// components/ui/theme-toggle.tsx
// 使用 useTheme() hook 切换,主题 class 应用到 <html> 元素
// Tailwind CSS 4 dark: variant 自动响应
9.4 响应式设计¶
| 断点 | 行为 |
|---|---|
| Desktop (≥1024px) | 双面板布局(侧边栏 + 主内容) |
| Tablet (768-1023px) | 侧边栏可折叠 |
| Mobile (<768px) | 底部导航,全屏内容 |
useMobile() hook 提供设备类型检测。
9.5 通知系统¶
使用 Sonner 提供 Toast 通知:
- 成功操作(绿色)
- 错误提示(红色)
- 加载状态(带进度指示)
- 支持 Action 按钮(如 "撤销")
9.6 面板分割¶
react-resizable-panels 提供可拖拽面板分割:
- Results 页面:左侧表格 / 右侧多 Tab 面板
- Chat 页面:侧边栏 / 主对话区
- 支持双击重置默认比例
10. 环境配置 (Environment Configuration)¶
10.1 环境变量¶
| 变量 | 类型 | 默认值 | 说明 |
|---|---|---|---|
NEXT_PUBLIC_TTD_API_BASE_URL |
URL | http://localhost:8000 |
Backend API 地址 |
NEXT_PUBLIC_TTD_DEFAULT_LANGUAGE |
zh | en |
zh |
UI 默认语言 |
NEXT_PUBLIC_TTD_ENABLE_DEBUG_TOKEN_INPUT |
true | false |
false |
是否启用 Debug Token 输入框 |
BETTER_AUTH_URL |
URL | http://localhost:3000 |
Better Auth 基础 URL |
BETTER_AUTH_SECRET |
string | — | 会话加密密钥(生产必须强随机值) |
AUTH_DATABASE_URL |
DSN | — | Better Auth 数据库连接串 |
GITHUB_CLIENT_ID |
string | — | GitHub OAuth App ID(可选) |
GITHUB_CLIENT_SECRET |
string | — | GitHub OAuth App Secret(可选) |
NEXT_PUBLIC_GITHUB_AUTH_ENABLED |
true | false |
— | 前端是否显示 GitHub 登录按钮 |
10.2 环境验证¶
环境变量在运行时通过 Zod Schema 验证:
// lib/env/index.ts
const envSchema = z.object({
NEXT_PUBLIC_TTD_API_BASE_URL: z.url(),
NEXT_PUBLIC_TTD_DEFAULT_LANGUAGE: z.enum(["zh", "en"]).default("zh"),
NEXT_PUBLIC_TTD_ENABLE_DEBUG_TOKEN_INPUT: z
.enum(["true", "false"]).default("false")
.transform((v) => v === "true"),
});
export function getEnv(): Env {
return envSchema.parse({...});
}
验证时机
getEnv() 在客户端首次调用时执行验证。如缺少必要变量,会抛出 Zod 错误并在控制台显示详细信息。
10.3 配置文件¶
| 文件 | 用途 |
|---|---|
.env.local |
本地开发配置(Git 忽略) |
.env.example |
配置模板(提交到仓库) |
next.config.ts |
Next.js 配置 |
tsconfig.json |
TypeScript 配置 |
biome.json |
Biome 格式化 + Lint 配置 |
postcss.config.mjs |
PostCSS(Tailwind 集成) |
openapi-ts.config.ts |
OpenAPI 代码生成配置 |
11. 构建与开发 (Build & Development)¶
11.1 开发命令¶
# 安装依赖
task web:install # bun install
# 启动开发服务器(Turbopack 加速)
task web:dev # next dev --turbopack
# 生产构建
task web:build # next build
# 启动生产服务器
task web:start # next start
# 代码检查
task web:check # biome check .
# 代码格式化
task web:format # biome format --write .
# 类型检查
task web:typecheck # tsc --noEmit
# 生成 OpenAPI 客户端
task web:generate:api # openapi-ts (从 Backend OpenAPI Schema 生成)
# 完整 CI 流程
task web:ci # check + typecheck
11.2 开发工作流¶
flowchart LR
A[修改代码] --> B[Turbopack HMR]
B --> C[浏览器热更新]
D[修改 Backend API] --> E[task web:generate:api]
E --> F[更新 lib/api/generated/]
F --> A
11.3 代码生成流程¶
# 1. 确保 Backend 运行中
task backend:dev
# 2. 生成 OpenAPI 客户端
task web:generate:api
# 等效于: OPENAPI_TS_INPUT=http://localhost:8000/openapi.json bun run generate:api
# 3. 生成文件位于 lib/api/generated/
# - client.gen.ts → HTTP 客户端配置
# - sdk.gen.ts → 按 operationId 命名的 SDK 函数
# - types.gen.ts → Request/Response TypeScript 类型
11.4 代码规范¶
Biome 2.2 同时负责格式化和 Lint:
| 规则 | 说明 |
|---|---|
| 缩进 | 2 空格(Tab 存储,空格显示) |
| 引号 | 双引号 |
| 分号 | 始终添加 |
| 行宽 | 100 字符 |
| Import 排序 | 自动排序 |
| 未使用变量 | 错误级别 |
11.5 项目依赖拓扑¶
graph TD
A[web] -->|openapi-ts| B[Backend OpenAPI Schema]
A -->|fetch| C[Backend REST API]
A -->|SSE| D[Backend Stream Endpoint]
A -->|环境变量| E[.env.local]
附录 A: SSE 事件流完整示例¶
event: chat
data: {"chat_id": "abc-123"}
event: message
data: {"message_id": "msg-456", "ordinal": 2}
event: pipeline_plan
data: {"nodes": ["intent", "sql_generation", "validation", "execution", "visualization"]}
event: node_start
data: {"node": "intent", "title": "意图解析"}
event: intent
data: {"intent": {"type": "metric_query", "complexity": "simple"}, "route_decision": "sql"}
event: node_complete
data: {"node": "intent", "status": "success"}
event: node_start
data: {"node": "sql_generation", "title": "SQL 生成"}
event: sql
data: {"sql": "SELECT date, SUM(amount) FROM orders GROUP BY date", "explanation": "按日期汇总订单金额"}
event: node_complete
data: {"node": "sql_generation", "status": "success"}
event: validation
data: {"syntax_pass": true, "policy_pass": true, "explain_pass": true}
event: data
data: {"columns": ["date", "total"], "rows": [["2024-01-01", 1500], ["2024-01-02", 2300]], "row_count": 2, "has_more": false, "execution_time_ms": 45}
event: visualization
data: {"chart_type": "line", "echarts_option": {"xAxis": {"data": ["2024-01-01", "2024-01-02"]}, "series": [{"data": [1500, 2300], "type": "line"}]}, "template_ref": {"template_id": "trend_line", "score": 0.9, "theme": "default", "data_mapping": {"category_col": 0, "value_cols": [1], "series_col": null, "time_col": 0}}}
event: insights
data: {"items": ["订单金额呈上升趋势,1月2日环比增长53%"]}
event: suggested_followups
data: {"items": [{"text": "按产品分类查看", "intent_hint": "drill_down", "depth": null}]}
event: done
data: {"status": "completed", "message_id": "msg-456"}
附录 B: Store 状态生命周期¶
stateDiagram-v2
[*] --> idle
idle --> connecting: submit()
connecting --> streaming: 首个 SSE event
streaming --> streaming: handleStreamEvent()
streaming --> clarification: clarification event
clarification --> idle: 用户选择后重新提交
streaming --> done: done event
streaming --> error: error event / 网络失败
done --> idle: 新查询
error --> idle: 重试 / 新查询
附录 C: 文件引用索引¶
| 关注领域 | 核心文件 |
|---|---|
| SSE 协议 | lib/api/chat-stream.ts, lib/api/query-stream.ts |
| Schema 定义 | lib/api/sse-schema.ts |
| 状态管理 | stores/chat-store.ts, stores/query-workspace-store.ts |
| Chat 核心 | hooks/use-chat-stream.ts, components/chat/ |
| 可视化 | components/charts/, lib/chart-templates/ |
| API 生成 | openapi-ts.config.ts, lib/api/generated/ |
| 环境配置 | lib/env/index.ts, .env.example |
| UI 组件 | components/ui/ (54 个) |