flow_chat 0.3.0 โ†’ 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/README.md +642 -86
  4. data/examples/initializer.rb +31 -0
  5. data/examples/media_prompts_examples.rb +28 -0
  6. data/examples/multi_tenant_whatsapp_controller.rb +244 -0
  7. data/examples/ussd_controller.rb +264 -0
  8. data/examples/whatsapp_controller.rb +140 -0
  9. data/examples/whatsapp_media_examples.rb +406 -0
  10. data/examples/whatsapp_message_job.rb +111 -0
  11. data/lib/flow_chat/base_processor.rb +67 -0
  12. data/lib/flow_chat/config.rb +36 -0
  13. data/lib/flow_chat/session/cache_session_store.rb +84 -0
  14. data/lib/flow_chat/session/middleware.rb +14 -6
  15. data/lib/flow_chat/simulator/controller.rb +78 -0
  16. data/lib/flow_chat/simulator/views/simulator.html.erb +1707 -0
  17. data/lib/flow_chat/ussd/app.rb +25 -0
  18. data/lib/flow_chat/ussd/gateway/nalo.rb +2 -0
  19. data/lib/flow_chat/ussd/gateway/nsano.rb +6 -0
  20. data/lib/flow_chat/ussd/middleware/resumable_session.rb +1 -1
  21. data/lib/flow_chat/ussd/processor.rb +14 -42
  22. data/lib/flow_chat/ussd/prompt.rb +39 -5
  23. data/lib/flow_chat/version.rb +1 -1
  24. data/lib/flow_chat/whatsapp/app.rb +64 -0
  25. data/lib/flow_chat/whatsapp/client.rb +439 -0
  26. data/lib/flow_chat/whatsapp/configuration.rb +113 -0
  27. data/lib/flow_chat/whatsapp/gateway/cloud_api.rb +213 -0
  28. data/lib/flow_chat/whatsapp/middleware/executor.rb +30 -0
  29. data/lib/flow_chat/whatsapp/processor.rb +26 -0
  30. data/lib/flow_chat/whatsapp/prompt.rb +251 -0
  31. data/lib/flow_chat/whatsapp/send_job_support.rb +79 -0
  32. data/lib/flow_chat/whatsapp/template_manager.rb +162 -0
  33. data/lib/flow_chat.rb +1 -0
  34. metadata +21 -3
  35. data/lib/flow_chat/ussd/simulator/controller.rb +0 -51
  36. data/lib/flow_chat/ussd/simulator/views/simulator.html.erb +0 -239
data/README.md CHANGED
@@ -1,14 +1,16 @@
1
1
  # FlowChat
2
2
 
3
- FlowChat is a Rails framework designed for building sophisticated conversational workflows, particularly for USSD (Unstructured Supplementary Service Data) systems. It provides an intuitive Ruby DSL for creating multi-step, menu-driven conversations with automatic session management, input validation, and flow control.
3
+ FlowChat is a Rails framework designed for building sophisticated conversational workflows for both USSD (Unstructured Supplementary Service Data) systems and WhatsApp messaging. It provides an intuitive Ruby DSL for creating multi-step, menu-driven conversations with automatic session management, input validation, and flow control.
4
4
 
5
5
  **Key Features:**
6
6
  - ๐ŸŽฏ **Declarative Flow Definition** - Define conversation flows as Ruby classes
7
7
  - ๐Ÿ”„ **Automatic Session Management** - Persistent state across requests
8
8
  - โœ… **Input Validation & Transformation** - Built-in validation and data conversion
9
9
  - ๐ŸŒŠ **Middleware Architecture** - Flexible request processing pipeline
10
- - ๐Ÿ“ฑ **USSD Gateway Support** - Currently supports Nalo and Nsano gateways
11
- - ๐Ÿงช **Built-in Testing Tools** - USSD simulator for local development
10
+ - ๐Ÿ“ฑ **USSD Gateway Support** - Currently supports Nalo gateways
11
+ - ๐Ÿ’ฌ **WhatsApp Integration** - Full WhatsApp Cloud API support with multiple processing modes
12
+ - ๐Ÿ”ง **Reusable WhatsApp Client** - Standalone client for out-of-band messaging
13
+ - ๐Ÿงช **Built-in Testing Tools** - Unified simulator for both USSD and WhatsApp testing
12
14
 
13
15
  ## Architecture Overview
14
16
 
