Case study · OneTrust · Draft, in progress
OneAI: A Voice Assistant for OneTrust GRC
A cross-domain voice and text assistant layered on top of three existing OneTrust GRC prototypes, designed to answer real questions about issues, risks, and ethics cases in natural language, hands-free.
This case study is a working outline, not a finished write-up. The prototype is real and the decisions below are real; a few fields in the summary table and the outcomes/reflection sections are still pending and are marked as such rather than filled in with guesses.
The problem
OneTrust's GRC suite already contains dense, structured data, issues,
risks, controls, vendors, ethics cases, spread across separate
tools: a Health Dashboard for issue triage, a Relationship Map for
tracing risk-to-control-to-vendor connections, and SpeakUp for ethics
case intake. Getting an answer to a simple question ("which issue is
most critical?", "what's connected to AWS?", "how many cases does
J. Park have?") means knowing which tool has that data, then
manually filtering, searching, or tracing a graph by hand.
The question this project explores: what if you could just ask?
Not a chatbot bolted onto one page, a single assistant that follows the user across tools, understands the data underneath each one, and answers in natural language, by voice or text, without requiring the user to leave what they're doing.
Goals & constraints
- Answer real questions from real (mock) data, not scripted demo responses. Every answer traces back to the same
ISSUES,GRAPH, andSPEAKUP_CASESdata structures the underlying prototypes already use. - Voice-first, but never voice-only. Every voice interaction has a typed equivalent; the assistant must be fully usable by keyboard and screen reader.
- Bridge tools without merging them. The three prototypes stay independent products; OneAI is the connective layer, not a rebuild.
- No paid infrastructure. This is a self-funded proof of concept. Speech-to-text and text-to-speech run entirely on the free, built-in browser Web Speech API, no API keys, no backend.
- WCAG AA minimum, AAA where feasible. Accessibility wasn't an afterthought pass; it shaped component decisions (contrast, focus states, live regions, reduced motion) from early on.
Process
1. Establishing feasibility
Before any UI work, the first question was architectural: can a static, client-side prototype credibly demonstrate "voice AI across a GRC suite" without a real backend or LLM? The answer shaped everything downstream. A local intent-matching engine (keyword/entity extraction over the same mock data already in the prototypes) stands in for what would be a retrieval-augmented LLM in production, while the interaction design (listening states, follow-up memory, hands-free flow) is built exactly as it would need to work with a real model behind it.
2. Phased build
Rather than designing the full cross-domain assistant up front, the work moved in phases, each one validated before expanding scope:
- Phase 1, voice Q&A over a single domain (Issues) to prove the STT → intent-match → TTS loop worked at all.
- Phase 2, voice-driven navigation of the Relationship Map, proving the assistant could trigger real UI actions in a live page, not just answer questions about it.
- Unification, rather than two separate demo widgets, the two phases were merged into one shared script (
oneai-assistant.js) injected via a floating action button into all three real prototype pages, so the same assistant is available regardless of which tool the user is in.
3. Iterating on the interaction model
Early text-forward drafts made it clear that voice deserved its own dedicated mode rather than being a feature bolted onto a chat panel. That realization led to Focused Voice Mode, an immersive, full-screen conversational view modeled after hands-free voice assistant patterns, with a continuously listening microphone, spoken and visual answers, and an optional panel for retrieved data visuals.
4. Accessibility passes
Two dedicated audits (general assistant UI, then a follow-up pass specifically on Focused Voice Mode) checked contrast ratios, focus indicators, live-region announcements, and non-color state cues against WCAG AA/AAA. Several colors were adjusted as a direct result (see Key decisions below).
Information architecture & flow
The assistant is designed around one core idea: the user's location in the product shouldn't limit what they can ask. The flow shows the assistant's states from entry to answer, and how the same core engine serves three different entry points.
Three domains, one engine. Issues, the Relationship Map, and SpeakUp cases are answered by the same assistant instance without the user declaring which "mode" they're in, the intent matcher tries each domain in sequence and the first confident match wins.
Follow-up memory. A single tracked "last mentioned" record lets a user ask "how old is it?" or "who owns it?" without repeating an ID, a deliberate, scoped piece of conversational memory rather than full multi-turn context.
User on any OneTrust page (Health Dashboard, Relationship Map, or SpeakUp) → Floating Action Button:
- Click spark icon → Compact Overlay, type or speak a question → Expand → Advanced View (persistent history + examples), or click the waveform icon → Focused Voice Mode
- Focused Voice Mode (full-screen, hands-free) → continuous listening starts automatically → user asks a question by voice or typed → local intent engine routes to:
- Issues data → ranking / status / owner / age answer
- Relationship Map data → graph traversal answer, plus live map navigation if on that page
- SpeakUp data → case lookup / assignee answer
- Every answer is spoken aloud and shown in the transcript → a follow-up question either resolves against the same tracked topic ("how old is it?"), starts a new topic, or ends the session (stop listening / close mode)
Key screens & use cases
1. Entry point, the floating action button
A single, repositionable button (corner-snap, persisted per user) is the assistant's only footprint on the page when idle, it never competes with the host product's own UI.
2. Compact overlay, quick question, quick answer
For a single question without leaving the current view, the compact overlay is deliberately small and dismissible.
3. Advanced view, for repeated / exploratory use
Expanding the overlay reveals conversation history and example prompts side by side, for users who want to ask several things in a row without re-reading a cramped scroll area.
4. Focused Voice Mode, the hands-free experience
The core of the project: a full-screen, immersive mode that opens with listening already active, no click-to-talk required. The product's real top navigation is preserved (pulled verbatim from the host page) so the user never loses their sense of place.
5. Retrieved artifact panel, grounding answers in real data
When an answer touches a real node in the Relationship Map's graph, an optional side panel renders a small live diagram of that node and its direct connections, generated from the same graph data as the rest of the app, never a stock image or fabricated visual. When more than one node is relevant, a numbered carousel lets the user step through each.
6. Voice bridging into a live product surface
Asking the assistant to "show me Risk L" while actually on the Relationship Map page doesn't just describe the answer, it drives the real page's own graph component.
7. A second real product surface, SpeakUp
The same assistant, with no reconfiguration, answers questions about an entirely different data domain (ethics case intake).
8. Voice output customization
Free, OS-level premium/enhanced voices (where available) are surfaced ahead of standard voices in the picker, since most people will use whichever option is easiest to find.
Key decisions
Full rationale for each of these lives in a separate, dated decision log; this is a curated summary.
- Free browser TTS/STT over a paid provider. Ruled out ElevenLabs/Deepgram/OpenAI Realtime early, this is a self-funded POC, and the Web Speech API (
SpeechRecognition/speechSynthesis) already demonstrates the interaction model without recurring cost or a backend proxy for API keys. - One shared script across three separate products, not a merged app. The prototypes deliberately stay independent; voice is the bridge, not a replacement for their individual product surfaces.
- Flexbox over CSS Grid for Focused Mode's layout, after a Grid-based version collapsed unpredictably in testing with a root cause that couldn't be confirmed via static review, resolved defensively with the simpler, more predictable layout primitive.
- Continuous listening by default, one Stop button, no mic-click-per-question. Early versions required clicking the mic before every question, which undercut the point of a "conversation." Removing that friction required first fixing a real bug: a denied microphone permission was silently retriggering the browser's permission prompt in an infinite loop, traced to a missing state flag in the recognition error handler.
- Contrast fixes for AA compliance. The brand green (#16A34A) measured ~3.3:1 for text and text-on-fill combinations, failing WCAG AA's 4.5:1 minimum. A darker shade (#0f5132, ~9.4:1) replaced it wherever it carried text, preserving brand color everywhere else.
- Deterministic synthetic data, clearly labeled. The real prototypes' issue records have no age/date field, so a
daysOpenvalue was synthesized per record (clearly commented as mock in code and in the decision log) so ranking and "how old" questions have something honest to answer from, never fabricated on the fly.
Challenges
- A Grid layout collapse with no confirmed root cause. Full-viewport content squished to the left edge in testing; static code review couldn't conclusively identify why. Resolved by rebuilding with Flexbox rather than chasing the Grid bug further, a pragmatic trade-off between root-cause certainty and shipping a stable experience.
- An infinite microphone permission-prompt loop. A denied mic permission fell through to auto-restart logic and re-prompted indefinitely, a real, reproducible bug (not a design gap), fixed by ensuring the error handler always marks the session state as stopped.
- A duplicate-question submission bug. Calling
.stop()on the speech recognizer fires one trailingresultevent beforeend, that trailing event was scheduling a second, unguarded submission of the same question. Fixed with an explicit "already submitted this turn" guard. - Keyword matching vs. "ask it anything." The intent engine is deliberately not an LLM, it's regex/keyword matching over structured mock data. Supporting compound questions ("what's the most critical issue and who owns it?") required a scoped, conservative approach (splitting only on an unambiguous "and + question word" boundary) rather than a general parser, to avoid false splits on questions that legitimately contain "and."
Outcomes
Not yet available. Pending user testing and stakeholder feedback; nothing here is filled in with a guess.
- Stakeholder / self-review of the working prototype: planned, not yet done.
- Documented accessibility audit results (AA achieved; AAA gaps and why): planned, not yet done.
- Any quantifiable before/after (steps-to-answer reduced from N clicks across M pages to one spoken question): planned, not yet done.
What's next
- Phase 3 (not started): Q&A over product help/Confluence documentation, extending the assistant beyond structured data into unstructured help content.
- Cross-domain follow-up memory: currently "how old is it?" only resolves within the domain it was asked in. Logged as a known, deliberate limitation.
- A real LLM/RAG backend, if this moves past proof-of-concept: the current local intent matcher was always meant to demonstrate the interaction design, not to be the production answer engine.
Note on the prototype
The prototype is an interactive HTML/CSS/JS build, not a recorded video: three real product pages (Health Dashboard, Relationship Map, SpeakUp) with a shared assistant script injected into each. No video walkthrough exists yet. The full, dated rationale for every decision above lives in a separate architecture blueprint and decision log alongside this case study.