smart_message 0.0.5 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c388c9738746603d14a57d6c4e04fb7d6e48156c4e571cd82dffd461217e111
4
- data.tar.gz: 975779de0b52686b8b08baa94070fea52578c86f5fb1a3752aa25cad98a812d7
3
+ metadata.gz: eac068dc19706e57d2c66a1dfe36981fbac33e6d7b180fe0429f81d874727cd4
4
+ data.tar.gz: 91585bc79637c4feab1256716519c0c3c7aa36c2b313ed09ebee7788b11d3f1a
5
5
  SHA512:
6
- metadata.gz: b425fa9d66a2716394a1dc695b8ba82c9acc9c82dc616fc00cf8eeab2639a7833640e71240969614f31836ee0d325ae8980fa4f4d266e6961dfd6a8971172420
7
- data.tar.gz: 711381ff80115a8582551fc58f22630c9c103c24d46f04b1edc54b87d41fd181d80a0f730cc6d14a000ec3b5478330062385edb6e5344fe1e541559e82652c97
6
+ metadata.gz: a0c0ead05e3cb104873e5cfa53cfc182ee06c6fd2f2e56fe02c0d64a4313dc4356b84d3b5be251e5438e6e381812848f6f587b005a315282204d8160f785f87b
7
+ data.tar.gz: 3a84537cca151b3b8f3efa16b9ad8591811be19ab5547013fe9f33d7df58474e5db2a74e85e669fb95c17e5b375dd2d889b3a3051b6ded765120dd208246c26a
data/CHANGELOG.md CHANGED
@@ -7,6 +7,73 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.0.6] 2025-08-19
11
+
12
+ ### Added
13
+ - **Entity-Aware Message Filtering**: Advanced subscription filtering system enabling precise message routing
14
+ - New subscription filter parameters: `broadcast:`, `to:`, `from:` for `subscribe` method
15
+ - Filter by broadcast messages only: `MyMessage.subscribe(broadcast: true)`
16
+ - Filter by destination entity: `MyMessage.subscribe(to: 'service-name')`
17
+ - Filter by sender entity: `MyMessage.subscribe(from: 'sender-service')`
18
+ - Support for array-based filters: `subscribe(from: ['admin', 'system'])`
19
+ - Combined filters with OR logic: `subscribe(broadcast: true, to: 'my-service')`
20
+ - String-to-array automatic conversion for convenience: `subscribe(to: 'service')` becomes `['service']`
21
+ - Full backward compatibility - existing subscriptions work unchanged
22
+ - **Real-Time Header Synchronization**: Message headers now update automatically when addressing fields change
23
+ - Instance-level `from()`, `to()`, `reply_to()` methods now update both instance variables and message headers
24
+ - Enables filtering to work correctly when addressing is changed after message creation
25
+ - Reset methods (`reset_from`, `reset_to`, `reset_reply_to`) also update headers
26
+ - Critical for entity-aware filtering functionality
27
+ - **Enhanced Example Programs**
28
+ - New comprehensive filtering example: `examples/08_entity_addressing_with_filtering.rb`
29
+ - Demonstrates all filtering capabilities with real-world microservice scenarios
30
+ - Improved timing with sleep statements for better output visualization
31
+ - Updated basic addressing example: `examples/08_entity_addressing_basic.rb`
32
+ - Both examples now show clear interleaved publish/receive output flow
33
+
34
+ ### Changed
35
+ - **Message Subscription Architecture**: Subscription storage updated to support filtering
36
+ - Dispatcher now stores subscription objects with filter criteria instead of simple method strings
37
+ - Subscription objects contain `{process_method: string, filters: hash}` structure
38
+ - All transport implementations updated to pass filter options through subscription chain
39
+ - RedisTransport updated to accept new filter_options parameter
40
+ - **Header Addressing Behavior**: Message headers now reflect real-time addressing changes
41
+ - **BREAKING**: Headers are no longer immutable after creation - they update when addressing methods are called
42
+ - This change enables entity-aware filtering to work correctly with dynamic addressing
43
+ - Previous behavior kept original addressing in headers while instance methods showed new values
44
+
45
+ ### Fixed
46
+ - **Message Filtering Logic**: Resolved critical filtering implementation issues
47
+ - Fixed message_matches_filters? method to properly evaluate filter criteria
48
+ - Corrected AND/OR logic for combined broadcast and entity-specific filters
49
+ - Ensured filtering works with both class-level and instance-level addressing
50
+ - **Test Suite Compatibility**: Updated all tests to work with new subscription structure
51
+ - Fixed ProcHandlerTest to expect subscription objects instead of string arrays
52
+ - Updated TransportTest to handle new subscription object format
53
+ - Fixed AddressingTest to reflect new real-time header update behavior
54
+ - All existing functionality preserved with full backward compatibility
55
+
56
+ ### Enhanced
57
+ - **Message Processing Performance**: Filtering happens at subscription level, reducing processing overhead
58
+ - Messages not matching filter criteria are ignored by handlers, improving efficiency
59
+ - Enables microservices to process only relevant messages
60
+ - Reduces unnecessary handler invocations and processing cycles
61
+ - **Developer Experience**: Clear examples demonstrate filtering benefits and usage patterns
62
+ - Examples show both what DOES and DOESN'T get processed
63
+ - Demonstrates gateway patterns, admin message handling, and microservice communication
64
+ - Educational value enhanced with comprehensive console output and timing
65
+
66
+ ### Documentation
67
+ - **Entity-Aware Filtering Guide**: Comprehensive examples showing all filtering capabilities
68
+ - Broadcast vs directed message handling patterns
69
+ - Admin/monitoring system integration examples
70
+ - Request-reply routing with filters
71
+ - Gateway pattern implementations with dynamic routing
72
+ - Best practices for microservice message filtering
73
+ - **Breaking Change Documentation**: Clear explanation of header behavior changes
74
+ - Migration guide for applications depending on immutable headers
75
+ - Benefits of real-time header updates for filtering functionality
76
+
10
77
  ## [0.0.5] 2025-08-18
