familia 2.0.0.pre5 → 2.0.0.pre7

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 (151) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/claude-code-review.yml +57 -0
  3. data/.github/workflows/claude.yml +71 -0
  4. data/.gitignore +5 -1
  5. data/.rubocop.yml +3 -0
  6. data/CLAUDE.md +32 -10
  7. data/Gemfile +2 -2
  8. data/Gemfile.lock +4 -3
  9. data/docs/wiki/API-Reference.md +95 -18
  10. data/docs/wiki/Connection-Pooling-Guide.md +437 -0
  11. data/docs/wiki/Encrypted-Fields-Overview.md +40 -3
  12. data/docs/wiki/Expiration-Feature-Guide.md +596 -0
  13. data/docs/wiki/Feature-System-Guide.md +631 -0
  14. data/docs/wiki/Features-System-Developer-Guide.md +892 -0
  15. data/docs/wiki/Field-System-Guide.md +784 -0
  16. data/docs/wiki/Home.md +82 -15
  17. data/docs/wiki/Implementation-Guide.md +126 -33
  18. data/docs/wiki/Quantization-Feature-Guide.md +721 -0
  19. data/docs/wiki/Relationships-Guide.md +684 -0
  20. data/docs/wiki/Security-Model.md +65 -25
  21. data/docs/wiki/Transient-Fields-Guide.md +280 -0
  22. data/examples/bit_encoding_integration.rb +237 -0
  23. data/examples/redis_command_validation_example.rb +231 -0
  24. data/examples/relationships_basic.rb +273 -0
  25. data/lib/familia/base.rb +1 -1
  26. data/lib/familia/connection.rb +3 -3
  27. data/lib/familia/data_type/types/counter.rb +38 -0
  28. data/lib/familia/data_type/types/hashkey.rb +18 -0
  29. data/lib/familia/data_type/types/lock.rb +43 -0
  30. data/lib/familia/data_type/types/string.rb +9 -2
  31. data/lib/familia/data_type.rb +9 -6
  32. data/lib/familia/encryption/encrypted_data.rb +137 -0
  33. data/lib/familia/encryption/manager.rb +21 -4
  34. data/lib/familia/encryption/providers/aes_gcm_provider.rb +20 -0
  35. data/lib/familia/encryption/providers/xchacha20_poly1305_provider.rb +20 -0
  36. data/lib/familia/encryption.rb +1 -1
  37. data/lib/familia/errors.rb +17 -3
  38. data/lib/familia/features/encrypted_fields/concealed_string.rb +293 -0
  39. data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +94 -26
  40. data/lib/familia/features/encrypted_fields.rb +413 -4
  41. data/lib/familia/features/expiration.rb +319 -33
  42. data/lib/familia/features/quantization.rb +385 -44
  43. data/lib/familia/features/relationships/cascading.rb +438 -0
  44. data/lib/familia/features/relationships/indexing.rb +370 -0
  45. data/lib/familia/features/relationships/membership.rb +503 -0
  46. data/lib/familia/features/relationships/permission_management.rb +264 -0
  47. data/lib/familia/features/relationships/querying.rb +620 -0
  48. data/lib/familia/features/relationships/redis_operations.rb +274 -0
  49. data/lib/familia/features/relationships/score_encoding.rb +442 -0
  50. data/lib/familia/features/relationships/tracking.rb +379 -0
  51. data/lib/familia/features/relationships.rb +466 -0
  52. data/lib/familia/features/safe_dump.rb +1 -1
  53. data/lib/familia/features/transient_fields/redacted_string.rb +1 -1
  54. data/lib/familia/features/transient_fields.rb +192 -10
  55. data/lib/familia/features.rb +2 -1
  56. data/lib/familia/field_type.rb +5 -2
  57. data/lib/familia/horreum/{connection.rb → core/connection.rb} +2 -8
  58. data/lib/familia/horreum/{database_commands.rb → core/database_commands.rb} +14 -3
  59. data/lib/familia/horreum/core/serialization.rb +535 -0
  60. data/lib/familia/horreum/{utils.rb → core/utils.rb} +0 -2
  61. data/lib/familia/horreum/core.rb +21 -0
  62. data/lib/familia/horreum/{settings.rb → shared/settings.rb} +0 -2
  63. data/lib/familia/horreum/{definition_methods.rb → subclass/definition.rb} +45 -29
  64. data/lib/familia/horreum/{management_methods.rb → subclass/management.rb} +9 -8
  65. data/lib/familia/horreum/{related_fields_management.rb → subclass/related_fields_management.rb} +15 -10
  66. data/lib/familia/horreum.rb +17 -17
  67. data/lib/familia/validation/command_recorder.rb +336 -0
  68. data/lib/familia/validation/expectations.rb +519 -0
  69. data/lib/familia/validation/test_helpers.rb +443 -0
  70. data/lib/familia/validation/validator.rb +412 -0
  71. data/lib/familia/validation.rb +140 -0
  72. data/lib/familia/version.rb +1 -1
  73. data/lib/familia.rb +1 -1
  74. data/try/core/create_method_try.rb +240 -0
  75. data/try/core/database_consistency_try.rb +299 -0
  76. data/try/core/errors_try.rb +25 -4
  77. data/try/core/familia_try.rb +1 -1
  78. data/try/core/persistence_operations_try.rb +297 -0
  79. data/try/data_types/counter_try.rb +93 -0
  80. data/try/data_types/lock_try.rb +133 -0
  81. data/try/debugging/debug_aad_process.rb +82 -0
  82. data/try/debugging/debug_concealed_internal.rb +59 -0
  83. data/try/debugging/debug_concealed_reveal.rb +61 -0
  84. data/try/debugging/debug_context_aad.rb +68 -0
  85. data/try/debugging/debug_context_simple.rb +80 -0
  86. data/try/debugging/debug_cross_context.rb +62 -0
  87. data/try/debugging/debug_database_load.rb +64 -0
  88. data/try/debugging/debug_encrypted_json_check.rb +53 -0
  89. data/try/debugging/debug_encrypted_json_step_by_step.rb +62 -0
  90. data/try/debugging/debug_exists_lifecycle.rb +54 -0
  91. data/try/debugging/debug_field_decrypt.rb +74 -0
  92. data/try/debugging/debug_fresh_cross_context.rb +73 -0
  93. data/try/debugging/debug_load_path.rb +66 -0
  94. data/try/debugging/debug_method_definition.rb +46 -0
  95. data/try/debugging/debug_method_resolution.rb +41 -0
  96. data/try/debugging/debug_minimal.rb +24 -0
  97. data/try/debugging/debug_provider.rb +68 -0
  98. data/try/debugging/debug_secure_behavior.rb +73 -0
  99. data/try/debugging/debug_string_class.rb +46 -0
  100. data/try/debugging/debug_test.rb +46 -0
  101. data/try/debugging/debug_test_design.rb +80 -0
  102. data/try/edge_cases/hash_symbolization_try.rb +1 -0
  103. data/try/edge_cases/reserved_keywords_try.rb +1 -0
  104. data/try/edge_cases/string_coercion_try.rb +2 -0
  105. data/try/encryption/encryption_core_try.rb +6 -4
  106. data/try/features/categorical_permissions_try.rb +515 -0
  107. data/try/features/encrypted_fields_core_try.rb +19 -11
  108. data/try/features/encrypted_fields_integration_try.rb +66 -70
  109. data/try/features/encrypted_fields_no_cache_security_try.rb +22 -8
  110. data/try/features/encrypted_fields_security_try.rb +151 -144
  111. data/try/features/encryption_fields/aad_protection_try.rb +108 -23
  112. data/try/features/encryption_fields/concealed_string_core_try.rb +253 -0
  113. data/try/features/encryption_fields/context_isolation_try.rb +30 -8
  114. data/try/features/encryption_fields/error_conditions_try.rb +6 -6
  115. data/try/features/encryption_fields/fresh_key_derivation_try.rb +20 -14
  116. data/try/features/encryption_fields/fresh_key_try.rb +27 -22
  117. data/try/features/encryption_fields/key_rotation_try.rb +16 -10
  118. data/try/features/encryption_fields/nonce_uniqueness_try.rb +15 -13
  119. data/try/features/encryption_fields/secure_by_default_behavior_try.rb +310 -0
  120. data/try/features/encryption_fields/thread_safety_try.rb +6 -6
  121. data/try/features/encryption_fields/universal_serialization_safety_try.rb +174 -0
  122. data/try/features/feature_dependencies_try.rb +3 -3
  123. data/try/features/relationships_edge_cases_try.rb +145 -0
  124. data/try/features/relationships_performance_minimal_try.rb +132 -0
  125. data/try/features/relationships_performance_simple_try.rb +155 -0
  126. data/try/features/relationships_performance_try.rb +420 -0
  127. data/try/features/relationships_performance_working_try.rb +144 -0
  128. data/try/features/relationships_try.rb +237 -0
  129. data/try/features/safe_dump_try.rb +3 -0
  130. data/try/features/transient_fields/redacted_string_try.rb +2 -0
  131. data/try/features/transient_fields/single_use_redacted_string_try.rb +2 -0
  132. data/try/features/transient_fields_core_try.rb +1 -1
  133. data/try/features/transient_fields_integration_try.rb +1 -1
  134. data/try/helpers/test_helpers.rb +26 -1
  135. data/try/horreum/base_try.rb +14 -8
  136. data/try/horreum/enhanced_conflict_handling_try.rb +3 -1
  137. data/try/horreum/initialization_try.rb +1 -1
  138. data/try/horreum/relations_try.rb +2 -2
  139. data/try/horreum/serialization_persistent_fields_try.rb +8 -8
  140. data/try/horreum/serialization_try.rb +39 -4
  141. data/try/models/customer_safe_dump_try.rb +1 -1
  142. data/try/models/customer_try.rb +1 -1
  143. data/try/validation/atomic_operations_try.rb.disabled +320 -0
  144. data/try/validation/command_validation_try.rb.disabled +207 -0
  145. data/try/validation/performance_validation_try.rb.disabled +324 -0
  146. data/try/validation/real_world_scenarios_try.rb.disabled +390 -0
  147. metadata +81 -12
  148. data/TEST_COVERAGE.md +0 -40
  149. data/lib/familia/features/relatable_objects.rb +0 -125
  150. data/lib/familia/horreum/serialization.rb +0 -473
  151. data/try/features/relatable_objects_try.rb +0 -220