@@ -21,9 +23,9 @@ User Input โ†’ Gateway โ†’ Session โ†’ Pagination โ†’ Custom โ†’ Executor โ†’ Fl
21
23
  ```
22
24
 
23
25
  **Middleware Pipeline:**
24
- - **Gateway**: USSD provider communication (Nalo/Nsano)
26
+ - **Gateway**: Communication with providers (USSD: Nalo, WhatsApp: Cloud API)
25
27
  - **Session**: Load/save conversation state
26
- - **Pagination**: Split long responses into pages
28
+ - **Pagination**: Split long responses into pages (USSD only)
27
29
  - **Custom**: Your application middleware (logging, auth, etc.)
28
30
  - **Executor**: Execute flow methods and handle interrupts
29
31
 
@@ -43,6 +45,10 @@ bundle install
43
45
 
44
46
  ## Quick Start
45
47
 
48
+ FlowChat supports both USSD and WhatsApp. Choose the platform that fits your needs:
49
+
50
+ ### USSD Setup
51
+
46
52
  ### 1. Create Your First Flow
47
53
 
48
54
  Create a flow class in `app/flow_chat/welcome_flow.rb`:
@@ -60,7 +66,7 @@ class WelcomeFlow < FlowChat::Flow
60
66
  end
61
67
  ```
62
68
 
63
- ### 2. Set Up the Controller
69
+ ### 2. Set Up the USSD Controller
64
70
 
65
71
  Create a controller to handle USSD requests:
66
72
 
@@ -89,6 +95,501 @@ Rails.application.routes.draw do
89
95
  end
