docs(06-03): complete AdvisorPage plan — streaming chat UI, /advisor route, TopBar link
This commit is contained in:
parent
bcc360892c
commit
f34cf401a0
1 changed files with 96 additions and 0 deletions
96
.planning/phases/06-lab-advisor/06-03-SUMMARY.md
Normal file
96
.planning/phases/06-lab-advisor/06-03-SUMMARY.md
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
---
|
||||
phase: 06-lab-advisor
|
||||
plan: "03"
|
||||
subsystem: frontend
|
||||
tags: [advisor, chat, streaming, sse, react, tanstack-query]
|
||||
dependency_graph:
|
||||
requires: [06-02]
|
||||
provides: [advisor-ui, streaming-chat-frontend]
|
||||
affects: [web/src/router.tsx, web/src/components/layout/TopBar.tsx, web/src/components/layout/AppShell.tsx]
|
||||
tech_stack:
|
||||
added: []
|
||||
patterns: [ReadableStream SSE parsing, TanStack Query refetchInterval sidebar, optimistic user messages, streaming cursor animation]
|
||||
key_files:
|
||||
created:
|
||||
- web/src/api/advisor.ts
|
||||
- web/src/pages/AdvisorPage.tsx
|
||||
modified:
|
||||
- web/src/router.tsx
|
||||
- web/src/components/layout/TopBar.tsx
|
||||
- web/src/components/layout/AppShell.tsx
|
||||
decisions:
|
||||
- "Used fetch + ReadableStream instead of EventSource for SSE — POST body required for chat endpoint"
|
||||
- "Used a ref (streamingContentRef) alongside state to capture latest streaming content inside async callbacks without stale closure issues"
|
||||
- "Added noPadding prop to AppShell to support full-height two-panel layout without max-width constraint"
|
||||
- "Model label in sidebar shows only the model slug (after /) to keep sidebar compact"
|
||||
metrics:
|
||||
duration: "~8 minutes"
|
||||
completed: "2026-04-10T07:39:59Z"
|
||||
tasks_completed: 2
|
||||
files_changed: 5
|
||||
---
|
||||
|
||||
# Phase 06 Plan 03: AdvisorPage Frontend Summary
|
||||
|
||||
**One-liner:** Two-panel streaming chat UI at /advisor — sidebar conversation list, fetch+ReadableStream SSE token streaming, model dropdown, ClickHouse dark theme.
|
||||
|
||||
## Tasks Completed
|
||||
|
||||
| # | Task | Commit | Files |
|
||||
|---|------|--------|-------|
|
||||
| 1 | API wrappers for advisor endpoints | 811223d | web/src/api/advisor.ts |
|
||||
| 2 | AdvisorPage component, route, and TopBar link | bcc3608 | web/src/pages/AdvisorPage.tsx, web/src/router.tsx, web/src/components/layout/TopBar.tsx, web/src/components/layout/AppShell.tsx |
|
||||
|
||||
## What Was Built
|
||||
|
||||
### web/src/api/advisor.ts
|
||||
Typed API wrappers for all three advisor endpoints:
|
||||
- `fetchConversations()` — GET /api/advisor/conversations, returns `[]` on 404
|
||||
- `fetchConversation(id)` — GET /api/advisor/conversations/:id
|
||||
- `streamChat(params, onToken, onDone, onError)` — POST /api/advisor/chat, reads response.body via `getReader()` + `TextDecoder`, splits on `\n\n` SSE delimiters, parses `data:` lines, calls `onToken` per token and `onDone` on `[DONE]`
|
||||
|
||||
### web/src/pages/AdvisorPage.tsx
|
||||
Full two-panel AdvisorPage:
|
||||
- Left sidebar (280px, hidden on mobile): "Lab Advisor" heading, "New Chat" button, conversation list with `refetchInterval: 5000`, selected state highlighted
|
||||
- Main panel: messages area (scrolls to bottom on new content), optimistic user messages (right-aligned bg-[#1a1a1a]), assistant messages (left-aligned bg-[#111]), streaming assistant turn with animated cursor
|
||||
- Input row: model `<select>` (4 OpenRouter models), textarea (Enter to send, Shift+Enter for newline), Send button disabled while streaming or empty
|
||||
- State: `streamingContentRef` ref pattern avoids stale closure in async SSE callbacks while `streamingContent` state drives render
|
||||
|
||||
### web/src/router.tsx
|
||||
Lazy `AdvisorPage` import + `advisorRoute` at path `/advisor` added to route tree.
|
||||
|
||||
### web/src/components/layout/TopBar.tsx
|
||||
`MessageSquare` icon + Advisor `Button variant="outline"` link inserted between Test and Scan buttons.
|
||||
|
||||
### web/src/components/layout/AppShell.tsx
|
||||
Added `noPadding?: boolean` prop — when true, wraps children in `flex-1 flex flex-col overflow-hidden` instead of the default padded/max-width container. Required for AdvisorPage's full-viewport two-panel layout.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 2 - Missing Feature] AppShell noPadding prop**
|
||||
- **Found during:** Task 2
|
||||
- **Issue:** AppShell forced `px-4 py-6 max-w-7xl mx-auto` padding on all pages. AdvisorPage needs a full-height flex container with no max-width for the two-panel sidebar+chat layout.
|
||||
- **Fix:** Added `noPadding?: boolean` prop to AppShell. When true, renders `flex-1 flex flex-col overflow-hidden` wrapper. Backward compatible — all existing pages unaffected.
|
||||
- **Files modified:** web/src/components/layout/AppShell.tsx
|
||||
- **Commit:** bcc3608
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None — all data flows are wired to real backend endpoints from plan 06-02. Conversations and messages load from the API; streaming connects to POST /api/advisor/chat.
|
||||
|
||||
## Threat Surface Scan
|
||||
|
||||
No new network endpoints or auth paths introduced in this plan. All frontend calls go to existing backend endpoints established in 06-02. Assistant message tokens rendered as React text nodes (JSX children) — no `dangerouslySetInnerHTML` used anywhere. T-06-03-01 (XSS) mitigated.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- [x] web/src/api/advisor.ts — created
|
||||
- [x] web/src/pages/AdvisorPage.tsx — created
|
||||
- [x] web/src/router.tsx — /advisor route added
|
||||
- [x] web/src/components/layout/TopBar.tsx — Advisor link added
|
||||
- [x] web/src/components/layout/AppShell.tsx — noPadding prop added
|
||||
- [x] Commit 811223d — feat(06-03): add advisor API wrappers
|
||||
- [x] Commit bcc3608 — feat(06-03): add AdvisorPage, /advisor route, and TopBar link
|
||||
- [x] `npm run build` — exits 0, AdvisorPage-C_DruhTJ.js 6.72 kB in bundle
|
||||
Loading…
Add table
Reference in a new issue