flow_chat 0.8.2 → 0.9.0

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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/.cliff.toml +74 -0
  3. data/.github/workflows/ci.yml +2 -3
  4. data/.github/workflows/release.yml +56 -0
  5. data/.standard.yml +4 -0
  6. data/CHANGELOG.md +22 -0
  7. data/CLAUDE.md +327 -0
  8. data/CONTRIBUTING.md +134 -0
  9. data/Gemfile +1 -0
  10. data/README.md +290 -105
  11. data/Rakefile +5 -1
  12. data/SECURITY.md +42 -349
  13. data/docs/architecture.md +510 -0
  14. data/docs/async-background-processing.md +298 -0
  15. data/docs/configuration.md +556 -226
  16. data/docs/factory-pattern.md +355 -0
  17. data/docs/gateway-context-variables.md +171 -0
  18. data/docs/gateway-development.md +723 -0
  19. data/docs/getting-started.md +429 -0
  20. data/docs/instrumentation.md +264 -153
  21. data/docs/platforms/telegram.md +1013 -0
  22. data/docs/platforms/ussd.md +693 -0
  23. data/docs/platforms/whatsapp.md +1395 -0
  24. data/docs/testing.md +243 -365
  25. data/examples/custom_session_id_example.rb +119 -0
  26. data/examples/http_controller.rb +11 -11
  27. data/examples/intercom_configuration_example.rb +118 -0
  28. data/examples/intercom_controller.rb +194 -0
  29. data/examples/multi_tenant_whatsapp_controller.rb +4 -4
  30. data/examples/ussd_controller.rb +9 -9
  31. data/examples/whatsapp_controller.rb +2 -2
  32. data/flow_chat.gemspec +4 -0
  33. data/lib/flow_chat/{base_app.rb → app.rb} +16 -9
  34. data/lib/flow_chat/async_job.rb +176 -0
  35. data/lib/flow_chat/config.rb +10 -30
  36. data/lib/flow_chat/{base_executor.rb → executor.rb} +6 -11
  37. data/lib/flow_chat/factory.rb +94 -0
  38. data/lib/flow_chat/gateway_async_support.rb +106 -0
  39. data/lib/flow_chat/generic_async_job.rb +30 -0
  40. data/lib/flow_chat/http/gateway/simple.rb +81 -33
  41. data/lib/flow_chat/http/renderer.rb +3 -3
  42. data/lib/flow_chat/instrumentation/setup.rb +1 -1
  43. data/lib/flow_chat/instrumentation.rb +23 -0
  44. data/lib/flow_chat/intercom/client.rb +155 -0
  45. data/lib/flow_chat/intercom/configuration.rb +149 -0
  46. data/lib/flow_chat/intercom/gateway/intercom_api.rb +396 -0
  47. data/lib/flow_chat/intercom/renderer.rb +71 -0
  48. data/lib/flow_chat/phone_number_util.rb +37 -35
  49. data/lib/flow_chat/processor.rb +188 -0
  50. data/lib/flow_chat/renderers/markdown_support.rb +58 -0
  51. data/lib/flow_chat/session/middleware.rb +25 -9
  52. data/lib/flow_chat/telegram/client.rb +240 -0
  53. data/lib/flow_chat/telegram/configuration.rb +118 -0
  54. data/lib/flow_chat/telegram/gateway/bot_api.rb +300 -0
  55. data/lib/flow_chat/telegram/middleware/choice_mapper.rb +35 -0
  56. data/lib/flow_chat/telegram/renderer.rb +125 -0
  57. data/lib/flow_chat/telegram.rb +7 -0
  58. data/lib/flow_chat/ussd/gateway/nalo.rb +24 -4
  59. data/lib/flow_chat/ussd/middleware/pagination.rb +9 -5
  60. data/lib/flow_chat/ussd/renderer.rb +1 -1
  61. data/lib/flow_chat/version.rb +1 -1
  62. data/lib/flow_chat/whatsapp/client.rb +144 -13
  63. data/lib/flow_chat/whatsapp/configuration.rb +1 -1
  64. data/lib/flow_chat/whatsapp/gateway/cloud_api.rb +132 -96
  65. data/lib/flow_chat/whatsapp/id_generator.rb +124 -0
  66. data/lib/flow_chat/whatsapp/middleware/choice_mapper.rb +147 -0
  67. data/lib/flow_chat/whatsapp/renderer.rb +145 -11
  68. data/lib/flow_chat.rb +11 -1
  69. data/lib/tasks/release.rake +165 -0
  70. metadata +84 -25
  71. data/docs/flows.md +0 -320
  72. data/docs/http-gateway-protocol.md +0 -432
  73. data/docs/images/simulator.png +0 -0
  74. data/docs/media.md +0 -153
  75. data/docs/sessions.md +0 -433
  76. data/docs/ussd-setup.md +0 -322
  77. data/docs/whatsapp-setup.md +0 -162
  78. data/examples/whatsapp_message_job.rb +0 -113
  79. data/lib/flow_chat/base_processor.rb +0 -146
  80. data/lib/flow_chat/http/app.rb +0 -6
  81. data/lib/flow_chat/http/middleware/executor.rb +0 -24
  82. data/lib/flow_chat/http/processor.rb +0 -33
  83. data/lib/flow_chat/session/rails_session_store.rb +0 -68
  84. data/lib/flow_chat/ussd/app.rb +0 -6
  85. data/lib/flow_chat/ussd/gateway/nsano.rb +0 -96
  86. data/lib/flow_chat/ussd/middleware/executor.rb +0 -24
  87. data/lib/flow_chat/ussd/processor.rb +0 -39
  88. data/lib/flow_chat/whatsapp/app.rb +0 -29
  89. data/lib/flow_chat/whatsapp/middleware/executor.rb +0 -24
  90. data/lib/flow_chat/whatsapp/processor.rb +0 -32
  91. data/lib/flow_chat/whatsapp/send_job_support.rb +0 -79