90
96
  ```
91
97
 
98
+ ๐Ÿ’ก **Tip**: See [examples/ussd_controller.rb](examples/ussd_controller.rb) for a complete USSD controller example with payment flows, customer support, and custom middleware.
99
+
100
+ ### WhatsApp Setup
101
+
102
+ ### 1. Configure WhatsApp Credentials
103
+
104
+ FlowChat supports two ways to configure WhatsApp credentials:
105
+
106
+ **Option A: Using Rails Credentials**
107
+
108
+ Add your WhatsApp credentials to Rails credentials:
109
+
110
+ ```bash
111
+ rails credentials:edit
112
+ ```
113
+
114
+ ```yaml
115
+ whatsapp:
116
+ access_token: "your_access_token"
117
+ phone_number_id: "your_phone_number_id"
118
+ verify_token: "your_verify_token"
119
+ app_id: "your_app_id"
120
+ app_secret: "your_app_secret"
121
+ webhook_url: "your_webhook_url"
122
+ business_account_id: "your_business_account_id"
123
+ ```
124
+
125
+ **Option B: Using Environment Variables**
126
+
127
+ Alternatively, you can use environment variables:
128
+
129
+ ```bash
130
+ # Add to your .env file or environment
131
+ export WHATSAPP_ACCESS_TOKEN="your_access_token"
132
+ export WHATSAPP_PHONE_NUMBER_ID="your_phone_number_id"
133
+ export WHATSAPP_VERIFY_TOKEN="your_verify_token"
134
+ export WHATSAPP_APP_ID="your_app_id"
135
+ export WHATSAPP_APP_SECRET="your_app_secret"
136
+ export WHATSAPP_WEBHOOK_URL="your_webhook_url"
137
+ export WHATSAPP_BUSINESS_ACCOUNT_ID="your_business_account_id"
138
+ ```
139
+
140
+ FlowChat will automatically use Rails credentials first, falling back to environment variables if credentials are not available.
141
+
142
+ **Option C: Per-Setup Configuration**
143
+
144
+ For multi-tenant applications or when you need different WhatsApp accounts per endpoint:
145
+
146
+ ```ruby
147
+ # Create custom configuration
148
+ custom_config = FlowChat::Whatsapp::Configuration.new
149
+ custom_config.access_token = "your_specific_access_token"
150
+ custom_config.phone_number_id = "your_specific_phone_number_id"
151
+ custom_config.verify_token = "your_specific_verify_token"
152
+ custom_config.app_id = "your_specific_app_id"
153
+ custom_config.app_secret = "your_specific_app_secret"
154
+ custom_config.business_account_id = "your_specific_business_account_id"
155
+
156
+ # Use in processor
157
+ processor = FlowChat::Whatsapp::Processor.new(self) do |config|
158
+ config.use_gateway FlowChat::Whatsapp::Gateway::CloudApi, custom_config
159
+ config.use_session_store FlowChat::Session::CacheSessionStore
160
+ end
161
+ ```
162
+
163
+ ๐Ÿ’ก **Tip**: See [examples/multi_tenant_whatsapp_controller.rb](examples/multi_tenant_whatsapp_controller.rb) for comprehensive multi-tenant and per-setup configuration examples.
164
+
165
+ ### 2. Choose Message Handling Mode
166
+
167
+ FlowChat offers three WhatsApp message handling modes. Configure them in an initializer:
168
+
169
+ **Create an initializer** `config/initializers/flowchat.rb`:
170
+
171
+ ```ruby
172
+ # config/initializers/flowchat.rb
173
+
174
+ # Configure WhatsApp message handling mode
175
+ FlowChat::Config.whatsapp.message_handling_mode = :inline # or :background, :simulator
176
+ FlowChat::Config.whatsapp.background_job_class = 'WhatsappMessageJob'
177
+ ```
178
+
179
+ **Inline Mode (Default)** - Process messages synchronously:
180
+ ```ruby
181
+ # config/initializers/flowchat.rb
182
+ FlowChat::Config.whatsapp.message_handling_mode = :inline
183
+
184
+ # app/controllers/whatsapp_controller.rb
185
+ class WhatsappController < ApplicationController
186
+ skip_forgery_protection
187
+
188
+ def webhook
189
+ processor = FlowChat::Whatsapp::Processor.new(self) do |config|
190
+ config.use_gateway FlowChat::Whatsapp::Gateway::CloudApi
191
+ config.use_session_store FlowChat::Session::CacheSessionStore
192
+ end
193
+
194
+ processor.run WelcomeFlow, :main_page
195
+ end
196
+ end
197
+ ```
198
+
199
+ **Background Mode** - Process flows synchronously, send responses asynchronously:
200
+ ```ruby
201
+ # config/initializers/flowchat.rb
202
+ FlowChat::Config.whatsapp.message_handling_mode = :background
203
+ FlowChat::Config.whatsapp.background_job_class = 'WhatsappMessageJob'
204
+
205
+ # app/controllers/whatsapp_controller.rb
206
+ class WhatsappController < ApplicationController
207
+ skip_forgery_protection
208
+
209
+ def webhook
210
+ processor = FlowChat::Whatsapp::Processor.new(self) do |config|
211
+ config.use_gateway FlowChat::Whatsapp::Gateway::CloudApi
212
+ config.use_session_store FlowChat::Session::CacheSessionStore
213
+ end
214
+
215
+ processor.run WelcomeFlow, :main_page
216
+ end
217
+ end
218
+ ```
219
+
220
+ **Simulator Mode** - Return response data instead of sending via WhatsApp API:
221
+ ```ruby
222
+ # config/initializers/flowchat.rb
223
+ FlowChat::Config.whatsapp.message_handling_mode = :simulator
224
+
225
+ # app/controllers/whatsapp_controller.rb
226
+ class WhatsappController < ApplicationController
227
+ skip_forgery_protection
228
+
229
+ def webhook
230
+ processor = FlowChat::Whatsapp::Processor.new(self) do |config|
231
+ config.use_gateway FlowChat::Whatsapp::Gateway::CloudApi
232
+ config.use_session_store FlowChat::Session::CacheSessionStore
233
+ end
234
+
235
+ processor.run WelcomeFlow, :main_page
236
+ end
237
+ end
238
+ ```
239
+
240
+ ๐Ÿ’ก **See [examples/README_whatsapp_modes.md](examples/README_whatsapp_modes.md) for detailed mode explanations and use cases.**
241
+
242
+ ### 3. Add WhatsApp Route
243
+
244
+ ```ruby
245
+ Rails.application.routes.draw do
246
+ match '/whatsapp/webhook', to: 'whatsapp#webhook', via: [:get, :post]
247
+ end
248
+ ```
249
+
250
+ ### 4. Enhanced Features for WhatsApp
251
+
252
+ The same flow works for both USSD and WhatsApp, but WhatsApp provides additional data and better interactive features:
253
+
254
+ ```ruby
255
+ class WelcomeFlow < FlowChat::Flow
256
+ def main_page
257
+ # Access WhatsApp-specific data
258
+ Rails.logger.info "Contact: #{app.contact_name}, Phone: #{app.phone_number}"
259
+ Rails.logger.info "Message ID: #{app.message_id}, Timestamp: #{app.timestamp}"
260
+
261
+ # Handle location sharing
262
+ if app.location
263
+ app.say "Thanks for sharing your location! We see you're at #{app.location['latitude']}, #{app.location['longitude']}"
264
+ return
265
+ end
266
+
267
+ # Handle media messages
268
+ if app.media
269
+ app.say "Thanks for the #{app.media['type']} file! We received: #{app.media['id']}"
270
+ return
271
+ end
272
+
273
+ name = app.screen(:name) do |prompt|
274
+ prompt.ask "Hello! Welcome to our WhatsApp service. What's your name?",
275
+ transform: ->(input) { input.strip.titleize }
276
+ end
277
+
278
+ # WhatsApp supports interactive buttons and lists via prompt.select
279
+ choice = app.screen(:main_menu) do |prompt|
280
+ prompt.select "Hi #{name}! How can I help you?", {
281
+ "info" => "๐Ÿ“‹ Get Information",
282
+ "support" => "๐Ÿ†˜ Contact Support",
283
+ "feedback" => "๐Ÿ’ฌ Give Feedback"
284
+ }
285
+ end
286
+
287
+ case choice
288
+ when "info"
289
+ show_information_menu
290
+ when "support"
291
+ contact_support
292
+ when "feedback"
293
+ collect_feedback
294
+ end
295
+ end
296
+
297
+ private
298
+
299
+ def show_information_menu
300
+ info_choice = app.screen(:info_menu) do |prompt|
301
+ prompt.select "What information do you need?", {
302
+ "hours" => "๐Ÿ•’ Business Hours",
303
+ "location" => "๐Ÿ“ Our Location",
304
+ "services" => "๐Ÿ’ผ Our Services"
305
+ }
306
+ end
307
+
308
+ case info_choice
309
+ when "hours"
310
+ app.say "We're open Monday-Friday 9AM-6PM, Saturday 10AM-4PM. Closed Sundays."
311
+ when "location"
312
+ app.say "๐Ÿ“ Visit us at 123 Main Street, Downtown. We're next to the coffee shop!"
313
+ when "services"
314
+ app.say "๐Ÿ’ผ We offer: Web Development, Mobile Apps, Cloud Services, and IT Consulting."
315
+ end
316
+ end
317
+
318
+ def contact_support
319
+ support_choice = app.screen(:support_menu) do |prompt|
320
+ prompt.select "How would you like to contact support?", {
321
+ "call" => "๐Ÿ“ž Call Us",
322
+ "email" => "๐Ÿ“ง Email Us",
323
+ "chat" => "๐Ÿ’ฌ Continue Here"
324
+ }
325
+ end
326
+
327
+ case support_choice
328
+ when "call"
329
+ app.say "๐Ÿ“ž Call us at: +1-555-HELP (4357)\nAvailable Mon-Fri 9AM-5PM"
330
+ when "email"
331
+ app.say "๐Ÿ“ง Email us at: support@company.com\nWe typically respond within 24 hours"
332
+ when "chat"
333
+ app.say "๐Ÿ’ฌ Great! Please describe your issue and we'll help you right away."
334
+ end
335
+ end
336
+
337
+ def collect_feedback
338
+ rating = app.screen(:rating) do |prompt|
339
+ prompt.select "How would you rate our service?", {
340
+ "5" => "โญโญโญโญโญ Excellent",
341
+ "4" => "โญโญโญโญ Good",
342
+ "3" => "โญโญโญ Average",
343
+ "2" => "โญโญ Poor",
344
+ "1" => "โญ Very Poor"
345
+ }
346
+ end
347
+
348
+ feedback = app.screen(:feedback_text) do |prompt|
349
+ prompt.ask "Thank you for the #{rating}-star rating! Please share any additional feedback:"
350
+ end
351
+
352
+ # Use WhatsApp-specific data for logging
353
+ Rails.logger.info "Feedback from #{app.contact_name} (#{app.phone_number}): #{rating} stars - #{feedback}"
354
+
355
+ app.say "Thank you for your feedback! We really appreciate it. ๐Ÿ™"
356
+ end
357
+ end
358
+ ```
359
+
360
+ For detailed WhatsApp setup instructions, see [WhatsApp Integration Guide](docs/whatsapp_setup.md).
361
+
362
+ ## ๐Ÿ”ง Reusable WhatsApp Client
363
+
364
+ FlowChat provides a standalone WhatsApp client for out-of-band messaging:
365
+
366
+ ```ruby
367
+ # Initialize client
368
+ config = FlowChat::Whatsapp::Configuration.from_credentials
369
+ client = FlowChat::Whatsapp::Client.new(config)
370
+
371
+ # Send text message
372
+ client.send_text("+1234567890", "Hello, World!")
373
+
374
+ # Send interactive buttons
375
+ client.send_buttons(
376
+ "+1234567890",
377
+ "Choose an option:",
378
+ [
379
+ { id: 'option1', title: 'Option 1' },
380
+ { id: 'option2', title: 'Option 2' }
381
+ ]
382
+ )
383
+
384
+ # Send interactive list
385
+ client.send_list(
386
+ "+1234567890",
387
+ "Select from menu:",
388
+ [
389
+ {
390
+ title: "Services",
391
+ rows: [
392
+ { id: 'service1', title: 'Service 1', description: 'Description 1' },
393
+ { id: 'service2', title: 'Service 2', description: 'Description 2' }
394
+ ]
395
+ }
396
+ ]
397
+ )
398
+
399
+ # Handle media
400
+ media_url = client.get_media_url("media_id_123")
401
+ media_content = client.download_media("media_id_123")
402
+ ```
403
+
404
+ ### Out-of-Band Messaging Service Example
405
+
406
+ ```ruby
407
+ class NotificationService
408
+ def initialize
409
+ @config = FlowChat::Whatsapp::Configuration.from_credentials
410
+ @client = FlowChat::Whatsapp::Client.new(@config)
411
+ end
412
+
413
+ def send_order_confirmation(phone_number, order_id, items, total)
414
+ item_list = items.map { |item| "โ€ข #{item[:name]} x#{item[:quantity]}" }.join("\n")
415
+
416
+ @client.send_buttons(
417
+ phone_number,
418
+ "โœ… Order Confirmed!\n\nOrder ##{order_id}\n\n#{item_list}\n\nTotal: $#{total}",
419
+ [
420
+ { id: 'track_order', title: '๐Ÿ“ฆ Track Order' },
421
+ { id: 'contact_support', title: '๐Ÿ’ฌ Contact Support' }
422
+ ]
423
+ )
424
+ end
425
+
426
+ def send_appointment_reminder(phone_number, appointment)
427
+ @client.send_buttons(
428
+ phone_number,
429
+ "๐Ÿฅ Appointment Reminder\n\n#{appointment[:service]} with #{appointment[:provider]}\n๐Ÿ“… #{appointment[:date]}\n๐Ÿ• #{appointment[:time]}",
430
+ [
431
+ { id: 'confirm', title: 'โœ… Confirm' },
432
+ { id: 'reschedule', title: '๐Ÿ“… Reschedule' },
433
+ { id: 'cancel', title: 'โŒ Cancel' }
434
+ ]
435
+ )
436
+ end
437
+ end
438
+ ```
439
+
440
+ ๐Ÿ’ก **See [examples/whatsapp_controller_modes.rb](examples/whatsapp_controller_modes.rb) for comprehensive usage examples.**
441
+
442
+ ## Cross-Platform Compatibility
443
+
444
+ FlowChat provides a unified API that works across both USSD and WhatsApp platforms, with graceful degradation for platform-specific features:
445
+
446
+ ### Shared Features (Both USSD & WhatsApp)
447
+ - โœ… `app.screen()` - Interactive screens with prompts
448
+ - โœ… `app.say()` - Send messages to users
449
+ - โœ… `prompt.ask()` - Text input collection
450
+ - โœ… `prompt.select()` - Menu selection (renders as numbered list in USSD, interactive buttons/lists in WhatsApp)
451
+ - โœ… `prompt.yes?()` - Yes/no questions
452
+ - โœ… `app.phone_number` - User's phone number
453
+ - โœ… `app.message_id` - Unique message identifier
454
+ - โœ… `app.timestamp` - Message timestamp
455
+
456
+ ### WhatsApp-Only Features
457
+ - โœ… `app.contact_name` - WhatsApp contact name (returns `nil` in USSD)
458
+ - โœ… `app.location` - Location sharing data (returns `nil` in USSD)
459
+ - โœ… `app.media` - Media file attachments (returns `nil` in USSD)
460
+ - โœ… Rich interactive elements (buttons, lists) automatically generated from `prompt.select()`
461
+
462
+ This design allows you to write flows once and deploy them on both platforms, with WhatsApp users getting enhanced interactive features automatically.
463
+
464
+ ## ๐Ÿ“ฑ Media Support
465
+
466
+ FlowChat supports rich media attachments for enhanced conversational experiences. Media can be attached to `ask()` and `say()` prompts, with automatic cross-platform optimization.
467
+
468
+ ### Supported Media Types
469
+
470
+ - **๐Ÿ“ท Images** (`type: :image`) - Photos, screenshots, diagrams
471
+ - **๐Ÿ“„ Documents** (`type: :document`) - PDFs, forms, receipts
472
+ - **๐ŸŽฅ Videos** (`type: :video`) - Tutorials, demos, explanations
473
+ - **๐ŸŽต Audio** (`type: :audio`) - Voice messages, recordings
474
+ - **๐Ÿ˜Š Stickers** (`type: :sticker`) - Fun visual elements
475
+
476
+ ### Basic Usage
477
+
478
+ ```ruby
479
+ class ProductFlow < FlowChat::Flow
480
+ def main_page
481
+ # โœ… Text input with context image
482
+ feedback = app.screen(:feedback) do |prompt|
483
+ prompt.ask "What do you think of our new product?",
484
+ media: {
485
+ type: :image,
486
+ url: "https://cdn.example.com/products/new_product.jpg"
487
+ }
488
+ end
489
+
490
+ # โœ… Send informational media
491
+ app.say "Thanks for your feedback! Here's what's coming next:",
492
+ media: {
493
+ type: :video,
494
+ url: "https://videos.example.com/roadmap.mp4"
495
+ }
496
+
497
+ # โœ… Document with filename
498
+ app.say "Here's your receipt:",
499
+ media: {
500
+ type: :document,
501
+ url: "https://api.example.com/receipt.pdf",
502
+ filename: "receipt.pdf"
503
+ }
504
+ end
505
+ end
506
+ ```
507
+
508
+ ### Media Hash Format
509
+
510
+ ```ruby
511
+ {
512
+ type: :image, # Required: :image, :document, :audio, :video, :sticker
513
+ url: "https://...", # Required: URL to the media file OR WhatsApp media ID
514
+ filename: "doc.pdf" # Optional: Only for documents
515
+ }
516
+ ```
517
+
518
+ ### Using WhatsApp Media IDs
519
+
520
+ For better performance and to avoid external dependencies, you can upload files to WhatsApp and use the media ID:
521
+
522
+ ```ruby
523
+ # Upload a file first
524
+ client = FlowChat::Whatsapp::Client.new(config)
525
+ media_id = client.upload_media('path/to/image.jpg', 'image/jpeg')
526
+
527
+ # Then use the media ID in your flow
528
+ app.screen(:product_demo) do |prompt|
529
+ prompt.ask "What do you think?",
530
+ media: {
531
+ type: :image,
532
+ url: media_id # Use the media ID instead of URL
533
+ }
534
+ end
535
+ ```
536
+
537
+ ### Client Media Methods
538
+
539
+ The WhatsApp client provides methods for uploading and sending media:
540
+
541
+ ```ruby
542
+ client = FlowChat::Whatsapp::Client.new(config)
543
+
544
+ # Upload media and get media ID
545
+ media_id = client.upload_media('image.jpg', 'image/jpeg')
546
+ media_id = client.upload_media(file_io, 'image/jpeg', 'photo.jpg')
547
+
548
+ # Send media directly
549
+ client.send_image("+1234567890", "https://example.com/image.jpg", "Caption")
550
+ client.send_image("+1234567890", media_id, "Caption")
551
+
552
+ # Send document with MIME type and filename
553
+ client.send_document("+1234567890", "https://example.com/doc.pdf", "Your receipt", "receipt.pdf", "application/pdf")
554
+
555
+ # Send other media types
556
+ client.send_video("+1234567890", "https://example.com/video.mp4", "Demo video", "video/mp4")
557
+ client.send_audio("+1234567890", "https://example.com/audio.mp3", "audio/mpeg")
558
+ client.send_sticker("+1234567890", "https://example.com/sticker.webp", "image/webp")
559
+ ```
560
+
561
+ ### Cross-Platform Behavior
562
+
563
+ **WhatsApp Experience:**
564
+ - Media is sent directly to the chat
565
+ - Prompt text becomes the media caption
566
+ - Rich, native messaging experience
567
+
568
+ **USSD Experience:**
569
+ - Media URL is included in text message
570
+ - Graceful degradation with clear media indicators
571
+ - Users can access media via the provided link
572
+
573
+ ```ruby
574
+ # This code works on both platforms:
575
+ app.screen(:help) do |prompt|
576
+ prompt.ask "Describe your issue:",
577
+ media: {
578
+ type: :image,
579
+ url: "https://support.example.com/help_example.jpg"
580
+ }
581
+ end
582
+ ```
583
+
584
+ **WhatsApp Result:** Image sent with caption "Describe your issue:"
585
+
586
+ **USSD Result:**
587
+ ```
588
+ Describe your issue:
589
+
590
+ ๐Ÿ“ท Image: https://support.example.com/help_example.jpg
591
+ ```
592
+
92
593
  ## Core Concepts
93
594
 
94
595
  ### Flows and Screens
@@ -228,6 +729,68 @@ app.screen(:credit_card) do |prompt|
228
729
  end
229
730
  ```
