From de3877b28d07cbed298a42342f00e05b03f62a07 Mon Sep 17 00:00:00 2001 From: Flea Flicker Date: Thu, 21 May 2026 19:20:07 +0000 Subject: [PATCH] docs(app): add UAT_PLAYBOOK.md section 4.20 for STOP/HELP consent handler Adds 12 test cases covering: - STOP/START/HELP flows and their auto-reply verification - Alias keywords (STOPALL, UNSUBSCRIBE, CANCEL, END, QUIT / UNSTOP, YES, SUBSCRIBE, INFO) - Idempotency for double STOP and double START - Case-insensitivity and whitespace trimming - Non-keyword message rejection - Consent event audit log verification Refs: GRO-1205, GRO-1469, PR #426 Co-Authored-By: Paperclip --- UAT_PLAYBOOK.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/UAT_PLAYBOOK.md b/UAT_PLAYBOOK.md index 3fdc957..f4d1cd8 100644 --- a/UAT_PLAYBOOK.md +++ b/UAT_PLAYBOOK.md @@ -235,6 +235,23 @@ GroomBook is an open-source, self-hostable pet grooming business management & CR | TC-APP-4.20.5 | Unread indicator | 1. Client sends a new message | Thread marked unread until staff views it | | TC-APP-4.20.6 | Cross-tenant isolation | 1. Staff from Business A attempts to read Business B conversations | 403 or empty response returned | + +### 4.21 SMS Consent (STOP/HELP Keyword Handler) + +| # | Scenario | Steps | Expected | +|---|----------|-------|----------| +| TC-APP-4.21.1 | STOP → unsubscribe + auto-reply | 1. Send `STOP` (case-insensitive, with whitespace) from a subscribed client's phone number | Client is opted out (`smsOptIn=false`, `smsOptOutDate` set), event is logged, user receives auto-reply: "You have been unsubscribed and will no longer receive messages. Reply START to resubscribe." | +| TC-APP-4.21.2 | START → resubscribe + auto-reply | 1. Send `START` (case-insensitive) from an opted-out client's phone number | Client is opted back in (`smsOptIn=true`, `smsConsentDate` updated, `smsOptOutDate` cleared), event is logged, user receives auto-reply: "You have been resubscribed to messages. Reply STOP to unsubscribe. Msg & data rates may apply." | +| TC-APP-4.21.3 | HELP → no opt-in change + default reply | 1. Send `HELP` (case-insensitive) from any client's phone number | No change to opt-in state, no database update, event is logged, user receives auto-reply: "Reply STOP to unsubscribe or START to resubscribe. For help, contact your groomer directly." | +| TC-APP-4.21.4 | STOPALL / UNSUBSCRIBE / CANCEL / END / QUIT → opt-out | 1. Send each alias from a subscribed client's phone | Same behaviour as STOP: opt-out applied, correct reply sent | +| TC-APP-4.21.5 | UNSTOP / YES / SUBSCRIBE → opt-in | 1. Send each alias from an opted-out client's phone | Same behaviour as START: opt-in applied, correct reply sent | +| TC-APP-4.21.6 | INFO → help reply | 1. Send `INFO` from any client's phone | Same behaviour as HELP: no state change, help reply returned | +| TC-APP-4.21.7 | Double STOP (idempotency) | 1. Send `STOP` from an already-opted-out client | Event is logged, no update call made, idempotent — no duplicate update | +| TC-APP-4.21.8 | Double START (idempotency) | 1. Send `START` from an already-subscribed client | Event is logged, no update call made, idempotent — no duplicate update | +| TC-APP-4.21.9 | Case insensitivity | 1. Send `stop`, `Stop`, `sToP`, ` stop ` from subscribed client | All variants are detected and handled as opt-out | +| TC-APP-4.21.10 | Whitespace trimming | 1. Send ` START ` or `\tSTOP\n` | Keywords are trimmed before matching | +| TC-APP-4.21.11 | Non-keyword messages ignored | 1. Send `STOP IT`, `help me`, `hello` | Returns null from `detectKeyword`, no consent event inserted, no reply sent | +| TC-APP-4.21.12 | Consent event audit log | 1. After any keyword, query `messageConsentEvents` table | Record exists with correct `clientId`, `businessId`, `kind`, and `source: "sms_keyword"` | ## 5. Pass/Fail Criteria **Pass:** All test cases execute without errors. Expected results match actual results. No regressions are observed. All functionality works as documented.