data/docs/ussd-setup.md DELETED
@@ -1,322 +0,0 @@
1
- # USSD Setup Guide
2
-
3
- This guide covers USSD configuration and implementation patterns for FlowChat.
4
-
5
- ## Basic Setup
6
-
7
- ### 1. Create a Flow
8
-
9
- Create a flow in `app/flow_chat/welcome_flow.rb`:
10
-
11
- ```ruby
12
- class WelcomeFlow < FlowChat::Flow
13
- def main_page
14
- name = app.screen(:name) do |prompt|
15
- prompt.ask "Welcome! What's your name?",
16
- transform: ->(input) { input.strip.titleize }
17
- end
18
-
19
- service = app.screen(:service) do |prompt|
20
- prompt.select "Choose a service:", {
21
- "balance" => "Check Balance",
22
- "transfer" => "Transfer Money",
23
- "history" => "Transaction History"
24
- }
25
- end
26
-
27
- case service
28
- when "balance"
29
- show_balance
30
- when "transfer"
31
- transfer_money
32
- when "history"
33
- show_history
34
- end
35
- end
36
-
37
- private
38
-
39
- def show_balance
40
- # Simulate balance check
41
- balance = fetch_user_balance(app.phone_number)
42
- app.say "Hello #{app.session.get(:name)}! Your balance is $#{balance}."
43
- end
44
- end
45
- ```
46
-
47
- ### 2. Create Controller
48
-
49
- ```ruby
50
- class UssdController < ApplicationController
51
- skip_forgery_protection
52
-
53
- def process_request
54
- processor = FlowChat::Ussd::Processor.new(self) do |config|
55
- config.use_gateway FlowChat::Ussd::Gateway::Nalo
56
- config.use_session_store FlowChat::Session::CacheSessionStore
57
- end
58
-
59
- processor.run WelcomeFlow, :main_page
60
- end
61
- end
62
- ```
63
-
64
- ### 3. Configure Routes
65
-
66
- ```ruby
67
- # config/routes.rb
68
- Rails.application.routes.draw do
69
- post 'ussd' => 'ussd#process_request'
70
- end
71
- ```
72
-
73
- ## Gateway Configuration
74
-
75
- ### Nalo Gateway
76
-
77
- FlowChat currently supports Nalo USSD gateways:
78
-
79
- ```ruby
80
- processor = FlowChat::Ussd::Processor.new(self) do |config|
81
- config.use_gateway FlowChat::Ussd::Gateway::Nalo
82
- config.use_session_store FlowChat::Session::CacheSessionStore
83
- end
84
- ```
85
-
86
- The Nalo gateway expects these parameters in the request:
87
- - `msisdn` - User's phone number
88
- - `input` - User's input text
89
- - `session_id` - Session identifier
90
-
91
- ## Pagination
92
-
93
- USSD messages are automatically paginated when they exceed character limits:
94
-
95
- ```ruby
96
- # Configure pagination behavior
97
- FlowChat::Config.ussd.pagination_page_size = 140 # characters per page
98
- FlowChat::Config.ussd.pagination_next_option = "#" # option for next page
99
- FlowChat::Config.ussd.pagination_next_text = "More" # text for next option
100
- FlowChat::Config.ussd.pagination_back_option = "0" # option for previous page
101
- FlowChat::Config.ussd.pagination_back_text = "Back" # text for back option
102
- ```
103
-
104
- ### Example Long Message
105
-
106
- ```ruby
107
- def show_terms
108
- terms = "Very long terms and conditions text that exceeds 140 characters..."
109
- app.say terms # Automatically paginated
110
- end
111
- ```
112
-
113
- **USSD Output:**
114
- ```
115
- Terms and Conditions:
116
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt...
117
-
118
- # More
119
- 0 Back
120
- ```
121
-
122
- ## Session Management
123
-
124
- Configure session behavior for better user experience:
125
-
126
- ```ruby
127
- processor = FlowChat::Ussd::Processor.new(self) do |config|
128
- config.use_gateway FlowChat::Ussd::Gateway::Nalo
129
- config.use_session_store FlowChat::Session::CacheSessionStore
130
-
131
- # Enable durable sessions (shorthand)
132
- config.use_durable_sessions
133
- end
134
- ```
135
-
136
- ### Session Boundaries
137
-
138
- Session boundaries control how session IDs are constructed:
139
-
140
- - **`:flow`** - Separate sessions per flow class
141
- - **`:platform`** - Separate USSD from WhatsApp sessions
142
- - **`:gateway`** - Separate sessions per gateway
143
- - **`[]`** - Global sessions (no boundaries)
144
-
145
- Session identifier options:
146
-
147
- - **`nil`** - Platform chooses default (`:request_id` for USSD, `:msisdn` for WhatsApp)
148
- - **`:msisdn`** - Use phone number (durable sessions)
149
- - **`:request_id`** - Use request ID (ephemeral sessions)
150
- - **`hash_identifiers`** - Hash identifiers for privacy (recommended)
151
-
152
- ## Middleware
153
-
154
- ### Custom Middleware
155
-
156
- ```ruby
157
- class AuthenticationMiddleware
158
- def initialize(app)
159
- @app = app
160
- end
161
-
162
- def call(context)
163
- phone = context["request.msisdn"]
164
-
165
- unless user_exists?(phone)
166
- # Return appropriate response for unregistered user
167
- return [:prompt, "Please register first. Visit our website to sign up.", nil, nil]
168
- end
169
-
170
- @app.call(context)
171
- end
172
-
173
- private
174
-
175
- def user_exists?(phone)
176
- User.exists?(phone: phone)
177
- end
178
- end
179
-
180
- # Use custom middleware
181
- processor = FlowChat::Ussd::Processor.new(self) do |config|
182
- config.use_gateway FlowChat::Ussd::Gateway::Nalo
183
- config.use_session_store FlowChat::Session::CacheSessionStore
184
- config.use_middleware AuthenticationMiddleware
185
- end
186
- ```
187
-
188
- ## Advanced Patterns
189
-
190
- ### Menu-Driven Navigation
191
-
192
- ```ruby
193
- class MenuFlow < FlowChat::Flow
194
- def main_page
195
- choice = app.screen(:main_menu) do |prompt|
196
- prompt.select "Main Menu:", {
197
- "1" => "Account Services",
198
- "2" => "Transfer Services",
199
- "3" => "Customer Support"
200
- }
201
- end
202
-
203
- case choice
204
- when "1"
205
- account_services
206
- when "2"
207
- transfer_services
208
- when "3"
209
- customer_support
210
- end
211
- end
212
-
213
- def account_services
214
- choice = app.screen(:account_menu) do |prompt|
215
- prompt.select "Account Services:", {
216
- "1" => "Check Balance",
217
- "2" => "Mini Statement",
218
- "0" => "Back to Main Menu"
219
- }
220
- end
221
-
222
- case choice
223
- when "1"
224
- check_balance
225
- when "2"
226
- mini_statement
227
- when "0"
228
- main_page # Return to main menu
229
- end
230
- end
231
- end
232
- ```
233
-
234
- ### Error Handling
235
-
236
- ```ruby
237
- def transfer_money
238
- begin
239
- amount = app.screen(:amount) do |prompt|
240
- prompt.ask "Enter amount:",
241
- validate: ->(input) {
242
- return "Amount must be numeric" unless input.match?(/^\d+(\.\d{2})?$/)
243
- return "Minimum transfer is $1" unless input.to_f >= 1.0
244
- nil
245
- },
246
- transform: ->(input) { input.to_f }
247
- end
248
-
249
- recipient = app.screen(:recipient) do |prompt|
250
- prompt.ask "Enter recipient phone number:",
251
- validate: ->(input) {
252
- return "Invalid phone number" unless valid_phone?(input)
253
- nil
254
- }
255
- end
256
-
257
- process_transfer(amount, recipient)
258
- app.say "Transfer of $#{amount} to #{recipient} successful!"
259
-
260
- rescue TransferError => e
261
- app.say "Transfer failed: #{e.message}. Please try again."
262
- transfer_money # Retry
263
- end
264
- end
265
- ```
266
-
267
- ### Session Data Management
268
-
269
- ```ruby
270
- class RegistrationFlow < FlowChat::Flow
271
- def main_page
272
- collect_personal_info
273
- collect_preferences
274
- confirm_and_save
275
- end
276
-
277
- private
278
-
279
- def collect_personal_info
280
- app.screen(:first_name) { |p| p.ask "First name:" }
281
- app.screen(:last_name) { |p| p.ask "Last name:" }
282
- app.screen(:email) { |p| p.ask "Email address:" }
283
- end
284
-
285
- def collect_preferences
286
- app.screen(:language) { |p| p.select "Language:", ["English", "French"] }
287
- app.screen(:notifications) { |p| p.yes? "Enable SMS notifications?" }
288
- end
289
-
290
- def confirm_and_save
291
- summary = build_summary_from_session
292
- confirmed = app.screen(:confirm) { |p| p.yes? "Save profile?\n\n#{summary}" }
293
-
294
- if confirmed
295
- save_user_profile
296
- app.say "Registration complete!"
297
- else
298
- app.say "Registration cancelled."
299
- end
300
- end
301
-
302
- def build_summary_from_session
303
- first_name = app.session.get(:first_name)
304
- last_name = app.session.get(:last_name)
305
- email = app.session.get(:email)
306
- language = app.session.get(:language)
307
-
308
- "Name: #{first_name} #{last_name}\nEmail: #{email}\nLanguage: #{language}"
309
- end
310
- end
311
- ```
312
-
313
- ## Testing USSD Flows
314
-
315
- Use the built-in simulator for testing USSD flows:
316
-
317
- ```ruby
318
- # config/initializers/flowchat.rb
319
- FlowChat::Config.simulator_secret = "your_secure_secret"
320
- ```
321
-
322
- See [Testing Guide](testing.md) for comprehensive testing strategies and [examples/ussd_controller.rb](../examples/ussd_controller.rb) for complete implementation examples.
@@ -1,162 +0,0 @@
1
- # WhatsApp Setup Guide
2
-
3
- This guide covers comprehensive WhatsApp configuration for FlowChat, including security, multi-tenant setups, and different processing modes.
4
-
5
- ## Credential Configuration
6
-
7
- FlowChat supports multiple ways to configure WhatsApp credentials:
8
-
9
- ### Option 1: Rails Credentials
10
-
11
- ```bash
12
- rails credentials:edit
13
- ```
14
-
15
- ```yaml
16
- whatsapp:
17
- access_token: "your_access_token"
18
- phone_number_id: "your_phone_number_id"
19
- verify_token: "your_verify_token"
20
- app_id: "your_app_id"
21
- app_secret: "your_app_secret"
22
- business_account_id: "your_business_account_id"
23
- skip_signature_validation: false # Set to true only for development/testing
24
- ```
25
-
26
- ### Option 2: Environment Variables
27
-
28
- ```bash
29
- export WHATSAPP_ACCESS_TOKEN="your_access_token"
30
- export WHATSAPP_PHONE_NUMBER_ID="your_phone_number_id"
31
- export WHATSAPP_VERIFY_TOKEN="your_verify_token"
32
- export WHATSAPP_APP_ID="your_app_id"
33
- export WHATSAPP_APP_SECRET="your_app_secret"
34
- export WHATSAPP_BUSINESS_ACCOUNT_ID="your_business_account_id"
35
- export WHATSAPP_SKIP_SIGNATURE_VALIDATION="false"
36
- ```
37
-
38
- ### Option 3: Per-Setup Configuration
39
-
40
- For multi-tenant applications:
41
-
42
- ```ruby
43
- custom_config = FlowChat::Whatsapp::Configuration.new
44
- custom_config.access_token = "your_specific_access_token"
45
- custom_config.phone_number_id = "your_specific_phone_number_id"
46
- custom_config.verify_token = "your_specific_verify_token"
47
- custom_config.app_id = "your_specific_app_id"
48
- custom_config.app_secret = "your_specific_app_secret"
49
- custom_config.business_account_id = "your_specific_business_account_id"
50
- custom_config.skip_signature_validation = false
51
-
52
- processor = FlowChat::Whatsapp::Processor.new(self) do |config|
53
- config.use_gateway FlowChat::Whatsapp::Gateway::CloudApi, custom_config
54
- config.use_session_store FlowChat::Session::CacheSessionStore
55
- end
56
- ```
57
-
58
- ## Message Handling Modes
59
-
60
- Configure message processing behavior in `config/initializers/flowchat.rb`:
61
-
62
- ### Inline Mode (Default)
63
-
64
- Process messages synchronously:
65
-
66
- ```ruby
67
- FlowChat::Config.whatsapp.message_handling_mode = :inline
68
- ```
69
-
70
- ### Background Mode
71
-
72
- Process flows synchronously, send responses asynchronously:
73
-
74
- ```ruby
75
- FlowChat::Config.whatsapp.message_handling_mode = :background
76
- FlowChat::Config.whatsapp.background_job_class = 'WhatsappMessageJob'
77
- ```
78
-
79
- ### Simulator Mode
80
-
81
- Return response data instead of sending via WhatsApp API:
82
-
83
- ```ruby
84
- FlowChat::Config.whatsapp.message_handling_mode = :simulator
85
- ```
86
-
87
- ## Security Configuration
88
-
89
- ### Webhook Signature Validation (Production)
90
-
91
- ```ruby
92
- custom_config.app_secret = "your_whatsapp_app_secret"
93
- custom_config.skip_signature_validation = false # Default: enforce validation
94
- ```
95
-
96
- ### Development Mode
97
-
98
- ```ruby
99
- custom_config.app_secret = nil
100
- custom_config.skip_signature_validation = true # Disable validation
101
- ```
102
-
103
- ⚠️ **Security Warning**: Only disable signature validation in development/testing environments.
104
-
105
- ## Multi-Tenant Setup
106
-
107
- See [examples/multi_tenant_whatsapp_controller.rb](../examples/multi_tenant_whatsapp_controller.rb) for a complete multi-tenant implementation.
108
-
109
- ## Background Job Setup
110
-
111
- When using background jobs with programmatic WhatsApp configurations, you must register configurations in an initializer so they're available to background jobs:
112
-
113
- ```ruby
114
- # config/initializers/whatsapp_configs.rb
115
- tenant_a_config = FlowChat::Whatsapp::Configuration.new(:tenant_a)
116
- tenant_a_config.access_token = "tenant_a_token"
117
- tenant_a_config.phone_number_id = "tenant_a_phone"
118
- tenant_a_config.verify_token = "tenant_a_verify"
119
- tenant_a_config.app_secret = "tenant_a_secret"
120
- # Configuration is automatically registered as :tenant_a
121
-
122
- tenant_b_config = FlowChat::Whatsapp::Configuration.new(:tenant_b)
123
- tenant_b_config.access_token = "tenant_b_token"
124
- tenant_b_config.phone_number_id = "tenant_b_phone"
125
- tenant_b_config.verify_token = "tenant_b_verify"
126
- tenant_b_config.app_secret = "tenant_b_secret"
127
- # Configuration is automatically registered as :tenant_b
128
- ```
129
-
130
- Then reference the named configuration in your controller:
131
-
132
- ```ruby
133
- processor = FlowChat::Whatsapp::Processor.new(self) do |config|
134
- # Use registered configuration by name
135
- tenant_config = FlowChat::Whatsapp::Configuration.get(:tenant_a)
136
- config.use_gateway FlowChat::Whatsapp::Gateway::CloudApi, tenant_config
137
- config.use_session_store FlowChat::Session::CacheSessionStore
138
- end
139
- ```
140
-
141
- **Why this is required:** Background jobs run in a separate context and cannot access configurations created in controller actions. Registered configurations are globally available.
142
-
143
- **Alternative:** Override the job's configuration resolution logic (see examples).
144
-
145
- See [examples/whatsapp_message_job.rb](../examples/whatsapp_message_job.rb) for job implementation and [Background Jobs Guide](background-jobs.md) for detailed setup.
146
-
147
- ## Troubleshooting
148
-
149
- ### Common Issues
150
-
151
- **Configuration Error**: Check that all required credentials are set
152
- **Signature Validation Failed**: Verify app_secret matches your WhatsApp app
153
- **Timeout Issues**: Consider using background mode for high-volume applications
154
-
155
- ### Debug Mode
156
-
157
- Enable debug logging in development:
158
-
159
- ```ruby
160
- # config/environments/development.rb
161
- config.log_level = :debug
162
- ```
@@ -1,113 +0,0 @@
1
- # Example Background Jobs for WhatsApp Response Delivery
2
- # Add these to your Rails application
3
-
4
- # Example: Basic WhatsApp Send Job
5
- # Only handles sending responses - flows are processed synchronously in the controller
6
- class WhatsappMessageJob < ApplicationJob
7
- include FlowChat::Whatsapp::SendJobSupport
8
-
9
- def perform(send_data)
10
- perform_whatsapp_send(send_data)
11
- end
12
- end
13
-
14
- # Example: Advanced WhatsApp Send Job with custom callbacks
15
- class AdvancedWhatsappMessageJob < ApplicationJob
16
- include FlowChat::Whatsapp::SendJobSupport
17
-
18
- queue_as :whatsapp_priority
19
- retry_on StandardError, wait: 2.seconds, attempts: 3
20
-
21
- def perform(send_data)
22
- perform_whatsapp_send(send_data)
23
- end
24
-
25
- private
26
-
27
- # Override for custom success handling
28
- def on_whatsapp_send_success(send_data, result)
29
- Rails.logger.info "Successfully sent WhatsApp message to #{send_data[:msisdn]}"
30
- UserEngagementTracker.track_message_sent(phone: send_data[:msisdn])
31
- end
32
-
33
- # Override for custom error handling
34
- def on_whatsapp_send_error(error, send_data)
35
- ErrorTracker.notify(error, user_phone: send_data[:msisdn])
36
- end
37
- end
38
-
39
- # Example: Priority send job for urgent messages
40
- class UrgentWhatsappSendJob < ApplicationJob
41
- include FlowChat::Whatsapp::SendJobSupport
42
-
43
- queue_as :urgent_whatsapp # Different queue for priority
44
- retry_on StandardError, wait: 1.second, attempts: 5 # Override retry policy
45
-
46
- def perform(send_data)
47
- perform_whatsapp_send(send_data)
48
- end
49
-
50
- private
51
-
52
- # Override error handling for urgent messages
53
- def handle_whatsapp_send_error(error, send_data, config = nil)
54
- # Immediately escalate urgent message failures
55
- AlertingService.send_urgent_alert(
56
- "Urgent WhatsApp send job failed",
57
- error: error.message,
58
- user: send_data[:msisdn]
59
- )
60
-
61
- # Still send user notification
62
- super
63
- end
64
- end
65
-
66
- # Example: Multi-tenant send job
67
- class MultiTenantWhatsappSendJob < ApplicationJob
68
- include FlowChat::Whatsapp::SendJobSupport
69
-
70
- def perform(send_data)
71
- perform_whatsapp_send(send_data)
72
- end
73
-
74
- private
75
-
76
- # Override config resolution for tenant-specific configs
77
- def resolve_whatsapp_config(send_data)
78
- # Use tenant-specific config if available
79
- tenant_name = extract_tenant_from_phone(send_data[:msisdn])
80
- if tenant_name && FlowChat::Whatsapp::Configuration.exists?(tenant_name)
81
- return FlowChat::Whatsapp::Configuration.get(tenant_name)
82
- end
83
-
84
- # Fallback to default
85
- super
86
- end
87
-
88
- def extract_tenant_from_phone(phone)
89
- case phone
90
- when /^\+1800/
91
- :enterprise
92
- when /^\+1888/
93
- :premium
94
- else
95
- :standard
96
- end
97
- end
98
- end
99
-
100
- # Usage in Rails configuration
101
- #
102
- # Add to config/application.rb:
103
- # config.active_job.queue_adapter = :sidekiq
104
- #
105
- # Add to config/initializers/flowchat.rb:
106
- # FlowChat::Config.whatsapp.message_handling_mode = :background
107
- # FlowChat::Config.whatsapp.background_job_class = 'WhatsappMessageJob'
108
- #
109
- # How it works:
110
- # 1. Controller receives WhatsApp webhook
111
- # 2. Flow is processed synchronously (maintains controller context)
112
- # 3. Response is queued for async delivery via background job
113
- # 4. Job only handles sending the response, not processing flows