230
731
 
732
+ ### Background Job Support
733
+
734
+ For high-volume WhatsApp applications, use background response delivery:
735
+
736
+ ```ruby
737
+ # app/jobs/whatsapp_message_job.rb
738
+ class WhatsappMessageJob < ApplicationJob
739
+ include FlowChat::Whatsapp::SendJobSupport
740
+
741
+ def perform(send_data)
742
+ perform_whatsapp_send(send_data)
743
+ end
744
+ end
745
+
746
+ # config/initializers/flowchat.rb
747
+ FlowChat::Config.whatsapp.message_handling_mode = :background
748
+ FlowChat::Config.whatsapp.background_job_class = 'WhatsappMessageJob'
749
+
750
+ # config/application.rb
751
+ config.active_job.queue_adapter = :sidekiq
752
+ ```
753
+
754
+ **The `SendJobSupport` module provides:**
755
+ - โœ… **Automatic config resolution** - Resolves named configurations automatically
756
+ - โœ… **Response delivery** - Handles sending responses to WhatsApp
757
+ - โœ… **Error handling** - Comprehensive error handling with user notifications
758
+ - โœ… **Retry logic** - Built-in exponential backoff retry
759
+ - โœ… **Extensible** - Override methods for custom behavior
760
+
761
+ **How it works:**
762
+ 1. **Controller receives webhook** - WhatsApp message arrives
763
+ 2. **Flow processes synchronously** - Maintains controller context and session state
764
+ 3. **Response queued for delivery** - Only the sending is moved to background
765
+ 4. **Job sends response** - Background job handles API call to WhatsApp
766
+
767
+ **Advanced job with custom callbacks:**
768
+
769
+ ```ruby
770
+ class AdvancedWhatsappMessageJob < ApplicationJob
771
+ include FlowChat::Whatsapp::SendJobSupport
772
+
773
+ def perform(send_data)
774
+ perform_whatsapp_send(send_data)
775
+ end
776
+
777
+ private
778
+
779
+ # Override for custom success handling
780
+ def on_whatsapp_send_success(send_data, result)
781
+ Rails.logger.info "Successfully sent WhatsApp message to #{send_data[:msisdn]}"
782
+ UserEngagementTracker.track_message_sent(phone: send_data[:msisdn])
783
+ end
784
+
785
+ # Override for custom error handling
786
+ def on_whatsapp_send_error(error, send_data)
787
+ ErrorTracker.notify(error, user_phone: send_data[:msisdn])
788
+ end
789
+ end
790
+ ```
791
+
792
+ ๐Ÿ’ก **See [examples/whatsapp_message_job.rb](examples/whatsapp_message_job.rb) for complete job implementation examples.**
793
+
231
794
  ### Middleware Configuration