11
78
 
12
79
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_message (0.0.4)
4
+ smart_message (0.0.6)
5
5
  activesupport
6
6
  concurrent-ruby
7
7
  hashie
data/README.md CHANGED
@@ -9,6 +9,7 @@ SmartMessage is a message abstraction framework that decouples business logic fr
9
9
 
10
10
  - **Transport Abstraction**: Plugin architecture supporting multiple message transports (Redis, RabbitMQ, Kafka, etc.)
11
11
  - **Serialization Flexibility**: Pluggable serialization formats (JSON, MessagePack, etc.)
12
+ - **Entity-to-Entity Addressing**: Built-in FROM/TO/REPLY_TO addressing for point-to-point and broadcast messaging patterns
12
13
  - **Schema Versioning**: Built-in version management with automatic compatibility validation
13
14
  - **Comprehensive Validation**: Property validation with custom error messages and automatic validation before publishing
14
15
  - **Message Documentation**: Built-in documentation support for message classes and properties with automatic defaults
@@ -47,6 +48,11 @@ class OrderMessage < SmartMessage::Base
47
48
  # Add a description for the message class
48
49
  description "Represents customer order data for processing and fulfillment"
49
50
 
51
+ # Configure entity addressing
52
+ from 'order-service'
53
+ to 'fulfillment-service' # Point-to-point message
54
+ reply_to 'order-service' # Responses come back here
55
+
50
56
  # Required properties with validation
51
57
  property :order_id,
52
58
  required: true,
@@ -153,6 +159,50 @@ end
153
159
  OrderMessage.subscribe(audit_handler)
