# Hope Rings Help Desk CRM — Spec coverage (prototype)

Source: *Help Desk CRM Technical Specification & Developer Brief v1.0 (22 Oct 2026)*. All sample data in the prototype is **fictitious demo data**.
Legend: **V** = visually demonstrated (screen → interaction) · **B** = not visual / backend only (reason) · **P** = partially shown (UI hint/label; real behaviour is backend).
Screens: `index.html` (Overview) and `app.html#/…` routes: inbox, ticket/<id>, customers, routing, sla, automation, csat, qa, reports, settings, migration, audit.

## 1. Executive summary & goals
| Item | Status | Where / reason |
|---|---|---|
| Centralize Email, Messenger, SMS | V | Inbox channel column + filter |
| Customer & order context | V | Ticket → right panel (customer, Shopify, history) |
| Active conversation stays in one ticket | V | Inbox → Simulate inbound → "Reply on latest ticket" appends |
| Contact after Solved/Closed → new linked ticket, history kept | V | Simulate inbound for Marco (ticket #1045 Solved) or Emily after close; "Linked to" banner |
| Closed permanent, never reopened | V | Close confirmation; Closed tickets read-only; status select disabled |
| Replace Zendesk after migration/cutover | V | Migration wizard step 6 |
| Least-loaded assignment, capacity, manager overrides | V | Routing page; ticket Assign/Remove |
| Reliable, auditable, configurable automations | V/P | Automations page; Audit log; reliability is B |
| Preserve history during migration | V | Historical ticket ZD-55120; migration wizard |

## 2. Scope & exclusions
| Item | Status | Where / reason |
|---|---|---|
| Unified inbox Email/Messenger/SMS; Instagram excluded | V | Inbox; Settings notes exclusion |
| Inbound/outbound messages | V | Ticket thread (in/out) |
| Attachments where supported | P | Attachment chip on #1045 message |
| Internal notes | V | Composer "Internal note" mode, yellow notes |
| Tags | V | Ticket left panel; automation "Add tag" |
| Canned responses | V | Composer macro dropdown |
| Teammate mentions | P | Typing `@` in a note shows mention toast; existing @ note on #1042 |
| Customer profiles, identity linking/merging, history | V | Customers page; ticket history panel |
| Read-only Shopify lookup & sidebar | V | Ticket Shopify panel |
| Three roles | V | Role switcher |
| Least-loaded, capacity/availability, unassigned queue, manager reassignment, viewer indicators, collision warnings | V | Routing; Inbox "Unassigned / Backlog" view; ticket #1047 |
| Configurable SLA, aging, CSAT, QA, productivity reports, CSV exports | V | SLA, CSAT, QA, Reports pages |
| Zendesk historical migration | V | Migration wizard |
| Security, privacy, monitoring, backup/restore | V/P | Settings page cards |
| Excluded: live monitoring dashboard, bulk marketing/Trustpilot/BBB, Shopify writes, SMS vendor before selection, FB/IG comments, lead forms | V (by absence) | Listed on Overview & Settings; Shopify panel says read-only |

## 3. Roles & permissions
| Item | Status | Where / reason |
|---|---|---|
| Super Admin: roles, integrations, API credentials, config, audit logs | V | Settings (credentials, users, MFA editable only as Owner); Audit log owner-only |
| CS Admin/Manager: agents, shifts, availability, capacity, routing, SLA/aging, overrides, QA, team reports/CSAT, exports | V/P | Routing, SLA, QA, Reports, CSAT unlocked for Manager. Shifts: P (availability only; shift scheduling not specified in detail) |
| CS Agent: work tickets, reply, notes, tags/macros/mentions, status, history, permitted Shopify, send CSAT | V | Agent role in ticket view; admin pages show 🔒 |
| Backend-enforced permissions | B | Server-side; prototype shows note on locked screens |
| Deactivated users lose access, history attributed | V | Settings → Deactivate; "Former Agent (deactivated)" on closed #987 |
| 3.1 One owner at a time | V | Assign disabled while an owner exists |
| 3.1 Remove before replace | V | Remove → Assign flow |
| 3.1 Record actor/timestamp/prev/new/reason | V | Remove dialog reason; Audit log |
| 3.1 Agents cannot bypass assignment | V | Agent cannot Remove; can only self-take unassigned |

## 4. Channels & ingestion
| Item | Status | Where / reason |
|---|---|---|
| 4.1 Email provider/IMAP/SMTP (selection in discovery) | P | Settings → Email card text |
| Capture headers, Message-ID, In-Reply-To, attachments | B | Data capture; listed in Settings card |
| Safe HTML/plain text; sanitize; untrusted attachments | B/P | Rendering escapes text; label on attachment |
| Retries, monitoring, secure auth, idempotency | V/P | Simulate duplicate webhook toast; Settings failed-event retry |
| Outbound delivery status & failure shown to agents | V | ✓ delivered / ⚠ Send failed + Retry on #1044 |
| Headers don't override lifecycle rules | B | Backend threading logic |
| 4.2 Messenger via Meta webhooks | P | Settings card |
| Replies only within permitted windows | V | #1044 failed send "outside messaging window" |
| Verify assets/permissions/webhooks/production access | V | Settings Messenger checklist |
| Expired credentials, duplicates, rate limits, rejected sends | V/P | "Token expires in 5 days" badge; rejected send |
| No Instagram/other Meta | V | Settings note |
| 4.3 Provider-neutral SMS adapter | V/P | Settings "Provider not selected" |
| SMS IDs, delivery states, webhook verification, retries, dedupe | B | Adapter internals |
| Confirm provider capabilities/costs | B | Discovery task |
| 4.4 Common message fields | B | Data model |
| Internal notes never sent to customers | V | Note label "never sent to customer" |

## 5. Customers, orders, identity
| Item | Status | Where / reason |
|---|---|---|
| Multiple identifiers preserved | V | Customers table (email/phone/Meta ID) |
| Manual merge with confirmation & audit; no silent merges | V | Customers → Review & merge (disabled for Agent) |
| Tickets link to customer; view history without changing status | V | Ticket history panel |
| Prompt for order number | V | Macro "Request order number" |
| Email/phone lookup + extra verification | P | "Verify identity" macro; lookup box |
| Order number not proof; hide details until verified | V | Ticket #1046 / #1044 (unverified) → locked order notice |
| Imported tickets don't trigger notifications/CSAT/assignment/automations | V | ZD-55120 read-only; Send CSAT disabled |

## 6. Tickets & status
| Item | Status | Where / reason |
|---|---|---|
| Statuses New/Open/Pending/Solved/Closed | V | Badges + unified Zendesk “Submit as [Status]” split button (§6.1 / §14.1) |
| Pending reason | V | Pending dialog; #1044 |
| Solved → CSAT once + auto-close timer / manual close | V | Status → Solved toast; countdown on #1045 |
| Status history (actor, time, old/new) | V | Audit log |
| 6.2 All six threading situations | V (5) / B (email references) | Simulate inbound (append, new, linked after Solved/Closed, duplicate). Email-reference case: B (header parsing) |
| 6.3 Durable scheduler, restart recovery | B | Worker infrastructure |
| 6.3 Leaving Solved cancels closure; re-solve schedules new timer | V | Toast "Pending auto-closure cancelled" |
| 6.3 New contact during Solved doesn't reset old timer | V | Simulate inbound toast |

## 7. Assignment & ownership
| Item | Status | Where / reason |
|---|---|---|
| Least-loaded among eligible active agents | V | Routing → preview; Simulate inbound auto-assigns |
| Manager sets capacity & availability | V | Routing table inputs |
| Active count = New/Open/Pending | V | Routing load column |
| Tie-breaker least-recently-assigned | V | Routing "Last assigned" + preview logic |
| No eligible → Unassigned/Backlog | V | Set all offline then preview / simulate |
| Option A for all new tickets; new agent sees full history | V | Ticket history panel |
| 7.2 Viewer indicator | V | #1047 "👁 viewing"; eye icon in list |
| Distinct composing indicator; warning | V | #1047 orange composing banner; confirm on send |
| Stale presence heartbeat timeout | V/B | Routing → heartbeat setting; real-time layer B |
| Prevent concurrent sends; log transfers | V/P | Send confirm; Audit + deflection report |

## 8. Shopify
| Item | Status | Where / reason |
|---|---|---|
| Admin GraphQL, secure token, read-only | P | Settings Shopify card; Owner-only credentials |
| Search by order number / email/phone | V/P | Sidebar lookup (order number) |
| Status, date, total, items, fulfillment, tracking in collapsible sidebar | V | #1042 Shopify panel |
| Pagination, rate limits, missing fields, unavailable orders, API errors | V | #HR-RATE, #HR-NOPERM, unknown number, "tracking not available" |
| Caching/webhooks | P | "Cached · refreshed via webhook" label; logic B |
| Scopes read_orders/read_customers/read_all_orders; verify | V | Settings; older order #HR-08811 labelled read_all_orders |
| No write scopes; no data for unverified identity | V | Read-only label; verification lock |
| Acceptance: recent + older lookup, graceful errors | V | Lookups above |

## 9. SLA, aging, automation
| Item | Status | Where / reason |
|---|---|---|
| Admin UI rule create/change, no code | V | SLA → New SLA rule |
| Multiple rules with overlap priority | V | Rule # column |
| First / subsequent response targets | V | Table columns |
| Pending follow-up targets | V | Column + automation reminder |
| Calendar/business hours, days, TZ, holidays | V | Business hours card |
| Pause/resume by status | V | "Pause on" column; Pending shows ⏸ |
| Rules by channel/priority/team | V | Conditions |
| Warning thresholds, breach alerts, report filters, audit | V | Threshold input; orange/red badges; "SLA breached" view; audit history card |
| Values configurable, not hard-coded | V | Inputs (demo values) |
| 9.2 Age from defined timestamp vs time since last reply | V | Age badge + hover; SLA page selector |
| Buckets <24h, 24–72h, 3–7d, 7d+ configurable | V | SLA aging card; Reports backlog chart |
| Durable, duplicate-safe jobs | B | Scheduler |

## 10. CSAT & QA
| Item | Status | Where / reason |
|---|---|---|
| First eligible Solved → one send | V | Status → Solved |
| Record eligibility, time, channel, delivery, response | V | CSAT log |
| Dedupe retried events; 24h cooldown configurable | V/B | Cooldown block on manual send; SLA page input; dedupe B |
| Follow-ups with csat_sent suppressed; manual Send CSAT button | V | Linked ticket → Solved toast; Send CSAT button |
| Retry behaviour; failed delivery shown | V | "failed (retry 3/3)" row |
| Reply after Solved/Closed doesn't retrigger CSAT | V | Simulate inbound + solve linked ticket |
| 10.2 Configurable scorecards (tone, accuracy, policy, resolution) | V/P | QA page (criteria shown; editing is P) |
| Evaluations: evaluator, date, scores, notes, version | V | QA evaluate + table |
| QA restricted by role | V | Agent sees 🔒 |

## 11. Reporting & exports
| Item | Status | Where / reason |
|---|---|---|
| Volume by channel/status/date/team/agent | V | Reports charts + filters |
| FRT/pending SLA & breach rates | V | KPI + trend chart (demo) |
| Backlog by aging; workload & capacity | V | Charts |
| Manual assign/removal/transfer counts | V | Deflection chart |
| CSAT sends/delivery/response/scores | V | CSAT page |
| QA results & trends | V | Reports QA chart |
| CSV export with permission checks & audit; TZ, range, historical treatment | V | Export dialog (downloads CSV, audited, include-historical toggle) |

## 12. Security, privacy, reliability
| Item | Status | Where / reason |
|---|---|---|
| Backend RBAC, least privilege | B (UI mirrored) | Locked screens |
| Auth/sessions, recovery, MFA for privileged | P | Settings MFA & session timeout; recovery B |
| TLS, encryption at rest | B | Infrastructure (labelled) |
| Secrets in secret storage, never logged | V/P | Masked credentials, Owner-only |
| Audit role/config/exports/merges/assignments | V | Audit log |
| Input validation, encoding, rate limiting, attachments | B/P | Text escaped; empty-message validation |
| Restrict production access | B | Ops |
| 12.2 Multi-jurisdiction privacy, data inventory, retention, DSRs, DPAs, consent | P | Settings privacy card (TBD items); legal confirmation B |
| 12.3 Backups, restore tests & evidence, RPO/RTO | P | Settings Backup card |
| Monitoring & alerts, safe retry of failed events | V/P | Webhook lag, failed events Inspect & retry |
| Dev/staging/prod | P | Label |

## 13. Zendesk migration
| Item | Status | Where / reason |
|---|---|---|
| No one-click promise; audit first | V | Wizard warning |
| 13.1 Data to assess (tickets, IDs, comments/notes, users, attachments, CSAT, channels) | V | Step 1 & 2 |
| 13.2 Steps 1–7 | V | Wizard steps 1–7 (pilot, reconciliation variance, re-run, cutover, report download) |
| 13.3 Imported marked historical; no messages/CSAT/assignment/automations; preserve IDs/timestamps | V | ZD-55120; "Imported (historical)" view; mapping |
| Measurable thresholds / zero variance target | V | Reconcile step |

## 14. Architecture & NFRs
All **B** (backend/infra): CRM API, database/storage, channel adapters, workers/scheduler, real-time layer, Shopify adapter, monitoring/backup, stack documentation, reliability, idempotency, performance targets, maintainability, observability, data integrity. Agent web app = this prototype. Real-time is simulated with static presence on #1047.

## 15.1 Acceptance tests
| Area | Status |
|---|---|
| Channel ingestion & dedupe | V (simulated) |
| Active conversation appends | V |
| Solved/Closed replies → linked ticket | V |
| Closure timer 48h, cancel, restart recovery | V (timer/cancel) / B (recovery) |
| CSAT once, dedupe, cooldown | V / B (dedupe) |
| Assignment least-loaded, skip capacity/offline, backlog | V |
| Manager reassignment remove-then-assign, audit, one owner | V |
| History without status change | V |
| Shopify recent/older, permission/rate limit, no writes | V |
| SLA change without deployment | V (UI) / B (timer recalculation) |
| Security: unauthorized API denied | B |
| Migration validation | V (mock) |
| Recovery: backup restore, failed-event retry | P |

## 15.2 Open decisions (as listed in spec)
| Item | Default or action |
|---|---|
| Capacity count | New/Open/Pending count as active; Solved/Closed excluded. Confirm with business. |
| Active-ticket inactivity | Define if/how an inactive New/Open/Pending ticket stops accepting replies; do not reopen Solved/Closed tickets. |
| Order verification | Business approves verification requirements by channel before private order details are shown. |
| Email and SMS provider | Choose during technical discovery; provider capabilities/costs may affect estimate. |
| Meta production access | Verify business assets, app permissions, webhook subscriptions, and current policy requirements. |
| Shopify access | Verify actual scopes, protected customer data access, historical order access, and tracking fields in the store. |
| SLA defaults | Set target values, business hours, timezone, holidays, and pause/resume rules. |
| CSAT | Confirm survey format/destination per channel; default 24-hour customer cooldown retained from source brief. |
| Zendesk migration | Audit source data and agree measurable acceptance criteria before promising completeness. |
| Operations | Agree expected scale, performance targets, RPO/RTO, backup retention, hosting, maintenance, and post-launch support. |

## 16. UI/UX & Appendix A
| Item | Status | Where / reason |
|---|---|---|
| Zendesk-like layout (dark navy header + workspace tabs, metadata left / thread center / Shopify+customer right) | V | app.html + ticket workspace (§14.1) |
| Exact colours verified from authorized reference | **Not done** | Colours are approximations in `js/theme.js`; must be verified |
| No Zendesk branding/assets | V | Own "HR" mark, system font |
| Central design tokens / reusable components | V | `js/theme.js`, `btn/card/badge` helpers in `js/app.js` |
| Confirmation for close, merge, export, assignment | V | Modals |
| Feedback: saving, sending, failures, empty, validation, permission | V | Toasts, empty view, 🔒 screens. Loading states: P |
| Responsive, keyboard focus, contrast | V/P | Responsive layout, focus rings |
| Design-system documentation | P | This doc + theme.js comments |
| Prototype of inbox & ticket detail for approval | V | This deliverable |
| Appendix A modules (all included items) | V | Mapped above; Live monitoring & bulk email excluded |
| A.2 delivery plan, A.3 handover deliverables | B | Commercial/project items, not UI |

## Summary
~150 line items reviewed. ≈ 112 visually demonstrated (V or V/P), ≈ 18 partially (P), ≈ 22 backend/infra/commercial only (B, incl. all of §14 and A.2/A.3).

---

## v2 redesign (2026-10-23): presentation changes only, no new requirements

- **Overview (index.html):**
  - one-sentence hero;
  - SVG architecture diagram: channels → ingestion → tickets → assignment → agent workspace → Shopify context (read-only) → SLA/automation → CSAT/QA → reports, plus the Zendesk migration feed;
  - 12 module cards, each with an "Open module" link;
  - ticket lifecycle (New → Open → Pending → Solved → Closed) with three rule cards: CSAT on solve, 48h auto-close, and a reply after Solved creating a linked ticket;
  - roles & permissions matrix (Agent / CS Manager / Owner).
- **Guided demo** (index "Start guided demo", the sidebar button, or `app.html#tour`). It has 8 spotlight steps with Next/Back, arrow keys and Esc:
  - an inbound Messenger message creates demo ticket #1048;
  - least-loaded auto-assign;
  - the Shopify order #HR-10482 panel;
  - a prefilled reply;
  - Solved, then CSAT logged;
  - Reports.
  - The tour switches the role to CS Manager and restores the previous role when it ends.
- **Design system:**
  - slate/white surfaces, navy #1b2a4e with gold #b08d57 accent, Inter font;
  - Lucide SVG icons, with all emoji removed (including from the demo data);
  - consistent cards, tables, badges, empty states and breadcrumbs.
- **Module pages:** every module page has a breadcrumb, title, one-line description and a collapsible "How it works" listing the spec rules that page shows.
- **Labelling:** "Prototype · demo data" is now a small pill in the top bar.
- **Coverage:** all v1 screens and interactions are kept. The checklist above still applies unchanged.

## v3: Inbox, ticket and reports redesign (2026-10-23)
- **Inbox:** 3-pane layout. Views rail (with counts), compact ticket list (avatar, customer, subject, snippet, channel icon, status/priority/SLA pills, time, selected state) and an empty-state pane.
- **Ticket:**
  - Header: subject, requester, channel, status pill, assignee, priority and SLA countdown.
  - Distinct bubbles for customer, agent and internal notes (yellow). Delivery state and failed/retry are shown.
  - Sticky composer: Reply/Internal note tabs, macros, attach, @mention, and send with status.
  - Tabbed sidebar: Customer, Shopify order (line items with placeholder thumbnails, totals, fulfillment/tracking, read-only), History, Linked. It becomes an overlay below 1024px.
- **SLA/age badges:** unified pill style. Pending shows as "Paused".
- **Reports dashboard (Chart.js 4.4.1 CDN):**
  - Toolbar: date range, channel, team and include-imported filters, plus audited export.
  - Six KPI cards with deltas and ten chart cards.
  - Each card opens `#/report/<key>` with a breadcrumb, explanation, large chart, data table and audited per-report CSV export.
  - All figures are demo data; trend series are illustrative.
- **Audit:** no horizontal overflow on any route or role at 1440x900, 1280x800 or 1024x768 (verify3.py). Index lifecycle min-width fixed.


## v4: Zendesk theme & pane realignment (2026-10-27)
- **Theme (§14.1):** primary submit actions use Zendesk green `#2F855A`; Internal Note composer tint `#FEFCBF`; top bar is dark navy Zendesk header (`#03363d`) with open-ticket workspace tabs.
- **3-pane ticket (§14.1):** Left = metadata (Assignee, Status, Priority, Tags, Type, Channel, SLA). Center = conversation thread + composer only. Right = read-only Shopify (orders/fulfillment/tracking) + Customer Profile.
- **Submit control (§6.1 / §14.1):** standalone Send + status select replaced by “Submit as [Status]” split button (Open / Pending / Solved).
- **CSAT & collision:** “Send CSAT” in ticket header toolbar; eye + collision warning banners at top of conversation view.
- **Names:** agent/admin mock names are English (Sarah Mitchell, Omar Rivera, Lena Ford, Brian Kane, Natalie Shaw, Alex Owner).