232
795
 
233
796
  FlowChat uses a **middleware architecture** to process USSD requests through a configurable pipeline. Each request flows through multiple middleware layers in a specific order.
@@ -240,7 +803,7 @@ When you run a flow, FlowChat automatically builds this middleware stack:
240
803
  User Input โ†’ Gateway โ†’ Session โ†’ Pagination โ†’ Custom Middleware โ†’ Executor โ†’ Flow
241
804
  ```
242
805
 
243
- 1. **Gateway Middleware** - Handles USSD provider communication (Nalo/Nsano)
806
+ 1. **Gateway Middleware** - Handles USSD provider communication (Nalo)
244
807
  2. **Session Middleware** - Manages session storage and retrieval
245
808
  3. **Pagination Middleware** - Automatically splits long responses across pages
246
809
  4. **Custom Middleware** - Your application-specific middleware (optional)
@@ -338,9 +901,6 @@ FlowChat supports multiple USSD gateways:
338
901
  ```ruby
339
902
  # Nalo Solutions Gateway
340
903
  config.use_gateway FlowChat::Ussd::Gateway::Nalo
341
-
342
- # Nsano Gateway
343
- config.use_gateway FlowChat::Ussd::Gateway::Nsano
344
904
  ```
345
905
 
346
906
  ## Testing
@@ -465,27 +1025,79 @@ class ProcessorMiddlewareTest < Minitest::Test
465
1025
  end
466
1026
  ```
467
1027
 
468
- ### USSD Simulator
1028
+ ### FlowChat Unified Simulator
469
1029
 
470
- Use the built-in simulator for interactive testing:
1030
+ Use the built-in unified simulator for interactive testing of both USSD and WhatsApp flows:
471
1031
 
472
1032
  ```ruby
473
- class UssdSimulatorController < ApplicationController
474
- include FlowChat::Ussd::Simulator::Controller
1033
+ class SimulatorController < ApplicationController
1034
+ include FlowChat::Simulator::Controller
1035
+
1036
+ def index
1037
+ flowchat_simulator
1038
+ end
475
1039
 
476
1040
  protected
477
1041
 
478
- def default_endpoint
479
- '/ussd'
1042
+ def configurations
1043
+ {
1044
+ production_ussd: {
1045
+ name: "Production USSD",
1046
+ icon: "๐Ÿญ",
1047
+ processor_type: "ussd",
1048
+ provider: "nalo",
1049
+ endpoint: "/ussd",
1050
+ color: "#28a745"
1051
+ },
1052
+ staging_whatsapp: {
1053
+ name: "Staging WhatsApp",
1054
+ icon: "๐Ÿงช",
1055
+ processor_type: "whatsapp",
1056
+ provider: "cloud_api",
1057
+ endpoint: "/whatsapp/webhook",
1058
+ color: "#17a2b8"
1059
+ },
1060
+ local_ussd: {
1061
+ name: "Local USSD",
1062
+ icon: "๐Ÿ’ป",
1063
+ processor_type: "ussd",
1064
+ provider: "nalo",
1065
+ endpoint: "http://localhost:3000/ussd",
1066
+ color: "#6f42c1"
1067
+ }
1068
+ }
480
1069
  end
481
1070
 
482
- def default_provider
483
- :nalo
1071
+ def default_config_key
1072
+ :local_ussd
1073
+ end
1074
+
1075
+ def default_phone_number
1076
+ "+254712345678"
1077
+ end
1078
+
1079
+ def default_contact_name
1080
+ "John Doe"
484
1081
  end
485
1082
  end
486
1083
  ```
