familia 2.0.0.pre8 → 2.0.0.pre12

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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +13 -0
  3. data/.github/workflows/docs.yml +1 -1
  4. data/.gitignore +9 -9
  5. data/.rubocop.yml +19 -0
  6. data/.yardopts +22 -1
  7. data/CHANGELOG.md +247 -0
  8. data/CLAUDE.md +12 -59
  9. data/Gemfile.lock +1 -1
  10. data/README.md +62 -2
  11. data/changelog.d/README.md +77 -0
  12. data/docs/archive/.gitignore +2 -0
  13. data/docs/archive/FAMILIA_RELATIONSHIPS.md +210 -0
  14. data/docs/archive/FAMILIA_TECHNICAL.md +823 -0
  15. data/docs/archive/FAMILIA_UPDATE.md +226 -0
  16. data/docs/archive/README.md +63 -0
  17. data/docs/guides/.gitignore +2 -0
  18. data/docs/{wiki → guides}/Home.md +1 -1
  19. data/docs/{wiki → guides}/Implementation-Guide.md +1 -1
  20. data/docs/{wiki → guides}/Relationships-Guide.md +103 -50
  21. data/docs/guides/relationships-methods.md +266 -0
  22. data/docs/migrating/.gitignore +2 -0
  23. data/docs/migrating/v2.0.0-pre.md +84 -0
  24. data/docs/migrating/v2.0.0-pre11.md +255 -0
  25. data/docs/migrating/v2.0.0-pre12.md +306 -0
  26. data/docs/migrating/v2.0.0-pre5.md +110 -0
  27. data/docs/migrating/v2.0.0-pre6.md +154 -0
  28. data/docs/migrating/v2.0.0-pre7.md +222 -0
  29. data/docs/overview.md +6 -7
  30. data/{examples/redis_command_validation_example.rb → docs/reference/auditing_database_commands.rb} +29 -32
  31. data/examples/{bit_encoding_integration.rb → permissions.rb} +30 -27
  32. data/examples/relationships.rb +205 -0
  33. data/examples/safe_dump.rb +281 -0
  34. data/familia.gemspec +4 -4
  35. data/lib/familia/base.rb +52 -0
  36. data/lib/familia/connection.rb +4 -21
  37. data/lib/familia/{encryption_request_cache.rb → encryption/request_cache.rb} +1 -1
  38. data/lib/familia/errors.rb +2 -0
  39. data/lib/familia/features/autoloader.rb +57 -0
  40. data/lib/familia/features/external_identifier.rb +310 -0
  41. data/lib/familia/features/object_identifier.rb +307 -0
  42. data/lib/familia/features/relationships/indexing.rb +160 -175
  43. data/lib/familia/features/relationships/membership.rb +16 -21
  44. data/lib/familia/features/relationships/tracking.rb +61 -21
  45. data/lib/familia/features/relationships.rb +15 -8
  46. data/lib/familia/features/safe_dump.rb +66 -72
  47. data/lib/familia/features.rb +93 -5
  48. data/lib/familia/horreum/subclass/definition.rb +49 -3
  49. data/lib/familia/horreum.rb +15 -24
  50. data/lib/familia/secure_identifier.rb +51 -75
  51. data/lib/familia/verifiable_identifier.rb +162 -0
  52. data/lib/familia/version.rb +1 -1
  53. data/lib/familia.rb +1 -0
  54. data/setup.cfg +5 -0
  55. data/try/core/secure_identifier_try.rb +47 -18
  56. data/try/core/verifiable_identifier_try.rb +171 -0
  57. data/try/features/{external_identifiers/external_identifiers_try.rb → external_identifier/external_identifier_try.rb} +25 -28
  58. data/try/features/feature_improvements_try.rb +126 -0
  59. data/try/features/{object_identifiers/object_identifiers_integration_try.rb → object_identifier/object_identifier_integration_try.rb} +28 -30
  60. data/try/features/{object_identifiers/object_identifiers_try.rb → object_identifier/object_identifier_try.rb} +13 -13
  61. data/try/features/real_feature_integration_try.rb +7 -6
  62. data/try/features/relationships/relationships_api_changes_try.rb +339 -0
  63. data/try/features/relationships/relationships_try.rb +6 -5
  64. data/try/features/safe_dump/safe_dump_try.rb +8 -9
  65. data/try/helpers/test_helpers.rb +17 -17
  66. metadata +62 -41
  67. data/examples/relationships_basic.rb +0 -273
  68. data/lib/familia/features/external_identifiers/external_identifier_field_type.rb +0 -120
  69. data/lib/familia/features/external_identifiers.rb +0 -111
  70. data/lib/familia/features/object_identifiers/object_identifier_field_type.rb +0 -91
  71. data/lib/familia/features/object_identifiers.rb +0 -194
  72. /data/docs/{wiki → guides}/API-Reference.md +0 -0
  73. /data/docs/{wiki → guides}/Connection-Pooling-Guide.md +0 -0
  74. /data/docs/{wiki → guides}/Encrypted-Fields-Overview.md +0 -0
  75. /data/docs/{wiki → guides}/Expiration-Feature-Guide.md +0 -0
  76. /data/docs/{wiki → guides}/Feature-System-Guide.md +0 -0
  77. /data/docs/{wiki → guides}/Features-System-Developer-Guide.md +0 -0
  78. /data/docs/{wiki → guides}/Field-System-Guide.md +0 -0
  79. /data/docs/{wiki → guides}/Quantization-Feature-Guide.md +0 -0
  80. /data/docs/{wiki → guides}/Security-Model.md +0 -0
  81. /data/docs/{wiki → guides}/Transient-Fields-Guide.md +0 -0