154
160
  ```
155
161
 
162
+ ### 4. Entity Addressing
163
+
164
+ SmartMessage supports entity-to-entity addressing with FROM/TO/REPLY_TO fields for advanced message routing:
165
+
166
+ ```ruby
167
+ # Point-to-point messaging
168
+ class PaymentMessage < SmartMessage::Base
169
+ version 1
170
+ from 'payment-service' # Required: sender identity
171
+ to 'bank-gateway' # Optional: specific recipient
172
+ reply_to 'payment-service' # Optional: where responses go
173
+
174
+ property :amount, required: true
175
+ property :account_id, required: true
176
+ end
177
+
178
+ # Broadcast messaging (no 'to' specified)
179
+ class SystemAnnouncementMessage < SmartMessage::Base
180
+ version 1
181
+ from 'admin-service' # Required: sender identity
182
+ # No 'to' field = broadcast to all subscribers
183
+
184
+ property :message, required: true
185
+ property :priority, default: 'normal'
186
+ end
187
+
188
+ # Instance-level addressing override
189
+ payment = PaymentMessage.new(amount: 100.00, account_id: "ACCT-123")
190
+ payment.to('backup-gateway') # Override destination for this instance
191
+ payment.publish
192
+
193
+ # Access addressing information
194
+ puts payment._sm_header.from # => 'payment-service'
195
+ puts payment._sm_header.to # => 'backup-gateway'
196
+ puts payment._sm_header.reply_to # => 'payment-service'
197
+ ```
198
+
199
+ #### Messaging Patterns Supported
200
+
201
+ - **Point-to-Point**: Set `to` field for direct entity targeting
202
+ - **Broadcast**: Omit `to` field (nil) for message broadcast to all subscribers
203
+ - **Request-Reply**: Use `reply_to` field to specify response routing
204
+ - **Gateway Patterns**: Override addressing at instance level for message forwarding
205
+
156
206
  ## Architecture
157
207
 
158
208
  ### Core Components
@@ -323,15 +373,16 @@ end
323
373
  ## Message Lifecycle
324
374
 
325
375
  1. **Definition**: Create message class inheriting from `SmartMessage::Base`
326
- 2. **Configuration**: Set transport, serializer, and logger plugins
327
- 3. **Validation**: Messages are automatically validated before publishing (properties, header, version compatibility)
328
- 4. **Publishing**: Message instance is encoded and sent through transport
376
+ 2. **Configuration**: Set transport, serializer, logger plugins, and entity addressing (from/to/reply_to)
377
+ 3. **Validation**: Messages are automatically validated before publishing (properties, header, addressing, version compatibility)
378
+ 4. **Publishing**: Message instance is encoded with addressing metadata and sent through transport
329
379
  5. **Subscription**: Message classes register handlers with dispatcher for processing
330
380
  - Default handlers (`self.process` method)
331
381
  - Custom method handlers (`"ClassName.method_name"`)
332
382
  - Block handlers (`subscribe do |h,p|...end`)
333
383
  - Proc/Lambda handlers (`subscribe(proc {...})`)
334
- 6. **Processing**: Received messages are decoded and routed to registered handlers
384
+ 6. **Routing**: Dispatcher uses addressing metadata to route messages (point-to-point vs broadcast)
385
+ 7. **Processing**: Received messages are decoded and routed to registered handlers
335
386
 
336
387
  ## Schema Versioning and Validation
337
388
 
@@ -588,6 +639,9 @@ puts message._sm_header.uuid
588
639
  puts message._sm_header.message_class
589
640
  puts message._sm_header.published_at
590
641
  puts message._sm_header.publisher_pid
642
+ puts message._sm_header.from
643
+ puts message._sm_header.to
644
+ puts message._sm_header.reply_to
591
645
  ```
592
646
 
593
647
  ## Development
data/docs/README.md CHANGED
@@ -16,6 +16,7 @@ Welcome to the comprehensive documentation for SmartMessage, a Ruby gem that abs
16
16
  ### Components
17
17
  - [SmartMessage::Base](base.md)
18
18
  - [Property System](properties.md)
19
+ - [Entity Addressing](addressing.md)
19
20
  - [Transport Layer](transports.md)
20
21
  - [Serializers](serializers.md)
21
22
  - [Logging System](logging.md)
