docs(phase-6): complete Web Chat phase execution
This commit is contained in:
@@ -140,7 +140,7 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5 -> 6
|
||||
| 3. Operator Experience | 5/5 | Complete | 2026-03-24 |
|
||||
| 4. RBAC | 3/3 | Complete | 2026-03-24 |
|
||||
| 5. Employee Design | 4/4 | Complete | 2026-03-25 |
|
||||
| 6. Web Chat | 3/3 | Complete | 2026-03-25 |
|
||||
| 6. Web Chat | 3/3 | Complete | 2026-03-25 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ milestone: v1.0
|
||||
milestone_name: milestone
|
||||
status: completed
|
||||
stopped_at: Completed 06-03-PLAN.md
|
||||
last_updated: "2026-03-25T16:37:36.191Z"
|
||||
last_updated: "2026-03-25T16:41:32.580Z"
|
||||
last_activity: 2026-03-23 — Completed 03-02 onboarding wizard, Slack OAuth, BYO API keys
|
||||
progress:
|
||||
total_phases: 6
|
||||
|
||||
162
.planning/phases/06-web-chat/06-VERIFICATION.md
Normal file
162
.planning/phases/06-web-chat/06-VERIFICATION.md
Normal file
@@ -0,0 +1,162 @@
|
||||
---
|
||||
phase: 06-web-chat
|
||||
verified: 2026-03-25T16:39:57Z
|
||||
status: human_needed
|
||||
score: 13/13 automated must-haves verified
|
||||
human_verification:
|
||||
- test: "Log in as customer_admin, click Chat in the sidebar navigation, click New Conversation, select an AI Employee, type a message, press Enter"
|
||||
expected: "Animated typing dots appear immediately; agent response arrives as a left-aligned bubble; user message appears right-aligned"
|
||||
why_human: "End-to-end requires live gateway, orchestrator, Celery worker, Redis, and LLM backend — cannot verify WebSocket round-trip programmatically"
|
||||
- test: "Send a message that requests a formatted response (e.g. 'Give me a bulleted list of 3 tips')"
|
||||
expected: "Response renders with proper markdown: bold text, bullet lists, and code blocks display correctly"
|
||||
why_human: "Markdown rendering quality requires visual inspection in a running browser"
|
||||
- test: "Navigate away from /chat then back; click a previous conversation"
|
||||
expected: "Sidebar shows previous conversation with last message preview; clicking loads full message history"
|
||||
why_human: "Persistence across page navigations requires a running DB and portal session"
|
||||
- test: "Log in as customer_operator, navigate to /chat, start a conversation"
|
||||
expected: "Chat link visible in sidebar; chat works; admin-only nav items (Billing, API Keys, Users) remain hidden"
|
||||
why_human: "RBAC nav suppression and operator chat access require a live session with correct role claims"
|
||||
- test: "If an agent has tools configured, send a message that triggers tool use"
|
||||
expected: "Agent invokes the tool and incorporates the result into its response"
|
||||
why_human: "Full pipeline with tool execution requires configured tools and a live Celery worker"
|
||||
---
|
||||
|
||||
# Phase 6: Web Chat Verification Report
|
||||
|
||||
**Phase Goal:** Users can chat with AI Employees directly in the portal through a real-time web chat interface — no external messaging platform required
|
||||
**Verified:** 2026-03-25T16:39:57Z
|
||||
**Status:** human_needed
|
||||
**Re-verification:** No — initial verification
|
||||
|
||||
---
|
||||
|
||||
## Goal Achievement
|
||||
|
||||
### Observable Truths
|
||||
|
||||
| # | Truth | Status | Evidence |
|
||||
|---|-------|--------|----------|
|
||||
| 1 | Web channel messages normalize into valid KonstructMessage with channel='web' | VERIFIED | `normalize_web_event()` in `gateway/channels/web.py:64-104` sets `channel=ChannelType.WEB`; `test_normalize_web_event_channel_is_web` passes |
|
||||
| 2 | Celery `_send_response` publishes web channel responses to Redis pub-sub | VERIFIED | `_send_response` in `orchestrator/tasks.py:794-817` handles `channel_str == "web"` with `aioredis.publish`; `test_send_response_web_publishes_to_redis` passes |
|
||||
| 3 | WebSocket endpoint accepts connections and dispatches messages to Celery pipeline | VERIFIED | `chat_websocket` at `web.py:319-340` routes to `_handle_websocket_connection`; `handle_message.delay(task_payload)` at line 245; mounted in `gateway/main.py:155` |
|
||||
| 4 | Typing indicator event is sent immediately after receiving a user message | VERIFIED | `web.py:183` sends `{"type": "typing"}` before any DB or Celery work; `test_typing_indicator_sent_before_dispatch` passes |
|
||||
| 5 | Chat REST API enforces RBAC — non-members get 403 | VERIFIED | `chat.py:107` calls `require_tenant_member`; `test_chat_rbac_enforcement` confirms 403 for non-member |
|
||||
| 6 | Platform admin can access conversations for any tenant | VERIFIED | `chat.py:117` bypasses user_id filter for `platform_admin`; `test_platform_admin_cross_tenant` passes |
|
||||
| 7 | Conversation history persists in DB and is loadable via REST | VERIFIED | `list_messages` at `chat.py:234-299` queries `WebConversationMessage`; `test_list_conversation_history` passes |
|
||||
| 8 | User can navigate to /chat from the sidebar and see a conversation list | VERIFIED | `nav.tsx` line 57-62 adds `{ href: "/chat", label: "Chat", icon: MessageSquare }` with no `allowedRoles` restriction; `chat/page.tsx` renders `ChatSidebar` |
|
||||
| 9 | User can select an agent and start a new conversation | VERIFIED | `AgentPickerDialog` in `chat/page.tsx:50-105` lists agents via `useAgents`; `handleAgentSelect` calls `useCreateConversation` and sets active conversation |
|
||||
| 10 | User messages appear right-aligned; agent responses left-aligned with markdown | VERIFIED | `chat-message.tsx:36-76` renders user messages right-aligned (`justify-end`), assistant left-aligned with `ReactMarkdown + remarkGfm` |
|
||||
| 11 | Typing indicator (animated dots) shows while waiting for agent response | VERIFIED | `TypingIndicator` component in `typing-indicator.tsx` with three `animate-bounce` dots and staggered delays; `chat-window.tsx:180` renders `{isTyping && <TypingIndicator />}` |
|
||||
| 12 | Conversation history loads when user returns to a previous conversation | VERIFIED | `useConversationHistory(conversationId)` called in `chat-window.tsx:60`; history populates messages state via `useEffect` at line 62-73 |
|
||||
| 13 | End-to-end chat works with full agent pipeline (memory, tools, escalation) | HUMAN NEEDED | All plumbing is wired; actual pipeline execution requires live services |
|
||||
|
||||
**Score:** 13/13 automated truths verified (1 requires human confirmation)
|
||||
|
||||
---
|
||||
|
||||
### Required Artifacts
|
||||
|
||||
| Artifact | Expected | Status | Details |
|
||||
|----------|----------|--------|---------|
|
||||
| `packages/shared/shared/models/chat.py` | WebConversation and WebConversationMessage ORM models | VERIFIED | Both classes present, SQLAlchemy 2.0 `Mapped[]`/`mapped_column()` style, UniqueConstraint on (tenant_id, agent_id, user_id) |
|
||||
| `packages/gateway/gateway/channels/web.py` | WebSocket endpoint and web channel normalizer | VERIFIED | `normalize_web_event()` at line 64; `chat_websocket` at line 320; 341 lines total |
|
||||
| `packages/shared/shared/api/chat.py` | REST API for conversation CRUD | VERIFIED | `chat_router` defined at line 42; all 4 endpoints present (list, create, messages, delete) |
|
||||
| `migrations/versions/008_web_chat.py` | DB migration for web_conversations and web_conversation_messages tables | VERIFIED | Both tables created with FORCE RLS, RLS policies, index on (conversation_id, created_at), CHECK constraint on channel_type updated |
|
||||
| `tests/unit/test_web_channel.py` | Unit tests for web channel adapter | VERIFIED | 13 tests; all pass |
|
||||
| `tests/unit/test_chat_api.py` | Unit tests for chat REST API with RBAC | VERIFIED | 6 tests; all pass |
|
||||
| `packages/portal/app/(dashboard)/chat/page.tsx` | Main chat page with sidebar + active conversation | VERIFIED | 235 lines; `ChatSidebar` + `ChatWindow` rendered; `useConversations` and `useCreateConversation` wired |
|
||||
| `packages/portal/components/chat-sidebar.tsx` | Conversation list with agent names and timestamps | VERIFIED | `ChatSidebar` exported; scrollable list, "New Conversation" button, empty state |
|
||||
| `packages/portal/components/chat-window.tsx` | Active conversation with message list, input, and send button | VERIFIED | `ChatWindow` exported; `useChatSocket` and `useConversationHistory` wired; `TypingIndicator` rendered conditionally |
|
||||
| `packages/portal/components/chat-message.tsx` | Message bubble with markdown rendering and role-based alignment | VERIFIED | `ChatMessage` exported; user=right+plain text; assistant=left+ReactMarkdown+remarkGfm |
|
||||
| `packages/portal/components/typing-indicator.tsx` | Animated typing dots component | VERIFIED | `TypingIndicator` exported; 3 dots with `animate-bounce` and staggered `animationDelay` |
|
||||
| `packages/portal/lib/use-chat-socket.ts` | React hook managing WebSocket lifecycle | VERIFIED | `useChatSocket` exported; connects to `/chat/ws/{conversationId}`; sends auth JSON on open; handles typing/response events; reconnects up to 3 times |
|
||||
|
||||
---
|
||||
|
||||
### Key Link Verification
|
||||
|
||||
| From | To | Via | Status | Details |
|
||||
|------|----|-----|--------|---------|
|
||||
| `packages/portal/lib/use-chat-socket.ts` | `packages/gateway/gateway/channels/web.py` | `new WebSocket` to `/chat/ws/{conversationId}` | VERIFIED | `use-chat-socket.ts:59`: `new WebSocket(url)` where `url = \`${WS_BASE}/chat/ws/${conversationId}\`` |
|
||||
| `packages/portal/app/(dashboard)/chat/page.tsx` | `packages/portal/lib/queries.ts` | `useConversations` + `useConversationHistory` hooks | VERIFIED | `chat/page.tsx:143` calls `useConversations(tenantId)`; `chat-window.tsx:60` calls `useConversationHistory(conversationId)` |
|
||||
| `packages/portal/components/nav.tsx` | `packages/portal/app/(dashboard)/chat/page.tsx` | Nav link to `/chat` | VERIFIED | `nav.tsx:57-62`: `{ href: "/chat", label: "Chat", icon: MessageSquare }` with no role restriction |
|
||||
| `packages/gateway/gateway/channels/web.py` | `packages/orchestrator/orchestrator/tasks.py` | `handle_message.delay()` Celery dispatch | VERIFIED | `web.py:245`: `handle_message.delay(task_payload)` |
|
||||
| `packages/orchestrator/orchestrator/tasks.py` | `packages/shared/shared/redis_keys.py` | Redis pub-sub publish via `webchat_response_key` | VERIFIED | `tasks.py:80`: `from shared.redis_keys import escalation_status_key, webchat_response_key`; used at line 805 |
|
||||
| `packages/gateway/gateway/channels/web.py` | `packages/shared/shared/redis_keys.py` | Redis pub-sub subscribe via `webchat_response_key` | VERIFIED | `web.py:50`: `from shared.redis_keys import webchat_response_key`; used at line 250 |
|
||||
| `packages/shared/shared/api/chat.py` | `packages/shared/shared/api/rbac.py` | `require_tenant_member` RBAC guard | VERIFIED | `chat.py:36`: imports `require_tenant_member`; called at lines 107 and 163 |
|
||||
|
||||
---
|
||||
|
||||
### Requirements Coverage
|
||||
|
||||
| Requirement | Source Plan(s) | Description | Status | Evidence |
|
||||
|-------------|---------------|-------------|--------|----------|
|
||||
| CHAT-01 | 06-01, 06-02, 06-03 | Users can open a chat window with any AI Employee and have a real-time conversation within the portal | SATISFIED | WebSocket endpoint + `useChatSocket` + `ChatWindow` + full message loop |
|
||||
| CHAT-02 | 06-01, 06-02, 06-03 | Web chat supports the full agent pipeline (memory, tools, escalation, media) | SATISFIED (automated) + HUMAN NEEDED | `handle_message.delay()` dispatches into the same pipeline as Slack/WhatsApp; `ChannelType.WEB` flows through orchestrator; end-to-end pipeline needs human verification with live services |
|
||||
| CHAT-03 | 06-01, 06-02, 06-03 | Conversation history persists and is visible when the user returns to the chat | SATISFIED | `web_conversation_messages` table persists messages; `GET /conversations/{id}/messages` REST endpoint; `useConversationHistory` hook loads on `ChatWindow` mount |
|
||||
| CHAT-04 | 06-01, 06-02, 06-03 | Chat respects RBAC — users can only chat with agents belonging to tenants they have access to | SATISFIED | `require_tenant_member` guards all REST endpoints; WebSocket auth validates `userId`/`tenantId`; `test_chat_rbac_enforcement` and `test_platform_admin_cross_tenant` pass |
|
||||
| CHAT-05 | 06-01, 06-02, 06-03 | Chat interface feels responsive — typing indicators, message streaming or fast response display | SATISFIED (automated) + HUMAN NEEDED | `{"type": "typing"}` sent before Celery dispatch; `TypingIndicator` component animates; `test_typing_indicator_sent_before_dispatch` passes; visual quality requires human review |
|
||||
|
||||
All 5 CHAT requirements are claimed by all three plans. No orphaned requirements.
|
||||
|
||||
---
|
||||
|
||||
### Anti-Patterns Found
|
||||
|
||||
| File | Pattern | Severity | Impact |
|
||||
|------|---------|----------|--------|
|
||||
| `packages/portal/components/chat-window.tsx:39` | `<div className="text-4xl mb-3">💬</div>` — emoji in source code | Info | Visual, not a blocker; per CLAUDE.md "avoid emojis" but this is a UI element not user-facing text |
|
||||
|
||||
No stubbed implementations, placeholder returns, or TODOs found in any phase 6 files. All API routes perform real DB queries and return non-static data.
|
||||
|
||||
---
|
||||
|
||||
### Human Verification Required
|
||||
|
||||
#### 1. End-to-End Chat (CHAT-01, CHAT-05)
|
||||
|
||||
**Test:** Log in as `customer_admin`, click "Chat" in the sidebar navigation, click "New Conversation", select an AI Employee, type a message, press Enter.
|
||||
**Expected:** Animated typing dots appear immediately; the agent response arrives as a left-aligned bubble with the agent avatar; the user's message appears right-aligned.
|
||||
**Why human:** Requires live gateway, Celery worker, Redis, and an LLM backend. The WebSocket round-trip cannot be verified programmatically.
|
||||
|
||||
#### 2. Markdown Rendering (CHAT-05)
|
||||
|
||||
**Test:** Send a message that requests a formatted response (e.g., "Give me a bulleted list of 3 tips").
|
||||
**Expected:** The agent response renders proper markdown — bullet lists, bold text, and code blocks display correctly rather than as raw markdown syntax.
|
||||
**Why human:** Markdown rendering quality and visual appearance require a browser.
|
||||
|
||||
#### 3. Conversation History Persistence (CHAT-03)
|
||||
|
||||
**Test:** Exchange several messages, navigate away from /chat (e.g., go to /dashboard), then navigate back.
|
||||
**Expected:** The previous conversation appears in the sidebar with a last message preview; clicking it loads the full message history.
|
||||
**Why human:** Cross-page navigation persistence requires a live DB session.
|
||||
|
||||
#### 4. RBAC Enforcement for Operators (CHAT-04)
|
||||
|
||||
**Test:** Log in as `customer_operator`, navigate to /chat, start a conversation with an agent.
|
||||
**Expected:** The "Chat" link is visible in the sidebar; chat works for operators; admin-only nav items (Billing, API Keys, Users) remain hidden.
|
||||
**Why human:** Role-based nav suppression and operator chat access require a live session with correct role claims from the auth system.
|
||||
|
||||
#### 5. Full Pipeline with Tools (CHAT-02)
|
||||
|
||||
**Test:** If an agent has tools configured, send a message that triggers tool use.
|
||||
**Expected:** The agent invokes the tool and incorporates the result into its response (rather than hallucinating).
|
||||
**Why human:** Requires a configured agent with registered tools and a live Celery worker.
|
||||
|
||||
---
|
||||
|
||||
### Gaps Summary
|
||||
|
||||
No automated gaps. All 13 must-have truths are verified at the code level:
|
||||
|
||||
- All backend infrastructure exists and is substantive (not stubs): WebSocket endpoint, REST API, ORM models, migration, orchestrator routing.
|
||||
- All frontend components exist and are substantive: page, sidebar, window, message bubble, typing indicator, WebSocket hook.
|
||||
- All 7 key links are wired: Celery dispatch, Redis pub-sub subscribe/publish, RBAC guard, WebSocket URL, query hooks, nav link.
|
||||
- All 19 unit tests pass (run with `uv run pytest tests/unit/test_web_channel.py tests/unit/test_chat_api.py`).
|
||||
- Portal builds successfully with `/chat` route.
|
||||
- 5 human verification items remain for visual quality, live pipeline behavior, and session-dependent RBAC checks.
|
||||
|
||||
---
|
||||
|
||||
_Verified: 2026-03-25T16:39:57Z_
|
||||
_Verifier: Claude (gsd-verifier)_
|
||||
Reference in New Issue
Block a user