@@ -0,0 +1,306 @@
1
+ # Migrating Guide: v2.0.0-pre12
2
+
3
+ This version introduces significant security improvements to Familia's identifier system, including verifiable identifiers with HMAC signatures, scoped identifier namespaces, and hardened external identifier derivation to prevent potential security vulnerabilities.
4
+
5
+ ## VerifiableIdentifier Feature
6
+
7
+ ### Overview
8
+
9
+ The new `Familia::VerifiableIdentifier` module allows applications to create and verify identifiers with embedded HMAC signatures. This enables stateless confirmation that an identifier was generated by your application, preventing forged IDs from malicious sources.
10
+
11
+ ### Basic Usage
12
+
13
+ ```ruby
14
+ class Customer < Familia::Horreum
15
+ feature :verifiable_identifier
16
+
17
+ # Required: Set the HMAC secret (do this once in your app initialization)
18
+ # Generate with: SecureRandom.hex(64)
19
+ ENV['VERIFIABLE_ID_HMAC_SECRET'] = 'your_64_character_hex_secret'
20
+ end
21
+
22
+ # Generate a verifiable identifier
23
+ customer = Customer.new
24
+ verifiable_id = customer.generate_verifiable_id
25
+ # => "cust_1234567890abcdef_a1b2c3d4e5f6789..."
26
+
27
+ # Verify the identifier later (stateless verification)
28
+ if Customer.verified_identifier?(verifiable_id)
29
+ # Identifier is valid and was generated by this application
30
+ original_id = Customer.extract_identifier(verifiable_id)
31
+ customer = Customer.new(original_id)
32
+ else
33
+ # Identifier is forged or corrupted
34
+ raise SecurityError, "Invalid identifier"
35
+ end
36
+ ```
37
+
38
+ ### Scoped VerifiableIdentifier
39
+
40
+ The new `scope` parameter enables cryptographically isolated identifier namespaces for multi-tenant, multi-domain, or multi-environment applications.
41
+
42
+ #### Before (Global Scope)
43
+ ```ruby
44
+ # All identifiers share the same cryptographic space
45
+ admin_id = admin.generate_verifiable_id
46
+ user_id = user.generate_verifiable_id
47
+
48
+ # Risk: Cross-contamination between different contexts
49
+ ```
50
+
51
+ #### After (Scoped Namespaces)
52
+ ```ruby
53
+ # Production environment
54
+ prod_customer_id = customer.generate_verifiable_id(scope: 'production')
55
+ prod_admin_id = admin.generate_verifiable_id(scope: 'production:admin')
56
+
57
+ # Development environment
58
+ dev_customer_id = customer.generate_verifiable_id(scope: 'development')
59
+
60
+ # Multi-tenant application
61
+ tenant_a_id = user.generate_verifiable_id(scope: "tenant:#{tenant_a.id}")
62
+ tenant_b_id = user.generate_verifiable_id(scope: "tenant:#{tenant_b.id}")
63
+
64
+ # Verification requires matching scope
65
+ Customer.verified_identifier?(prod_customer_id, scope: 'production') # => true
66
+ Customer.verified_identifier?(prod_customer_id, scope: 'development') # => false
67
+ ```
68
+
69
+ **Scope Benefits:**
70
+ - **Multi-tenant isolation**: Tenant A cannot forge identifiers for Tenant B
71
+ - **Environment separation**: Production IDs cannot be used in development
72
+ - **Role-based security**: Admin scopes separate from user scopes
73
+ - **Full backward compatibility**: Existing code without scopes continues to work
74
+
75
+ ### Key Management
76
+
77
+ #### Secure Secret Generation
78
+ ```ruby
79
+ # Generate a cryptographically secure HMAC secret
80
+ require 'securerandom'
81
+ secret = SecureRandom.hex(64) # 512-bit secret
82
+ puts "VERIFIABLE_ID_HMAC_SECRET=#{secret}"
83
+ ```
84
+
85
+ #### Environment Configuration
86
+ ```ruby
87
+ # config/application.rb or equivalent
88
+ # Set this BEFORE any VerifiableIdentifier usage
89
+ ENV['VERIFIABLE_ID_HMAC_SECRET'] = Rails.application.credentials.verifiable_id_secret
90
+
91
+ # Or configure programmatically
92
+ Familia::VerifiableIdentifier.hmac_secret = your_secret_string
93
+ ```
94
+
95
+ ## ObjectIdentifier Feature Improvements
96
+
97
+ ### Method Renaming
98
+
99
+ Method names have been updated for clarity and consistency:
100
+
101
+ #### Before
102
+ ```ruby
103
+ customer = Customer.new
104
+ objid = customer.generate_objid # Unclear what this generates
105
+ extid = Customer.generate_extid(objid) # Less secure class method
106
+ ```
107
+
108
+ #### After
109
+ ```ruby
110
+ customer = Customer.new
111
+ objid = customer.generate_object_identifier # Clear: generates object ID
112
+ extid = customer.derive_external_identifier # Clear: derives from objid, instance method
113
+ ```
114
+
115
+ **Migration:**
116
+ - Replace `generate_objid` → `generate_object_identifier`
117
+ - Replace `generate_external_identifier` → `derive_external_identifier`
118
+ - Remove usage of `generate_extid` (deprecated for security reasons)
119
+
120
+ ### Provenance Tracking
121
+
122
+ ObjectIdentifier now tracks which generator was used for each identifier:
123
+
124
+ ```ruby
125
+ class Customer < Familia::Horreum
126
+ feature :object_identifier
127
+
128
+ # Configure generator type
129
+ object_identifier_generator :uuid_v7 # or :uuid_v4, :hex, custom proc
130
+ end
131
+
132
+ customer = Customer.new
133
+ objid = customer.generate_object_identifier
134
+
135
+ # Provenance information available
136
+ puts customer.object_identifier_generator_type # => :uuid_v7
137
+ puts customer.objid_format # => :uuid (normalized format)
138
+ ```
139
+
140
+ **Benefits:**
141
+ - **Security auditing**: Know which generator created each identifier
142
+ - **Format normalization**: Eliminates ambiguity between UUID and hex formats
143
+ - **Migration support**: Track mixed generator usage during transitions
144
+
145
+ ## ExternalIdentifier Security Hardening
146
+
147
+ ### Provenance Validation
148
+
149
+ ExternalIdentifier now validates that objid values come from the ObjectIdentifier feature before deriving external identifiers.
150
+
151
+ #### Before (Potential Security Risk)
152
+ ```ruby
153
+ # Could derive external IDs from any string, including malicious input
154
+ extid = customer.derive_external_identifier("malicious_input")
155
+ ```
156
+
157
+ #### After (Hardened)
158
+ ```ruby
159
+ customer = Customer.new
160
+ customer.generate_object_identifier # Must generate objid first
161
+
162
+ # Only works with validated objid from ObjectIdentifier feature
163
+ extid = customer.derive_external_identifier # Secure: uses validated objid
164
+ ```
165
+
166
+ ### Improved Security Model
167
+
168
+ External identifiers are now derived using the internal objid as a seed for a new random value, rather than directly deriving from objid.
169
+
170
+ #### Before
171
+ ```ruby
172
+ # Direct derivation could leak information about objid
173
+ extid = hash(objid) # Information leakage risk
174
+ ```
175
+
176
+ #### After
177
+ ```ruby
178
+ # objid used as seed for new random value
179
+ extid = secure_hash(objid + additional_entropy) # No information leakage
180
+ ```
181
+
182
+ ### Error Handling Improvements
183
+
184
+ External identifier now raises clear errors for invalid usage:
185
+
186
+ ```ruby
187
+ class Customer < Familia::Horreum
188
+ feature :external_identifier # Missing: object_identifier dependency
189
+ end
190
+
191
+ customer = Customer.new
192
+ # Raises ExternalIdentifierError instead of returning nil
193
+ customer.derive_external_identifier
194
+ # => Familia::ExternalIdentifierError: Model does not have an objid field
195
+ ```
196
+
197
+ ## Migration Steps
198
+
199
+ ### 1. Update Method Names
200
+
201
+ Replace deprecated method names in your codebase:
202
+
203
+ ```bash
204
+ # Search and replace patterns:
205
+ grep -r "generate_objid" --include="*.rb" .
206
+ # Replace with: generate_object_identifier
207
+
208
+ grep -r "generate_external_identifier" --include="*.rb" .
209
+ # Replace with: derive_external_identifier
210
+
211
+ grep -r "generate_extid" --include="*.rb" .
212
+ # Remove usage - use derive_external_identifier instead
213
+ ```
214
+
215
+ ### 2. Add HMAC Secret for VerifiableIdentifier
216
+
217
+ If you plan to use VerifiableIdentifier:
218
+
219
+ ```ruby
220
+ # Generate secret
221
+ require 'securerandom'
222
+ secret = SecureRandom.hex(64)
223
+
224
+ # Add to your environment configuration
225
+ # .env, Rails credentials, or similar
226
+ VERIFIABLE_ID_HMAC_SECRET=your_generated_secret
227
+
228
+ # Verify configuration
229
+ puts ENV['VERIFIABLE_ID_HMAC_SECRET']&.length # Should be 128 characters
230
+ ```
231
+
232
+ ### 3. Update ExternalIdentifier Usage
233
+
234
+ Ensure proper dependency chain:
235
+
236
+ ```ruby
237
+ class YourModel < Familia::Horreum
238
+ # Required: ObjectIdentifier must come before ExternalIdentifier
239
+ feature :object_identifier
240
+ feature :external_identifier
241
+
242
+ # Configure generator if needed
243
+ object_identifier_generator :uuid_v7
244
+ end
245
+
246
+ # Usage pattern
247
+ model = YourModel.new
248
+ model.generate_object_identifier # Generate objid first
249
+ extid = model.derive_external_identifier # Then derive external ID
250
+ ```
251
+
252
+ ### 4. Review Security-Sensitive Code
253
+
254
+ Audit any code that processes identifiers from external sources:
255
+
256
+ ```ruby
257
+ # Before: Potentially unsafe
258
+ def process_identifier(external_id)
259
+ # Could process forged identifiers
260
+ model = Model.find_by_external_id(external_id)
261
+ end
262
+
263
+ # After: With verification
264
+ def process_identifier(verifiable_id)
265
+ # Verify identifier authenticity first
266
+ unless Model.verified_identifier?(verifiable_id)
267
+ raise SecurityError, "Invalid identifier"
268
+ end
269
+
270
+ original_id = Model.extract_identifier(verifiable_id)
271
+ model = Model.new(original_id)
272
+ end
273
+ ```
274
+
275
+ ## Breaking Changes
276
+
277
+ 1. **`generate_extid` removed** - Use instance-level `derive_external_identifier` instead
278
+ 2. **ExternalIdentifier validation** - Now raises `ExternalIdentifierError` instead of returning `nil` for models without objid
279
+ 3. **Method names changed** - `generate_objid` → `generate_object_identifier`, `generate_external_identifier` → `derive_external_identifier`
280
+
281
+ ## New Security Capabilities
282
+
283
+ 1. **Cryptographic identifier verification** - Prevent forged IDs with HMAC signatures
284
+ 2. **Scoped namespaces** - Isolate identifiers by tenant, environment, or role
285
+ 3. **Provenance tracking** - Know which generator created each identifier
286
+ 4. **Information leakage prevention** - External IDs no longer directly expose internal IDs
287
+ 5. **Input validation** - Clear error messages for invalid operations
288
+
289
+ ## Testing Your Migration
290
+
291
+ ```ruby
292
+ # Test ObjectIdentifier changes
293
+ model = YourModel.new
294
+ objid = model.generate_object_identifier
295
+ extid = model.derive_external_identifier
296
+ puts "Generator: #{model.object_identifier_generator_type}"
297
+
298
+ # Test VerifiableIdentifier (if using)
299
+ vid = model.generate_verifiable_id
300
+ puts "Verifiable: #{YourModel.verified_identifier?(vid)}"
301
+
302
+ # Test scoped identifiers (if using)
303
+ scoped_vid = model.generate_verifiable_id(scope: 'production')
304
+ puts "Scoped valid: #{YourModel.verified_identifier?(scoped_vid, scope: 'production')}"
305
+ puts "Wrong scope: #{YourModel.verified_identifier?(scoped_vid, scope: 'development')}"
306
+ ```
@@ -0,0 +1,110 @@
1
+ # Migrating Guide: Security Features (v2.0.0-pre5)
2
+
3
+ This guide covers adopting the security enhancements introduced in v2.0.0-pre5.
4
+
5
+ ## Security Feature Adoption
6
+
7
+ ### 1. Configure Encryption Keys
8
+
9
+ Before using encrypted fields, configure encryption keys:
10
+
11
+ ```ruby
12
+ Familia.configure do |config|
13
+ config.encryption_keys = {
14
+ v1: 'your-32-byte-base64-encoded-key==',
15
+ v2: 'newer-32-byte-base64-encoded-key=='
16
+ }
17
+ config.current_key_version = :v2
18
+ end
19
+ ```
20
+
21
+ **Key Management:**
22
+ - Use secure key storage (environment variables, key management services)
23
+ - Rotate keys regularly by adding new versions
24
+ - Never remove old key versions while data exists
25
+
26
+ ### 2. Identify Sensitive Fields
27
+
28
+ Mark fields that contain sensitive data:
29
+
30
+ **For Encryption:**
31
+ ```ruby
32
+ class Vault < Familia::Horreum
33
+ feature :encrypted_fields
34
+
35
+ field :name # Plaintext
36
+ encrypted_field :secret_key # Encrypted at rest
37
+ encrypted_field :api_token # Transparent access
38
+ end
39
+ ```
40
+
41
+ **For Transient Fields:**
42
+ ```ruby
43
+ class User < Familia::Horreum
44
+ feature :transient_fields
45
+
46
+ field :email # Persisted
47
+ transient_field :password # Never persisted
48
+ transient_field :session_token # Runtime only
49
+ end
50
+ ```
51
+
52
+ ### 3. Update Serialization Code
53
+
54
+ Handle `RedactedString` in serialization:
55
+
56
+ **Before:**
57
+ ```ruby
58
+ def to_json
59
+ { name: name, password: password }.to_json
60
+ end
61
+ ```
62
+
63
+ **After:**
64
+ ```ruby
65
+ def to_json
66
+ # RedactedString automatically excluded from serialization
67
+ { name: name }.to_json # password field omitted if transient
68
+ end
69
+ ```
70
+
71
+ **Manual RedactedString Handling:**
72
+ ```ruby
73
+ # Access original value when needed
74
+ password.reveal # Returns actual string value
75
+ password.redacted? # Returns true if redacted
76
+ ```
77
+
78
+ ### 4. Implement Key Rotation Procedures
79
+
80
+ **Rotation Process:**
81
+ 1. Add new key version to configuration
82
+ 2. Update `current_key_version`
83
+ 3. Re-encrypt existing data gradually
84
+ 4. Remove old keys after migration complete
85
+
86
+ **Example Rotation Script:**
87
+ ```ruby
88
+ # Add new key version
89
+ Familia.config.encryption_keys[:v3] = 'new-key'
90
+ Familia.config.current_key_version = :v3
91
+
92
+ # Re-encrypt existing records
93
+ Vault.all.each do |vault|
94
+ vault.save # Automatically uses new key version
95
+ end
96
+ ```
97
+
98
+ ## Security Best Practices
99
+
100
+ - **Environment Variables:** Store keys in environment variables, not code
101
+ - **Key Rotation:** Rotate encryption keys regularly (quarterly/annually)
102
+ - **Field Selection:** Only encrypt fields that truly need protection
103
+ - **Memory Clearing:** Use transient fields for temporary sensitive data
104
+ - **Logging:** Verify RedactedString prevents accidental logging
105
+
106
+ ## Next Steps
107
+
108
+ After implementing security features:
109
+ 1. Review [Architecture Migration](v2.0.0-pre6.md) for persistence improvements
110
+ 2. Explore [Relationships Migration](v2.0.0-pre7.md) for the relationship system
@@ -0,0 +1,154 @@
1
+ # Migrating Guide: Architecture Improvements (v2.0.0-pre6)
2
+
3
+ This guide covers the architecture enhancements and new persistence methods in v2.0.0-pre6.
4
+
5
+ ## Architecture Improvements
6
+
7
+ ### 1. Enhanced Persistence Operations
8
+
9
+ **New `save_if_not_exists` Method:**
10
+ ```ruby
11
+ user = User.new(email: 'user@example.com')
12
+
13
+ # Only save if the user doesn't already exist
14
+ if user.save_if_not_exists
15
+ puts "User created successfully"
16
+ else
17
+ puts "User already exists"
18
+ end
19
+ ```
20
+
21
+ **Atomic Persistence with Transactions:**
22
+ ```ruby
23
+ user.transaction do |conn|
24
+ conn.set(user.key, user.serialize)
25
+ conn.sadd("all_users", user.identifier)
26
+ conn.expire(user.key, user.ttl) if user.ttl
27
+ end
28
+ ```
29
+
30
+ ### 2. Modular Class Structure
31
+
32
+ The Horreum class structure was reorganized for better maintainability:
33
+
34
+ **Core Modules:**
35
+ - `Familia::Horreum::Core` - Essential functionality
36
+ - `Familia::Horreum::ClassMethods` - Class-level methods
37
+ - `Familia::Horreum::Serialization` - Object serialization
38
+ - `Familia::Horreum::Commands` - Redis command wrappers
39
+
40
+ **Feature System Improvements:**
41
+ - Dependency management between features
42
+ - Cleaner feature activation
43
+ - Better error handling for missing dependencies
44
+
45
+ ### 3. Enhanced Error Handling
46
+
47
+ **New Exception Types:**
48
+ ```ruby
49
+ begin
50
+ user.save!
51
+ rescue Familia::PersistenceError => e
52
+ puts "Failed to save: #{e.message}"
53
+ rescue Familia::ValidationError => e
54
+ puts "Validation failed: #{e.message}"
55
+ end
56
+ ```
57
+
58
+ **Improved Data Consistency:**
59
+ - Automatic retry for transient Redis connection issues
60
+ - Better handling of concurrent modifications
61
+ - Enhanced validation before persistence operations
62
+
63
+ ## Migration Steps
64
+
65
+ ### 1. Update Error Handling
66
+
67
+ **Before (v2.0.0-pre5):**
68
+ ```ruby
69
+ begin
70
+ user.save
71
+ rescue => e
72
+ puts "Something went wrong: #{e}"
73
+ end
74
+ ```
75
+
76
+ **After (v2.0.0-pre6):**
77
+ ```ruby
78
+ begin
79
+ user.save
80
+ rescue Familia::PersistenceError => e
81
+ puts "Persistence failed: #{e.message}"
82
+ # Handle specific persistence issues
83
+ rescue Familia::ValidationError => e
84
+ puts "Invalid data: #{e.message}"
85
+ # Handle validation failures
86
+ end
87
+ ```
88
+
89
+ ### 2. Adopt Conditional Persistence
90
+
91
+ Replace existence checks with atomic operations:
92
+
93
+ **Before:**
94
+ ```ruby
95
+ user = User.new(email: email)
96
+ unless User.exists?(email)
97
+ user.save
98
+ end
99
+ ```
100
+
101
+ **After:**
102
+ ```ruby
103
+ user = User.new(email: email)
104
+ user.save_if_not_exists
105
+ ```
106
+
107
+ ### 3. Leverage Transaction Support
108
+
109
+ For complex operations, use transactions:
110
+
111
+ ```ruby
112
+ # Before - Multiple separate operations
113
+ user.save
114
+ user.tags.add(tag)
115
+ user.scores.add(score, timestamp)
116
+
117
+ # After - Atomic transaction
118
+ user.transaction do |conn|
119
+ conn.set(user.key, user.serialize)
120
+ conn.sadd(user.tags.key, tag)
121
+ conn.zadd(user.scores.key, timestamp, score)
122
+ end
123
+ ```
124
+
125
+ ## Performance Improvements
126
+
127
+ ### Connection Management
128
+ - Improved connection pooling with better resource utilization
129
+ - Reduced connection overhead through intelligent connection reuse
130
+ - Enhanced concurrent operation support
131
+
132
+ ### Feature System
133
+ - Lazy feature loading reduces memory footprint
134
+ - Optimized method dispatch for feature methods
135
+ - Better dependency resolution
136
+
137
+ ## Breaking Changes
138
+
139
+ ### Method Signatures
140
+ - Some internal methods changed signatures for better consistency
141
+ - Error handling improved with specific exception types
142
+ - Transaction block interface standardized
143
+
144
+ ### Feature Dependencies
145
+ - Features now explicitly declare dependencies
146
+ - Better error messages for missing feature requirements
147
+ - Automatic dependency resolution where possible
148
+
149
+ ## Next Steps
150
+
151
+ After completing architecture migration:
152
+ 1. Explore [Relationships Migration](v2.0.0-pre7.md) for the comprehensive relationship system
153
+ 2. Review updated documentation for architectural patterns
154
+ 3. Consider adopting new persistence patterns in your application