模块 1 · 路由与登录

四角色路由、HashRouter
与 Demo 账号

前端在 web/,用 React + HashRouter 做四角色工作台。登录后按角色跳进不同「家」——改路由时先对 App.tsx 和 demoAccounts.ts。

四角色默认入口

CUST-9527客户 → /app/customer/home
STAFF-10086理财师 → /app/advisor/home
STAFF-20001分析员 → /app/analyst/home
STAFF-30001风控 → /app/risk/home

登录页一键 Demo:LoginPage 调 POST /api/auth/login 拿 JWT,saveAuth 写入 localStorage,再 navigate(defaultRoute)。

路由树(App.tsx)

customer/*

home、profile、holdings、trades、chat。持仓/流水走平台 API,对话走 ChatPanel。

advisor/*

home、customers、chat。顾问助手 SSE,可指定 customer_id 查名下客户。

analyst/*

home、analytics/query(问数)、analytics/assets、analytics/chat。问数走 /api/analyst/*。

risk/*

home、alerts、simulate、chat。台账 REST + 风控对话,JWT 须带 risk 角色。

HashRouter 为什么? 构建产物是纯静态文件,#/app/customer/home 不依赖服务端路由重写,双击 dist/index.html 也能跑(API 仍要 proxy 或同域)。
main.tsx + App.tsx
// main.tsx
<HashRouter>
  <AppRoutes />
</HashRouter>

// demoAccounts.ts
defaultRoute: '#/app/customer/home'

// App.tsx · RequireAuth
if (!auth) return <Navigate to="/login" />
白话

整站包在 HashRouter 里,路径变化不刷新整页。

每个 Demo 账号绑好「登录后跳哪」——带 # 前缀,和 Hash 路由一致。

/app 下子路由都要过 RequireAuth:没 token 踢回登录页。

分析员 Demo 登录成功,默认打开哪条路径?

模块 2 · 对话与鉴权

ChatPanel / useChatPanel:
三条 API 线的头不一样

对话 UI 统一用 ChatPanel + useChatPanel,但后端入口分三条: /api/chat(四 Agent)、/api/analyst/*(问数平台)、风控台账 REST。 指挥 AI 接新页面时,先对表再写 headers。

鉴权差异对照

前端模块APIAuthorizationX-Agent-Type
api/chat.ts/api/chat, /stream, sessionsBearer必须(与 prop agentType 一致)
api/analyst.ts/api/analyst/chat 等Bearer(apiFetch)不要
api/risk.ts/api/risk/*Bearer必须 risk
持仓/产品页/api/customers/* 等Bearer不要
真实 bug: risk.ts 曾漏 X-Agent-Type: risk,JWT 正确也 401。接新风控页先 grep 这个头。

数据流:理财师打开顾问助手

💬ChatPanel
🪝useChatPanel
📡api/chat.ts
🚪对话 HTTP 入口(chat.py)

对比:问数走 analyst.ts,无 X-Agent-Type

chat.ts vs analyst.ts
// chat.ts — 对话线
function chatHeaders(token, agentType) {
  return {
    Authorization: `Bearer ${token}`,
    'X-Agent-Type': agentType,
  }
}

// analyst.ts — 问数平台线
apiFetch('/api/analyst/chat', { method: 'POST', token, body })
// apiFetch 只加 Authorization,不加 X-Agent-Type
白话

Chat 相关请求:token 证明身份,agentType 证明走哪条 Agent 线。

useChatPanel 把 agentType 从页面 prop 一路传到每次 list/send/close。

问数用 apiFetch 通用封装,后端走 get_platform_auth_context,不需要 Agent 头。

customer 线 mode 常用 sync(后端 LangGraph 整图跑完再推);advisor/risk 用 stream SSE。

RiskChatPage 发消息,请求头应长什么样?

模块 3 · 本地调试

npm run dev、Vite proxy
与 401 排障

前端 dev 服务器跑在 5173,API 在 8000。 Vite proxy 帮你转发——没起后端或头带错,Network 面板一眼 401。

启动顺序

1
后端 · 应用入口(main.py):uvicorn app.main:app --reload --port 8000(Core 模拟库 + Redis 6380 按需)
2
前端:cd web && npm run dev → 打开 http://localhost:5173
3
登录:点 Demo 账号 → 看 localStorage 里 token → 再点各角色菜单
vite.config.ts
server: {
  port: 5173,
  proxy: {
    '/api': {
      target: 'http://127.0.0.1:8000',
      changeOrigin: true,
    },
  },
},
白话

浏览器请求 localhost:5173/api/... 时,Vite 偷偷转给 8000 端口。

前端代码里写相对路径 /api 即可,不用硬编码 :8000。

生产构建没有 proxy,要 Nginx 或同域部署反代。

常见 401 速查

AUTH_401_MISSING_BEARER

没登录或 token 过期 → 重新点 Demo 登录;改过后端角色也要重登拿新 JWT。

AUTH_401_MISSING_AGENT_TYPE

走了 /api/chat 但没带 X-Agent-Type → 查 ChatPanel 的 agentType 和 chat.ts headers。

AUTH_403_AGENT_MISMATCH

JWT 角色和 X-Agent-Type 不配,如客户 token 却带 advisor → 换账号或改 prop。

连不上 API

8000 没起或 proxy 失效 → curl http://127.0.0.1:8000/health 先确认后端活着。

客户持仓页 401,响应 AUTH_401_MISSING_AGENT_TYPE,最可能原因是?

npm run dev 时,/api/chat 实际打到哪?

模块 4 · 未接线

菜单有 ≠ API 已接
Chat 还有 B 方案三端点

前端 P0 主链路已真接(含风控三页 · 问数标签 · Dashboard hooks),但仍有分析对话占位、看板无钻取等缝。 开发态若 Dashboard「先闪错再正常」,多半是 StrictMode 双请求——已用 useAsyncSequence 丢弃过期响应。

仍开放 / 已修清单(2026-09-10)

风控 UI

台账筛选 · 适当性校验 · AML 扫描页已接 REST;高级运营能力仍简版。

问数

AnalystChatShell 占位 · 真问数在 AnalystQueryPage(模板/缓存标签 + dashboard/assets)。

竞态修复

useAsyncSequence 用于 Dashboard hooks、ChatPanel、风控/客户列表页等。

游客

VisitorChatWidget 首页试聊 · 与登录 ChatPanel 不同 API。

Chat 方案 B:三端点 + SSE 注意点

会话 API
GET  /api/chat/sessions
GET  /api/chat/sessions/{id}/messages
POST /api/chat/sessions/{id}/close
POST /api/chat/stream  → customer SSE
白话

列表/历史/关闭与发消息共用同一套鉴权(Bearer + X-Agent-Type)。

SSE 无心跳:断连可能留下半空回合——排障时查 session 表 + 是否 uvicorn 重启。

HashRouter:URL 带 #,生产 Nginx 要配 SPA fallback。

改 URL 进别人工作台

RequireAuth 只验「有没有 token」,不验「这个角色能不能进 /app/risk」。菜单隐藏 ≠ 安全——后端 AGENT_ACCESS_MATRIX 和平台 RBAC 才拒 403。

客户账号手动打开 /app/risk/alerts,只靠前端能拦住吗?