e11y 0.1.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 (157) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +4 -0
  3. data/.rubocop.yml +69 -0
  4. data/CHANGELOG.md +26 -0
  5. data/CODE_OF_CONDUCT.md +64 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +179 -0
  8. data/Rakefile +37 -0
  9. data/benchmarks/run_all.rb +33 -0
  10. data/config/README.md +83 -0
  11. data/config/loki-local-config.yaml +35 -0
  12. data/config/prometheus.yml +15 -0
  13. data/docker-compose.yml +78 -0
  14. data/docs/00-ICP-AND-TIMELINE.md +483 -0
  15. data/docs/01-SCALE-REQUIREMENTS.md +858 -0
  16. data/docs/ADR-001-architecture.md +2617 -0
  17. data/docs/ADR-002-metrics-yabeda.md +1395 -0
  18. data/docs/ADR-003-slo-observability.md +3337 -0
  19. data/docs/ADR-004-adapter-architecture.md +2385 -0
  20. data/docs/ADR-005-tracing-context.md +1372 -0
  21. data/docs/ADR-006-security-compliance.md +4143 -0
  22. data/docs/ADR-007-opentelemetry-integration.md +1385 -0
  23. data/docs/ADR-008-rails-integration.md +1911 -0
  24. data/docs/ADR-009-cost-optimization.md +2993 -0
  25. data/docs/ADR-010-developer-experience.md +2166 -0
  26. data/docs/ADR-011-testing-strategy.md +1836 -0
  27. data/docs/ADR-012-event-evolution.md +958 -0
  28. data/docs/ADR-013-reliability-error-handling.md +2750 -0
  29. data/docs/ADR-014-event-driven-slo.md +1533 -0
  30. data/docs/ADR-015-middleware-order.md +1061 -0
  31. data/docs/ADR-016-self-monitoring-slo.md +1234 -0
  32. data/docs/API-REFERENCE-L28.md +914 -0
  33. data/docs/COMPREHENSIVE-CONFIGURATION.md +2366 -0
  34. data/docs/IMPLEMENTATION_NOTES.md +2804 -0
  35. data/docs/IMPLEMENTATION_PLAN.md +1971 -0
  36. data/docs/IMPLEMENTATION_PLAN_ARCHITECTURE.md +586 -0
  37. data/docs/PLAN.md +148 -0
  38. data/docs/QUICK-START.md +934 -0
  39. data/docs/README.md +296 -0
  40. data/docs/design/00-memory-optimization.md +593 -0
  41. data/docs/guides/MIGRATION-L27-L28.md +692 -0
  42. data/docs/guides/PERFORMANCE-BENCHMARKS.md +434 -0
  43. data/docs/guides/README.md +44 -0
  44. data/docs/prd/01-overview-vision.md +440 -0
  45. data/docs/use_cases/README.md +119 -0
  46. data/docs/use_cases/UC-001-request-scoped-debug-buffering.md +813 -0
  47. data/docs/use_cases/UC-002-business-event-tracking.md +1953 -0
  48. data/docs/use_cases/UC-003-pattern-based-metrics.md +1627 -0
  49. data/docs/use_cases/UC-004-zero-config-slo-tracking.md +728 -0
  50. data/docs/use_cases/UC-005-sentry-integration.md +759 -0
  51. data/docs/use_cases/UC-006-trace-context-management.md +905 -0
  52. data/docs/use_cases/UC-007-pii-filtering.md +2648 -0
  53. data/docs/use_cases/UC-008-opentelemetry-integration.md +1153 -0
  54. data/docs/use_cases/UC-009-multi-service-tracing.md +1043 -0
  55. data/docs/use_cases/UC-010-background-job-tracking.md +1018 -0
  56. data/docs/use_cases/UC-011-rate-limiting.md +1906 -0
  57. data/docs/use_cases/UC-012-audit-trail.md +2301 -0
  58. data/docs/use_cases/UC-013-high-cardinality-protection.md +2127 -0
  59. data/docs/use_cases/UC-014-adaptive-sampling.md +1940 -0
  60. data/docs/use_cases/UC-015-cost-optimization.md +735 -0
  61. data/docs/use_cases/UC-016-rails-logger-migration.md +785 -0
  62. data/docs/use_cases/UC-017-local-development.md +867 -0
  63. data/docs/use_cases/UC-018-testing-events.md +1081 -0
  64. data/docs/use_cases/UC-019-tiered-storage-migration.md +562 -0
  65. data/docs/use_cases/UC-020-event-versioning.md +708 -0
  66. data/docs/use_cases/UC-021-error-handling-retry-dlq.md +956 -0
  67. data/docs/use_cases/UC-022-event-registry.md +648 -0
  68. data/docs/use_cases/backlog.md +226 -0
  69. data/e11y.gemspec +76 -0
  70. data/lib/e11y/adapters/adaptive_batcher.rb +207 -0
  71. data/lib/e11y/adapters/audit_encrypted.rb +239 -0
  72. data/lib/e11y/adapters/base.rb +580 -0
  73. data/lib/e11y/adapters/file.rb +224 -0
  74. data/lib/e11y/adapters/in_memory.rb +216 -0
  75. data/lib/e11y/adapters/loki.rb +333 -0
  76. data/lib/e11y/adapters/otel_logs.rb +203 -0
  77. data/lib/e11y/adapters/registry.rb +141 -0
  78. data/lib/e11y/adapters/sentry.rb +230 -0
  79. data/lib/e11y/adapters/stdout.rb +108 -0
  80. data/lib/e11y/adapters/yabeda.rb +370 -0
  81. data/lib/e11y/buffers/adaptive_buffer.rb +339 -0
  82. data/lib/e11y/buffers/base_buffer.rb +40 -0
  83. data/lib/e11y/buffers/request_scoped_buffer.rb +246 -0
  84. data/lib/e11y/buffers/ring_buffer.rb +267 -0
  85. data/lib/e11y/buffers.rb +14 -0
  86. data/lib/e11y/console.rb +122 -0
  87. data/lib/e11y/current.rb +48 -0
  88. data/lib/e11y/event/base.rb +894 -0
  89. data/lib/e11y/event/value_sampling_config.rb +84 -0
  90. data/lib/e11y/events/base_audit_event.rb +43 -0
  91. data/lib/e11y/events/base_payment_event.rb +33 -0
  92. data/lib/e11y/events/rails/cache/delete.rb +21 -0
  93. data/lib/e11y/events/rails/cache/read.rb +23 -0
  94. data/lib/e11y/events/rails/cache/write.rb +22 -0
  95. data/lib/e11y/events/rails/database/query.rb +45 -0
  96. data/lib/e11y/events/rails/http/redirect.rb +21 -0
  97. data/lib/e11y/events/rails/http/request.rb +26 -0
  98. data/lib/e11y/events/rails/http/send_file.rb +21 -0
  99. data/lib/e11y/events/rails/http/start_processing.rb +26 -0
  100. data/lib/e11y/events/rails/job/completed.rb +22 -0
  101. data/lib/e11y/events/rails/job/enqueued.rb +22 -0
  102. data/lib/e11y/events/rails/job/failed.rb +22 -0
  103. data/lib/e11y/events/rails/job/scheduled.rb +23 -0
  104. data/lib/e11y/events/rails/job/started.rb +22 -0
  105. data/lib/e11y/events/rails/log.rb +56 -0
  106. data/lib/e11y/events/rails/view/render.rb +23 -0
  107. data/lib/e11y/events.rb +18 -0
  108. data/lib/e11y/instruments/active_job.rb +201 -0
  109. data/lib/e11y/instruments/rails_instrumentation.rb +141 -0
  110. data/lib/e11y/instruments/sidekiq.rb +175 -0
  111. data/lib/e11y/logger/bridge.rb +205 -0
  112. data/lib/e11y/metrics/cardinality_protection.rb +172 -0
  113. data/lib/e11y/metrics/cardinality_tracker.rb +134 -0
  114. data/lib/e11y/metrics/registry.rb +234 -0
  115. data/lib/e11y/metrics/relabeling.rb +226 -0
  116. data/lib/e11y/metrics.rb +102 -0
  117. data/lib/e11y/middleware/audit_signing.rb +174 -0
  118. data/lib/e11y/middleware/base.rb +140 -0
  119. data/lib/e11y/middleware/event_slo.rb +167 -0
  120. data/lib/e11y/middleware/pii_filter.rb +266 -0
  121. data/lib/e11y/middleware/pii_filtering.rb +280 -0
  122. data/lib/e11y/middleware/rate_limiting.rb +214 -0
  123. data/lib/e11y/middleware/request.rb +163 -0
  124. data/lib/e11y/middleware/routing.rb +157 -0
  125. data/lib/e11y/middleware/sampling.rb +254 -0
  126. data/lib/e11y/middleware/slo.rb +168 -0
  127. data/lib/e11y/middleware/trace_context.rb +131 -0
  128. data/lib/e11y/middleware/validation.rb +118 -0
  129. data/lib/e11y/middleware/versioning.rb +132 -0
  130. data/lib/e11y/middleware.rb +12 -0
  131. data/lib/e11y/pii/patterns.rb +90 -0
  132. data/lib/e11y/pii.rb +13 -0
  133. data/lib/e11y/pipeline/builder.rb +155 -0
  134. data/lib/e11y/pipeline/zone_validator.rb +110 -0
  135. data/lib/e11y/pipeline.rb +12 -0
  136. data/lib/e11y/presets/audit_event.rb +65 -0
  137. data/lib/e11y/presets/debug_event.rb +34 -0
  138. data/lib/e11y/presets/high_value_event.rb +51 -0
  139. data/lib/e11y/presets.rb +19 -0
  140. data/lib/e11y/railtie.rb +138 -0
  141. data/lib/e11y/reliability/circuit_breaker.rb +216 -0
  142. data/lib/e11y/reliability/dlq/file_storage.rb +277 -0
  143. data/lib/e11y/reliability/dlq/filter.rb +117 -0
  144. data/lib/e11y/reliability/retry_handler.rb +207 -0
  145. data/lib/e11y/reliability/retry_rate_limiter.rb +117 -0
  146. data/lib/e11y/sampling/error_spike_detector.rb +225 -0
  147. data/lib/e11y/sampling/load_monitor.rb +161 -0
  148. data/lib/e11y/sampling/stratified_tracker.rb +92 -0
  149. data/lib/e11y/sampling/value_extractor.rb +82 -0
  150. data/lib/e11y/self_monitoring/buffer_monitor.rb +79 -0
  151. data/lib/e11y/self_monitoring/performance_monitor.rb +97 -0
  152. data/lib/e11y/self_monitoring/reliability_monitor.rb +146 -0
  153. data/lib/e11y/slo/event_driven.rb +150 -0
  154. data/lib/e11y/slo/tracker.rb +119 -0
  155. data/lib/e11y/version.rb +9 -0
  156. data/lib/e11y.rb +283 -0
  157. metadata +452 -0