@@ -0,0 +1,631 @@
1
+ # Feature System Guide
2
+
3
+ ## Overview
4
+
5
+ Familia's feature system provides a modular architecture for extending Horreum classes with reusable functionality. Features are self-contained modules that can be mixed into classes with dependency management, conflict resolution, and automatic registration.
6
+
7
+ ## Core Concepts
8
+
9
+ ### Feature Architecture
10
+
11
+ The feature system consists of several key components:
12
+
13
+ 1. **Feature Modules**: Self-contained functionality modules
14
+ 2. **Registration System**: Automatic feature discovery and registration
15
+ 3. **Dependency Management**: Explicit feature dependencies
16
+ 4. **Conflict Resolution**: Handling method name conflicts
17
+ 5. **Category-based Fields**: Special field types for different purposes
18
+
19
+ ### Feature Lifecycle
20
+
21
+ ```ruby
22
+ # 1. Feature definition and registration (automatic)
23
+ class MyFeature
24
+ def self.included(base)
25
+ base.extend ClassMethods
26
+ base.prepend InstanceMethods
27
+ end
28
+
29
+ # Self-register with Familia
30
+ Familia::Base.add_feature self, :my_feature, depends_on: [:other_feature]
31
+ end
32
+
33
+ # 2. Feature activation in classes
34
+ class Customer < Familia::Horreum
35
+ feature :my_feature # Validates, checks dependencies, includes module
36
+ end
37
+
38
+ # 3. Runtime usage
39
+ customer = Customer.new
40
+ customer.my_feature_method # Available after feature inclusion
41
+ ```
42
+
43
+ ## Built-in Features
44
+
45
+ ### Core Features
46
+
47
+ #### Expiration
48
+ ```ruby
49
+ class Session < Familia::Horreum
50
+ feature :expiration
51
+ default_expiration 1.hour
52
+
53
+ field :user_id, :data
54
+ end
55
+
56
+ session = Session.new(user_id: 123)
57
+ session.update_expiration(30.minutes) # Custom TTL
58
+ session.ttl # Check remaining time
59
+ ```
60
+
61
+ #### SafeDump
62
+ ```ruby
63
+ class Customer < Familia::Horreum
64
+ feature :safe_dump
65
+
66
+ field :name, :email
67
+ field :ssn # Sensitive field
68
+ field :password # Sensitive field
69
+
70
+ # Whitelist fields for API responses
71
+ safe_dump_fields :name, :email # Excludes ssn, password
72
+ end
73
+
74
+ customer.safe_dump # => { name: "John", email: "john@example.com" }
75
+ customer.dump # => { name: "John", email: "john@example.com", ssn: "123-45-6789", password: "secret" }
76
+ ```
77
+
78
+ #### Encrypted Fields
79
+ ```ruby
80
+ class Vault < Familia::Horreum
81
+ feature :encrypted_fields
82
+
83
+ field :name # Regular field
84
+ encrypted_field :secret_key # Encrypted storage
85
+ encrypted_field :api_token # Another encrypted field
86
+ end
87
+
88
+ vault = Vault.new(secret_key: "super-secret")
89
+ vault.save
90
+ # secret_key is encrypted in Redis, decrypted on access
91
+ ```
92
+
93
+ #### Transient Fields
94
+ ```ruby
95
+ class ApiClient < Familia::Horreum
96
+ feature :transient_fields
97
+
98
+ field :endpoint # Persistent field
99
+ transient_field :auth_token # Runtime only, RedactedString
100
+ end
101
+
102
+ client = ApiClient.new(auth_token: ENV['API_TOKEN'])
103
+ client.auth_token.expose { |token| make_api_call(token) }
104
+ client.auth_token.clear! # Explicit cleanup
105
+ ```
106
+
107
+ #### Relationships
108
+ ```ruby
109
+ class Customer < Familia::Horreum
110
+ feature :relationships
111
+
112
+ identifier_field :custid
113
+ field :custid, :name, :email
114
+
115
+ # Define relationship collections
116
+ tracked_in :active_users, type: :sorted_set
117
+ indexed_by :email_lookup, field: :email
118
+ set :domains
119
+ end
120
+
121
+ class Domain < Familia::Horreum
122
+ feature :relationships
123
+
124
+ identifier_field :domain_id
125
+ field :domain_id, :name
126
+
127
+ # Declare membership in customer collections
128
+ member_of Customer, :domains, type: :set
129
+ end
130
+
131
+ # Usage
132
+ customer = Customer.new(custid: "cust123", name: "Acme Corp")
133
+ domain = Domain.new(domain_id: "dom456", name: "acme.com")
134
+
135
+ # Establish bidirectional relationships
136
+ domain.add_to_customer_domains(customer.custid)
137
+ customer.domains.add(domain.identifier)
138
+
139
+ # Query relationships
140
+ domain.in_customer_domains?(customer.custid) # => true
141
+ ```
142
+
143
+ #### Quantization
144
+ ```ruby
145
+ class Metric < Familia::Horreum
146
+ feature :quantization
147
+
148
+ field :value
149
+ quantized_field :hourly_stats, interval: 1.hour
150
+ quantized_field :daily_stats, interval: 1.day
151
+ end
152
+
153
+ # Automatically buckets data by time intervals
154
+ metric = Metric.new(value: 42)
155
+ metric.hourly_stats # Bucketed by hour
156
+ metric.daily_stats # Bucketed by day
157
+ ```
158
+
159
+ ## Creating Custom Features
160
+
161
+ ### Basic Feature Structure
162
+
163
+ ```ruby
164
+ module Familia
165
+ module Features
166
+ module MyCustomFeature
167
+ def self.included(base)
168
+ Familia.trace :LOADED, self, base, caller(1..1) if Familia.debug?
169
+ base.extend ClassMethods
170
+ base.prepend InstanceMethods # Use prepend for method interception
171
+ end
172
+
173
+ module ClassMethods
174
+ def custom_class_method
175
+ "Available on #{self} class"
176
+ end
177
+ end
178
+
179
+ module InstanceMethods
180
+ def custom_instance_method
181
+ "Available on #{self.class} instances"
182
+ end
183
+
184
+ # Intercept field access (if needed)
185
+ def field_value=(value)
186
+ # Custom processing before field assignment
187
+ processed_value = process_value(value)
188
+ super(processed_value) # Call original field setter
189
+ end
190
+ end
191
+
192
+ # Register the feature
193
+ Familia::Base.add_feature self, :my_custom_feature
194
+ end
195
+ end
196
+ end
197
+ ```
198
+
199
+ ### Advanced Feature with Dependencies
200
+
201
+ ```ruby
202
+ module Familia
203
+ module Features
204
+ module AdvancedAudit
205
+ def self.included(base)
206
+ base.extend ClassMethods
207
+ base.prepend InstanceMethods
208
+
209
+ # Initialize audit tracking
210
+ base.class_list :audit_log
211
+ base.class_hashkey :field_history
212
+ end
213
+
214
+ module ClassMethods
215
+ def enable_audit_for(*field_names)
216
+ @audited_fields ||= Set.new
217
+ @audited_fields.merge(field_names.map(&:to_sym))
218
+ end
219
+
220
+ def audited_fields
221
+ @audited_fields || Set.new
222
+ end
223
+ end
224
+
225
+ module InstanceMethods
226
+ def save
227
+ # Audit before saving
228
+ audit_changes if respond_to?(:audit_changes)
229
+ super
230
+ end
231
+
232
+ private
233
+
234
+ def audit_changes
235
+ self.class.audited_fields.each do |field|
236
+ if instance_variable_changed?(field)
237
+ record_field_change(field)
238
+ end
239
+ end
240
+ end
241
+
242
+ def record_field_change(field)
243
+ change_record = {
244
+ field: field,
245
+ old_value: instance_variable_was(field),
246
+ new_value: instance_variable_get("@#{field}"),
247
+ timestamp: Time.now.to_f
248
+ }
249
+
250
+ self.class.audit_log.append(change_record.to_json)
251
+ end
252
+ end
253
+
254
+ # Register with dependency on safe_dump
255
+ Familia::Base.add_feature self, :advanced_audit, depends_on: [:safe_dump]
256
+ end
257
+ end
258
+ end
259
+
260
+ # Usage
261
+ class Customer < Familia::Horreum
262
+ feature :safe_dump # Dependency satisfied first
263
+ feature :advanced_audit # Now can be loaded
264
+
265
+ enable_audit_for :name, :email, :status
266
+
267
+ field :name, :email, :status, :created_at
268
+ end
269
+ ```
270
+
271
+ ### Feature with Custom Field Types
272
+
273
+ ```ruby
274
+ module Familia
275
+ module Features
276
+ module TimestampTracking
277
+ def self.included(base)
278
+ base.extend ClassMethods
279
+
280
+ # Add timestamp fields automatically
281
+ base.timestamp_field :created_at
282
+ base.timestamp_field :updated_at
283
+ end
284
+
285
+ module ClassMethods
286
+ def timestamp_field(name, auto_update: true)
287
+ # Create custom field type for timestamps
288
+ require_relative '../field_types/timestamp_field_type'
289
+
290
+ field_type = TimestampFieldType.new(
291
+ name,
292
+ auto_update: auto_update,
293
+ format: :iso8601
294
+ )
295
+ register_field_type(field_type)
296
+ end
297
+ end
298
+
299
+ # Register feature
300
+ Familia::Base.add_feature self, :timestamp_tracking
301
+ end
302
+ end
303
+ end
304
+
305
+ # Custom field type (separate file)
306
+ class TimestampFieldType < Familia::FieldType
307
+ def initialize(name, auto_update: true, format: :unix, **options)
308
+ super(name, **options)
309
+ @auto_update = auto_update
310
+ @format = format
311
+ end
312
+
313
+ def serialize_value(record, value)
314
+ case @format
315
+ when :unix then value&.to_f
316
+ when :iso8601 then value&.iso8601
317
+ else value&.to_s
318
+ end
319
+ end
320
+
321
+ def deserialize_value(record, stored_value)
322
+ return nil if stored_value.nil?
323
+
324
+ case @format
325
+ when :unix then Time.at(stored_value.to_f)
326
+ when :iso8601 then Time.parse(stored_value)
327
+ else Time.parse(stored_value)
328
+ end
329
+ end
330
+ end
331
+ ```
332
+
333
+ ## Feature Dependencies
334
+
335
+ ### Declaring Dependencies
336
+
337
+ ```ruby
338
+ # Feature with dependencies
339
+ Familia::Base.add_feature MyFeature, :my_feature, depends_on: [:safe_dump, :expiration]
340
+
341
+ # Will verify dependencies when feature is activated:
342
+ class Model < Familia::Horreum
343
+ feature :safe_dump # Must be loaded first
344
+ feature :expiration # Must be loaded first
345
+ feature :my_feature # Dependencies satisfied
346
+ end
347
+ ```
348
+
349
+ ### Dependency Validation
350
+
351
+ ```ruby
352
+ # This will raise an error:
353
+ class BadModel < Familia::Horreum
354
+ feature :my_feature # Error: requires safe_dump, expiration
355
+ end
356
+ # => Familia::Problem: my_feature requires: safe_dump, expiration
357
+
358
+ # Correct order:
359
+ class GoodModel < Familia::Horreum
360
+ feature :safe_dump
361
+ feature :expiration
362
+ feature :my_feature # ✅ Dependencies satisfied
363
+ end
364
+ ```
365
+
366
+ ## Method Conflict Resolution
367
+
368
+ ### Conflict Detection
369
+
370
+ ```ruby
371
+ class Customer < Familia::Horreum
372
+ field :status # Defines status= and status methods
373
+
374
+ # This would conflict with field-generated method
375
+ def status
376
+ "custom implementation" # ⚠️ Potential conflict
377
+ end
378
+ end
379
+ ```
380
+
381
+ ### Conflict Resolution Strategies
382
+
383
+ ```ruby
384
+ # 1. Raise on conflict (default)
385
+ field :name, on_conflict: :raise # Raises if method exists
386
+
387
+ # 2. Skip definition if conflict
388
+ field :name, on_conflict: :skip # Skips if method exists
389
+
390
+ # 3. Warn but proceed
391
+ field :name, on_conflict: :warn # Warns but defines method
392
+
393
+ # 4. Ignore silently
394
+ field :name, on_conflict: :ignore # Proceeds without warning
395
+ ```
396
+
397
+ ### Using Prepend for Method Interception
398
+
399
+ ```ruby
400
+ module MyFeature
401
+ def self.included(base)
402
+ # Use prepend to intercept method calls
403
+ base.prepend InstanceMethods
404
+ end
405
+
406
+ module InstanceMethods
407
+ def save
408
+ # Pre-processing
409
+ validate_before_save
410
+
411
+ # Call original save method
412
+ result = super
413
+
414
+ # Post-processing
415
+ notify_after_save
416
+
417
+ result
418
+ end
419
+ end
420
+ end
421
+ ```
422
+
423
+ ## Feature Categories and Field Types
424
+
425
+ ### Field Categories
426
+
427
+ ```ruby
428
+ class Document < Familia::Horreum
429
+ field :title # Regular field
430
+ field :content, category: :encrypted # Encrypted field
431
+ field :api_key, category: :transient # Transient field
432
+ field :tags, category: :indexed # Custom category
433
+ end
434
+ ```
435
+
436
+ ### Category-based Processing
437
+
438
+ ```ruby
439
+ # Features can process fields by category
440
+ module IndexingFeature
441
+ def self.included(base)
442
+ base.extend ClassMethods
443
+
444
+ # Process all :indexed category fields
445
+ base.field_definitions.select { |f| f.category == :indexed }.each do |field|
446
+ create_index_for(field.name)
447
+ end
448
+ end
449
+ end
450
+ ```
451
+
452
+ ## Feature Discovery and Loading
453
+
454
+ ### Automatic Loading
455
+
456
+ Features are automatically loaded from the `lib/familia/features/` directory:
457
+
458
+ ```ruby
459
+ # lib/familia/features.rb automatically loads:
460
+ features_dir = File.join(__dir__, 'features')
461
+ Dir.glob(File.join(features_dir, '*.rb')).each do |feature_file|
462
+ require_relative feature_file
463
+ end
464
+ ```
465
+
466
+ ### Manual Feature Registration
467
+
468
+ ```ruby
469
+ # For features outside the standard directory
470
+ class ExternalFeature
471
+ # Feature implementation...
472
+ end
473
+
474
+ # Register manually
475
+ Familia::Base.add_feature ExternalFeature, :external_feature, depends_on: []
476
+ ```
477
+
478
+ ## Advanced Usage Patterns
479
+
480
+ ### Feature Composition
481
+
482
+ ```ruby
483
+ class AdvancedModel < Familia::Horreum
484
+ # Combine multiple features for rich functionality
485
+ feature :expiration # TTL support
486
+ feature :safe_dump # API-safe serialization
487
+ feature :encrypted_fields # Secure storage
488
+ feature :quantization # Time-based bucketing
489
+ feature :transient_fields # Runtime secrets
490
+
491
+ # Now has capabilities from all features
492
+ field :name
493
+ encrypted_field :api_key
494
+ transient_field :session_token
495
+ quantized_field :metrics, interval: 1.hour
496
+
497
+ default_expiration 24.hours
498
+ safe_dump_fields :name, :created_at
499
+ end
500
+ ```
501
+
502
+ ### Conditional Feature Loading
503
+
504
+ ```ruby
505
+ class ConfigurableModel < Familia::Horreum
506
+ # Load features based on configuration
507
+ if Rails.env.production?
508
+ feature :encrypted_fields
509
+ feature :advanced_audit
510
+ end
511
+
512
+ if defined?(Sidekiq)
513
+ feature :background_processing
514
+ end
515
+
516
+ feature :safe_dump # Always load
517
+ end
518
+ ```
519
+
520
+ ### Runtime Feature Checking
521
+
522
+ ```ruby
523
+ class Model < Familia::Horreum
524
+ feature :expiration
525
+
526
+ def available_features
527
+ self.class.features_enabled
528
+ end
529
+ end
530
+
531
+ model = Model.new
532
+ model.available_features # => [:expiration]
533
+ ```
534
+
535
+ ## Testing Features
536
+
537
+ ### Feature Testing
538
+
539
+ ```ruby
540
+ RSpec.describe MyCustomFeature do
541
+ let(:test_class) do
542
+ Class.new(Familia::Horreum) do
543
+ feature :my_custom_feature
544
+ field :name
545
+ end
546
+ end
547
+
548
+ it "includes feature methods" do
549
+ instance = test_class.new
550
+ expect(instance).to respond_to(:custom_instance_method)
551
+ expect(test_class).to respond_to(:custom_class_method)
552
+ end
553
+
554
+ it "validates dependencies" do
555
+ expect {
556
+ Class.new(Familia::Horreum) do
557
+ feature :advanced_audit # Missing safe_dump dependency
558
+ end
559
+ }.to raise_error(Familia::Problem, /requires.*safe_dump/)
560
+ end
561
+ end
562
+ ```
563
+
564
+ ### Integration Testing
565
+
566
+ ```ruby
567
+ RSpec.describe "Feature Integration" do
568
+ it "combines features correctly" do
569
+ combined_class = Class.new(Familia::Horreum) do
570
+ feature :safe_dump
571
+ feature :expiration
572
+ feature :encrypted_fields
573
+
574
+ field :name
575
+ encrypted_field :secret
576
+ safe_dump_fields :name
577
+ default_expiration 1.hour
578
+ end
579
+
580
+ instance = combined_class.new(name: "test", secret: "hidden")
581
+
582
+ # All features work together
583
+ expect(instance.safe_dump).to eq(name: "test")
584
+ expect(instance.secret).to eq("hidden") # Decrypted
585
+ expect(instance.ttl).to be > 0 # Has expiration
586
+ end
587
+ end
588
+ ```
589
+
590
+ ## Best Practices
591
+
592
+ ### Feature Design
593
+
594
+ 1. **Single Responsibility**: Each feature should have one clear purpose
595
+ 2. **Minimal Dependencies**: Avoid complex dependency chains
596
+ 3. **Graceful Degradation**: Handle missing dependencies gracefully
597
+ 4. **Clear Naming**: Use descriptive feature and method names
598
+ 5. **Documentation**: Document feature capabilities and usage
599
+
600
+ ### Method Organization
601
+
602
+ ```ruby
603
+ module MyFeature
604
+ def self.included(base)
605
+ base.extend ClassMethods
606
+ base.prepend InstanceMethods # For interception
607
+ base.include HelperMethods # For additional utilities
608
+ end
609
+
610
+ module ClassMethods
611
+ # Class-level functionality
612
+ end
613
+
614
+ module InstanceMethods
615
+ # Instance method interception/override
616
+ end
617
+
618
+ module HelperMethods
619
+ # Additional utility methods
620
+ end
621
+ end
622
+ ```
623
+
624
+ ### Performance Considerations
625
+
626
+ 1. **Lazy Loading**: Initialize expensive resources only when needed
627
+ 2. **Caching**: Cache computed values appropriately
628
+ 3. **Method Interception**: Use prepend sparingly for performance-critical methods
629
+ 4. **Field Processing**: Minimize overhead in field serialization/deserialization
630
+
631
+ The feature system provides a powerful foundation for extending Familia with reusable, composable functionality while maintaining clean separation of concerns and explicit dependency management.