Conversations (omnichannel inbox)
How admins read every learner's MOEgent conversation across web, WhatsApp and voice from one two-pane inbox.
Every learner talks to MOEgent (the CLIP Learn AI tutor, shown as "Moe") — sometimes on the web app, sometimes over WhatsApp, sometimes by voice. The Conversations inbox pulls all of those threads into one place so you can read what learners are asking and how the assistant is answering. It is a two-pane messaging view (list on the left, transcript on the right), modelled on a chat inbox rather than a flat log.
This page lives at /admin/conversations.
Who can see this
Conversations is ADMIN-only. These transcripts can contain course content, exam-style questions and a learner's personal study struggles, so access is deliberately narrow.
| Role | Access |
|---|---|
| ADMIN | Full access — sees every conversation in the tenant |
| FACULTY (trainer) | No access |
| CORPORATE (sponsor) | No access — deliberately excluded for learner privacy |
| CANDIDATE (learner) | No access |
Why sponsors are locked out
A corporate sponsor pays for seats but does not get to read what their sponsored learners ask the tutor. The page and its data API both reject any non-admin: opening the page as another role redirects you to /app, and the underlying request returns 403 Forbidden.
Everything is also tenant-scoped — you only ever see conversations belonging to learners who are members of your own tenant. A conversation whose owner is not in your tenant returns "Not found", even to an admin.
What appears in the inbox
The inbox lists conversations that meet all of these conditions:
- The learner is a member of your tenant.
- The conversation has at least one message (empty threads are hidden).
- Up to the 300 most recent conversations are loaded.
Rows are ordered by the time of their most recent message, newest first.
Reading the two panes
The conversation list (left pane)
Each row shows, from top to bottom:
| Element | What it shows | Notes |
|---|---|---|
| Learner name | The conversation owner's name | Truncated if long |
| Timestamp | Time of the last message | Format DD Mon HH:MM in UTC, e.g. 09 Jul 14:32 |
| Message preview | The text of the most recent message | Prefixed with Moe: when the last message was from the assistant; single line, truncated |
| Channel badges | Which channels this thread has used | One badge per distinct channel — this is the "omnichannel" signal |
The currently selected row is highlighted. If nothing matches your search or filter, the list shows "No conversations match."
Search
The search box (placeholder "Search name, email, message…") filters the list live as you type. It is a case-insensitive match against three fields of each conversation:
- the learner's name
- the learner's email
- the last message text of the thread
Matching is a substring match, so typing part of a name or a phrase from the latest message is enough. Search does not scan the full transcript — only the most recent message line.
Channel filters
Four buttons sit under the search box. They filter the list by channel:
| Button | Keeps conversations that… |
|---|---|
| All | Everything (default) |
| Web | Have at least one message sent over the web app |
| Have at least one message sent over WhatsApp | |
| Voice | Have at least one voice message |
Only one filter is active at a time; the active button is highlighted. Because a single thread can span several channels, the same conversation can appear under more than one filter. Search and the channel filter combine — the list must satisfy both.
Channel badges
A small tag marks which channel a message or thread came in on. You will see badges on list rows, on the transcript header, and on each individual message bubble.
| Badge | Meaning | Colour |
|---|---|---|
| Web | Message came from the web chat | Slate/grey |
| Message came over WhatsApp | Green | |
| Voice | Message came from a voice session | Violet |
| Trainer | Trainer-originated message | Brand tint |
| Onboarding | Message from the onboarding flow | Amber |
If a message carries a channel value the app does not recognise, the badge falls back to showing that raw value in a neutral grey style.
The transcript (right pane)
Before you select anything, the right pane shows a placeholder: a chat icon and "Select a conversation to read it."
When you click a row, the transcript is fetched on demand and cached in memory for the rest of your session, so re-opening the same thread is instant. While it loads you see a spinner.
Transcript header
At the top of the transcript you see the learner's name, their email underneath, and the thread's channel badges on the right. On mobile a back arrow appears here to return to the list.
Message bubbles
Messages are shown oldest-first, top to bottom. Each bubble carries:
| Part | What it shows |
|---|---|
| Sender label | MOEGENT for assistant replies, or the learner's name for their own messages |
| Channel badge | The channel that individual message arrived on |
| Timestamp | DD Mon HH:MM in UTC |
| Body | The message text, rendered with formatting (Markdown) |
| Citations line | If the message cited sources, a line reading N source cited / N sources cited |
Assistant (MOEgent) bubbles align to the left in a white box; learner bubbles align to the right in a tinted box. Because each bubble carries its own channel badge, you can see within a single thread where a learner switched from, say, web to WhatsApp mid-conversation.
If the thread somehow has no messages, the pane reads "No messages in this conversation." If loading fails, it shows the same empty state rather than an error dialog.
Read-only
A footer under every transcript states: "Read-only — MOEgent handles the learner's replies across every channel." There is no reply box. Admins observe conversations here; they do not join or respond to them. All learner-facing replies are produced by the assistant.
Deep links and the old transcript URL
You can link straight to a specific conversation with the query parameter ?c=<conversationId> on the inbox URL — for example /admin/conversations?c=abc123. Opening that URL pre-selects and loads that thread.
The older per-conversation URL /admin/conversations/<id> still works: it redirects to /admin/conversations?c=<id>, folding the standalone transcript page back into the inbox.
Empty and edge states at a glance
| Situation | What you see |
|---|---|
| No thread selected | Chat icon + "Select a conversation to read it" |
| Search/filter matches nothing | "No conversations match." |
| Transcript loading | Spinner |
| Thread has no messages, or load failed | "No messages in this conversation." |
| Non-admin opens the page | Redirected to /app |
| No tenant resolved for your session | Page not found |
Learners & cohorts
Admin guide to the learner roster, opening a trainee journey, cohort analytics, the mastery heatmap, and assigning learners to a cohort.
Knowledge base & audit log
The two admin transparency tools: the Knowledge base showing every source MOEgent may answer from, and the immutable Audit log recording every privileged action.