487
1084
 
488
- Add to routes and visit `http://localhost:3000/ussd_simulator`.
1085
+ Add to routes and visit `http://localhost:3000/simulator`.
1086
+
1087
+ **Key Features:**
1088
+ - ๐Ÿ”„ **Platform Toggle** - Switch between USSD and WhatsApp modes with configuration selection
1089
+ - ๐Ÿ“ฑ **USSD Mode** - Classic green-screen terminal simulation with provider support (Nalo, Nsano)
1090
+ - ๐Ÿ’ฌ **WhatsApp Mode** - Full WhatsApp interface with interactive buttons, lists, and rich messaging
1091
+ - โš™๏ธ **Multi-Environment** - Support for different configurations (local, staging, production)
1092
+ - ๐ŸŽจ **Modern UI** - Beautiful, responsive interface with real-time status indicators
1093
+ - ๐Ÿ“Š **Request Logging** - View all HTTP requests and responses in real-time
1094
+ - ๐Ÿ”ง **Developer Tools** - Character counts, connection status, and comprehensive error handling
1095
+
1096
+ The simulator automatically adapts its interface based on the selected configuration:
1097
+ - **USSD**: Shows traditional terminal-style interface with character limits and pagination
1098
+ - **WhatsApp**: Displays realistic WhatsApp chat interface with support for interactive elements
1099
+
1100
+ ๐Ÿ’ก **Tip**: See [examples/simulator_controller.rb](examples/simulator_controller.rb) for advanced configurations including multi-tenant support and environment-specific endpoints.
489
1101
 