@@ -0,0 +1,648 @@
1
+ # UC-022: Event Registry & Introspection
2
+
3
+ **Status:** Developer Experience Feature (v1.1+)
4
+ **Complexity:** Low
5
+ **Setup Time:** 5-10 minutes
6
+ **Target Users:** Backend Developers, QA Engineers, Documentation Writers
7
+
8
+ ---
9
+
10
+ ## ๐Ÿ“‹ Overview
11
+
12
+ ### Problem Statement
13
+
14
+ **Current Pain Points:**
15
+
16
+ 1. **No catalog of events**
17
+ - What events exist in the system?
18
+ - Need to grep codebase to find event classes
19
+ - Hard to document all events
20
+
21
+ 2. **No runtime introspection**
22
+ - Can't list all registered events at runtime
23
+ - Can't find event class by name
24
+ - Can't inspect event schema programmatically
25
+
26
+ 3. **Hard to build tooling**
27
+ - Can't build event explorer UI (no registry)
28
+ - Can't auto-generate documentation
29
+ - Can't validate that all events are documented
30
+
31
+ ### E11y Solution
32
+
33
+ **Event Registry with Full Introspection:**
34
+
35
+ - Automatic registration of all event classes
36
+ - Query registry by event name, version, adapter
37
+ - Schema introspection (fields, types, validations)
38
+ - Build developer tools (event explorer, documentation generator)
39
+
40
+ **Result:** Full visibility into all events in the system.
41
+
42
+ ---
43
+
44
+ ## ๐ŸŽฏ Use Case Scenarios
45
+
46
+ ### Scenario 1: List All Events
47
+
48
+ **Problem:** Need to document all events in the system.
49
+
50
+ ```ruby
51
+ # Without registry (MANUAL GREP):
52
+ $ grep -r "class.*< E11y::Event::Base" app/events/
53
+ # โ†’ Manual, error-prone, outdated
54
+
55
+ # With registry (AUTOMATIC):
56
+ E11y::Registry.all_events
57
+ # => [
58
+ # Events::OrderCreated,
59
+ # Events::OrderPaid,
60
+ # Events::UserSignup,
61
+ # Events::PaymentFailed,
62
+ # ...
63
+ # ]
64
+
65
+ # Generate documentation:
66
+ E11y::Registry.all_events.each do |event_class|
67
+ puts "## #{event_class.event_name}"
68
+ puts "Version: #{event_class.version}"
69
+ puts "Schema: #{event_class.schema_definition}"
70
+ end
71
+ ```
72
+
73
+ ---
74
+
75
+ ### Scenario 2: Find Event by Name
76
+
77
+ **Problem:** Need to find event class for dynamic event tracking.
78
+
79
+ ```ruby
80
+ # Without registry (STRING EVAL - DANGEROUS!):
81
+ event_name = 'order.created'
82
+ event_class = eval("Events::#{event_name.classify}") # โŒ DANGEROUS!
83
+
84
+ # With registry (SAFE):
85
+ event_class = E11y::Registry.find('order.created')
86
+ # => Events::OrderCreated
87
+
88
+ # Dynamic tracking:
89
+ event_class.track(order_id: '123', amount: 99.99)
90
+ ```
91
+
92
+ ---
93
+
94
+ ### Scenario 3: Schema Introspection
95
+
96
+ **Problem:** Need to generate API documentation showing event schemas.
97
+
98
+ ```ruby
99
+ # Introspect event schema
100
+ event = Events::OrderPaid
101
+
102
+ event.event_name
103
+ # => "order.paid"
104
+
105
+ event.version
106
+ # => 2
107
+
108
+ event.schema_definition
109
+ # => {
110
+ # order_id: { type: :string, required: true },
111
+ # amount: { type: :decimal, required: true },
112
+ # currency: { type: :string, required: true }
113
+ # }
114
+
115
+ event.adapters
116
+ # => [:loki, :sentry, :file]
117
+
118
+ event.severity_level
119
+ # => :info
120
+
121
+ # Generate OpenAPI spec:
122
+ {
123
+ "event.name": event.event_name,
124
+ "properties": event.schema_definition.transform_values { |v| v[:type] }
125
+ }
126
+ ```
127
+
128
+ ---
129
+
130
+ ### Scenario 4: Event Explorer UI
131
+
132
+ **Problem:** Developers need to see all events and test them.
133
+
134
+ ```ruby
135
+ # Rails controller for event explorer
136
+ class EventExplorerController < ApplicationController
137
+ def index
138
+ @events = E11y::Registry.all_events.map do |event_class|
139
+ {
140
+ name: event_class.event_name,
141
+ version: event_class.version,
142
+ schema: event_class.schema_definition,
143
+ adapters: event_class.adapters,
144
+ examples: event_class.example_payloads
145
+ }
146
+ end
147
+ end
148
+
149
+ def show
150
+ @event = E11y::Registry.find(params[:name])
151
+
152
+ # Show details:
153
+ # - Schema
154
+ # - Recent tracked events
155
+ # - Metrics (how many times tracked)
156
+ end
157
+
158
+ def test
159
+ event_class = E11y::Registry.find(params[:name])
160
+ payload = JSON.parse(params[:payload])
161
+
162
+ # Test tracking
163
+ event_class.track(**payload)
164
+
165
+ flash[:success] = "Event tracked successfully!"
166
+ end
167
+ end
168
+ ```
169
+
170
+ ---
171
+
172
+ ## ๐Ÿ—๏ธ Architecture
173
+
174
+ ### Registry Structure
175
+
176
+ ```
177
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
178
+ โ”‚ E11y::Registry (Global Singleton) โ”‚
179
+ โ”‚ โ”‚
180
+ โ”‚ @events = { โ”‚
181
+ โ”‚ 'order.created' => { โ”‚
182
+ โ”‚ v1: Events::OrderCreatedV1, โ”‚
183
+ โ”‚ v2: Events::OrderCreatedV2 (current) โ”‚
184
+ โ”‚ }, โ”‚
185
+ โ”‚ 'order.paid' => { โ”‚
186
+ โ”‚ v1: Events::OrderPaidV1, โ”‚
187
+ โ”‚ v2: Events::OrderPaidV2 (current) โ”‚
188
+ โ”‚ }, โ”‚
189
+ โ”‚ 'user.signup' => { โ”‚
190
+ โ”‚ v1: Events::UserSignup (current) โ”‚
191
+ โ”‚ } โ”‚
192
+ โ”‚ } โ”‚
193
+ โ”‚ โ”‚
194
+ โ”‚ Indexes: โ”‚
195
+ โ”‚ - by_name: 'order.created' โ†’ Events::OrderCreatedV2 โ”‚
196
+ โ”‚ - by_adapter: :sentry โ†’ [Events::PaymentFailed, ...] โ”‚
197
+ โ”‚ - by_severity: :error โ†’ [Events::SystemError, ...] โ”‚
198
+ โ”‚ - by_version: 2 โ†’ [Events::OrderCreatedV2, ...] โ”‚
199
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
200
+ ```
201
+
202
+ ### Auto-Registration
203
+
204
+ ```ruby
205
+ # Event classes automatically register on load
206
+ module Events
207
+ class OrderCreated < E11y::Event::Base
208
+ # On class definition:
209
+ # 1. E11y::Registry.register(self)
210
+ # 2. Store: event_name, version, schema, adapters
211
+ end
212
+ end
213
+
214
+ # Behind the scenes:
215
+ class E11y::Event::Base
216
+ def self.inherited(subclass)
217
+ super
218
+ E11y::Registry.register(subclass) # Auto-register
219
+ end
220
+ end
221
+ ```
222
+
223
+ ---
224
+
225
+ ## ๐Ÿ”ง Configuration
226
+
227
+ ### Basic Setup
228
+
229
+ ```ruby
230
+ # config/initializers/e11y.rb
231
+ E11y.configure do |config|
232
+ config.registry do
233
+ enabled true
234
+
235
+ # Eager load event classes (for registry)
236
+ eager_load true
237
+ eager_load_paths [
238
+ Rails.root.join('app', 'events')
239
+ ]
240
+
241
+ # Registry features
242
+ enable_introspection true
243
+ enable_event_explorer true # Web UI at /e11y/events
244
+ end
245
+ end
246
+ ```
247
+
248
+ ---
249
+
250
+ ## ๐Ÿ“ Registry API
251
+
252
+ > **Implementation:** See [ADR-010 Section 5: Event Registry](../ADR-010-developer-experience.md#5-event-registry) for full registry architecture, including event discovery API, introspection, version tracking, and dynamic dispatch.
253
+
254
+ ### Query Events
255
+
256
+ ```ruby
257
+ # === List All Events ===
258
+ E11y::Registry.all_events
259
+ # => [Events::OrderCreated, Events::OrderPaid, ...]
260
+
261
+ E11y::Registry.count
262
+ # => 42
263
+
264
+ # === Find by Name ===
265
+ E11y::Registry.find('order.created')
266
+ # => Events::OrderCreated (latest version)
267
+
268
+ E11y::Registry.find('order.created', version: 1)
269
+ # => Events::OrderCreatedV1
270
+
271
+ # === Find by Criteria ===
272
+ E11y::Registry.where(adapter: :sentry)
273
+ # => [Events::PaymentFailed, Events::SystemError, ...]
274
+
275
+ E11y::Registry.where(severity: :error)
276
+ # => [Events::PaymentFailed, ...]
277
+
278
+ E11y::Registry.where(version: 2)
279
+ # => [Events::OrderCreatedV2, Events::OrderPaidV2, ...]
280
+
281
+ # === Search ===
282
+ E11y::Registry.search('payment')
283
+ # => [Events::PaymentProcessed, Events::PaymentFailed, ...]
284
+
285
+ # === Filtering ===
286
+ E11y::Registry.filter do |event_class|
287
+ event_class.adapters.include?(:sentry) &&
288
+ event_class.severity_level == :error
289
+ end
290
+ # => [Events::PaymentFailed, Events::SystemError]
291
+ ```
292
+
293
+ ### Introspection API
294
+
295
+ ```ruby
296
+ event = Events::OrderPaid
297
+
298
+ # === Basic Info ===
299
+ event.event_name
300
+ # => "order.paid"
301
+
302
+ event.version
303
+ # => 2
304
+
305
+ event.default_version?
306
+ # => true
307
+
308
+ event.deprecated?
309
+ # => false
310
+
311
+ # === Schema ===
312
+ event.schema_definition
313
+ # => {
314
+ # order_id: { type: :string, required: true },
315
+ # amount: { type: :decimal, required: true },
316
+ # currency: { type: :string, required: true }
317
+ # }
318
+
319
+ event.required_fields
320
+ # => [:order_id, :amount, :currency]
321
+
322
+ event.optional_fields
323
+ # => []
324
+
325
+ event.field_type(:amount)
326
+ # => :decimal
327
+
328
+ # === Adapters ===
329
+ event.adapters
330
+ # => [:loki, :sentry]
331
+
332
+ event.uses_adapter?(:sentry)
333
+ # => true
334
+
335
+ # === Severity ===
336
+ event.severity_level
337
+ # => :info
338
+
339
+ event.track_success?
340
+ # => false
341
+
342
+ # === Examples ===
343
+ event.example_payloads
344
+ # => [
345
+ # { order_id: '123', amount: 99.99, currency: 'USD' },
346
+ # { order_id: '456', amount: 49.99, currency: 'EUR' }
347
+ # ]
348
+ ```
349
+
350
+ ### Statistics
351
+
352
+ ```ruby
353
+ # === Registry Stats ===
354
+ E11y::Registry.stats
355
+ # => {
356
+ # total_events: 42,
357
+ # by_adapter: {
358
+ # loki: 42,
359
+ # sentry: 15,
360
+ # file: 42
361
+ # },
362
+ # by_severity: {
363
+ # debug: 10,
364
+ # info: 20,
365
+ # warn: 8,
366
+ # error: 4
367
+ # },
368
+ # by_version: {
369
+ # 1: 30,
370
+ # 2: 12
371
+ # },
372
+ # deprecated: 5
373
+ # }
374
+
375
+ # === Event Usage Stats (requires tracking) ===
376
+ E11y::Registry.usage_stats
377
+ # => {
378
+ # 'order.created' => { total: 1000, last_24h: 100 },
379
+ # 'order.paid' => { total: 800, last_24h: 80 },
380
+ # ...
381
+ # }
382
+ ```
383
+
384
+ ---
385
+
386
+ ## ๐Ÿ’ก Developer Tools
387
+
388
+ ### 1. Event Explorer Web UI
389
+
390
+ ```ruby
391
+ # Available at: http://localhost:3000/e11y/events
392
+
393
+ # Features:
394
+ # - List all events
395
+ # - Search/filter events
396
+ # - View event schema
397
+ # - Test event tracking
398
+ # - View recent tracked events
399
+ # - View event metrics
400
+
401
+ # Enable in config:
402
+ E11y.configure do |config|
403
+ config.development.event_explorer do
404
+ enabled true
405
+ mount_path '/e11y/events'
406
+
407
+ # Authentication (production)
408
+ authenticate_with do |username, password|
409
+ username == ENV['E11Y_USER'] && password == ENV['E11Y_PASS']
410
+ end
411
+ end
412
+ end
413
+ ```
414
+
415
+ ### 2. Documentation Generator
416
+
417
+ ```ruby
418
+ # Rake task: generate event documentation
419
+ # lib/tasks/e11y_docs.rake
420
+ namespace :e11y do
421
+ desc 'Generate event documentation'
422
+ task docs: :environment do
423
+ output = StringIO.new
424
+
425
+ output.puts "# E11y Events Documentation"
426
+ output.puts
427
+ output.puts "Total events: #{E11y::Registry.count}"
428
+ output.puts
429
+
430
+ E11y::Registry.all_events.each do |event_class|
431
+ output.puts "## #{event_class.event_name}"
432
+ output.puts
433
+ output.puts "**Version:** #{event_class.version}"
434
+ output.puts "**Severity:** #{event_class.severity_level}"
435
+ output.puts "**Adapters:** #{event_class.adapters.join(', ')}"
436
+ output.puts
437
+ output.puts "### Schema"
438
+ output.puts
439
+ output.puts "| Field | Type | Required |"
440
+ output.puts "|-------|------|----------|"
441
+
442
+ event_class.schema_definition.each do |field, opts|
443
+ output.puts "| #{field} | #{opts[:type]} | #{opts[:required] ? 'Yes' : 'No'} |"
444
+ end
445
+
446
+ output.puts
447
+ output.puts "### Example"
448
+ output.puts
449
+ output.puts "```ruby"
450
+ output.puts "#{event_class.name}.track("
451
+ event_class.example_payloads.first.each do |key, value|
452
+ output.puts " #{key}: #{value.inspect},"
453
+ end
454
+ output.puts ")"
455
+ output.puts "```"
456
+ output.puts
457
+ end
458
+
459
+ File.write('docs/EVENTS.md', output.string)
460
+ puts "โœ… Documentation generated: docs/EVENTS.md"
461
+ end
462
+ end
463
+
464
+ # Run:
465
+ # $ rake e11y:docs
466
+ ```
467
+
468
+ ### 3. Event Validator
469
+
470
+ ```ruby
471
+ # Validate all events are documented
472
+ # lib/tasks/e11y_validate.rake
473
+ namespace :e11y do
474
+ desc 'Validate all events'
475
+ task validate: :environment do
476
+ errors = []
477
+
478
+ E11y::Registry.all_events.each do |event_class|
479
+ # Check: has example payload
480
+ if event_class.example_payloads.empty?
481
+ errors << "#{event_class.name} has no example payloads"
482
+ end
483
+
484
+ # Check: has documentation comment
485
+ unless event_class.documented?
486
+ errors << "#{event_class.name} has no documentation"
487
+ end
488
+
489
+ # Check: deprecated events have deprecation_date
490
+ if event_class.deprecated? && event_class.deprecation_date.nil?
491
+ errors << "#{event_class.name} is deprecated but no deprecation_date"
492
+ end
493
+ end
494
+
495
+ if errors.any?
496
+ puts "โŒ Found #{errors.size} issues:"
497
+ errors.each { |err| puts " - #{err}" }
498
+ exit 1
499
+ else
500
+ puts "โœ… All events valid"
501
+ end
502
+ end
503
+ end
504
+
505
+ # Run in CI:
506
+ # $ rake e11y:validate
507
+ ```
508
+
509
+ ### 4. OpenAPI Generator
510
+
511
+ ```ruby
512
+ # Generate OpenAPI spec for events
513
+ namespace :e11y do
514
+ desc 'Generate OpenAPI spec'
515
+ task openapi: :environment do
516
+ spec = {
517
+ openapi: '3.0.0',
518
+ info: {
519
+ title: 'E11y Events API',
520
+ version: '1.0.0'
521
+ },
522
+ paths: {}
523
+ }
524
+
525
+ E11y::Registry.all_events.each do |event_class|
526
+ spec[:paths]["/events/#{event_class.event_name}"] = {
527
+ post: {
528
+ summary: "Track #{event_class.event_name} event",
529
+ requestBody: {
530
+ content: {
531
+ 'application/json': {
532
+ schema: {
533
+ type: 'object',
534
+ properties: event_class.schema_definition.transform_values { |v|
535
+ { type: v[:type].to_s }
536
+ },
537
+ required: event_class.required_fields.map(&:to_s)
538
+ }
539
+ }
540
+ }
541
+ }
542
+ }
543
+ }
544
+ end
545
+
546
+ File.write('docs/openapi.json', JSON.pretty_generate(spec))
547
+ puts "โœ… OpenAPI spec generated: docs/openapi.json"
548
+ end
549
+ end
550
+ ```
551
+
552
+ ---
553
+
554
+ ## ๐Ÿงช Testing
555
+
556
+ ### RSpec Examples
557
+
558
+ ```ruby
559
+ RSpec.describe E11y::Registry do
560
+ describe '.all_events' do
561
+ it 'returns all registered events' do
562
+ events = E11y::Registry.all_events
563
+
564
+ expect(events).to include(Events::OrderCreated)
565
+ expect(events).to include(Events::OrderPaid)
566
+ expect(events.size).to be > 0
567
+ end
568
+ end
569
+
570
+ describe '.find' do
571
+ it 'finds event by name' do
572
+ event = E11y::Registry.find('order.created')
573
+
574
+ expect(event).to eq(Events::OrderCreated)
575
+ end
576
+
577
+ it 'finds event by name and version' do
578
+ event = E11y::Registry.find('order.created', version: 1)
579
+
580
+ expect(event).to eq(Events::OrderCreatedV1)
581
+ end
582
+
583
+ it 'returns nil for unknown event' do
584
+ event = E11y::Registry.find('unknown.event')
585
+
586
+ expect(event).to be_nil
587
+ end
588
+ end
589
+
590
+ describe '.where' do
591
+ it 'filters by adapter' do
592
+ events = E11y::Registry.where(adapter: :sentry)
593
+
594
+ expect(events).to all(satisfy { |e| e.adapters.include?(:sentry) })
595
+ end
596
+
597
+ it 'filters by severity' do
598
+ events = E11y::Registry.where(severity: :error)
599
+
600
+ expect(events).to all(have_attributes(severity_level: :error))
601
+ end
602
+ end
603
+
604
+ describe 'introspection' do
605
+ let(:event) { Events::OrderPaid }
606
+
607
+ it 'exposes event metadata' do
608
+ expect(event.event_name).to eq('order.paid')
609
+ expect(event.version).to eq(2)
610
+ expect(event.adapters).to include(:loki, :sentry)
611
+ end
612
+
613
+ it 'exposes schema' do
614
+ schema = event.schema_definition
615
+
616
+ expect(schema).to include(
617
+ order_id: { type: :string, required: true },
618
+ amount: { type: :decimal, required: true }
619
+ )
620
+ end
621
+ end
622
+ end
623
+ ```
624
+
625
+ ---
626
+
627
+ ## ๐Ÿ”— Related Use Cases
628
+
629
+ - **[UC-017: Local Development](./UC-017-local-development.md)** - Event Explorer UI
630
+ - **[UC-020: Event Versioning](./UC-020-event-versioning.md)** - Version registry
631
+ - **[UC-002: Business Event Tracking](./UC-002-business-event-tracking.md)** - Event definitions
632
+
633
+ ---
634
+
635
+ ## ๐Ÿš€ Quick Start Checklist
636
+
637
+ - [ ] Enable registry in config
638
+ - [ ] Enable eager loading of event classes
639
+ - [ ] Access registry: `E11y::Registry.all_events`
640
+ - [ ] Enable event explorer UI (development only)
641
+ - [ ] Set up documentation generator rake task
642
+ - [ ] Run validation in CI: `rake e11y:validate`
643
+
644
+ ---
645
+
646
+ **Status:** โœ… Developer Experience Feature
647
+ **Priority:** Nice-to-Have (v1.1+)
648
+ **Complexity:** Low