flow_chat 0.9.0 → 0.10.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.
- checksums.yaml +4 -4
- data/.github/workflows/pages.yml +43 -0
- data/CHANGELOG.md +26 -0
- data/README.md +166 -295
- data/Rakefile +12 -1
- data/SECURITY.md +1 -1
- data/docs/architecture.md +52 -479
- data/docs/async-background-processing.md +31 -265
- data/docs/configuration.md +106 -613
- data/docs/factory-pattern.md +27 -324
- data/docs/gateway-context-variables.md +140 -143
- data/docs/gateway-development.md +86 -650
- data/docs/getting-started.md +40 -379
- data/docs/instrumentation.md +88 -279
- data/docs/platforms/instagram.md +278 -0
- data/docs/platforms/messenger.md +205 -0
- data/docs/platforms/telegram.md +47 -951
- data/docs/platforms/ussd.md +38 -653
- data/docs/platforms/whatsapp.md +73 -1321
- data/docs/superpowers/plans/2026-07-09-inbound-media-support.md +732 -0
- data/docs/superpowers/plans/2026-07-09-inbound-media-support.md.tasks.json +58 -0
- data/docs/superpowers/plans/2026-08-10-messenger-instagram.md +4064 -0
- data/docs/superpowers/plans/2026-08-10-messenger-instagram.md.tasks.json +226 -0
- data/docs/superpowers/plans/2026-08-16-unified-choice-resolution.md +972 -0
- data/docs/superpowers/plans/2026-08-16-unified-choice-resolution.md.tasks.json +88 -0
- data/docs/superpowers/specs/2026-07-09-inbound-media-support-design.md +195 -0
- data/docs/superpowers/specs/2026-08-10-messenger-instagram-design.md +391 -0
- data/docs/testing.md +26 -297
- data/examples/http_controller.rb +12 -10
- data/examples/intercom_configuration_example.rb +19 -24
- data/examples/intercom_controller.rb +8 -20
- data/examples/multi_tenant_whatsapp_controller.rb +61 -166
- data/examples/simulator_controller.rb +0 -1
- data/examples/ussd_controller.rb +86 -158
- data/examples/whatsapp_controller.rb +16 -15
- data/examples/whatsapp_media_examples.rb +27 -79
- data/lib/flow_chat/app.rb +129 -11
- data/lib/flow_chat/choice_titles.rb +95 -0
- data/lib/flow_chat/config.rb +124 -1
- data/lib/flow_chat/delivery_error.rb +9 -0
- data/lib/flow_chat/http/configuration_error.rb +9 -0
- data/lib/flow_chat/http/gateway/simple.rb +24 -4
- data/lib/flow_chat/http/middleware/choice_mapper.rb +94 -0
- data/lib/flow_chat/input.rb +86 -0
- data/lib/flow_chat/instagram/client.rb +32 -0
- data/lib/flow_chat/instagram/configuration.rb +147 -0
- data/lib/flow_chat/instagram/configuration_error.rb +7 -0
- data/lib/flow_chat/instagram/gateway/send_api.rb +63 -0
- data/lib/flow_chat/instagram/middleware/choice_mapper.rb +22 -0
- data/lib/flow_chat/instagram/renderer.rb +23 -0
- data/lib/flow_chat/instrumentation/metrics_collector.rb +6 -1
- data/lib/flow_chat/instrumentation.rb +160 -1
- data/lib/flow_chat/intercom/client.rb +34 -28
- data/lib/flow_chat/intercom/configuration.rb +2 -49
- data/lib/flow_chat/intercom/configuration_error.rb +9 -0
- data/lib/flow_chat/intercom/gateway/intercom_api.rb +81 -57
- data/lib/flow_chat/intercom/middleware/choice_mapper.rb +101 -0
- data/lib/flow_chat/intercom/renderer.rb +57 -5
- data/lib/flow_chat/media.rb +121 -0
- data/lib/flow_chat/messenger/client.rb +264 -0
- data/lib/flow_chat/messenger/configuration.rb +103 -0
- data/lib/flow_chat/messenger/configuration_error.rb +9 -0
- data/lib/flow_chat/messenger/gateway/send_api.rb +42 -0
- data/lib/flow_chat/messenger/middleware/choice_mapper.rb +185 -0
- data/lib/flow_chat/messenger/renderer.rb +150 -0
- data/lib/flow_chat/meta/challenge.rb +24 -0
- data/lib/flow_chat/meta/choice_ladder.rb +37 -0
- data/lib/flow_chat/meta/configuration_error.rb +7 -0
- data/lib/flow_chat/meta/gateway_identity.rb +38 -0
- data/lib/flow_chat/meta/messaging_gateway.rb +468 -0
- data/lib/flow_chat/meta/signature.rb +30 -0
- data/lib/flow_chat/meta/signature_validation.rb +66 -0
- data/lib/flow_chat/meta/webhook_verification.rb +43 -0
- data/lib/flow_chat/named_configuration.rb +65 -0
- data/lib/flow_chat/prompt.rb +13 -16
- data/lib/flow_chat/renderers/markdown_support.rb +109 -0
- data/lib/flow_chat/security.rb +76 -0
- data/lib/flow_chat/session/middleware.rb +11 -2
- data/lib/flow_chat/simulator/controller.rb +31 -15
- data/lib/flow_chat/simulator/views/simulator.html.erb +184 -20
- data/lib/flow_chat/telegram/client.rb +47 -4
- data/lib/flow_chat/telegram/configuration.rb +2 -42
- data/lib/flow_chat/telegram/configuration_error.rb +9 -0
- data/lib/flow_chat/telegram/gateway/bot_api.rb +46 -28
- data/lib/flow_chat/telegram/middleware/choice_mapper.rb +77 -16
- data/lib/flow_chat/telegram/renderer.rb +10 -2
- data/lib/flow_chat/text_truncator.rb +75 -0
- data/lib/flow_chat/ussd/middleware/choice_mapper.rb +10 -0
- data/lib/flow_chat/version.rb +1 -1
- data/lib/flow_chat/whatsapp/client.rb +14 -7
- data/lib/flow_chat/whatsapp/configuration.rb +12 -51
- data/lib/flow_chat/whatsapp/configuration_error.rb +9 -0
- data/lib/flow_chat/whatsapp/gateway/cloud_api.rb +254 -203
- data/lib/flow_chat/whatsapp/middleware/choice_mapper.rb +144 -57
- data/lib/flow_chat/whatsapp/renderer.rb +121 -60
- data/lib/flow_chat.rb +0 -10
- data/site/.nojekyll +0 -0
- data/site/.og-card.html +89 -0
- data/site/favicon.svg +6 -0
- data/site/index.html +209 -0
- data/site/og.png +0 -0
- metadata +51 -3
- data/lib/flow_chat/whatsapp/id_generator.rb +0 -124
data/docs/getting-started.md
CHANGED
|
@@ -1,429 +1,90 @@
|
|
|
1
|
-
# Getting Started
|
|
1
|
+
# Getting Started
|
|
2
2
|
|
|
3
|
-
This guide
|
|
3
|
+
This guide takes you from an empty Rails app to a running FlowChat flow. It reuses the same flow and processor shown in the [README](../README.md).
|
|
4
4
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
7
|
+
- A Rails application.
|
|
8
|
+
- Ruby 3.0 or newer.
|
|
9
|
+
- A cache the session store can use, such as `Rails.cache`.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Install
|
|
12
12
|
|
|
13
|
-
Add
|
|
13
|
+
Add the gem to your Gemfile:
|
|
14
14
|
|
|
15
15
|
```ruby
|
|
16
|
-
|
|
17
|
-
gem 'flow_chat'
|
|
16
|
+
gem "flow_chat"
|
|
18
17
|
```
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
bundle install
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Quick Start: Your First Multi-Platform App
|
|
25
|
-
|
|
26
|
-
Let's build a simple survey application that works across USSD, WhatsApp, Telegram, and HTTP APIs.
|
|
19
|
+
Then run `bundle install`. There are no migrations and no generators to run.
|
|
27
20
|
|
|
28
|
-
|
|
21
|
+
## Configure the cache
|
|
29
22
|
|
|
30
|
-
|
|
23
|
+
The cache-backed session store needs a cache. Set it once during boot, for example in an initializer:
|
|
31
24
|
|
|
32
25
|
```ruby
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
# Welcome message that works on all platforms
|
|
36
|
-
name = app.screen(:name) do |prompt|
|
|
37
|
-
prompt.ask "Welcome to our survey! What's your name?",
|
|
38
|
-
validate: ->(input) {
|
|
39
|
-
return "Name must be at least 2 characters" if input.length < 2
|
|
40
|
-
nil
|
|
41
|
-
},
|
|
42
|
-
transform: ->(input) { input.strip.titleize }
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Rating question with platform-appropriate choices
|
|
46
|
-
rating = app.screen(:rating) do |prompt|
|
|
47
|
-
prompt.select "Hi #{name}! Rate our service:", {
|
|
48
|
-
"5" => "⭐⭐⭐⭐⭐ Excellent",
|
|
49
|
-
"4" => "⭐⭐⭐⭐ Good",
|
|
50
|
-
"3" => "⭐⭐⭐ Average",
|
|
51
|
-
"2" => "⭐⭐ Poor",
|
|
52
|
-
"1" => "⭐ Very Poor"
|
|
53
|
-
}
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Feedback collection
|
|
57
|
-
feedback = app.screen(:feedback) do |prompt|
|
|
58
|
-
prompt.ask "Any additional feedback?",
|
|
59
|
-
validate: ->(input) {
|
|
60
|
-
return "Feedback too short" if input.length < 5
|
|
61
|
-
nil
|
|
62
|
-
}
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
# Save the survey (your business logic)
|
|
66
|
-
save_survey(name, rating, feedback, app.msisdn)
|
|
67
|
-
|
|
68
|
-
# Thank you message
|
|
69
|
-
app.say "Thank you #{name}! Your feedback (#{rating}⭐) has been recorded."
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
private
|
|
73
|
-
|
|
74
|
-
def save_survey(name, rating, feedback, phone)
|
|
75
|
-
# Your database logic here
|
|
76
|
-
Rails.logger.info "Survey: #{name} (#{phone}) rated #{rating}/5: #{feedback}"
|
|
77
|
-
|
|
78
|
-
# Example: Save to database
|
|
79
|
-
# Survey.create!(
|
|
80
|
-
# name: name,
|
|
81
|
-
# rating: rating.to_i,
|
|
82
|
-
# feedback: feedback,
|
|
83
|
-
# phone: phone,
|
|
84
|
-
# platform: app.platform
|
|
85
|
-
# )
|
|
86
|
-
end
|
|
87
|
-
end
|
|
26
|
+
# config/initializers/flow_chat.rb
|
|
27
|
+
FlowChat::Config.cache = Rails.cache
|
|
88
28
|
```
|
|
89
29
|
|
|
90
|
-
|
|
30
|
+
Without a cache configured, `FlowChat::Session::CacheSessionStore` raises when it tries to read or write a session.
|
|
31
|
+
|
|
32
|
+
## Write your first flow
|
|
91
33
|
|
|
92
|
-
|
|
34
|
+
A flow is a class that inherits `FlowChat::Flow` and reads and writes the conversation through `app`. Each `app.screen` is one step:
|
|
93
35
|
|
|
94
36
|
```ruby
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
config.use_gateway FlowChat::Ussd::Gateway::Nalo
|
|
102
|
-
config.use_session_store FlowChat::Session::CacheSessionStore
|
|
103
|
-
|
|
104
|
-
# Optional: Configure USSD-specific settings
|
|
105
|
-
config.use_session_config(boundaries: [:flow, :platform])
|
|
37
|
+
class RegistrationFlow < FlowChat::Flow
|
|
38
|
+
def main_page
|
|
39
|
+
name = app.screen(:name) { |prompt| prompt.ask "What's your name?" }
|
|
40
|
+
|
|
41
|
+
email = app.screen(:email) do |prompt|
|
|
42
|
+
prompt.ask "Your email?", validate: ->(input) { "Invalid email" unless input.include?("@") }
|
|
106
43
|
end
|
|
107
44
|
|
|
108
|
-
|
|
45
|
+
app.say "Welcome #{name}!"
|
|
109
46
|
end
|
|
110
47
|
end
|
|
111
48
|
```
|
|
112
49
|
|
|
113
|
-
|
|
50
|
+
FlowChat re-runs this method from the top on every webhook. Each `screen` returns its stored answer when the session already holds one, and re-prompts when it does not, so the method reads as a straight-line script even though each turn is a separate stateless request. For the mechanics, see [How the replay engine works](../README.md#how-the-replay-engine-works).
|
|
114
51
|
|
|
115
|
-
|
|
116
|
-
# app/controllers/whatsapp_controller.rb
|
|
117
|
-
class WhatsappController < ApplicationController
|
|
118
|
-
skip_forgery_protection
|
|
119
|
-
|
|
120
|
-
def webhook
|
|
121
|
-
processor = FlowChat::Processor.new(self) do |config|
|
|
122
|
-
config.use_gateway FlowChat::Whatsapp::Gateway::CloudApi
|
|
123
|
-
config.use_session_store FlowChat::Session::CacheSessionStore
|
|
124
|
-
end
|
|
52
|
+
Put the flow anywhere Rails autoloads it, for example `app/flow_chat/registration_flow.rb`.
|
|
125
53
|
|
|
126
|
-
|
|
127
|
-
rescue => e
|
|
128
|
-
Rails.logger.error "WhatsApp error: #{e.message}"
|
|
129
|
-
head :internal_server_error
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
```
|
|
54
|
+
## Wire a controller
|
|
133
55
|
|
|
134
|
-
|
|
56
|
+
Build a processor in your webhook action, choose a gateway and session store, and run the flow. Here `self` is the controller:
|
|
135
57
|
|
|
136
58
|
```ruby
|
|
137
|
-
# app/controllers/
|
|
138
|
-
class
|
|
59
|
+
# app/controllers/ussd_controller.rb
|
|
60
|
+
class UssdController < ApplicationController
|
|
139
61
|
skip_forgery_protection
|
|
140
62
|
|
|
141
63
|
def webhook
|
|
142
64
|
processor = FlowChat::Processor.new(self) do |config|
|
|
143
|
-
config.use_gateway FlowChat::
|
|
144
|
-
config.use_session_store FlowChat::Session::CacheSessionStore
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
processor.run SurveyFlow, :start
|
|
148
|
-
rescue => e
|
|
149
|
-
Rails.logger.error { "Telegram error: #{e.message}" }
|
|
150
|
-
head :internal_server_error
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
#### HTTP API Controller
|
|
156
|
-
|
|
157
|
-
```ruby
|
|
158
|
-
# app/controllers/api/chat_controller.rb
|
|
159
|
-
class Api::ChatController < ApplicationController
|
|
160
|
-
before_action :authenticate_api_user # Your auth logic
|
|
161
|
-
|
|
162
|
-
def message
|
|
163
|
-
processor = FlowChat::Processor.new(self) do |config|
|
|
164
|
-
config.use_gateway FlowChat::Http::Gateway::Simple
|
|
65
|
+
config.use_gateway FlowChat::Ussd::Gateway::Nalo
|
|
165
66
|
config.use_session_store FlowChat::Session::CacheSessionStore
|
|
166
|
-
|
|
167
|
-
# Session isolation per API user
|
|
168
|
-
config.use_session_config(identifier: :user_id)
|
|
169
67
|
end
|
|
170
68
|
|
|
171
|
-
processor.run
|
|
172
|
-
# Automatically returns JSON response
|
|
69
|
+
processor.run RegistrationFlow, :main_page
|
|
173
70
|
end
|
|
174
71
|
end
|
|
175
72
|
```
|
|
176
73
|
|
|
177
|
-
|
|
74
|
+
`skip_forgery_protection` is needed because gateway webhooks are POSTs from an external service that cannot carry a Rails CSRF token. Point a route at the action:
|
|
178
75
|
|
|
179
76
|
```ruby
|
|
180
77
|
# config/routes.rb
|
|
181
|
-
|
|
182
|
-
# USSD routes
|
|
183
|
-
post '/ussd/nalo', to: 'ussd#nalo_webhook'
|
|
184
|
-
|
|
185
|
-
# WhatsApp routes
|
|
186
|
-
post '/whatsapp/webhook', to: 'whatsapp#webhook'
|
|
187
|
-
get '/whatsapp/webhook', to: 'whatsapp#verify' # For webhook verification
|
|
188
|
-
|
|
189
|
-
# Telegram routes
|
|
190
|
-
post '/telegram/webhook', to: 'telegram#webhook'
|
|
191
|
-
|
|
192
|
-
# API routes
|
|
193
|
-
namespace :api do
|
|
194
|
-
post '/chat/message', to: 'chat#message'
|
|
195
|
-
end
|
|
196
|
-
end
|
|
78
|
+
post "/ussd", to: "ussd#webhook"
|
|
197
79
|
```
|
|
198
80
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
#### Environment Variables
|
|
202
|
-
|
|
203
|
-
Add these to your `.env` file:
|
|
81
|
+
To run the same flow on another platform, change only `config.use_gateway`. The gateway classes and their platform symbols are listed in the [README](../README.md#wiring-a-platform).
|
|
204
82
|
|
|
205
|
-
|
|
206
|
-
# WhatsApp Configuration
|
|
207
|
-
WHATSAPP_ACCESS_TOKEN=your_access_token
|
|
208
|
-
WHATSAPP_PHONE_NUMBER_ID=your_phone_number_id
|
|
209
|
-
WHATSAPP_VERIFY_TOKEN=your_verify_token
|
|
210
|
-
WHATSAPP_APP_SECRET=your_app_secret
|
|
211
|
-
|
|
212
|
-
# Telegram Configuration
|
|
213
|
-
TELEGRAM_BOT_TOKEN=your_bot_token
|
|
214
|
-
TELEGRAM_SECRET_TOKEN=your_webhook_secret # Optional: for webhook validation
|
|
215
|
-
```
|
|
83
|
+
## Try it in the simulator
|
|
216
84
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
Create `config/initializers/flow_chat.rb`:
|
|
220
|
-
|
|
221
|
-
```ruby
|
|
222
|
-
FlowChat::Config.logger = Rails.logger
|
|
223
|
-
FlowChat::Config.cache = Rails.cache
|
|
224
|
-
|
|
225
|
-
# USSD Configuration
|
|
226
|
-
FlowChat::Config.ussd.pagination_page_size = 160 # Adjust for your network
|
|
227
|
-
FlowChat::Config.ussd.pagination_next_option = "#"
|
|
228
|
-
FlowChat::Config.ussd.pagination_back_option = "0"
|
|
229
|
-
|
|
230
|
-
# WhatsApp Configuration
|
|
231
|
-
FlowChat::Config.whatsapp.message_handling_mode = :inline # or :background
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### 5. Test Your Application
|
|
235
|
-
|
|
236
|
-
#### Using the Built-in Simulator
|
|
237
|
-
|
|
238
|
-
Create a simple test in `rails console`:
|
|
239
|
-
|
|
240
|
-
```ruby
|
|
241
|
-
# Start a simulator session
|
|
242
|
-
simulator = FlowChat::Simulator.new(SurveyFlow, :start)
|
|
85
|
+
FlowChat ships a web simulator for driving flows locally without a real gateway. It requires `FlowChat::Config.simulator_secret` to be set (for example in your initializer). Once set, you can step through a flow from the browser during development. See [testing.md](testing.md) for how to mount and use it.
|
|
243
86
|
|
|
244
|
-
|
|
245
|
-
simulator.start
|
|
246
|
-
# => "Welcome to our survey! What's your name?"
|
|
247
|
-
|
|
248
|
-
simulator.send_message("John Doe")
|
|
249
|
-
# => "Hi John Doe! Rate our service:"
|
|
250
|
-
|
|
251
|
-
simulator.select_option("5")
|
|
252
|
-
# => "Any additional feedback?"
|
|
253
|
-
|
|
254
|
-
simulator.send_message("Great service, very helpful!")
|
|
255
|
-
# => "Thank you John Doe! Your feedback (5⭐) has been recorded."
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
#### Testing HTTP API
|
|
259
|
-
|
|
260
|
-
```bash
|
|
261
|
-
# Test the HTTP endpoint
|
|
262
|
-
curl -X POST http://localhost:3000/api/chat/message \
|
|
263
|
-
-H "Content-Type: application/json" \
|
|
264
|
-
-H "Authorization: Bearer your_api_token" \
|
|
265
|
-
-d '{
|
|
266
|
-
"user_id": "user123",
|
|
267
|
-
"input": "Hello"
|
|
268
|
-
}'
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
#### Testing USSD (using simulator)
|
|
272
|
-
|
|
273
|
-
Visit your Rails app with the simulator enabled:
|
|
274
|
-
|
|
275
|
-
```ruby
|
|
276
|
-
# In development, add this to your controller
|
|
277
|
-
processor = FlowChat::Processor.new(self, enable_simulator: true) do |config|
|
|
278
|
-
config.use_gateway FlowChat::Ussd::Gateway::Nalo
|
|
279
|
-
# ... other config
|
|
280
|
-
end
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
## Key Concepts
|
|
284
|
-
|
|
285
|
-
### 1. Screen-Based Navigation
|
|
286
|
-
|
|
287
|
-
FlowChat uses a **screen-based** approach where each `app.screen(:key)` represents a step in your conversation:
|
|
288
|
-
|
|
289
|
-
- **Automatic State Management**: Each screen's result is automatically cached
|
|
290
|
-
- **Navigation Stack**: FlowChat tracks where users are in the flow
|
|
291
|
-
- **Resume Capability**: Users can return to where they left off
|
|
292
|
-
|
|
293
|
-
### 2. Platform Abstraction
|
|
294
|
-
|
|
295
|
-
The same flow code works across all platforms because:
|
|
296
|
-
|
|
297
|
-
- **Unified Prompts**: `prompt.ask()` and `prompt.select()` adapt to each platform
|
|
298
|
-
- **Context Normalization**: All platforms provide consistent context (phone number, input, etc.)
|
|
299
|
-
- **Flexible Rendering**: Emojis show on WhatsApp, get stripped for USSD
|
|
300
|
-
|
|
301
|
-
### 3. Pluggable Gateways
|
|
302
|
-
|
|
303
|
-
Each platform can have multiple gateway implementations:
|
|
304
|
-
|
|
305
|
-
```ruby
|
|
306
|
-
# USSD with different providers
|
|
307
|
-
config.use_gateway FlowChat::Ussd::Gateway::Nalo
|
|
308
|
-
# config.use_gateway FlowChat::Ussd::Gateway::Africaist
|
|
309
|
-
# config.use_gateway YourCompany::Ussd::Gateway::CustomProvider
|
|
310
|
-
|
|
311
|
-
# WhatsApp with different APIs
|
|
312
|
-
config.use_gateway FlowChat::Whatsapp::Gateway::CloudApi
|
|
313
|
-
# config.use_gateway FlowChat::Whatsapp::Gateway::OnPremise
|
|
314
|
-
# config.use_gateway YourCompany::Whatsapp::Gateway::Twilio
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
### 4. Session Management
|
|
318
|
-
|
|
319
|
-
FlowChat provides flexible session configuration:
|
|
320
|
-
|
|
321
|
-
```ruby
|
|
322
|
-
# Ephemeral sessions (restart on each request)
|
|
323
|
-
config.use_session_config(identifier: :request_id)
|
|
324
|
-
|
|
325
|
-
# Durable sessions (persist across timeouts using phone number)
|
|
326
|
-
config.use_durable_sessions
|
|
327
|
-
|
|
328
|
-
# Cross-platform sessions (same user, different platforms)
|
|
329
|
-
config.use_cross_platform_sessions
|
|
330
|
-
|
|
331
|
-
# Multi-tenant isolation
|
|
332
|
-
config.use_url_isolation
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
## Next Steps
|
|
336
|
-
|
|
337
|
-
Now that you have a basic multi-platform application running:
|
|
338
|
-
|
|
339
|
-
1. **Explore Platform Features**: Learn platform-specific capabilities
|
|
340
|
-
- [USSD Development](platforms/ussd.md) - Pagination, choice mapping
|
|
341
|
-
- [WhatsApp Development](platforms/whatsapp.md) - Rich media, templates
|
|
342
|
-
- [Telegram Development](platforms/telegram.md) - Inline keyboards, media, callbacks
|
|
343
|
-
- [HTTP Development](platforms/http.md) - API integration patterns
|
|
344
|
-
|
|
345
|
-
2. **Advanced Topics**:
|
|
346
|
-
- [Session Management](../session-management.md) - Deep dive into session boundaries
|
|
347
|
-
- [Middleware Development](../middleware.md) - Custom processing logic
|
|
348
|
-
- [Gateway Development](../gateway-development.md) - Build your own platform support
|
|
349
|
-
|
|
350
|
-
3. **Production Deployment**:
|
|
351
|
-
- [Configuration](../configuration.md) - Production-ready settings
|
|
352
|
-
- [Background Jobs](../background-jobs.md) - Async processing for WhatsApp
|
|
353
|
-
- [Testing](../testing.md) - Comprehensive testing strategies
|
|
354
|
-
|
|
355
|
-
## Common Patterns
|
|
356
|
-
|
|
357
|
-
### Validation and Transformation
|
|
358
|
-
|
|
359
|
-
```ruby
|
|
360
|
-
app.screen(:phone) do |prompt|
|
|
361
|
-
prompt.ask "Enter your phone number:",
|
|
362
|
-
validate: ->(input) {
|
|
363
|
-
return "Invalid phone format" unless input.match?(/^\+?[\d\s-()]+$/)
|
|
364
|
-
parsed = Phonelib.parse(input)
|
|
365
|
-
return "Invalid phone number" unless parsed.valid?
|
|
366
|
-
nil
|
|
367
|
-
},
|
|
368
|
-
transform: ->(input) { Phonelib.parse(input).e164 }
|
|
369
|
-
end
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
### Conditional Flow Logic
|
|
373
|
-
|
|
374
|
-
```ruby
|
|
375
|
-
def main_menu
|
|
376
|
-
user_type = determine_user_type(app.msisdn)
|
|
377
|
-
|
|
378
|
-
if user_type == :premium
|
|
379
|
-
premium_menu
|
|
380
|
-
else
|
|
381
|
-
basic_menu
|
|
382
|
-
end
|
|
383
|
-
end
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
### Error Handling
|
|
387
|
-
|
|
388
|
-
```ruby
|
|
389
|
-
def payment_flow
|
|
390
|
-
begin
|
|
391
|
-
amount = app.screen(:amount) { |p| p.ask "Enter amount:" }
|
|
392
|
-
process_payment(amount)
|
|
393
|
-
app.say "Payment successful!"
|
|
394
|
-
rescue PaymentError => e
|
|
395
|
-
app.say "Payment failed: #{e.message}"
|
|
396
|
-
end
|
|
397
|
-
end
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
## Troubleshooting
|
|
401
|
-
|
|
402
|
-
### Common Issues
|
|
403
|
-
|
|
404
|
-
1. **Session Not Persisting**
|
|
405
|
-
- Check your session store configuration
|
|
406
|
-
- Verify session boundaries match your use case
|
|
407
|
-
|
|
408
|
-
2. **Gateway Errors**
|
|
409
|
-
- Ensure environment variables are set correctly
|
|
410
|
-
- Check gateway-specific configuration requirements
|
|
411
|
-
|
|
412
|
-
3. **Platform Differences**
|
|
413
|
-
- Test flows on each platform's simulator
|
|
414
|
-
- Be aware of character limits (USSD) vs rich features (WhatsApp)
|
|
415
|
-
|
|
416
|
-
### Debug Mode
|
|
417
|
-
|
|
418
|
-
Enable comprehensive logging:
|
|
419
|
-
|
|
420
|
-
```ruby
|
|
421
|
-
# config/initializers/flow_chat.rb
|
|
422
|
-
FlowChat::Config.logger.level = Logger::DEBUG
|
|
423
|
-
|
|
424
|
-
# In your flow
|
|
425
|
-
Rails.logger.debug "Current screen: #{app.navigation_stack.last}"
|
|
426
|
-
Rails.logger.debug "User input: #{app.input.inspect}"
|
|
427
|
-
```
|
|
87
|
+
## Next steps
|
|
428
88
|
|
|
429
|
-
|
|
89
|
+
- [configuration.md](configuration.md) for the full config surface and session options.
|
|
90
|
+
- [platforms/ussd.md](platforms/ussd.md), [platforms/whatsapp.md](platforms/whatsapp.md), and [platforms/telegram.md](platforms/telegram.md) for platform-specific behavior.
|