490
1102
  ## Best Practices
491
1103
 
@@ -554,76 +1166,20 @@ def main_page
554
1166
  end
555
1167
  ```
556
1168
 
557
- ## Configuration
558
-
559
- ### Session Storage Options
1169
+ ### 5. Choose the Right WhatsApp Mode
560
1170
 
561
- Configure different session storage backends:
1171
+ Configure the appropriate mode in your initializer:
562
1172
 
563
1173
  ```ruby
564
- # Rails session (default)
565
- config.use_session_store FlowChat::Session::RailsSessionStore
566
-
567
- # Custom session store
568
- class MySessionStore
569
- def initialize(context)
570
- @context = context
571
- end
572
-
573
- def get(key)
574
- # Your storage logic
575
- end
576
-
577
- def set(key, value)
578
- # Your storage logic
579
- end
580
- end
581
-
582
- config.use_session_store MySessionStore
583
- ```
584
-
585
- ## Development
586
-
587
- ### Running Tests
588
-
589
- FlowChat uses Minitest for testing:
590
-
591
- ```bash
592
- # Run all tests
593
- bundle exec rake test
594
-
595
- # Run specific test file
596
- bundle exec rake test TEST=test/unit/flow_test.rb
597
-
598
- # Run specific test
599
- bundle exec rake test TESTOPTS="--name=test_flow_initialization"
600
- ```
601
-
602
- ### Contributing
603
-
604
- 1. Fork the repository
605
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
606
- 3. Add tests for your changes
607
- 4. Ensure all tests pass (`bundle exec rake test`)
608
- 5. Commit your changes (`git commit -am 'Add amazing feature'`)
609
- 6. Push to the branch (`git push origin feature/amazing-feature`)
610
- 7. Open a Pull Request
611
-
612
- ## Roadmap
613
-
614
- - ๐Ÿ“ฑ **WhatsApp Integration** - Support for WhatsApp Business API
615
- - ๐Ÿ’ฌ **Telegram Bot Support** - Native Telegram bot integration
616
- - ๐Ÿ”„ **Sub-flows** - Reusable conversation components
617
- - ๐Ÿ“Š **Analytics Integration** - Built-in conversation analytics
618
- - ๐ŸŒ **Multi-language Support** - Internationalization features
619
- - โšก **Performance Optimizations** - Improved middleware performance
620
-
621
- ## License
1174
+ # config/initializers/flowchat.rb
622
1175
 
623
- FlowChat is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
1176
+ # Development/Testing - use simulator mode
1177
+ FlowChat::Config.whatsapp.message_handling_mode = :simulator
624
1178
 
625
- ## Support
1179
+ # Low-volume Applications - use inline mode
1180
+ FlowChat::Config.whatsapp.message_handling_mode = :inline
626
1181
 
627
- - ๐Ÿ“– **Documentation**: [GitHub Repository](https://github.com/radioactive-labs/flow_chat)
628
- - ๐Ÿ› **Bug Reports**: [GitHub Issues](https://github.com/radioactive-labs/flow_chat/issues)
629
- - ๐Ÿ’ฌ **Community**: Join our discussions for help and feature requests
1182
+ # High-volume Production - use background mode (sync processing + async sending)
1183
+ FlowChat::Config.whatsapp.message_handling_mode = :background
1184
+ FlowChat::Config.whatsapp.background_job_class = 'WhatsappMessageJob'
1185
+ ```