@@ -0,0 +1,364 @@
1
+ # Entity Addressing
2
+
3
+ SmartMessage supports entity-to-entity addressing through built-in FROM/TO/REPLY_TO fields in message headers. This enables sophisticated messaging patterns including point-to-point communication, broadcast messaging, and request-reply workflows.
4
+
5
+ ## Overview
6
+
7
+ Entity addressing in SmartMessage provides:
8
+
9
+ - **Sender Identification**: Required `from` field identifies the sending entity
10
+ - **Recipient Targeting**: Optional `to` field for point-to-point messaging
11
+ - **Response Routing**: Optional `reply_to` field for request-reply patterns
12
+ - **Broadcast Support**: Omitting `to` field enables broadcast to all subscribers
13
+ - **Dual-Level Configuration**: Class and instance-level addressing configuration
14
+
15
+ ## Address Fields
16
+
17
+ ### FROM (Required)
18
+ The `from` field identifies the entity sending the message. This is required for all messages.
19
+
20
+ ```ruby
21
+ class MyMessage < SmartMessage::Base
22
+ from 'order-service' # Required sender identity
23
+
24
+ property :data
25
+ end
26
+ ```
27
+
28
+ ### TO (Optional)
29
+ The `to` field specifies the intended recipient entity. When present, creates point-to-point messaging. When `nil`, the message is broadcast to all subscribers.
30
+
31
+ ```ruby
32
+ # Point-to-point messaging
33
+ class DirectMessage < SmartMessage::Base
34
+ from 'sender-service'
35
+ to 'recipient-service' # Specific target
36
+
37
+ property :content
38
+ end
39
+
40
+ # Broadcast messaging
41
+ class AnnouncementMessage < SmartMessage::Base
42
+ from 'admin-service'
43
+ # No 'to' field = broadcast to all subscribers
44
+
45
+ property :announcement
46
+ end
47
+ ```
48
+
49
+ ### REPLY_TO (Optional)
50
+ The `reply_to` field specifies where responses should be sent. Defaults to the `from` entity if not specified.
51
+
52
+ ```ruby
53
+ class RequestMessage < SmartMessage::Base
54
+ from 'client-service'
55
+ to 'api-service'
56
+ reply_to 'client-callback-service' # Responses go here
57
+
58
+ property :request_data
59
+ end
60
+ ```
61
+
62
+ ## Configuration Patterns
63
+
64
+ ### Class-Level Configuration
65
+
66
+ Set default addressing for all instances of a message class:
67
+
68
+ ```ruby
69
+ class PaymentMessage < SmartMessage::Base
70
+ version 1
71
+
72
+ # Class-level addressing
73
+ from 'payment-service'
74
+ to 'bank-gateway'
75
+ reply_to 'payment-service'
76
+
77
+ property :amount, required: true
78
+ property :account_id, required: true
79
+ end
80
+
81
+ # All instances inherit class addressing
82
+ payment = PaymentMessage.new(amount: 100.00, account_id: "ACCT-123")
83
+ puts payment._sm_header.from # => 'payment-service'
84
+ puts payment._sm_header.to # => 'bank-gateway'
85
+ puts payment._sm_header.reply_to # => 'payment-service'
86
+ ```
87
+
88
+ ### Instance-Level Overrides
89
+
90
+ Override addressing for specific message instances:
91
+
92
+ ```ruby
93
+ class FlexibleMessage < SmartMessage::Base
94
+ from 'service-a'
95
+ to 'service-b'
96
+
97
+ property :data
98
+ end
99
+
100
+ # Override addressing for this instance
101
+ message = FlexibleMessage.new(data: "test")
102
+ message.from('different-sender')
103
+ message.to('different-recipient')
104
+ message.reply_to('different-reply-service')
105
+
106
+ puts message.from # => 'different-sender'
107
+ puts message.to # => 'different-recipient'
108
+ puts message.reply_to # => 'different-reply-service'
109
+
110
+ # Class defaults remain unchanged
111
+ puts FlexibleMessage.from # => 'service-a'
112
+ puts FlexibleMessage.to # => 'service-b'
113
+ ```
114
+
115
+ ## Messaging Patterns
116
+
117
+ ### Point-to-Point Messaging
118
+
119
+ Direct communication between two specific entities:
120
+
121
+ ```ruby
122
+ class OrderProcessingMessage < SmartMessage::Base
123
+ from 'order-service'
124
+ to 'inventory-service' # Direct target
125
+ reply_to 'order-service'
126
+
127
+ property :order_id, required: true
128
+ property :items, required: true
129
+ end
130
+
131
+ # Message goes directly to inventory-service
132
+ order = OrderProcessingMessage.new(
133
+ order_id: "ORD-123",
134
+ items: ["widget-1", "widget-2"]
135
+ )
136
+ order.publish # Only inventory-service receives this
137
+ ```
138
+
139
+ ### Broadcast Messaging
140
+
141
+ Send message to all subscribers by omitting the `to` field:
142
+
143
+ ```ruby
144
+ class SystemMaintenanceMessage < SmartMessage::Base
145
+ from 'admin-service'
146
+ # No 'to' field = broadcast
147
+
148
+ property :message, required: true
149
+ property :scheduled_time, required: true
150
+ end
151
+
152
+ # Message goes to all subscribers
153
+ maintenance = SystemMaintenanceMessage.new(
154
+ message: "System maintenance tonight at 2 AM",
155
+ scheduled_time: Time.parse("2024-01-15 02:00:00")
156
+ )
157
+ maintenance.publish # All subscribers receive this
158
+ ```
159
+
160
+ ### Request-Reply Pattern
161
+
162
+ Structured request-response communication:
163
+
164
+ ```ruby
165
+ # Request message
166
+ class UserLookupRequest < SmartMessage::Base
167
+ from 'web-service'
168
+ to 'user-service'
169
+ reply_to 'web-service' # Responses come back here
170
+
171
+ property :user_id, required: true
172
+ property :request_id, required: true # For correlation
173
+ end
174
+
175
+ # Response message
176
+ class UserLookupResponse < SmartMessage::Base
177
+ from 'user-service'
178
+ # 'to' will be set to the original 'reply_to' value
179
+
180
+ property :user_id, required: true
181
+ property :request_id, required: true # Correlation ID
182
+ property :user_data
183
+ property :success, default: true
184
+ end
185
+
186
+ # Send request
187
+ request = UserLookupRequest.new(
188
+ user_id: "USER-123",
189
+ request_id: SecureRandom.uuid
190
+ )
191
+ request.publish
192
+
193
+ # In user-service handler:
194
+ class UserLookupRequest
195
+ def self.process(header, payload)
196
+ request_data = JSON.parse(payload)
197
+
198
+ # Process lookup...
199
+ user_data = UserService.find(request_data['user_id'])
200
+
201
+ # Send response back to reply_to address
202
+ response = UserLookupResponse.new(
203
+ user_id: request_data['user_id'],
204
+ request_id: request_data['request_id'],
205
+ user_data: user_data
206
+ )
207
+ response.to(header.reply_to) # Send to original reply_to
208
+ response.publish
209
+ end
210
+ end
211
+ ```
212
+
213
+ ### Gateway Pattern
214
+
215
+ Forward messages between different transports/formats:
216
+
217
+ ```ruby
218
+ class GatewayMessage < SmartMessage::Base
219
+ from 'gateway-service'
220
+
221
+ property :original_message
222
+ property :source_format
223
+ property :target_format
224
+ end
225
+
226
+ # Receive from one transport/format
227
+ incoming = SomeMessage.new(data: "from system A")
228
+
229
+ # Forward to different system with different addressing
230
+ gateway_msg = GatewayMessage.new(
231
+ original_message: incoming.to_h,
232
+ source_format: 'json',
233
+ target_format: 'xml'
234
+ )
235
+
236
+ # Override transport and addressing for forwarding
237
+ gateway_msg.config do
238
+ transport DifferentTransport.new
239
+ serializer DifferentSerializer.new
240
+ end
241
+ gateway_msg.to('system-b')
242
+ gateway_msg.publish
243
+ ```
244
+
245
+ ## Address Validation
246
+
247
+ The `from` field is required and validated automatically:
248
+
249
+ ```ruby
250
+ class InvalidMessage < SmartMessage::Base
251
+ # No 'from' specified - will fail validation
252
+ property :data
253
+ end
254
+
255
+ message = InvalidMessage.new(data: "test")
256
+ message.publish # Raises SmartMessage::Errors::ValidationError
257
+ # => "The property 'from' From entity ID is required for message routing and replies"
258
+ ```
259
+
260
+ ## Header Access
261
+
262
+ Access addressing information from message headers:
263
+
264
+ ```ruby
265
+ class SampleMessage < SmartMessage::Base
266
+ from 'sample-service'
267
+ to 'target-service'
268
+ reply_to 'callback-service'
269
+
270
+ property :content
271
+ end
272
+
273
+ message = SampleMessage.new(content: "Hello")
274
+ header = message._sm_header
275
+
276
+ puts header.from # => 'sample-service'
277
+ puts header.to # => 'target-service'
278
+ puts header.reply_to # => 'callback-service'
279
+ puts header.uuid # => Generated UUID
280
+ puts header.message_class # => 'SampleMessage'
281
+ ```
282
+
283
+ ## Integration with Dispatcher
284
+
285
+ The dispatcher can use addressing metadata for advanced routing logic:
286
+
287
+ ```ruby
288
+ # Future enhancement: Dispatcher filtering by recipient
289
+ # dispatcher.route(message_header, payload) do |header|
290
+ # if header.to.nil?
291
+ # # Broadcast to all subscribers
292
+ # route_to_all_subscribers(header.message_class)
293
+ # else
294
+ # # Route only to specific recipient
295
+ # route_to_entity(header.to, header.message_class)
296
+ # end
297
+ # end
298
+ ```
299
+
300
+ ## Best Practices
301
+
302
+ ### Entity Naming
303
+ Use consistent, descriptive entity identifiers:
304
+
305
+ ```ruby
306
+ # Good: Descriptive service names
307
+ from 'order-management-service'
308
+ to 'inventory-tracking-service'
309
+ reply_to 'order-status-service'
310
+
311
+ # Avoid: Generic or unclear names
312
+ from 'service1'
313
+ to 'app'
314
+ ```
315
+
316
+ ### Address Consistency
317
+ Maintain consistent addressing patterns across your application:
318
+
319
+ ```ruby
320
+ # Consistent pattern for microservices
321
+ class OrderMessage < SmartMessage::Base
322
+ from 'order-service'
323
+ to 'fulfillment-service'
324
+ reply_to 'order-service'
325
+ end
326
+
327
+ class PaymentMessage < SmartMessage::Base
328
+ from 'payment-service'
329
+ to 'billing-service'
330
+ reply_to 'payment-service'
331
+ end
332
+ ```
333
+
334
+ ### Gateway Configuration
335
+ For gateway patterns, use instance-level overrides:
336
+
337
+ ```ruby
338
+ # Class defines default routing
339
+ class APIMessage < SmartMessage::Base
340
+ from 'api-gateway'
341
+ to 'internal-service'
342
+ end
343
+
344
+ # Override for external routing
345
+ message = APIMessage.new(data: "external request")
346
+ message.to('external-partner-service')
347
+ message.config do
348
+ transport ExternalTransport.new
349
+ serializer SecureSerializer.new
350
+ end
351
+ message.publish
352
+ ```
353
+
354
+ ## Future Enhancements
355
+
356
+ The addressing system provides the foundation for advanced features:
357
+
358
+ - **Dispatcher Filtering**: Route messages based on recipient targeting
359
+ - **Security Integration**: Entity-based authentication and authorization
360
+ - **Audit Trails**: Track message flow between entities
361
+ - **Load Balancing**: Distribute messages across entity instances
362
+ - **Circuit Breakers**: Per-entity failure handling
363
+
364
+ Entity addressing enables sophisticated messaging architectures while maintaining the simplicity and flexibility that makes SmartMessage powerful.
@@ -40,6 +40,11 @@ class WelcomeMessage < SmartMessage::Base
40
40
  # Add a description for the message class
