Skip to main content

h.work — Client × AI Specialist Interaction

Version: 2026-06-08 | Scope: WebChat · Slack Channel · Expert Dashboard


1. Architecture Overview

Client (org_admin / org_member)
├── WebChat (/client/chat)
└── Slack Channel (DM or @mention in a channel)

API (NestJS) — unified message entry point

Agent Service (Python) — AI-generated reply

Expert Dashboard (/workspace/queue)
├── Expert reviews AI draft
└── Approves / edits → reply sent via original channel

Core Principles

  • Messages from all channels are unified in the Expert Dashboard — no cross-channel mixing
  • Default HITL (Human-in-the-Loop): autoRespondThreshold = 101 — every AI reply must be approved by an Expert before delivery
  • Message dedup + idempotent writes to prevent double-processing

2. WebChat Module

2.1 Feature Description

After logging in, a Client navigates to /client/chat and can:

  • View all Specialists assigned to the org (left-side profile panel)
  • Start a new Thread with any Specialist
  • Maintain multiple independent Threads per Specialist
  • Send text, images, and file attachments
  • Receive AI Specialist replies in real time (Socket.io, 8-second polling fallback)

2.2 Current Implementation Status

FeatureStatus
Specialist selection + profile display✅ Done
New Thread / Thread list (left sidebar)✅ Done
Send message (text)✅ Done
Message attachments (images / files)✅ Done
Socket.io real-time reply delivery✅ Done
Thread rename / Resolve / Reopen✅ Done
Unread message badge✅ Done
Thread list sorted by latest message (descending)✅ Done
Thread status display (in_progress / awaiting_client / resolved)✅ Done
Channel source indicator (Slack / Email / WhatsApp icon)✅ Done

2.3 Message Flow

Client types message → POST /conversations/:id/messages
↓ Returns immediately (201)
Background async: runAgentPipeline()
→ Python Agent generates reply (with confidence / risk_level)
→ Default: enters Expert Queue (threshold = 101)
→ Expert approves → Socket.io pushes reply to Client

2.4 Open Items

#IssuePriority
W-1When creating a new Thread in an org with multiple Specialists, the user must explicitly select which Specialist to addressHigh
W-2WebChat's own channel icon is missing in the Thread list (only external-channel icons like email/slack are shown)Medium
W-3Client-side message status feedback is missing (sending / delivered / expert reviewing)Medium
W-4Attachment preview: inline image preview works; PDF/file shows only a chip with no content previewLow

3. Slack Channel Module

3.1 Design Goal

Each AI Specialist maps to a dedicated Slack App. Once a Client org installs the App into their Slack Workspace, org members can communicate with that Specialist via:

  • DM: Direct message the Slack App
  • Channel @mention: @mention the App in any channel
  • Bound Channel (opt-in): A channel explicitly bound to a Specialist routes all messages to that Specialist — no @mention required

3.2 Slack App Activation Flow

SuperAdmin / AM generates a Slack App Manifest for a Specialist in the Ops dashboard

Create the App in the Slack API Console using the Manifest
(includes bot scopes / Events API / OAuth settings)

Configure the App's Client ID / Client Secret / Signing Secret in Humanwork

Specialist ↔ Slack App association stored in IntegrationCredential (encrypted)

Client org admin clicks "Add to Slack" → OAuth 2.0 authorization flow

oauth.v2.access → bot_token stored in IntegrationCredential (org-scoped)

Activation complete: org members can DM or @mention the Specialist via Slack

3.3 Message Trigger Strategy (Three Layers, per PRD)

Layer 1 — Hard Triggers (always respond)

  • DM sent directly to the Slack App
  • @mention of the bot in any channel
  • Follow-up messages in a Thread the bot has already participated in (Thread continuation)

Layer 2 — Contextual Scoring (intelligent decision, Phase 2)

composite_score = channel_weight × (keyword_match + question_intent)

score > threshold_high → respond immediately
score > threshold_low → enter Expert review queue
else → silent storage

Layer 3 — Implicit Relevance (semantic vector matching, Phase 3)

  • Embedding-based similarity matching
  • Requires cold-start labeled data

3.4 Message Processing Flow

Slack Events API → POST /channels/slack/events
↓ HMAC-SHA256 signature verification → return 200 immediately

BullMQ channels-inbound queue (async)

handleRuntimeEvent()
├── team_id → IntegrationCredential → resolve orgId
├── Dedup: event_ts / event_id already processed? → skip
├── Classify trigger: DM / @mention / Bound Channel / Thread continuation
│ └── No trigger → silent ingest into channel_context_messages

findOrCreateConversation() (Slack user → customer mapping)

conversationsService.sendMessage() [synchronous — waits for Agent]

Agent generates reply → Expert Queue

Expert approves → BullMQ channels-outbound

slack.chat.postMessage(channel, text, thread_ts) → reply in original thread

3.5 Current Implementation Status

FeatureStatus
Slack App Manifest generation (SlackManifestSuggester)✅ Done
OAuth 2.0 install flow (Add to Slack)✅ Done
HMAC-SHA256 signature verification✅ Done
DM message ingestion + routing✅ Done
@mention message ingestion + routing✅ Done
Thread continuation tracking (slack_engaged_threads)✅ Done
Bound Channel (opt-in, no @mention required)✅ Done
Message dedup (Redis NX + event_ts)✅ Done
Silent ingest (channel_context_messages)✅ Done
Expert reply dispatched back to Slack thread✅ Done
Per-Specialist independent Slack App⚠️ Architecture supports it, but OAuth currently uses shared global SLACK_CLIENT_ID
Layer 2 Contextual Scoring🔲 Not implemented (Phase 2)
Layer 3 Semantic vector matching🔲 Not implemented (Phase 3)

3.6 Open Items

#IssuePriority
S-1Per-Specialist Slack App: current OAuth uses a global SLACK_CLIENT_ID/SECRET; need per-Specialist App credentials and independent install flowHigh
S-2Client-facing Slack connection management UI: show connected workspace, bound channels, disconnect / reconnect actionsHigh
S-3Bound Channel self-service UI (currently back-end only; Client Admin should be able to bind channels themselves)Medium
S-4Layer 2 Contextual Scoring engine implementationMedium
S-5Slack message image/file attachments forwarded to Expert DashboardMedium
S-6Expert replies support Slack mrkdwn rich-text formattingLow

4. Expert Dashboard Module

4.1 Feature Description

After logging in, an Expert navigates to /workspace/queue and can:

  • View all conversations pending review (from WebChat + Slack + Email + WhatsApp)
  • Read the AI-generated draft reply (with confidence score + risk level badge)
  • Edit the draft and confirm to send (reply delivered via the original channel)
  • Browse the full conversation history (Client messages + AI drafts + past Expert replies)
  • Sort conversations across multiple dimensions (risk level / created time / SLA)

4.2 Current Implementation Status

FeatureStatus
Queue list (pending conversations)✅ Done
AI draft display + confidence score✅ Done
Risk level badge (low / medium / high / critical)✅ Done
Expert edit draft + confirm send✅ Done
Reply dispatched via original channel (webchat / slack / email)✅ Done
Full conversation history (complete message list)✅ Done
Channel source badge (email / slack etc.)✅ Done (email has badge; other channels incomplete)
SLA timer✅ Done
Keyboard shortcuts✅ Done
Socket.io real-time new message notification✅ Done
Unread message badge✅ Done
Queue sorting (risk / time / SLA)✅ Done
Message attachment display (images / files)✅ Done (WebChat attachments; Slack attachment forwarding pending)
Multi-Specialist filter view⚠️ Filtered by expert_access permissions; no UI toggle
Per-conversation unread count⚠️ Global unreadCount exists; per-conversation count needs verification
Conversation status management⚠️ Status values exist (pending / awaiting_client / resolved); transition rules need to be defined

4.3 Open Items

#IssuePriority
E-1Unified channel source badge: all channels (webchat / slack / whatsapp / email) display their source badge in both the Queue list and conversation detailHigh
E-2Slack attachment forwarding: images and files from Slack messages must be forwarded and viewable in the Expert DashboardHigh
E-3Conversation status definition: formally define pending / open / awaiting_client / resolved — meanings, transition conditions, and UI display rulesHigh
E-4Per-Specialist filter view: when an Expert has access to multiple Specialists, support filtering conversations by SpecialistMedium
E-5Per-conversation unread count: show exact unread message count per Thread in the conversation listMedium
E-6Rich-text message rendering: Slack mrkdwn, Markdown, link previewsMedium
E-7Internal Note: Expert-to-Expert internal messages (API exists; UI completeness to be verified)Low

5. Task Summary

Module 1 — Expert Dashboard

Task IDDescriptionPriorityDepends On
E-1Unified channel source badge in Queue list for all channelsP0
E-2Slack attachment forwarding: storage + display in Expert DashboardP0S-5
E-3Define and implement conversation status transition rules + UI labelsP0
E-4Per-Specialist filter viewP1
E-5Per-conversation precise unread message countP1
E-6Rich-text message rendering (Markdown + Slack mrkdwn)P2
E-7Internal Note UI completeness auditP2

Module 2 — Slack Channel

Task IDDescriptionPriorityDepends On
S-1Per-Specialist independent Slack App credentials (separate Client ID / Secret / Signing Secret per Specialist)P0
S-2Client Admin Slack connection management UI (connected workspaces / disconnect / reconnect)P0S-1
S-3Bound Channel self-service binding UI for Client AdminP1S-2
S-4Layer 2 Contextual Scoring engine (PRD Phase 2)P1
S-5Slack message image/file attachment forwarding to Expert DashboardP1
S-6Expert reply supports Slack mrkdwn formattingP2E-6

Module 3 — WebChat

Task IDDescriptionPriorityDepends On
W-1Support Specialist selection when creating a new Thread (multi-Specialist org scenario)P0
W-2Client-side message send status feedback (sending / delivered / expert reviewing)P1
W-3WebChat channel icon in Thread list (channel dot)P2
W-4PDF / document attachment preview (currently shows chip only, no content preview)P2

6. Key Data Models

EntityDescription
conversationsEach Thread — contains channel / status / agentName / orgId
messagesMessage records — role (user / ai / expert) / attachments / heldForReview
expert_queue_itemsAI draft pending review; Expert acts on this
integration_credentialsSlack / Email / WhatsApp tokens — encrypted, org-scoped
slack_channel_bindingsChannel opt-in binding: channel_id → Specialist
slack_engaged_threadsThread continuation tracking (sliding-window engaged_at TTL)
channel_context_messagesSilent ingest context store (FTS index)
expert_accessExpert ↔ (Org × Specialist) access grant (ADR-007)

Based on impact and dependency order, suggested first tasks:

  1. S-1 — Per-Specialist Slack App credentials (unlocks the full multi-Specialist Slack story)
  2. E-1 — Unified channel source badge (low effort, high visibility)
  3. E-3 — Conversation status definition (blocking several downstream UI decisions)