mbuzz 0.6.2

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.
@@ -0,0 +1,346 @@
1
+ # Event IDs in API Response - Technical Specification
2
+
3
+ **Version**: 1.1.0
4
+ **Created**: 2025-11-26
5
+ **Status**: Ready for Implementation
6
+ **Breaking Change**: Yes (return type change for `track`)
7
+
8
+ ---
9
+
10
+ ## Overview
11
+
12
+ Update the Ruby SDK to return event IDs from the API response. This enables users to:
13
+ 1. Link events to conversions via the `event_id` parameter
14
+ 2. Debug and trace specific events
15
+ 3. Reference events in support requests
16
+
17
+ ---
18
+
19
+ ## Breaking Change
20
+
21
+ ### Before (v1.0)
22
+
23
+ ```ruby
24
+ result = Mbuzz::Client.track(
25
+ visitor_id: "abc123",
26
+ event_type: "page_view",
27
+ properties: { url: "https://example.com" }
28
+ )
29
+ # => true or false
30
+ ```
31
+
32
+ ### After (v1.1)
33
+
34
+ ```ruby
35
+ result = Mbuzz::Client.track(
36
+ visitor_id: "abc123",
37
+ event_type: "page_view",
38
+ properties: { url: "https://example.com" }
39
+ )
40
+ # => { success: true, event_id: "evt_abc123" } or false
41
+ ```
42
+
43
+ ### Migration Guide
44
+
45
+ **Existing code** (still works):
46
+ ```ruby
47
+ # Boolean check still works because Hash is truthy
48
+ if Mbuzz::Client.track(visitor_id: vid, event_type: "page_view")
49
+ puts "Event tracked"
50
+ end
51
+ ```
52
+
53
+ **New code** (recommended):
54
+ ```ruby
55
+ result = Mbuzz::Client.track(visitor_id: vid, event_type: "page_view")
56
+ if result && result[:success]
57
+ puts "Event ID: #{result[:event_id]}"
58
+ end
59
+
60
+ # Or with safe navigation
61
+ if result&.dig(:success)
62
+ event_id = result[:event_id]
63
+ end
64
+ ```
65
+
66
+ ---
67
+
68
+ ## API Changes
69
+
70
+ ### Backend Response Format
71
+
72
+ The Events API now returns event details in the response:
73
+
74
+ **POST /api/v1/events**
75
+
76
+ ```json
77
+ {
78
+ "accepted": 1,
79
+ "rejected": [],
80
+ "events": [
81
+ {
82
+ "id": "evt_abc123def456",
83
+ "event_type": "page_view",
84
+ "visitor_id": "65dabef8d611f332d5bb88f5d6870c733d89f962594575b66f0e1de1ede1ebf0",
85
+ "session_id": "sess_xyz789",
86
+ "status": "accepted"
87
+ }
88
+ ]
89
+ }
90
+ ```
91
+
92
+ ### Event ID Format
93
+
94
+ - **Prefix**: `evt_`
95
+ - **Entropy**: 128-bit (32 hex characters after prefix)
96
+ - **Example**: `evt_abc123def456789...`
97
+ - **Security**: Account-scoped, not guessable
98
+
99
+ ---
100
+
101
+ ## Implementation
102
+
103
+ ### Mbuzz::Api Changes
104
+
105
+ Add new method to return parsed response:
106
+
107
+ ```ruby
108
+ # lib/mbuzz/api.rb
109
+
110
+ def self.post_with_response(path, payload)
111
+ return nil unless enabled_and_configured?
112
+
113
+ response = http_client(path).request(build_request(path, payload))
114
+ return nil unless success?(response)
115
+
116
+ JSON.parse(response.body)
117
+ rescue ConfigurationError, Net::ReadTimeout, Net::OpenTimeout, Net::HTTPError, JSON::ParserError => e
118
+ log_error("#{e.class}: #{e.message}")
119
+ nil
120
+ end
121
+ ```
122
+
123
+ ### Mbuzz::Client Changes
124
+
125
+ Update `track` to use new API method and return event ID:
126
+
127
+ ```ruby
128
+ # lib/mbuzz/client.rb
129
+
130
+ def self.track(user_id: nil, visitor_id: nil, event_type:, properties: {})
131
+ return false unless valid_event_type?(event_type)
132
+ return false unless valid_properties?(properties)
133
+ return false unless valid_identifier?(user_id, visitor_id)
134
+
135
+ event = {
136
+ user_id: user_id,
137
+ visitor_id: visitor_id,
138
+ event_type: event_type,
139
+ properties: properties,
140
+ timestamp: Time.now.utc.iso8601
141
+ }.compact
142
+
143
+ response = Api.post_with_response(EVENTS_PATH, { events: [event] })
144
+ return false unless response
145
+
146
+ event_data = response["events"]&.first
147
+ return false unless event_data
148
+
149
+ {
150
+ success: true,
151
+ event_id: event_data["id"],
152
+ event_type: event_data["event_type"],
153
+ visitor_id: event_data["visitor_id"],
154
+ session_id: event_data["session_id"]
155
+ }
156
+ rescue StandardError => e
157
+ log_error("Track error: #{e.message}")
158
+ false
159
+ end
160
+
161
+ private_class_method def self.log_error(message)
162
+ warn "[mbuzz] #{message}" if Mbuzz.config.debug
163
+ end
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Use Cases
169
+
170
+ ### 1. Link Event to Conversion
171
+
172
+ ```ruby
173
+ # Track the purchase event
174
+ result = Mbuzz::Client.track(
175
+ visitor_id: mbuzz_visitor_id,
176
+ event_type: "purchase_completed",
177
+ properties: { order_id: order.id, total: order.total }
178
+ )
179
+
180
+ # Create conversion linked to the event
181
+ if result[:success]
182
+ Mbuzz::Client.conversion(
183
+ visitor_id: mbuzz_visitor_id,
184
+ conversion_type: "purchase",
185
+ revenue: order.total,
186
+ event_id: result[:event_id] # Link to triggering event
187
+ )
188
+ end
189
+ ```
190
+
191
+ ### 2. Debug Event Flow
192
+
193
+ ```ruby
194
+ result = Mbuzz::Client.track(
195
+ visitor_id: visitor_id,
196
+ event_type: "signup",
197
+ properties: { plan: "pro" }
198
+ )
199
+
200
+ if result[:success]
201
+ Rails.logger.info "Tracked signup: #{result[:event_id]} for visitor #{result[:visitor_id]}"
202
+ else
203
+ Rails.logger.warn "Failed to track signup for visitor #{visitor_id}"
204
+ end
205
+ ```
206
+
207
+ ### 3. Store Event References
208
+
209
+ ```ruby
210
+ class Order < ApplicationRecord
211
+ def track_purchase
212
+ result = Mbuzz::Client.track(
213
+ visitor_id: user.mbuzz_visitor_id,
214
+ event_type: "purchase",
215
+ properties: { order_id: id, total: total }
216
+ )
217
+
218
+ update!(mbuzz_event_id: result[:event_id]) if result[:success]
219
+ end
220
+ end
221
+ ```
222
+
223
+ ---
224
+
225
+ ## Testing
226
+
227
+ ### Unit Tests
228
+
229
+ ```ruby
230
+ class ClientTrackTest < Minitest::Test
231
+ def test_track_returns_event_id_on_success
232
+ stub_successful_events_response
233
+
234
+ result = Mbuzz::Client.track(
235
+ visitor_id: "abc123",
236
+ event_type: "page_view"
237
+ )
238
+
239
+ assert result[:success]
240
+ assert result[:event_id].start_with?("evt_")
241
+ end
242
+
243
+ def test_track_returns_false_on_validation_failure
244
+ result = Mbuzz::Client.track(
245
+ visitor_id: nil,
246
+ event_type: "page_view"
247
+ )
248
+
249
+ assert_equal false, result
250
+ end
251
+
252
+ def test_track_returns_false_on_api_failure
253
+ stub_failed_events_response
254
+
255
+ result = Mbuzz::Client.track(
256
+ visitor_id: "abc123",
257
+ event_type: "page_view"
258
+ )
259
+
260
+ assert_equal false, result
261
+ end
262
+
263
+ def test_track_still_truthy_for_boolean_checks
264
+ stub_successful_events_response
265
+
266
+ result = Mbuzz::Client.track(
267
+ visitor_id: "abc123",
268
+ event_type: "page_view"
269
+ )
270
+
271
+ # Backwards compatibility: result is truthy
272
+ assert result
273
+ if result
274
+ assert true, "Boolean check still works"
275
+ end
276
+ end
277
+ end
278
+ ```
279
+
280
+ ### Integration Test
281
+
282
+ ```ruby
283
+ def test_track_and_conversion_with_event_id
284
+ visitor_id = "test_#{SecureRandom.hex(8)}"
285
+
286
+ # Track event
287
+ track_result = Mbuzz::Client.track(
288
+ visitor_id: visitor_id,
289
+ event_type: "signup",
290
+ properties: { plan: "pro" }
291
+ )
292
+
293
+ assert track_result[:success]
294
+ assert track_result[:event_id].present?
295
+
296
+ # Create conversion linked to event
297
+ conv_result = Mbuzz::Client.conversion(
298
+ visitor_id: visitor_id,
299
+ conversion_type: "signup",
300
+ event_id: track_result[:event_id]
301
+ )
302
+
303
+ assert conv_result[:success]
304
+ assert conv_result[:conversion_id].present?
305
+ end
306
+ ```
307
+
308
+ ---
309
+
310
+ ## Backwards Compatibility
311
+
312
+ The change is **mostly backwards compatible**:
313
+
314
+ | Pattern | v1.0 | v1.1 | Works? |
315
+ |---------|------|------|--------|
316
+ | `if Mbuzz::Client.track(...)` | `true` | `{ success: true, ... }` | ✅ Yes (Hash is truthy) |
317
+ | `result == true` | `true` | `{ ... }` | ❌ No |
318
+ | `result[:event_id]` | Error | `"evt_..."` | ✅ Yes (new feature) |
319
+ | `!result` | `false` | `false` | ✅ Yes |
320
+
321
+ **Recommendation**: Update code to check `result[:success]` instead of `result == true`.
322
+
323
+ ---
324
+
325
+ ## Version Bump
326
+
327
+ This is a minor version bump (1.0 → 1.1) because:
328
+ - Return type change could break `result == true` checks
329
+ - New functionality added (event IDs)
330
+ - Existing boolean checks still work (Hash is truthy)
331
+
332
+ ---
333
+
334
+ ## Success Criteria
335
+
336
+ - [ ] `Api.post_with_response` method implemented
337
+ - [ ] `Client.track` returns hash with event_id on success
338
+ - [ ] `Client.track` returns `false` on failure (unchanged)
339
+ - [ ] Boolean checks still work (backwards compatible)
340
+ - [ ] Unit tests cover all cases
341
+ - [ ] Integration test validates event_id linking to conversion
342
+ - [ ] CHANGELOG updated with breaking change note
343
+
344
+ ---
345
+
346
+ Built for mbuzz.co