41
41
  description "Welcomes new users after successful signup"
42
42
 
43
+ # Configure entity addressing
44
+ from 'user-service' # Required: identifies sender
45
+ to 'notification-service' # Optional: specific recipient
46
+ reply_to 'user-service' # Optional: where responses go
47
+
43
48
  # Define message properties
44
49
  property :user_name
45
50
  property :email
@@ -153,6 +158,9 @@ puts message._sm_header.uuid # Unique identifier
153
158
  puts message._sm_header.message_class # "WelcomeMessage"
154
159
  puts message._sm_header.published_at # Timestamp when published
155
160
  puts message._sm_header.publisher_pid # Process ID of publisher
161
+ puts message._sm_header.from # 'user-service'
162
+ puts message._sm_header.to # 'notification-service'
163
+ puts message._sm_header.reply_to # 'user-service'
156
164
  ```
157
165
 
158
166
  ### Transports
@@ -222,6 +230,36 @@ OrderMessage.subscribe("OrderService.process_order")
222
230
  - **Proc**: Reusable handlers that work across multiple message types
223
231
  - **Method**: Complex business logic organized in service classes
224
232
 
233
+ ### Entity Addressing
234
+
235
+ SmartMessage supports entity-to-entity addressing for sophisticated messaging patterns:
236
+
237
+ ```ruby
238
+ # Point-to-point messaging
239
+ class PaymentMessage < SmartMessage::Base
240
+ from 'payment-service' # Required: sender identity
241
+ to 'bank-gateway' # Optional: specific recipient
242
+ reply_to 'payment-service' # Optional: where responses go
243
+
244
+ property :amount, required: true
245
+ end
246
+
247
+ # Broadcast messaging (no 'to' field)
248
+ class AnnouncementMessage < SmartMessage::Base
249
+ from 'admin-service' # Required sender
250
+ # No 'to' = broadcast to all subscribers
251
+
252
+ property :message, required: true
253
+ end
254
+
255
+ # Instance-level addressing override
256
+ payment = PaymentMessage.new(amount: 100.00)
257
+ payment.to('backup-gateway') # Override destination
258
+ payment.publish
259
+ ```
260
+
261
+ For more details, see [Entity Addressing](addressing.md).
262
+
225
263
  ## Next Steps
226
264
 
227
265
  Now that you have the basics working, explore: