Plan: RBD Customer Service Tool (rbd-cs-tool)
Repo: ~/ai-projects-local/rbd-cs-tool/ (local-only, git init pending)
Research: reports/customer-service-tool-research-2026-08-25.md · Discovery: reports/cs-inbox-discovery-2026-08-25.md
Objective
Replace the Gmail-only workflow for customerservice@rileyblakedesigns.com with a custom inbox tool that (1) triages every inbound contact — email AND voicemail — automatically, (2) shows live NetSuite order/invoice context per conversation and a customer-level rollup per wholesale account, and (3) prepares template-informed AI draft replies that reps review and send from the tool.
Why build (vs. buy)
Team decision (Cole, 2026-08-25): build-first. Benchmark: Hiver ($25–65/user/mo) is the buy-fallback — Gmail-native with a native NetSuite sidebar. The build exists for what no vendor has: RBD taxonomy, rb_warehouse context, voicemail pipeline from the 1wire PBX, account-value priority scoring, and PO-to-order extraction.
Decisions locked (2026-08-25 session)
- Two views: conversation-format inbox (primary workspace) + customer-level rollup view (one page per wholesale account). One click between them; thread sidebar = condensed account view.
- Three-axis tagging:
medium(deterministic from headers: email_direct / phone_voicemail / netsuite_thread / pepperi / system_digest / web_form-future) ·sender_role(roster+domain lookup, LLM fallback: internal_rep / internal_staff / wholesale_customer / retail_consumer / system / unknown) ·reasons[](LLM, multi-label — taxonomy v1 in discovery doc). Plus confidence + priority. - Account-centric identity: contacts (emails + phone numbers) roll up to NetSuite customer accounts. Seeded from NetSuite contact records; unknown senders resolved via SO-reference matching with human confirm-once, learned aliases stored. Rep-mediated messages attach to the account with rep as channel. CS assignee is a separate field.
- Case layer: conversations group into cases (same account + reason + SO/INV reference or high similarity within ~14 days → AI proposes merge, human confirms). Handles multi-medium duplicates (proven live: KC Framing email thread + voicemail same issue).
- Drafting = AI-composed, template-informed. Template library (per reason tag) provides voice/structure/policy context; live facts come only from thread + NetSuite + customer record. Hard guardrail: no fact in a draft without a source in provided data. Sept 1 meeting's "email template review" output becomes the seed library.
- Sending happens from the tool (Phase 2): Gmail API send as customerservice@, correct threadId + reply headers → threads and Sent stay intact in Gmail (fallback view preserved). AI has no code path to send; send endpoint requires authenticated human click; full audit log.
- Voicemail is a day-one pipeline branch: 1wire PBX emails → audio attachment → local faster-whisper transcription → same classify/summarize/link flow. Caller-number → NetSuite phone lookup. Repeat-caller detection = missed-callback alerts. PoC PASSED 2026-08-25 (5/5 clean transcripts incl. spoken SO numbers).
Architecture (verified against official docs — see research report §4)
- Ingest: Gmail API push (Pub/Sub) —
watch()renewed daily,history.listincremental sync, durable historyId, 404→full-resync fallback. (IMAP polling acceptable for dev only.) - Auth: service account
rbd-cs-inbox@rbd-cs-tool.iam.gserviceaccount.com(RBD-owned GCP projectrbd-cs-tool, org 72019268243) + domain-wide delegation. Client ID103256468351462195455. Phase 1 scope: gmail.readonly. Phase 2: + gmail.modify, gmail.compose, gmail.send. - Classification: Claude (Sonnet default), structured JSON via tool-use
{medium, sender_role, reasons[], confidence, priority, summary, extracted_refs[], draft?}, temp ~0.1. Header-derived axes computed in code, not by the model. NetSuite display-name parsing for system@sent-via.netsuite.com. - NetSuite context: SuiteTalk REST SuiteQL (order header + lines + customer in one round trip), OAuth 2.0 client-credentials M2M. Pull-on-open (Plain Customer Cards pattern), no data mirror; rb_warehouse MySQL for analytics context (presale, release months, rep mapping). NetSuite integration record creation = Cole (NetSuite admin).
- App: FastAPI + React (same stack as rbd-reorder-tool), deploy target rb.alpineanalytica.com pattern. DB: Postgres or SQLite-to-start for conversations/cases/accounts/audit; Gmail remains source of truth for mail.
- Transcription: faster-whisper base.en local (proven). No audio leaves the box.
Phases
P0 — Access (in flight): Austin authorizes DWD (email sent by Cole) → verify_dwd.py → revoke temp OAuth token. ✅ SA + project created.
P1 — Pipeline pilot (read-only): ingest → tag (3 axes) → transcribe voicemails → summarize → NetSuite lookup → daily digest or simple read-only UI. Zero write risk. Validate taxonomy accuracy vs. ~200 hand-checked threads; tune before UI investment.
P2 — Inbox UI: conversation view, views/queues (by medium/role/reason/SLA), assignment + claimed-by, internal notes, AI drafts (to Gmail drafts folder in-thread during transition).
P3 — Send + customer rollup: scopes expanded, send-from-tool with audit log, customer 360 view, case merging UI.
P4 — Actions: pre-filled NetSuite actions from rep-request extraction (hold release packet, RMA prep) — human-approved execution.
Open items
- ☐ Austin: DWD authorization (email drafted, Cole sending)
- ☐ Team: NetSuite sidebar field wishlist (Cole collecting)
- ☐ Team: existing canned responses/templates (Sept 1 meeting output)
- ☐ Cole: NetSuite integration record for SuiteTalk (OAuth2 client credentials)
- ☐ Decide P1 surface: daily digest email vs. minimal web UI
- ☐ Taxonomy validation set: hand-label ~200 threads
- ☐ Which additional inboxes later (info@, AR@)? Single-inbox first.
- ☐ Sept 1 demo prep: voicemail transcripts + mockup + discovery stats
Acceptance criteria (P1)
- ≥95% correct medium tagging (deterministic — should be ~100%)
- ≥90% sender_role, ≥85% primary-reason accuracy on validation set
- 100% of voicemails transcribed within 5 min of arrival
- NetSuite lookup resolves ≥80% of wholesale senders to an account
- Zero writes to the mailbox (readonly scope enforces)
Security posture (three-layer model)
Environment layer (strongest):
- Read-only OAuth scope = Google's servers refuse writes regardless of any bug in our code. Send capability doesn't exist until Phase 2 scopes.
- All processing local (Mini/server) + Anthropic API under business account (no training on API data). Whisper transcription fully local — audio never leaves the box.
- SA key + tokens: 600 perms in 700 dir, local-only (never iCloud/repo). TODO before DWD goes live: move SA key into encrypted secrets (master.key) — once Austin authorizes, that key IS mailbox access.
- NetSuite: dedicated integration record + role with minimum read permissions (SuiteQL on transaction/customer only), not admin creds.
Harness layer:
- AI pipeline has NO code path to send — classifier/drafter writes to DB only; send endpoint (P3) requires authenticated human session + click; append-only audit log (who/what/when, draft before/after edits).
- Structured-output schema constrains the classifier: it can only emit tags/summary/draft, never actions.
- Per-rep user accounts in the tool (identity for audit), HTTPS via the standard rb.alpineanalytica.com Apache/LE pattern, auth gate like the financials dashboard.
Known threat: prompt injection. Emails are untrusted input fed to an LLM (real phishing already observed in this inbox, twice). Mitigations: email content framed as data-to-classify (never as instructions), no tool-use in the classification call, security_flag category short-circuits drafting entirely, human review before any send, and drafts render as text (no live links auto-followed).
Data at rest: tool DB will hold customer comms + PII. Local-only during pilot; production DB on the RBD server with same access controls as financials dashboard. Discovery JSONL (721 threads, plaintext) is local-only on the Mini — delete after taxonomy validation or encrypt. Retention policy TBD with team.
Gaps to close before P1→P2:
- ☐ SA key into encrypted secrets storage
- ☐ Delete/encrypt discovery JSONL + voicemail audio after validation
- ☐ NetSuite minimum-permission role (not full access)
- ☐ Per-user auth in UI + audit log schema
- ☐ Prompt-injection test set (include the two real phishing samples)
Risks
- Temp token expiry (~7 days) before Austin authorizes → discovery re-auth needed. Mitigation: send email promptly.
- Taxonomy drift (ACH surge shows categories are temporal) → reasons config-driven, monthly distribution review.
- Team adoption — Patti's named-agent relationships must survive: drafts in team voice, no bot tone; pilot = assist-only.
- Marketing blasts from same address pollute the inbox; filter by sender=self + campaign headers early in pipeline.
Execution log
- 2026-08-25: Research (105-agent deep-research + 9 vendor teardowns + official-docs verification). Discovery pull 721 threads/30d, taxonomy derived. Mockup v1 shipped + team feedback. Voicemail PoC passed (5/5). GCP project + SA created (RBD-owned). Austin email drafted; temp read-only OAuth active. Decisions 1–7 locked with Cole.
~/ai-projects/mission-control/plans/rbd-cs-tool.md