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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +92 -0
- data/LICENSE.txt +21 -0
- data/README.md +173 -0
- data/Rakefile +8 -0
- data/lib/mbuzz/api.rb +102 -0
- data/lib/mbuzz/client/conversion_request.rb +85 -0
- data/lib/mbuzz/client/identify_request.rb +37 -0
- data/lib/mbuzz/client/session_request.rb +43 -0
- data/lib/mbuzz/client/track_request.rb +50 -0
- data/lib/mbuzz/client.rb +36 -0
- data/lib/mbuzz/configuration.rb +51 -0
- data/lib/mbuzz/controller_helpers.rb +34 -0
- data/lib/mbuzz/middleware/tracking.rb +157 -0
- data/lib/mbuzz/railtie.rb +13 -0
- data/lib/mbuzz/request_context.rb +40 -0
- data/lib/mbuzz/version.rb +5 -0
- data/lib/mbuzz/visitor/identifier.rb +13 -0
- data/lib/mbuzz.rb +178 -0
- data/lib/specs/old/SPECIFICATION.md +695 -0
- data/lib/specs/old/conversions.md +585 -0
- data/lib/specs/old/event_ids_response.md +346 -0
- data/lib/specs/old/v0.2.0_breaking_changes.md +519 -0
- data/lib/specs/old/v2.0.0_sessions_upgrade.md +265 -0
- data/lib/specs/v0.5.0_four_call_model.md +505 -0
- data/mbuzz-0.6.0.gem +0 -0
- data/sig/mbuzz.rbs +4 -0
- metadata +89 -0
|
@@ -0,0 +1,695 @@
|
|
|
1
|
+
# mbuzz Ruby Gem - Technical Specification
|
|
2
|
+
|
|
3
|
+
**Version**: 1.0.0
|
|
4
|
+
**Created**: 2025-11-17
|
|
5
|
+
**Status**: Ready for Implementation
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
A minimal, framework-agnostic Ruby gem for server-side multi-touch attribution tracking. The gem acts as a lightweight client wrapper that captures tracking events and sends them to the mbuzz SaaS API.
|
|
12
|
+
|
|
13
|
+
**Design Philosophy**: Inspired by Segment's analytics-ruby - simple class methods with named parameters, zero dependencies, and silent error handling.
|
|
14
|
+
|
|
15
|
+
**Primary Framework**: Rails (with expansion to Sinatra, Hanami, and other Ruby frameworks in future versions)
|
|
16
|
+
|
|
17
|
+
**Gem Name**: `mbuzz`
|
|
18
|
+
**Backend API**: Rails application at `mbuzz.co/api`
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## System Architecture
|
|
23
|
+
|
|
24
|
+
### High-Level Flow
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
28
|
+
│ CLIENT APPLICATION (Rails, Sinatra, etc.) │
|
|
29
|
+
│ │
|
|
30
|
+
│ ┌────────────────────────────────────────────────────────┐ │
|
|
31
|
+
│ │ mbuzz Gem (Client Library) │ │
|
|
32
|
+
│ │ │ │
|
|
33
|
+
│ │ Mbuzz.track(user_id: 1, event: 'Signup') │ │
|
|
34
|
+
│ │ Mbuzz.identify(user_id: 1, traits: {...}) │ │
|
|
35
|
+
│ │ Mbuzz.alias(user_id: 1, previous_id: 'abc') │ │
|
|
36
|
+
│ └────────────────────┬───────────────────────────────────┘ │
|
|
37
|
+
│ │ │
|
|
38
|
+
└───────────────────────┼──────────────────────────────────────┘
|
|
39
|
+
│ HTTP/JSON
|
|
40
|
+
│ Bearer Token Auth
|
|
41
|
+
▼
|
|
42
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
43
|
+
│ MBUZZ BACKEND (Rails at mbuzz.co/api) │
|
|
44
|
+
│ │
|
|
45
|
+
│ POST /api/v1/events │
|
|
46
|
+
│ GET /api/v1/validate │
|
|
47
|
+
│ GET /api/v1/health │
|
|
48
|
+
│ │
|
|
49
|
+
│ Services: │
|
|
50
|
+
│ - ApiKeys::AuthenticationService │
|
|
51
|
+
│ - Events::IngestionService │
|
|
52
|
+
│ - Events::ProcessingService (async via Solid Queue) │
|
|
53
|
+
│ - Events::ValidationService │
|
|
54
|
+
│ - Events::EnrichmentService │
|
|
55
|
+
│ - Visitors::IdentificationService │
|
|
56
|
+
│ - Visitors::LookupService │
|
|
57
|
+
│ - Sessions::IdentificationService │
|
|
58
|
+
│ - Sessions::TrackingService │
|
|
59
|
+
│ - Sessions::UtmCaptureService │
|
|
60
|
+
│ - Sessions::ChannelAttributionService │
|
|
61
|
+
│ │
|
|
62
|
+
│ Returns Set-Cookie headers for visitor/session tracking │
|
|
63
|
+
└─────────────────────────────────────────────────────────────┘
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Gem Responsibilities
|
|
67
|
+
|
|
68
|
+
**Capture**:
|
|
69
|
+
- Request context (URL, referrer, cookies, user agent)
|
|
70
|
+
- Generate visitor IDs if not present in cookies
|
|
71
|
+
- Build event payloads
|
|
72
|
+
|
|
73
|
+
**Send**:
|
|
74
|
+
- HTTP POST requests to `https://mbuzz.co/api/v1/events`
|
|
75
|
+
- Bearer token authentication
|
|
76
|
+
- Batch event submission (array of events)
|
|
77
|
+
|
|
78
|
+
**Integrate**:
|
|
79
|
+
- Forward Set-Cookie headers from API response
|
|
80
|
+
- Provide Rails middleware for automatic page view tracking
|
|
81
|
+
- Expose controller helpers for visitor ID access
|
|
82
|
+
|
|
83
|
+
**Resilience**:
|
|
84
|
+
- Handle errors gracefully (never raise exceptions)
|
|
85
|
+
- Log failures in debug mode
|
|
86
|
+
- Return boolean success indicators
|
|
87
|
+
|
|
88
|
+
### Backend Responsibilities
|
|
89
|
+
|
|
90
|
+
The mbuzz Rails backend (already implemented at mbuzz.co) handles:
|
|
91
|
+
|
|
92
|
+
**Authentication**:
|
|
93
|
+
- `ApiKeys::AuthenticationService` - Validates Bearer tokens
|
|
94
|
+
- `ApiKeys::RateLimiterService` - Enforces rate limits per account
|
|
95
|
+
|
|
96
|
+
**Event Processing**:
|
|
97
|
+
- `Events::IngestionService` - Accepts batch of events, validates, enqueues
|
|
98
|
+
- `Events::ValidationService` - Schema validation
|
|
99
|
+
- `Events::EnrichmentService` - Adds request metadata (URL, referrer, user agent)
|
|
100
|
+
- `Events::ProcessingService` - Async processing via Solid Queue jobs
|
|
101
|
+
|
|
102
|
+
**Visitor & Session Management**:
|
|
103
|
+
- `Visitors::IdentificationService` - Generates visitor IDs, manages cookies
|
|
104
|
+
- `Visitors::LookupService` - Find or create visitor records
|
|
105
|
+
- `Sessions::IdentificationService` - Manages session lifecycle
|
|
106
|
+
- `Sessions::TrackingService` - Creates/updates sessions
|
|
107
|
+
- `Sessions::UtmCaptureService` - Extracts UTM parameters from URLs
|
|
108
|
+
- `Sessions::ChannelAttributionService` - Derives channel from UTM/referrer
|
|
109
|
+
|
|
110
|
+
**Response**:
|
|
111
|
+
- Returns 202 Accepted for successful ingestion
|
|
112
|
+
- Returns Set-Cookie headers for `_mbuzz_vid` and `_mbuzz_sid`
|
|
113
|
+
- Returns accepted/rejected counts
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Gem Structure
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
mbuzz-ruby/
|
|
121
|
+
├── lib/
|
|
122
|
+
│ ├── mbuzz.rb # Main module & public API
|
|
123
|
+
│ └── mbuzz/
|
|
124
|
+
│ ├── version.rb # Gem version (1.0.0)
|
|
125
|
+
│ ├── configuration.rb # Config management
|
|
126
|
+
│ ├── client.rb # Core API (track, identify, alias)
|
|
127
|
+
│ ├── request_context.rb # Thread-safe request capture
|
|
128
|
+
│ ├── api.rb # HTTP client (net/http)
|
|
129
|
+
│ ├── visitor/
|
|
130
|
+
│ │ └── identifier.rb # Visitor ID generation
|
|
131
|
+
│ ├── middleware/
|
|
132
|
+
│ │ └── tracking.rb # Rack middleware
|
|
133
|
+
│ ├── controller_helpers.rb # Rails helpers
|
|
134
|
+
│ └── railtie.rb # Rails integration
|
|
135
|
+
├── test/ # Minitest test suite
|
|
136
|
+
├── mbuzz.gemspec
|
|
137
|
+
├── README.md
|
|
138
|
+
├── SPECIFICATION.md
|
|
139
|
+
├── CHANGELOG.md
|
|
140
|
+
└── LICENSE.txt
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Public API
|
|
146
|
+
|
|
147
|
+
### Mbuzz Module
|
|
148
|
+
|
|
149
|
+
The main namespace exposing three core methods:
|
|
150
|
+
|
|
151
|
+
#### Mbuzz.configure
|
|
152
|
+
|
|
153
|
+
Configure the gem with API credentials and options.
|
|
154
|
+
|
|
155
|
+
**Required Configuration**:
|
|
156
|
+
- `api_key` - Format: `sk_{environment}_{random}` (from mbuzz.co dashboard)
|
|
157
|
+
|
|
158
|
+
**Optional Configuration**:
|
|
159
|
+
- `api_url` - Defaults to `https://mbuzz.co/api/v1`
|
|
160
|
+
- `enabled` - Defaults to `true` (set `false` in test environment)
|
|
161
|
+
- `debug` - Defaults to `false` (enables verbose logging)
|
|
162
|
+
- `timeout` - Defaults to `5` seconds for HTTP requests
|
|
163
|
+
|
|
164
|
+
#### Mbuzz.track
|
|
165
|
+
|
|
166
|
+
Track events (page views, conversions, custom events).
|
|
167
|
+
|
|
168
|
+
**Parameters**:
|
|
169
|
+
- `user_id` - Database user ID (required if no anonymous_id)
|
|
170
|
+
- `anonymous_id` - Visitor ID from cookies (required if no user_id)
|
|
171
|
+
- `event` - Event name string (required)
|
|
172
|
+
- `properties` - Hash of event metadata (optional)
|
|
173
|
+
- `timestamp` - When event occurred (optional, defaults to now)
|
|
174
|
+
|
|
175
|
+
**Returns**:
|
|
176
|
+
- Success: `{ success: true, event_id: "evt_abc123" }`
|
|
177
|
+
- Failure: `false`
|
|
178
|
+
|
|
179
|
+
**Example**:
|
|
180
|
+
```ruby
|
|
181
|
+
result = Mbuzz::Client.track(
|
|
182
|
+
visitor_id: "abc123",
|
|
183
|
+
event_type: "page_view",
|
|
184
|
+
properties: { url: "https://example.com" }
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
if result[:success]
|
|
188
|
+
puts "Event tracked: #{result[:event_id]}"
|
|
189
|
+
end
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Backend Processing**: Events sent to `POST https://mbuzz.co/api/v1/events`, validated, enriched, and processed synchronously. Returns event ID with `evt_` prefix.
|
|
193
|
+
|
|
194
|
+
#### Mbuzz.identify
|
|
195
|
+
|
|
196
|
+
Associate traits with a user ID.
|
|
197
|
+
|
|
198
|
+
**Parameters**:
|
|
199
|
+
- `user_id` - Required
|
|
200
|
+
- `traits` - Hash of user attributes (email, name, plan, etc.)
|
|
201
|
+
- `timestamp` - Optional
|
|
202
|
+
|
|
203
|
+
**Returns**: `true` on success, `false` on failure
|
|
204
|
+
|
|
205
|
+
**Use Cases**:
|
|
206
|
+
- On signup (link user_id to visitor)
|
|
207
|
+
- When user attributes change
|
|
208
|
+
- On login (to refresh traits)
|
|
209
|
+
|
|
210
|
+
#### Mbuzz.alias
|
|
211
|
+
|
|
212
|
+
Link an anonymous visitor ID to a known user ID.
|
|
213
|
+
|
|
214
|
+
**Parameters**:
|
|
215
|
+
- `user_id` - The known user ID (required)
|
|
216
|
+
- `previous_id` - The anonymous visitor ID (required)
|
|
217
|
+
|
|
218
|
+
**Returns**: `true` on success, `false` on failure
|
|
219
|
+
|
|
220
|
+
**Use Case**: Connect pre-signup anonymous behavior to user account after registration.
|
|
221
|
+
|
|
222
|
+
#### Mbuzz.conversion
|
|
223
|
+
|
|
224
|
+
Track a conversion and retrieve attribution data.
|
|
225
|
+
|
|
226
|
+
**Parameters** (at least one identifier required):
|
|
227
|
+
- `event_id` - Prefixed event ID (`evt_*`) - visitor/session derived from event
|
|
228
|
+
- `visitor_id` - Raw visitor ID (64-char hex from `_mbuzz_vid`) - uses most recent session
|
|
229
|
+
- `conversion_type` - Type of conversion (required, e.g., "purchase", "signup")
|
|
230
|
+
- `revenue` - Revenue amount (optional)
|
|
231
|
+
- `currency` - Currency code (optional, default: "USD")
|
|
232
|
+
- `properties` - Additional metadata (optional)
|
|
233
|
+
|
|
234
|
+
**Returns**:
|
|
235
|
+
- Success: `{ success: true, conversion_id: "conv_...", attribution: {...} }`
|
|
236
|
+
- Failure: `false`
|
|
237
|
+
|
|
238
|
+
**Identifier Resolution**:
|
|
239
|
+
- If `event_id` provided: Use event's visitor and session (most precise)
|
|
240
|
+
- If only `visitor_id`: Look up visitor, use most recent session
|
|
241
|
+
- If both: `event_id` takes precedence
|
|
242
|
+
|
|
243
|
+
**Example**:
|
|
244
|
+
```ruby
|
|
245
|
+
# Event-based (recommended)
|
|
246
|
+
track_result = Mbuzz::Client.track(visitor_id: vid, event_type: "checkout")
|
|
247
|
+
if track_result[:success]
|
|
248
|
+
Mbuzz::Client.conversion(
|
|
249
|
+
event_id: track_result[:event_id],
|
|
250
|
+
conversion_type: "purchase",
|
|
251
|
+
revenue: 99.00
|
|
252
|
+
)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Visitor-based (simpler)
|
|
256
|
+
Mbuzz::Client.conversion(
|
|
257
|
+
visitor_id: vid,
|
|
258
|
+
conversion_type: "purchase",
|
|
259
|
+
revenue: 99.00
|
|
260
|
+
)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Use Cases**:
|
|
264
|
+
| Approach | When to Use |
|
|
265
|
+
|----------|-------------|
|
|
266
|
+
| `event_id` | Tie conversion to specific action (checkout button click) |
|
|
267
|
+
| `visitor_id` | Direct conversions, offline imports, webhook integrations |
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Service Objects
|
|
272
|
+
|
|
273
|
+
The gem uses a clean service object architecture:
|
|
274
|
+
|
|
275
|
+
### Mbuzz::Configuration
|
|
276
|
+
|
|
277
|
+
Manages gem configuration with validation.
|
|
278
|
+
|
|
279
|
+
**Responsibilities**:
|
|
280
|
+
- Store configuration values
|
|
281
|
+
- Validate required fields (API key)
|
|
282
|
+
- Provide defaults (`api_url` defaults to `https://mbuzz.co/api/v1`)
|
|
283
|
+
- Thread-safe access
|
|
284
|
+
|
|
285
|
+
### Mbuzz::Client
|
|
286
|
+
|
|
287
|
+
Orchestrates tracking calls.
|
|
288
|
+
|
|
289
|
+
**Responsibilities**:
|
|
290
|
+
- Validate parameters (user_id/anonymous_id present, event name required)
|
|
291
|
+
- Build event payloads
|
|
292
|
+
- Delegate HTTP calls to `Mbuzz::Api`
|
|
293
|
+
- Handle all errors gracefully
|
|
294
|
+
- Return result hash on success, `false` on failure
|
|
295
|
+
- Log failures in debug mode
|
|
296
|
+
|
|
297
|
+
**Public Methods**:
|
|
298
|
+
- `track(...)` - Track an event, returns `{ success: true, event_id: "evt_..." }` or `false`
|
|
299
|
+
- `identify(...)` - Identify a user, returns `true` or `false`
|
|
300
|
+
- `alias(...)` - Link visitor to user, returns `true` or `false`
|
|
301
|
+
- `conversion(...)` - Track conversion with attribution, returns `{ success: true, conversion_id: "conv_...", attribution: {...} }` or `false`
|
|
302
|
+
|
|
303
|
+
### Mbuzz::Api
|
|
304
|
+
|
|
305
|
+
HTTP client for communicating with mbuzz backend at mbuzz.co/api.
|
|
306
|
+
|
|
307
|
+
**Responsibilities**:
|
|
308
|
+
- Send POST requests to `https://mbuzz.co/api/v1/events`
|
|
309
|
+
- Add `Authorization: Bearer {api_key}` header
|
|
310
|
+
- Add `Content-Type: application/json` header
|
|
311
|
+
- Add `User-Agent: mbuzz-ruby/{version}` header
|
|
312
|
+
- Handle HTTP errors (4xx, 5xx) gracefully
|
|
313
|
+
- Handle network errors (timeout, connection refused)
|
|
314
|
+
- Return parsed response or boolean depending on method
|
|
315
|
+
|
|
316
|
+
**Public Methods**:
|
|
317
|
+
- `post(path, payload)` - Returns `true`/`false` (for identify, alias)
|
|
318
|
+
- `post_with_response(path, payload)` - Returns parsed JSON hash or `nil` (for track, conversion)
|
|
319
|
+
|
|
320
|
+
**Implementation**: Uses Ruby stdlib `net/http` only (zero external dependencies)
|
|
321
|
+
|
|
322
|
+
**Error Handling**: All errors caught, logged, but never raised
|
|
323
|
+
|
|
324
|
+
### Mbuzz::RequestContext
|
|
325
|
+
|
|
326
|
+
Thread-safe request/response storage.
|
|
327
|
+
|
|
328
|
+
**Responsibilities**:
|
|
329
|
+
- Store current request in thread-local variable
|
|
330
|
+
- Provide access to URL, referrer, user agent
|
|
331
|
+
- Clean up after request completes
|
|
332
|
+
- Work safely in multi-threaded environments (Puma, etc.)
|
|
333
|
+
|
|
334
|
+
**Pattern**: Thread-local storage with ensure block cleanup
|
|
335
|
+
|
|
336
|
+
**Public Methods**:
|
|
337
|
+
- `with_context(request:) { ... }` - Store request for block execution
|
|
338
|
+
- `current` - Get current request context (or nil)
|
|
339
|
+
|
|
340
|
+
**Instance Methods**:
|
|
341
|
+
- `url` - Current request URL
|
|
342
|
+
- `referrer` - HTTP Referer header
|
|
343
|
+
- `user_agent` - User-Agent header
|
|
344
|
+
|
|
345
|
+
### Mbuzz::Visitor::Identifier
|
|
346
|
+
|
|
347
|
+
Generates unique visitor IDs.
|
|
348
|
+
|
|
349
|
+
**Responsibilities**:
|
|
350
|
+
- Generate cryptographically secure random IDs
|
|
351
|
+
- Format: 64-character hex string (32 bytes from `SecureRandom`)
|
|
352
|
+
|
|
353
|
+
**Public Methods**:
|
|
354
|
+
- `generate` - Returns new visitor ID
|
|
355
|
+
|
|
356
|
+
**Note**: Backend's `Visitors::IdentificationService` also generates visitor IDs if client doesn't provide one. The gem generates them proactively to ensure consistent visitor tracking.
|
|
357
|
+
|
|
358
|
+
### Mbuzz::Middleware::Tracking
|
|
359
|
+
|
|
360
|
+
Rack middleware for automatic tracking.
|
|
361
|
+
|
|
362
|
+
**Responsibilities**:
|
|
363
|
+
- Capture request context in thread-local storage
|
|
364
|
+
- Track page views automatically for GET requests
|
|
365
|
+
- Filter out asset requests (JS, CSS, images)
|
|
366
|
+
- Clean up context after request completes
|
|
367
|
+
- Forward Set-Cookie headers from backend
|
|
368
|
+
|
|
369
|
+
**Integration**: Auto-installed via `Mbuzz::Railtie` in Rails apps
|
|
370
|
+
|
|
371
|
+
### Mbuzz::ControllerHelpers
|
|
372
|
+
|
|
373
|
+
Rails controller helper methods.
|
|
374
|
+
|
|
375
|
+
**Provides**:
|
|
376
|
+
- `mbuzz_visitor_id` - Get or generate visitor ID from cookies
|
|
377
|
+
|
|
378
|
+
**Usage**: Automatically included in all Rails controllers via Railtie
|
|
379
|
+
|
|
380
|
+
### Mbuzz::Railtie
|
|
381
|
+
|
|
382
|
+
Automatic Rails integration.
|
|
383
|
+
|
|
384
|
+
**Responsibilities**:
|
|
385
|
+
- Insert `Mbuzz::Middleware::Tracking` into Rack stack
|
|
386
|
+
- Include `Mbuzz::ControllerHelpers` in ActionController::Base
|
|
387
|
+
- Configure sensible defaults for Rails environment
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## Backend Integration Points
|
|
392
|
+
|
|
393
|
+
### API Endpoints
|
|
394
|
+
|
|
395
|
+
**POST https://mbuzz.co/api/v1/events**
|
|
396
|
+
- Accepts: `{ events: [{ event_type, user_id, anonymous_id, timestamp, properties }] }`
|
|
397
|
+
- Returns: `{ accepted: 1, rejected: [] }` with 202 Accepted status
|
|
398
|
+
- Processing: `Events::IngestionService` → `Events::ValidationService` → `Events::ProcessingJob`
|
|
399
|
+
|
|
400
|
+
**GET https://mbuzz.co/api/v1/validate**
|
|
401
|
+
- Validates API key
|
|
402
|
+
- Returns account info if valid
|
|
403
|
+
- Used for testing gem configuration
|
|
404
|
+
|
|
405
|
+
**GET https://mbuzz.co/api/v1/health**
|
|
406
|
+
- Health check endpoint
|
|
407
|
+
- Returns 200 OK if backend is healthy
|
|
408
|
+
|
|
409
|
+
### Cookie Management
|
|
410
|
+
|
|
411
|
+
**Visitor Cookie** (`_mbuzz_vid`):
|
|
412
|
+
- Generated by gem's `Mbuzz::Visitor::Identifier` OR backend's `Visitors::IdentificationService`
|
|
413
|
+
- Lifetime: 1 year
|
|
414
|
+
- Format: 64-character hex string
|
|
415
|
+
- Set via `Set-Cookie` header from backend response
|
|
416
|
+
|
|
417
|
+
**Session Cookie** (`_mbuzz_sid`):
|
|
418
|
+
- Generated by backend's `Sessions::IdentificationService`
|
|
419
|
+
- Lifetime: 30 minutes
|
|
420
|
+
- Format: Random hex string
|
|
421
|
+
- Set via `Set-Cookie` header from backend response
|
|
422
|
+
|
|
423
|
+
**Gem Responsibility**: Forward `Set-Cookie` headers from API response to client response
|
|
424
|
+
|
|
425
|
+
### Event Enrichment Flow
|
|
426
|
+
|
|
427
|
+
1. **Client**: Gem captures request context (URL, referrer, user agent)
|
|
428
|
+
2. **Client**: Gem sends event payload to `https://mbuzz.co/api/v1/events`
|
|
429
|
+
3. **Backend**: `Events::EnrichmentService` adds additional metadata
|
|
430
|
+
4. **Backend**: `Events::ValidationService` validates schema
|
|
431
|
+
5. **Backend**: `Events::ProcessingJob` processes asynchronously
|
|
432
|
+
6. **Backend**: `Sessions::UtmCaptureService` extracts UTM parameters
|
|
433
|
+
7. **Backend**: `Sessions::ChannelAttributionService` derives channel
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## Error Handling Philosophy
|
|
438
|
+
|
|
439
|
+
**Never raise exceptions to user code** - All errors are caught and logged.
|
|
440
|
+
|
|
441
|
+
**Error Categories**:
|
|
442
|
+
1. Configuration errors (missing API key)
|
|
443
|
+
2. Validation errors (missing required parameters)
|
|
444
|
+
3. Network errors (timeout, connection refused)
|
|
445
|
+
4. API errors (4xx, 5xx responses)
|
|
446
|
+
|
|
447
|
+
**Handling Strategy**:
|
|
448
|
+
- All public methods return `true` on success, `false` on failure
|
|
449
|
+
- Errors logged to `Rails.logger` (if available)
|
|
450
|
+
- In debug mode, print to STDERR
|
|
451
|
+
- Silent otherwise
|
|
452
|
+
|
|
453
|
+
**Rationale**: Tracking should never break the application.
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
## Features
|
|
458
|
+
|
|
459
|
+
### Phase 1 (MVP - This Gem)
|
|
460
|
+
|
|
461
|
+
**Core Tracking**:
|
|
462
|
+
- ✅ Track events with `Mbuzz.track`
|
|
463
|
+
- ✅ Identify users with `Mbuzz.identify`
|
|
464
|
+
- ✅ Alias visitors with `Mbuzz.alias`
|
|
465
|
+
|
|
466
|
+
**Rails Integration**:
|
|
467
|
+
- ✅ Automatic middleware installation via Railtie
|
|
468
|
+
- ✅ Automatic page view tracking
|
|
469
|
+
- ✅ Controller helper for visitor ID (`mbuzz_visitor_id`)
|
|
470
|
+
- ✅ Thread-safe request context
|
|
471
|
+
|
|
472
|
+
**Technical**:
|
|
473
|
+
- ✅ Zero runtime dependencies
|
|
474
|
+
- ✅ Silent error handling
|
|
475
|
+
- ✅ Bearer token authentication
|
|
476
|
+
- ✅ Synchronous HTTP requests
|
|
477
|
+
|
|
478
|
+
### Phase 2 (Future)
|
|
479
|
+
|
|
480
|
+
**Performance**:
|
|
481
|
+
- Batching events (queue in memory, flush periodically)
|
|
482
|
+
- Retry logic with exponential backoff
|
|
483
|
+
- Circuit breaker pattern
|
|
484
|
+
|
|
485
|
+
**Framework Support**:
|
|
486
|
+
- Sinatra adapter
|
|
487
|
+
- Hanami adapter
|
|
488
|
+
- Plain Rack support
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
## Testing Strategy
|
|
493
|
+
|
|
494
|
+
### Unit Tests
|
|
495
|
+
|
|
496
|
+
Test individual components:
|
|
497
|
+
- Configuration validation
|
|
498
|
+
- Client parameter validation
|
|
499
|
+
- Event payload building
|
|
500
|
+
- Visitor ID generation
|
|
501
|
+
- Request context capture
|
|
502
|
+
- API client HTTP requests
|
|
503
|
+
|
|
504
|
+
### Integration Tests
|
|
505
|
+
|
|
506
|
+
Test Rails integration:
|
|
507
|
+
- Middleware automatically installed
|
|
508
|
+
- Page views tracked
|
|
509
|
+
- Controller helper works
|
|
510
|
+
- Cookies managed correctly
|
|
511
|
+
- Set-Cookie headers forwarded
|
|
512
|
+
|
|
513
|
+
### Test Mode
|
|
514
|
+
|
|
515
|
+
Special mode for testing user applications:
|
|
516
|
+
- Capture calls without sending to API
|
|
517
|
+
- Assert on tracked events
|
|
518
|
+
- Clear captured calls between tests
|
|
519
|
+
|
|
520
|
+
---
|
|
521
|
+
|
|
522
|
+
## Dependencies
|
|
523
|
+
|
|
524
|
+
**Runtime**: ZERO
|
|
525
|
+
|
|
526
|
+
Uses only Ruby standard library:
|
|
527
|
+
- `net/http` - HTTP client
|
|
528
|
+
- `json` - JSON encoding/decoding
|
|
529
|
+
- `securerandom` - Visitor ID generation
|
|
530
|
+
- `uri` - URL parsing
|
|
531
|
+
|
|
532
|
+
**Development**:
|
|
533
|
+
- `minitest` - Testing framework
|
|
534
|
+
- `rake` - Build tasks
|
|
535
|
+
- `bundler` - Dependency management
|
|
536
|
+
|
|
537
|
+
**No external gems required** - Keeps gem size small and avoids dependency conflicts.
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## API Communication
|
|
542
|
+
|
|
543
|
+
### Authentication
|
|
544
|
+
|
|
545
|
+
**Method**: Bearer token in Authorization header
|
|
546
|
+
**Format**: `Authorization: Bearer sk_live_abc123...`
|
|
547
|
+
**Validation**: Backend's `ApiKeys::AuthenticationService` validates token
|
|
548
|
+
|
|
549
|
+
### Request Format
|
|
550
|
+
|
|
551
|
+
**Endpoint**: `POST https://mbuzz.co/api/v1/events`
|
|
552
|
+
|
|
553
|
+
**Headers**:
|
|
554
|
+
- `Authorization: Bearer {api_key}`
|
|
555
|
+
- `Content-Type: application/json`
|
|
556
|
+
- `User-Agent: mbuzz-ruby/{version}`
|
|
557
|
+
|
|
558
|
+
**Body**:
|
|
559
|
+
```json
|
|
560
|
+
{
|
|
561
|
+
"events": [{
|
|
562
|
+
"event_type": "Signup",
|
|
563
|
+
"user_id": "123",
|
|
564
|
+
"timestamp": "2025-11-17T10:30:00Z",
|
|
565
|
+
"properties": {
|
|
566
|
+
"url": "https://example.com/signup",
|
|
567
|
+
"referrer": "https://google.com",
|
|
568
|
+
"user_agent": "Mozilla/5.0...",
|
|
569
|
+
"plan": "pro"
|
|
570
|
+
}
|
|
571
|
+
}]
|
|
572
|
+
}
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Response Format
|
|
576
|
+
|
|
577
|
+
**Success** (202 Accepted):
|
|
578
|
+
```json
|
|
579
|
+
{
|
|
580
|
+
"accepted": 1,
|
|
581
|
+
"rejected": [],
|
|
582
|
+
"events": [
|
|
583
|
+
{
|
|
584
|
+
"id": "evt_abc123def456",
|
|
585
|
+
"event_type": "Signup",
|
|
586
|
+
"visitor_id": "65dabef8d611f332...",
|
|
587
|
+
"session_id": "xyz789...",
|
|
588
|
+
"status": "accepted"
|
|
589
|
+
}
|
|
590
|
+
]
|
|
591
|
+
}
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
**Event ID Format**: Prefixed IDs with `evt_` prefix (e.g., `evt_abc123def456`). These IDs can be used to:
|
|
595
|
+
- Link events to conversions via the `event_id` parameter
|
|
596
|
+
- Debug and trace specific events
|
|
597
|
+
- Reference events in support requests
|
|
598
|
+
|
|
599
|
+
**Headers**:
|
|
600
|
+
```
|
|
601
|
+
Set-Cookie: _mbuzz_vid=abc123...; Max-Age=31536000; HttpOnly; Secure; SameSite=Lax
|
|
602
|
+
Set-Cookie: _mbuzz_sid=xyz789...; Max-Age=1800; HttpOnly; Secure; SameSite=Lax
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
**Gem Responsibility**: Forward these Set-Cookie headers to the client response.
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
## Comparison to Segment
|
|
610
|
+
|
|
611
|
+
| Feature | Segment | mbuzz |
|
|
612
|
+
|---------|---------|-------|
|
|
613
|
+
| API Style | `Analytics.track(...)` | `Mbuzz.track(...)` |
|
|
614
|
+
| Dependencies | Many (faraday, concurrent-ruby) | **Zero** |
|
|
615
|
+
| Size | ~2000 LOC | ~500 LOC |
|
|
616
|
+
| Focus | Multi-destination routing | Single destination |
|
|
617
|
+
| Batching | Yes | Phase 2 |
|
|
618
|
+
| Async | Yes (thread pool) | Phase 2 |
|
|
619
|
+
| Framework Support | Many | Rails (expanding) |
|
|
620
|
+
| Server-side | Yes | Yes |
|
|
621
|
+
| Attribution Focus | No | **Yes** |
|
|
622
|
+
|
|
623
|
+
**mbuzz advantages**:
|
|
624
|
+
- Smaller, simpler codebase
|
|
625
|
+
- Zero dependencies
|
|
626
|
+
- Purpose-built for multi-touch attribution
|
|
627
|
+
- Tight integration with mbuzz backend services
|
|
628
|
+
|
|
629
|
+
---
|
|
630
|
+
|
|
631
|
+
## Implementation Phases
|
|
632
|
+
|
|
633
|
+
### Phase 1: Core Functionality (v1.0) - This Gem
|
|
634
|
+
|
|
635
|
+
- Configuration management (`Mbuzz.configure`)
|
|
636
|
+
- Client API (`Mbuzz.track`, `identify`, `alias`)
|
|
637
|
+
- HTTP client with `net/http`
|
|
638
|
+
- Request context (thread-safe)
|
|
639
|
+
- Visitor identification
|
|
640
|
+
- Rails integration (middleware, helpers, railtie)
|
|
641
|
+
- Error handling (silent failures)
|
|
642
|
+
- Test suite (>95% coverage)
|
|
643
|
+
- Documentation (README, SPECIFICATION)
|
|
644
|
+
|
|
645
|
+
### Phase 2: Performance & Reliability
|
|
646
|
+
|
|
647
|
+
- Event batching and queuing
|
|
648
|
+
- Retry logic with exponential backoff
|
|
649
|
+
- Circuit breaker for API failures
|
|
650
|
+
- Metrics and instrumentation
|
|
651
|
+
|
|
652
|
+
### Phase 3: Framework Expansion
|
|
653
|
+
|
|
654
|
+
- Sinatra support
|
|
655
|
+
- Hanami support
|
|
656
|
+
- Generic Rack adapter
|
|
657
|
+
|
|
658
|
+
---
|
|
659
|
+
|
|
660
|
+
## Success Criteria
|
|
661
|
+
|
|
662
|
+
**Functional**:
|
|
663
|
+
- ✅ Track events from anywhere (controllers, jobs, models)
|
|
664
|
+
- ✅ Automatic page view tracking in Rails
|
|
665
|
+
- ✅ Anonymous visitor tracking with cookies
|
|
666
|
+
- ✅ User identification and aliasing
|
|
667
|
+
- ✅ Request context enrichment
|
|
668
|
+
|
|
669
|
+
**Technical**:
|
|
670
|
+
- ✅ Zero runtime dependencies
|
|
671
|
+
- ✅ Silent error handling (never raises)
|
|
672
|
+
- ✅ Thread-safe in multi-threaded environments
|
|
673
|
+
- ✅ Integrates with mbuzz backend services at mbuzz.co/api
|
|
674
|
+
- ✅ Comprehensive test coverage (>95%)
|
|
675
|
+
|
|
676
|
+
**User Experience**:
|
|
677
|
+
- ✅ Simple, Segment-like API
|
|
678
|
+
- ✅ Automatic Rails integration via Railtie
|
|
679
|
+
- ✅ Clear documentation with examples
|
|
680
|
+
- ✅ Graceful degradation (tracking failures don't break app)
|
|
681
|
+
|
|
682
|
+
---
|
|
683
|
+
|
|
684
|
+
## Version History
|
|
685
|
+
|
|
686
|
+
- **v1.0.0** - Initial release
|
|
687
|
+
- Core tracking (track, identify, alias)
|
|
688
|
+
- Rails integration (middleware, helpers)
|
|
689
|
+
- Zero dependencies
|
|
690
|
+
- Silent error handling
|
|
691
|
+
- Integration with mbuzz backend at mbuzz.co/api
|
|
692
|
+
|
|
693
|
+
---
|
|
694
|
+
|
|
695
|
+
Built for mbuzz.co
|