# Product Requirements Document

## Validation Checklist

- [x] All required sections are complete
- [x] No [NEEDS CLARIFICATION] markers remain
- [x] Problem statement is specific and measurable
- [x] Problem is validated by evidence (not assumptions)
- [x] Context → Problem → Solution flow makes sense
- [x] Every persona has at least one user journey
- [x] All MoSCoW categories addressed (Must/Should/Could/Won't)
- [x] Every feature has testable acceptance criteria
- [x] Every metric has corresponding tracking events
- [x] No feature redundancy (check for duplicates)
- [x] No contradictions between sections
- [x] No technical implementation details included
- [x] A new team member could understand this PRD

---

## Product Overview

### Vision

Enable store staff to have real-time, two-way SMS conversations with customers directly from the Workbook, transforming one-way notifications into meaningful customer engagement while maintaining compliance and cost control.

### Problem Statement

**Current State**: Store staff can only send one-way transactional SMS messages to customers (e.g., "Your buy is ready for pickup"). When customers reply with questions ("What time do you close?", "Can I pick up tomorrow?"), these messages are logged but not surfaced to staff, and staff have no way to respond. This forces customers to call the store, creating friction and potentially lost business.

**Pain Points**:
1. **Staff Frustration**: Employees see missed opportunities when customers text back but can't respond
2. **Customer Friction**: Customers expect text conversations to be bidirectional; being forced to call feels outdated
3. **Lost Revenue**: Simple questions go unanswered, potentially causing customers to abandon pickups
4. **Competitive Disadvantage**: Modern retail platforms (Shopify, Square) offer two-way SMS; our stores cannot

**Evidence**:
- 98% SMS open rate vs. 20% for email (industry data)
- 90% of customers expect immediate response to service questions
- 72% want immediate service without channel switching
- Inbound SMS currently logged to `inboundSMSLog` table but not actionable by staff

### Value Proposition

**For Store Staff**: Respond to customer questions instantly from the Workbook without leaving their workflow, using quick canned responses or personalized messages once conversation is established.

**For Store Owners**: Gain visibility into customer communications, control messaging through templates, and track SMS usage for billing transparency.

**For Customers**: Get quick answers via their preferred channel (text) without calling, leading to smoother pickups and better service experience.

**Unique Value**: Integrated directly into the Workbook where staff already work, with intelligent store-matching for inbound messages and compliance-first design that protects both stores and customers.

## User Personas

### Primary Persona: Store Employee (Staff)
- **Demographics**: Ages 18-45, frontline retail workers, moderate technical comfort with smartphones/tablets
- **Goals**:
  - Quickly answer customer questions without interrupting workflow
  - Notify customers about their items efficiently
  - Avoid phone call interruptions during busy periods
- **Pain Points**:
  - Cannot respond when customers text back questions
  - Must stop what they're doing to answer phone calls
  - No visibility into what messages were already sent to a customer

### Secondary Persona: Store Manager/Owner (Admin)
- **Demographics**: Ages 30-60, business operators, varied technical expertise
- **Goals**:
  - Maintain professional, consistent customer communication
  - Control what staff can say to prevent brand damage
  - Understand SMS costs for budget planning
  - Review customer communication history when issues arise
- **Pain Points**:
  - No control over staff messaging (if enabled)
  - Cannot see chat history during customer disputes
  - No visibility into SMS costs per store

### Tertiary Persona: Customer (External)
- **Demographics**: Consignment sellers/buyers, ages 25-55, smartphone users
- **Goals**:
  - Get quick answers about their items/pickups
  - Communicate conveniently without calling
  - Know their message was received
- **Pain Points**:
  - Texts go unanswered; must call for simple questions
  - Unclear if store received their message
  - Phone calls during business hours are inconvenient

## User Journey Maps

### Primary User Journey: Staff Responds to Customer Question

1. **Trigger**: Customer receives "Your buy is ready!" SMS and replies "What time do you close today?"
2. **Notification**: Workbook chat panel shows unread message indicator with audio notification
3. **Discovery**: Staff clicks chat panel, sees thread with customer name and buy context
4. **Composition**: Staff sees freetext input (unlocked because customer replied), types response
5. **Send**: Staff sends "We close at 8pm today! See you soon!" - sees character count and delivery status
6. **Resolution**: Customer receives response, thread stays open for follow-up if needed

### Secondary User Journey: Staff Initiates Contact with Today's Customer

1. **Discovery**: Staff opens chat panel, sees list of today's buy customers eligible for messaging
2. **Selection**: Staff clicks customer "John D. - Buy #47" to open thread
3. **Template Selection**: System shows "Select a message to start conversation" with canned templates
4. **Preview**: Staff selects "Pickup Reminder" template, sees preview with wildcards filled in
5. **Send**: Staff sends canned message, thread shows "Awaiting customer reply"
6. **Wait**: Until customer replies, staff can only send additional canned messages (no freetext)

### Tertiary User Journey: Owner Reviews Customer History

1. **Access**: Owner navigates to Admin → Customer Lookup → searches customer
2. **Discovery**: Customer profile shows "Chat History" section with conversation count
3. **Review**: Owner expands to see all threads with timestamps and message previews
4. **Detail**: Owner clicks thread to see full conversation including delivery statuses
5. **Action**: Owner uses history to understand context for customer dispute resolution

### Admin User Journey: Owner Manages Templates

1. **Access**: Owner navigates to Admin → Chat Templates
2. **View**: Sees two sections: Transactional (system-required) and Canned Responses (custom)
3. **Edit**: Clicks "Buy Ready" transactional template to customize wording
4. **Preview**: Types new content, sees character count and wildcard preview in real-time
5. **Save**: Saves template, immediately available to all staff
6. **Create**: Clicks "Add Canned Response" to create new template for common scenarios

## Feature Requirements

### Must Have Features

#### Feature 1: Chat Panel in Workbook
- **User Story**: As a store employee, I want to see and respond to customer messages in my Workbook so that I can handle conversations without leaving my workflow.
- **Acceptance Criteria**:
  - [ ] Chat appears as a floating overlay panel that can be opened from the Workbook (e.g., KPI footer icon, buy queue badge)
  - [ ] Overlay can be minimized to the KPI footer and restored
  - [ ] Shows list of active threads sorted by most recent message
  - [ ] Unread threads display with visual indicator (badge count)
  - [ ] Audio notification plays when new inbound message arrives
  - [ ] Thread list shows customer name, buy number, and message preview

#### Feature 2: Inbound Message Routing
- **User Story**: As a system, I must route incoming customer SMS to the correct store so that staff at the right location can respond.
- **Acceptance Criteria**:
  - [ ] Inbound SMS matched to store via customer's most recent buy
  - [ ] Messages from unmatched phones are logged but not routed to any store
  - [ ] STOP/opt-out commands are processed before store routing
  - [ ] Matched messages create or update thread and notify store via real-time channel

#### Feature 3: Canned Message Requirement for Initial Contact
- **User Story**: As a store owner, I want staff to use pre-approved messages when initiating contact so that customer communication is consistent and professional.
- **Acceptance Criteria**:
  - [ ] Staff cannot send freetext as the first message in a thread
  - [ ] Template picker displays categorized canned messages
  - [ ] Selected template shows preview with wildcards replaced
  - [ ] Character count displayed before sending
  - [ ] After customer replies, freetext input unlocks for that thread

#### Feature 4: Freetext Response After Customer Reply
- **User Story**: As a store employee, I want to type custom responses after a customer has replied so that I can answer their specific questions naturally.
- **Acceptance Criteria**:
  - [ ] Freetext input appears only after customer has sent at least one message
  - [ ] Character counter shows remaining characters (max 320)
  - [ ] SMS segment count displayed (warns at 160 char boundary)
  - [ ] Send button disabled if message empty or exceeds limit

#### Feature 5: Eligibility Rules for Messaging
- **User Story**: As a system, I must restrict which customers staff can message so that we prevent unwanted contact and respect customer consent.
- **Acceptance Criteria**:
  - [ ] Staff can only initiate messages to customers with same-day buys
  - [ ] Exception: Open threads from previous days remain accessible until closed
  - [ ] Customers on do-not-text list are not messageable
  - [ ] Eligible customer list updates in real-time as buys are entered

#### Feature 6: Template Management (Admin)
- **User Story**: As a store owner, I want to create and manage canned message templates so that staff have appropriate responses for common situations.
- **Acceptance Criteria**:
  - [ ] Admin can view all templates organized by category
  - [ ] Admin can create new canned response templates
  - [ ] Admin can edit template content, short name, and active status
  - [ ] Character count and SMS segment count shown during editing
  - [ ] Wildcards ({{customer_name}}, {{store_phone}}, etc.) documented and insertable
  - [ ] Transactional templates (system) can be edited but not deleted

#### Feature 7: Delivery Status Tracking
- **User Story**: As a store employee, I want to see if my message was delivered so that I know the customer received it.
- **Acceptance Criteria**:
  - [ ] Outbound messages show status: Sending → Sent → Delivered / Failed
  - [ ] Failed messages display error reason
  - [ ] Status updates via webhook within 60 seconds typically
  - [ ] If no status after 60 seconds, show "Sent (unconfirmed)"

#### Feature 8: Chat History (Admin)
- **User Story**: As a store owner, I want to view chat history for any customer so that I can review communications when needed.
- **Acceptance Criteria**:
  - [ ] Customer lookup shows "Chat History" section
  - [ ] All threads with customer displayed with date range
  - [ ] Full message history viewable including delivery status
  - [ ] Filter by date range available

#### Feature 9: SMS Usage Tracking for Billing
- **User Story**: As a system, I must track all SMS for billing purposes so that stores can be charged for interactive message usage.
- **Acceptance Criteria**:
  - [ ] Every outbound message logged with category (transactional/interactive)
  - [ ] Transactional messages marked as included (free)
  - [ ] Interactive messages marked as billable
  - [ ] Usage aggregated by store and billing period
  - [ ] Usage report available to admin

#### Feature 10: TCPA Compliance - Opt-Out Handling
- **User Story**: As a system, I must honor opt-out requests within 10 business days (per TCPA 2025 rules) so that we remain legally compliant.
- **Acceptance Criteria**:
  - [ ] STOP and variations recognized: "stop", "unsubscribe", "cancel", "leave me alone"
  - [ ] Granular opt-out supported:
    - [ ] "STOP" (or equivalent) opts customer out of all messages
    - [ ] "STOP MARKETING" (or equivalent) opts customer out of marketing/interactive messages but still allows transactional notifications (e.g., buy ready)
  - [ ] Opt-out processed within 5 minutes (confirmation sent)
  - [ ] Customer added to do-not-text list immediately with appropriate `optout_type`
  - [ ] Only one confirmation message sent (no follow-up if they reply again)
  - [ ] Opted-out customers cannot receive any non-emergency messages beyond the allowed transactional scope for their `optout_type`

### Should Have Features

#### Feature 11: Thread Close/Archive
- **User Story**: As a store employee, I want to close a thread when conversation is complete so that my chat list stays manageable.
- **Acceptance Criteria**:
  - [ ] Close button available on each thread
  - [ ] Closed threads move to "Closed" section or hide from main list
  - [ ] Closed threads reopen automatically if customer sends new message
  - [ ] Admin can view closed thread history

#### Feature 12: Typing Indicator
- **User Story**: As a customer, I want to know when the store is typing a response so that I wait for their reply.
- **Acceptance Criteria**:
  - [ ] When staff is typing, system shows indicator to customer (if supported by provider)
  - [ ] Typing indicator does not persist if staff stops typing for 30 seconds

#### Feature 13: SMS Usage Dashboard
- **User Story**: As a store owner, I want to see my store's SMS usage so that I can monitor costs.
- **Acceptance Criteria**:
  - [ ] Dashboard shows: messages sent (by category), messages received, delivery rate
  - [ ] Filter by date range
  - [ ] Compare current period to previous period

#### Feature 14: Message Search
- **User Story**: As a store employee, I want to search through chat history so that I can find previous conversations.
- **Acceptance Criteria**:
  - [ ] Search by customer name or phone number
  - [ ] Search by message content
  - [ ] Results show thread with matching messages highlighted

### Could Have Features

#### Feature 15: Quick Reply Suggestions
- **User Story**: As a store employee, I want to see suggested responses so that I can reply faster.
- **Acceptance Criteria**:
  - [ ] Based on customer's message, suggest 2-3 relevant canned responses
  - [ ] One-click to insert suggested response
  - [ ] Suggestions learn from usage patterns over time

#### Feature 16: Multi-Store Thread View (For Multi-Store Owners)
- **User Story**: As a multi-store owner, I want to see chat activity across all my stores so that I can monitor customer engagement.
- **Acceptance Criteria**:
  - [ ] Aggregate view of active threads across stores
  - [ ] Filter by store
  - [ ] Drill down into individual store chats

#### Feature 17: Scheduled Messages
- **User Story**: As a store employee, I want to schedule a message for later so that I can prepare communications in advance.
- **Acceptance Criteria**:
  - [ ] Schedule message for specific time
  - [ ] Cancel scheduled message before send time
  - [ ] Scheduled messages visible in thread as "Scheduled for X"

### Won't Have (This Phase)

1. **MMS/Image Messaging**: Only text SMS; no photo sharing this phase
2. **Group Messaging**: One customer per thread; no multi-customer broadcasts via chat
3. **AI Auto-Response**: No automated AI responses to customers; all replies require human action
4. **WhatsApp/Messenger Integration**: SMS only; other messaging platforms out of scope
5. **Customer-Initiated Threads**: Customers can only reply to store-initiated messages; cannot start new conversations
6. **Multi-Language Templates**: English only for templates; translated templates future phase

## Detailed Feature Specifications

### Feature: Inbound Message Routing

**Description**: When a customer sends an SMS to the store's shortcode/number, the system must determine which store should receive the message based on the customer's purchase history. This is critical because all stores share a common SMS endpoint.

**User Flow**:
1. Customer sends SMS to store shortcode (e.g., 12345)
2. Vonage/Twilio webhook receives message with phone number and content
3. System normalizes phone number (strip formatting, ensure 10 digits)
4. System queries ALL active stores to find customer by phone number
5. For each match, system queries for most recent buy (entered or completed)
6. Store with most recent buy timestamp wins the routing
7. If no buy found in any store, message is logged as "unroutable" (admin visibility)
8. If routed, thread created/updated, Ably event published to store's channel
9. Staff sees new message in Workbook chat panel

**Business Rules**:
- Rule 1: Phone numbers must be normalized to 10-digit format before lookup
- Rule 2: Most recent buy timestamp (COALESCE of timeCompleted, timeEntered) wins routing
- Rule 3: Ties go to the store with the most recent timeEntered (most recent drop-off wins)
- Rule 4: STOP/opt-out messages processed BEFORE routing (opt-out applies globally)
- Rule 5: If customer has no buy in any store, log message but do not create thread
- Rule 6: Unroutable messages visible in admin monitoring dashboard

**Edge Cases**:
- Scenario 1: Customer has buys at two stores same day → Expected: Most recent buy timestamp wins
- Scenario 2: Customer's phone number changed since last buy → Expected: Message unroutable; cannot match
- Scenario 3: Customer opted out previously → Expected: STOP confirmation sent, no thread created
- Scenario 4: Vonage/Twilio webhook fails → Expected: Retry logic; message queued if endpoint unavailable
- Scenario 5: Very old customer (last buy 2 years ago) replies → Expected: Route to that store; thread opens despite age

### Feature: Canned Message Requirement (Freetext Lock)

**Description**: To maintain professional communication and prevent spam, staff must use pre-approved templates when initiating contact with a customer. Only after the customer has replied can staff send custom freetext messages.

**User Flow**:
1. Staff opens thread for customer who has not yet replied
2. Text input area shows "Select a template to send" (input disabled)
3. Staff clicks template picker button
4. Modal shows categorized templates: Transactional, Initial Contact, Follow-up
5. Staff selects template (e.g., "Pickup Reminder")
6. Preview pane shows message with wildcards filled: "Hi John, your buy #47 is ready!"
7. Staff confirms and sends
8. Thread shows sent message with delivery status
9. Freetext input remains disabled; shows "Awaiting customer reply"
10. Customer replies "Thanks! What time do you close?"
11. Freetext input enables; staff can now type custom response

**Business Rules**:
- Rule 1: `staff_can_freetext = FALSE` until customer has sent at least one message in thread
- Rule 2: Once `staff_can_freetext = TRUE`, it remains true for the life of the thread
- Rule 3: Staff can still use templates even after freetext unlocks (convenience)
- Rule 4: System messages (delivery confirmations) don't count as customer replies
- Rule 5: Transactional templates can only be used for transactional purposes (initial notification)

**Edge Cases**:
- Scenario 1: Staff sends 3 canned messages, customer never replies → Expected: Freetext stays locked
- Scenario 2: Customer replies with just emoji → Expected: Counts as reply; freetext unlocks
- Scenario 3: Customer replies with STOP → Expected: Opt-out processed; thread closes; no freetext opportunity
- Scenario 4: Thread closed and customer replies later → Expected: Thread reopens; freetext remains enabled (was already unlocked)

## Success Metrics

### Key Performance Indicators

- **Adoption**: 50% of active stores use chat feature weekly within 60 days of launch
- **Engagement**: Average 5+ messages per store per week (outbound + inbound)
- **Quality**: 98%+ message delivery rate (delivered / sent)
- **Speed**: <5 second latency from inbound SMS to Workbook notification
- **Customer Response Rate**: 25%+ of staff-initiated threads receive customer reply
- **Template Utilization**: Track usage of each template; identify top 10 and unused templates

### Tracking Requirements

| Event | Properties | Purpose |
|-------|------------|---------|
| `chat_panel_opened` | typeNum, employeeId, timestamp | Track feature engagement |
| `chat_thread_opened` | typeNum, threadId, customerId, buyId | Track thread interaction |
| `chat_message_sent` | typeNum, threadId, direction, category, templateId, characterCount | Track message volume and type |
| `chat_message_delivered` | typeNum, messageId, deliveryStatus, latencyMs | Track delivery quality |
| `chat_template_used` | typeNum, templateId, templateCategory | Track template effectiveness |
| `chat_freetext_unlocked` | typeNum, threadId, messagesBeforeUnlock | Track customer response behavior |
| `chat_thread_closed` | typeNum, threadId, messageCount, durationMinutes | Track conversation completion |
| `chat_optout_received` | phone, typeNum, optoutType | Track compliance events |
| `chat_message_failed` | typeNum, messageId, errorCode, errorMessage | Track delivery issues |

---

## Constraints and Assumptions

### Constraints
- **SMS Segment Limit**: Messages limited to 320 characters (2 segments) to control costs
- **Daily Message Limit**: Max 5 messages per phone per day (reuse existing global flood protection)
- **TCPA Compliance**: Must honor opt-outs within 10 business days (we'll do 5 minutes)
- **Character Encoding**: Emoji usage triggers Unicode mode (70 chars/segment vs 160)
- **Provider Dependency**: Vonage and Twilio API availability required for sending/receiving
- **Real-time Dependency**: Ably availability required for instant notifications

### Assumptions
- Users have reliable internet connection for real-time features
- Stores have existing SMS provider configuration (Vonage or Twilio)
- Customers receiving initial transactional SMS have implicitly consented to replies
- Staff will primarily use desktop/tablet for Workbook (not mobile-optimized this phase)
- Existing `loyaltyDoNotTextList` table will be used for opt-out tracking

## Risks and Mitigations

| Risk | Impact | Likelihood | Mitigation |
|------|--------|------------|------------|
| Cross-store routing error (wrong store gets message) | High | Low | Use most recent buy timestamp with tiebreaker logic; log all routing decisions for audit |
| TCPA violation (opt-out not honored) | High | Low | Process opt-outs synchronously before any routing; 5-minute confirmation SLA |
| Staff abuse (inappropriate messages) | Medium | Medium | Canned-only requirement until customer reply; audit logging; manager review capability |
| High SMS costs from unlimited usage | Medium | Medium | 320 char limit; 5 messages/day/phone limit; usage dashboard for visibility |
| Delivery delays cause confusion | Medium | Medium | Show "Sending" state; 60-second timeout to "Sent (unconfirmed)"; retry logic |
| Ably outage prevents real-time updates | Medium | Low | Fallback: periodic polling every 30 seconds if Ably disconnects |
| Customer expects instant response | Medium | High | Set expectation via template wording; consider auto-reply for after-hours |

## Open Questions

- [x] Should we support MMS (images)? → **Decision: No, text only this phase**
- [x] What is the billing rate per interactive SMS? → **Decision: To be configured in store settings; default $0.03/message**
- [x] How long should closed threads be retained? → **Decision: 90 days in active storage, then archived**
- [x] Should we notify customers when store is closed? → **Decision: Consider auto-reply in Should Have phase**
- [x] What happens if a customer texts while opted out of marketing but not transactional? → **Decision: Yes, support granular opt-out. Customers can opt out of marketing while still receiving transactional messages (buy ready, pickup reminders). STOP = all messages; STOP MARKETING = marketing only.**

---

## Supporting Research

### Competitive Analysis

| Platform | Two-Way SMS | Canned Templates | Chat in POS/Dashboard | Billing Model |
|----------|-------------|------------------|----------------------|---------------|
| Shopify POS | Via Postscript/Gorgias | Yes (app-specific) | Yes (integrated apps) | Per-message ($0.01-0.05) |
| Square | Via integrations | Limited | No native chat panel | Varies by integration |
| Toast | Via integrations | Yes | No (restaurant focus) | Per-message |
| **Our Solution** | Native | Yes (managed by owner) | Yes (Workbook integrated) | Transactional free + interactive charged |

**Key Differentiator**: Native integration in Workbook where staff already work; no separate app needed.

### User Research

- **Evidence from codebase**: Inbound SMS currently logged to `inboundSMSLog` table but not surfaced to staff
- **Existing capability**: Staff can send one-way transactional messages via `TextMessageService`
- **Permission structure**: `automation` permission already controls SMS features for staff roles
- **Real-time infrastructure**: Ably already used for Workbook (tasks, notes) - proven pattern

### Market Data

- **SMS Open Rate**: 98% (vs. 20% email) - customers read texts
- **Response Expectation**: 90% of customers expect immediate response to service questions
- **Conversion Impact**: Consumers receiving SMS marketing are 40% more likely to convert
- **Churn Risk**: 56% of consumers unsubscribe after >4 messages in 20 days - we mitigate with daily limits
- **Compliance Stakes**: TCPA violations: $500-$1,500 per message; major settlements in hundreds of millions

---

*PRD Complete - Ready for Solution Design Document (SDD)*
