familia 2.0.0.pre7 → 2.0.0.pre10

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 (91) 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 +184 -0
  8. data/CLAUDE.md +8 -5
  9. data/Gemfile +1 -1
  10. data/Gemfile.lock +3 -3
  11. data/README.md +97 -2
  12. data/changelog.d/README.md +66 -0
  13. data/changelog.d/fragments/.keep +0 -0
  14. data/changelog.d/template.md.j2 +29 -0
  15. data/docs/archive/.gitignore +2 -0
  16. data/docs/archive/FAMILIA_RELATIONSHIPS.md +210 -0
  17. data/docs/archive/FAMILIA_TECHNICAL.md +823 -0
  18. data/docs/archive/FAMILIA_UPDATE.md +226 -0
  19. data/docs/archive/README.md +67 -0
  20. data/docs/guides/.gitignore +2 -0
  21. data/docs/{wiki → guides}/Feature-System-Guide.md +0 -15
  22. data/docs/{wiki → guides}/Relationships-Guide.md +103 -50
  23. data/docs/guides/relationships-methods.md +266 -0
  24. data/examples/relationships_basic.rb +90 -157
  25. data/familia.gemspec +4 -4
  26. data/lib/familia/connection.rb +4 -21
  27. data/lib/familia/features/external_identifiers/external_identifier_field_type.rb +120 -0
  28. data/lib/familia/features/external_identifiers.rb +111 -0
  29. data/lib/familia/features/object_identifiers/object_identifier_field_type.rb +91 -0
  30. data/lib/familia/features/object_identifiers.rb +194 -0
  31. data/lib/familia/features/relationships/cascading.rb +0 -1
  32. data/lib/familia/features/relationships/indexing.rb +160 -176
  33. data/lib/familia/features/relationships/membership.rb +16 -22
  34. data/lib/familia/features/relationships/querying.rb +7 -12
  35. data/lib/familia/features/relationships/score_encoding.rb +1 -3
  36. data/lib/familia/features/relationships/tracking.rb +61 -22
  37. data/lib/familia/features/relationships.rb +15 -8
  38. data/lib/familia/features/transient_fields.rb +8 -10
  39. data/lib/familia/features.rb +16 -13
  40. data/lib/familia/horreum/core/serialization.rb +2 -5
  41. data/lib/familia/horreum/subclass/definition.rb +36 -0
  42. data/lib/familia/horreum.rb +15 -24
  43. data/lib/familia/version.rb +1 -3
  44. data/setup.cfg +12 -0
  45. data/try/core/errors_try.rb +1 -1
  46. data/try/features/{encrypted_fields_core_try.rb → encrypted_fields/encrypted_fields_core_try.rb} +1 -1
  47. data/try/features/{encrypted_fields_integration_try.rb → encrypted_fields/encrypted_fields_integration_try.rb} +1 -1
  48. data/try/features/{encrypted_fields_no_cache_security_try.rb → encrypted_fields/encrypted_fields_no_cache_security_try.rb} +1 -1
  49. data/try/features/{encrypted_fields_security_try.rb → encrypted_fields/encrypted_fields_security_try.rb} +1 -1
  50. data/try/features/{expiration_try.rb → expiration/expiration_try.rb} +1 -1
  51. data/try/features/external_identifiers/external_identifiers_try.rb +203 -0
  52. data/try/features/object_identifiers/object_identifiers_integration_try.rb +289 -0
  53. data/try/features/object_identifiers/object_identifiers_try.rb +191 -0
  54. data/try/features/{quantization_try.rb → quantization/quantization_try.rb} +1 -1
  55. data/try/features/{categorical_permissions_try.rb → relationships/categorical_permissions_try.rb} +1 -1
  56. data/try/features/relationships/relationships_api_changes_try.rb +339 -0
  57. data/try/features/{relationships_edge_cases_try.rb → relationships/relationships_edge_cases_try.rb} +1 -1
  58. data/try/features/{relationships_performance_minimal_try.rb → relationships/relationships_performance_minimal_try.rb} +1 -1
  59. data/try/features/{relationships_performance_simple_try.rb → relationships/relationships_performance_simple_try.rb} +1 -1
  60. data/try/features/{relationships_performance_try.rb → relationships/relationships_performance_try.rb} +1 -1
  61. data/try/features/{relationships_performance_working_try.rb → relationships/relationships_performance_working_try.rb} +1 -1
  62. data/try/features/{relationships_try.rb → relationships/relationships_try.rb} +7 -6
  63. data/try/features/{safe_dump_advanced_try.rb → safe_dump/safe_dump_advanced_try.rb} +1 -1
  64. data/try/features/{safe_dump_try.rb → safe_dump/safe_dump_try.rb} +1 -1
  65. data/try/features/{transient_fields_core_try.rb → transient_fields/transient_fields_core_try.rb} +1 -1
  66. data/try/features/{transient_fields_integration_try.rb → transient_fields/transient_fields_integration_try.rb} +1 -1
  67. metadata +80 -60
  68. /data/docs/{wiki → guides}/API-Reference.md +0 -0
  69. /data/docs/{wiki → guides}/Connection-Pooling-Guide.md +0 -0
  70. /data/docs/{wiki → guides}/Encrypted-Fields-Overview.md +0 -0
  71. /data/docs/{wiki → guides}/Expiration-Feature-Guide.md +0 -0
  72. /data/docs/{wiki → guides}/Features-System-Developer-Guide.md +0 -0
  73. /data/docs/{wiki → guides}/Field-System-Guide.md +0 -0
  74. /data/docs/{wiki → guides}/Home.md +0 -0
  75. /data/docs/{wiki → guides}/Implementation-Guide.md +0 -0
  76. /data/docs/{wiki → guides}/Quantization-Feature-Guide.md +0 -0
  77. /data/docs/{wiki → guides}/Security-Model.md +0 -0
  78. /data/docs/{wiki → guides}/Transient-Fields-Guide.md +0 -0
  79. /data/try/features/{encryption_fields → encrypted_fields}/aad_protection_try.rb +0 -0
  80. /data/try/features/{encryption_fields → encrypted_fields}/concealed_string_core_try.rb +0 -0
  81. /data/try/features/{encryption_fields → encrypted_fields}/context_isolation_try.rb +0 -0
  82. /data/try/features/{encryption_fields → encrypted_fields}/error_conditions_try.rb +0 -0
  83. /data/try/features/{encryption_fields → encrypted_fields}/fresh_key_derivation_try.rb +0 -0
  84. /data/try/features/{encryption_fields → encrypted_fields}/fresh_key_try.rb +0 -0
  85. /data/try/features/{encryption_fields → encrypted_fields}/key_rotation_try.rb +0 -0
  86. /data/try/features/{encryption_fields → encrypted_fields}/memory_security_try.rb +0 -0
  87. /data/try/features/{encryption_fields → encrypted_fields}/missing_current_key_version_try.rb +0 -0
  88. /data/try/features/{encryption_fields → encrypted_fields}/nonce_uniqueness_try.rb +0 -0
  89. /data/try/features/{encryption_fields → encrypted_fields}/secure_by_default_behavior_try.rb +0 -0
  90. /data/try/features/{encryption_fields → encrypted_fields}/thread_safety_try.rb +0 -0
  91. /data/try/features/{encryption_fields → encrypted_fields}/universal_serialization_safety_try.rb +0 -0
@@ -0,0 +1,226 @@
1
+ # Familia v2.0.0-pre Series Update Overview
2
+
3
+ **Familia** is a Ruby ORM for Redis/Valkey that provides object mapping and persistence capabilities. This document summarizes the major updates from v2.0.0-pre through v2.0.0-pre7, representing a significant evolution with new features, security enhancements, and architectural improvements.
4
+
5
+ ## Version Summary
6
+
7
+ | Version | Focus | Key Features |
8
+ |---------|-------|-------------|
9
+ | v2.0.0-pre | Foundation | Modern API, Valkey support, connection pooling |
10
+ | v2.0.0-pre5 | Security | Encrypted fields, transient fields, RedactedString |
11
+ | v2.0.0-pre6 | Architecture | Horreum reorganization, enhanced persistence |
12
+ | v2.0.0-pre7 | Relationships | Comprehensive relationship system, permissions |
13
+
14
+ ---
15
+
16
+ ## v2.0.0-pre - Foundation Release
17
+
18
+ ### Major API Modernization
19
+ - **Complete API redesign** for clarity and modern Ruby conventions
20
+ - **Valkey compatibility** alongside traditional Redis support
21
+ - **Ruby 3.4+ modernization** with fiber and thread safety improvements
22
+ - **Connection pooling foundation** with provider pattern architecture
23
+
24
+ ### Security & Dependency Management
25
+ - **Critical security fixes** in Ruby workflow vulnerabilities
26
+ - **Systematic dependency resolution** via multi-constraint optimization
27
+ - **GitHub Actions security hardening** with matrix optimization
28
+
29
+ ### Documentation Infrastructure
30
+ - **YARD documentation workflow** with automated GitHub Pages deployment
31
+ - **Comprehensive wiki system** with structured documentation
32
+ - **Developer-focused guides** for implementation and usage
33
+
34
+ ---
35
+
36
+ ## v2.0.0-pre5 - Security Enhancement Release
37
+
38
+ ### Encrypted Fields System
39
+ - **Field-level encryption** with transparent access patterns
40
+ - **Multiple encryption providers**:
41
+ - XChaCha20-Poly1305 (preferred, requires rbnacl)
42
+ - AES-256-GCM (fallback, OpenSSL-based)
43
+ - **Field-specific key derivation** for cryptographic domain separation
44
+ - **Configurable key versioning** supporting key rotation
45
+
46
+ ```ruby
47
+ class Vault < Familia::Horreum
48
+ feature :encrypted_fields
49
+
50
+ field :name # Plaintext
51
+ encrypted_field :secret_key # Encrypted at rest
52
+ encrypted_field :api_token # Transparent access
53
+ end
54
+ ```
55
+
56
+ ### Transient Fields & RedactedString
57
+ - **Non-persistent field storage** for sensitive runtime data
58
+ - **RedactedString wrapper** preventing accidental logging/serialization
59
+ - **Memory-safe handling** of sensitive data in Ruby objects
60
+ - **API-safe serialization** excluding transient fields
61
+
62
+ ```ruby
63
+ class User < Familia::Horreum
64
+ feature :transient_fields
65
+
66
+ field :email
67
+ transient_field :password # Never persisted
68
+ transient_field :session_token # Runtime only
69
+ end
70
+ ```
71
+
72
+ ### Connection Pooling Enhancement
73
+ - **Connection provider pattern** for flexible pooling strategies
74
+ - **Multi-database support** with intelligent pool management
75
+ - **Thread-safe connection handling** for concurrent applications
76
+ - **Configurable pool sizing** and timeout management
77
+
78
+ ---
79
+
80
+ ## v2.0.0-pre6 - Architecture Enhancement Release
81
+
82
+ ### Horreum Architecture Reorganization
83
+ - **Modular class structure** with cleaner separation of concerns
84
+ - **Enhanced feature system** with dependency management
85
+ - **Improved inheritance patterns** for better code organization
86
+ - **Streamlined base class functionality**
87
+
88
+ ### Enhanced Persistence Operations
89
+ - **New `save_if_not_exists` method** for conditional persistence
90
+ - **Atomic persistence operations** with transaction support
91
+ - **Enhanced error handling** for persistence failures
92
+ - **Improved data consistency** guarantees
93
+
94
+ ### Security Improvements
95
+ - **Encryption field security hardening** with additional validation
96
+ - **Enhanced memory protection** for sensitive data handling
97
+ - **Improved key management** patterns and best practices
98
+ - **Security test suite expansion** with comprehensive coverage
99
+
100
+ ---
101
+
102
+ ## v2.0.0-pre7 - Relationships & Permissions Release
103
+
104
+ ### Comprehensive Relationships System
105
+ - **Three relationship types** optimized for different use cases:
106
+ - `tracked_in` - Multi-presence tracking with score encoding
107
+ - `indexed_by` - O(1) hash-based lookups
108
+ - `member_of` - Bidirectional membership with collision-free naming
109
+
110
+ ```ruby
111
+ class Customer < Familia::Horreum
112
+ feature :relationships
113
+
114
+ identifier_field :custid
115
+ field :custid, :name, :email
116
+
117
+ # Define collections
118
+ set :domains
119
+ tracked_in :active_users, type: :sorted_set
120
+ end
121
+
122
+ class Domain < Familia::Horreum
123
+ feature :relationships
124
+
125
+ identifier_field :domain_id
126
+ field :domain_id, :name
127
+
128
+ # Bidirectional relationship
129
+ member_of Customer, :domains, type: :set
130
+ end
131
+ ```
132
+
133
+ ### Categorical Permission System
134
+ - **Bit-encoded permissions** for efficient storage and querying
135
+ - **Time-based permission scoring** for temporal access control
136
+ - **Permission tier hierarchies** with inheritance patterns
137
+ - **Scalable permission management** for large object collections
138
+
139
+ ### Advanced Relationship Features
140
+ - **Score-based sorting** with custom scoring functions
141
+ - **Permission-aware queries** filtering by access levels
142
+ - **Relationship validation framework** ensuring data integrity
143
+ - **Performance optimizations** for large-scale relationship operations
144
+
145
+ ---
146
+
147
+ ## Breaking Changes & Migration
148
+
149
+ ### v2.0.0-pre Series
150
+ - **API method renaming** for consistency and clarity
151
+ - **Configuration changes** in connection management
152
+ - **Feature activation syntax** updates for the new system
153
+ - **Identifier field declaration** syntax modernization
154
+
155
+ ### Security Considerations
156
+ - **Encryption key configuration** required for encrypted fields
157
+ - **Memory handling changes** for sensitive data protection
158
+ - **Permission system migration** for existing relationship data
159
+
160
+ ---
161
+
162
+ ## Performance Improvements
163
+
164
+ ### Connection Management
165
+ - **Pool-based connections** reducing connection overhead
166
+ - **Intelligent connection reuse** across operations
167
+ - **Concurrent operation support** with thread-safe pooling
168
+
169
+ ### Relationship Operations
170
+ - **O(1) indexed lookups** for field-based queries
171
+ - **Optimized sorted set operations** for scored relationships
172
+ - **Batch relationship operations** for bulk updates
173
+ - **Memory-efficient bit encoding** for permission storage
174
+
175
+ ### Feature System
176
+ - **Lazy feature loading** reducing memory footprint
177
+ - **Dependency-aware activation** preventing conflicts
178
+ - **Optimized method dispatch** for feature methods
179
+
180
+ ---
181
+
182
+ ## Migration Guide Summary
183
+
184
+ ### From v1.x to v2.0.0-pre
185
+ 1. **Update connection configuration** to use new pooling system
186
+ 2. **Migrate identifier declarations** to new syntax
187
+ 3. **Update feature activations** to use `feature :name` syntax
188
+ 4. **Review method calls** for renamed API methods
189
+
190
+ ### Security Feature Adoption
191
+ 1. **Configure encryption keys** for encrypted fields
192
+ 2. **Identify sensitive fields** for encryption/transient marking
193
+ 3. **Update serialization code** to handle RedactedString
194
+ 4. **Implement key rotation procedures** for production systems
195
+
196
+ ### Relationship System Migration
197
+ 1. **Analyze existing relationships** for optimization opportunities
198
+ 2. **Choose appropriate relationship types** based on usage patterns
199
+ 3. **Implement permission systems** for access-controlled relationships
200
+ 4. **Update queries** to use new relationship methods
201
+
202
+ ---
203
+
204
+ ## Next Steps & Roadmap
205
+
206
+ ### Immediate (v2.0.0 Final)
207
+ - **Production stability** testing and bug fixes
208
+ - **Performance benchmarking** and optimization
209
+ - **Documentation completion** for all features
210
+ - **Migration tooling** for existing applications
211
+
212
+ ### Future Releases
213
+ - **Advanced encryption features** with hardware security modules
214
+ - **Extended relationship types** for specialized use cases
215
+ - **Performance analytics** and monitoring integration
216
+ - **Cloud-native deployment** patterns and examples
217
+
218
+ ---
219
+
220
+ ## Resources
221
+
222
+ - [GitHub Repository](https://github.com/delano/familia)
223
+ - [Wiki Documentation](https://github.com/delano/familia/wiki)
224
+ - [API Reference](docs/wiki/API-Reference.md)
225
+ - [Implementation Guide](docs/wiki/Implementation-Guide.md)
226
+ - [Security Model](docs/wiki/Security-Model.md)
@@ -0,0 +1,67 @@
1
+ # Archived Documentation
2
+
3
+ This directory contains original documentation files that have been migrated to the new Scriv-based changelog system and reorganized documentation structure.
4
+
5
+ ## Migration Date
6
+ **September 1, 2025** - As part of implementing [Issue #84: Scriv-based changelog system](https://github.com/delano/familia/issues/84)
7
+
8
+ ## Archived Files
9
+
10
+ ### FAMILIA_UPDATE.md
11
+ **Original Purpose:** Version summary table and detailed release notes for v2.0.0-pre series
12
+
13
+ **Migration Destinations:**
14
+ - **Changelog entries** → Extracted to Scriv fragments, aggregated into `CHANGELOG.md`
15
+ - **Migration guides** → Reorganized into `docs/migration/v2.0.0-pre*.md`
16
+ - **Feature descriptions** → Cross-referenced with existing feature guides in `docs/guides/`
17
+
18
+ ### FAMILIA_RELATIONSHIPS.md
19
+ **Original Purpose:** Auto-generated relationship methods reference
20
+
21
+ **Migration Destination:**
22
+ - **Complete content** → Moved to `docs/guides/relationships-methods.md`
23
+ - **Cross-referenced** with existing `docs/guides/Relationships-Guide.md`
24
+
25
+ ### FAMILIA_TECHNICAL.md
26
+ **Original Purpose:** Technical API reference for v2.0.0-pre series classes and methods
27
+
28
+ **Migration Destination:**
29
+ - **Core technical content** → Moved to `docs/reference/api-technical.md`
30
+ - **Cross-referenced** with existing `docs/guides/API-Reference.md`
31
+
32
+ ## New Documentation Structure
33
+
34
+ ```
35
+ docs/
36
+ ├── migration/ # Version-specific migration guides
37
+ │ ├── v2.0.0-pre.md # Foundation migration
38
+ │ ├── v2.0.0-pre5.md # Security features
39
+ │ ├── v2.0.0-pre6.md # Architecture improvements
40
+ │ └── v2.0.0-pre7.md # Relationships system
41
+ ├── guides/ # Feature guides (moved from wiki/)
42
+ │ ├── relationships-methods.md # From FAMILIA_RELATIONSHIPS.md
43
+ │ └── [other guides...]
44
+ ├── reference/ # Technical reference
45
+ │ └── api-technical.md # From FAMILIA_TECHNICAL.md
46
+ └── archive/ # This directory
47
+ ```
48
+
49
+ ## Why These Files Were Archived
50
+
51
+ 1. **Sustainability** - The original files accumulated overlapping content without clear organization
52
+ 2. **Maintainability** - Scriv fragment system prevents documentation bloat
53
+ 3. **Clarity** - Separation of changelog, guides, and reference improves findability
54
+ 4. **Workflow** - Fragment-based workflow scales better with development
55
+
56
+ ## Finding Migrated Content
57
+
58
+ - **Version changes** → Check `CHANGELOG.md` (generated from fragments)
59
+ - **How to upgrade** → See `docs/migration/` for version-specific guides
60
+ - **Feature usage** → See `docs/guides/` for implementation examples
61
+ - **API reference** → See `docs/reference/` for technical details
62
+
63
+ ## References
64
+
65
+ - [Issue #84](https://github.com/delano/familia/issues/84) - Original migration plan
66
+ - [Scriv Documentation](https://scriv.readthedocs.io/) - Changelog management tool
67
+ - [Keep a Changelog](https://keepachangelog.com/) - Changelog format standard
@@ -0,0 +1,2 @@
1
+ # Even all wiki markdown docs get the blues
2
+ !*.md
@@ -517,21 +517,6 @@ class ConfigurableModel < Familia::Horreum
517
517
  end
518
518
  ```
519
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
520
  ## Testing Features
536
521
 
537
522
  ### Feature Testing
@@ -27,9 +27,13 @@ class Customer < Familia::Horreum
27
27
  identifier_field :custid
28
28
  field :custid, :name, :email
29
29
 
30
- # Define relationship collections
31
- tracked_in :active_users, type: :sorted_set
32
- indexed_by :email_lookup, type: :hash
30
+ # Collections for relationships
31
+ set :domains # Simple set of domain IDs
32
+ sorted_set :activity # Activity feed with timestamps
33
+
34
+ # Class-level relationship collections (automatically managed)
35
+ class_tracked_in :all_customers, score: :created_at
36
+ class_indexed_by :email, :email_lookup
33
37
  end
34
38
 
35
39
  class Domain < Familia::Horreum
@@ -39,7 +43,7 @@ class Domain < Familia::Horreum
39
43
  field :domain_id, :name, :dns_zone
40
44
 
41
45
  # Define bidirectional membership
42
- member_of Customer, :domains, type: :set
46
+ member_of Customer, :domains
43
47
  end
44
48
  ```
45
49
 
@@ -57,27 +61,26 @@ class User < Familia::Horreum
57
61
  field :user_id, :name, :score_value
58
62
 
59
63
  # Simple sorted set tracking
60
- tracked_in :leaderboard, type: :sorted_set, score: :score_value
64
+ class_tracked_in :leaderboard, score: :score_value
61
65
 
62
66
  # Time-based tracking with automatic timestamps
63
- tracked_in :activity_log, type: :sorted_set
67
+ class_tracked_in :activity_log, score: :created_at
64
68
 
65
69
  # Proc-based scoring for complex calculations
66
- tracked_in :performance_metrics, type: :sorted_set,
67
- score: ->(user) { (user.score_value || 0) * 2 }
70
+ class_tracked_in :performance_metrics, score: -> { (score_value || 0) * 2 }
68
71
  end
69
72
 
70
73
  # Usage
71
74
  user = User.new(user_id: 'user123', score_value: 85)
72
75
 
73
76
  # Add to collections
74
- User.add_to_leaderboard(user) # Uses score_value (85)
75
- User.add_to_activity_log(user) # Uses current timestamp
76
- User.add_to_performance_metrics(user) # Uses proc result (170)
77
+ User.add_to_leaderboard(user) # Uses score_value (85)
78
+ User.add_to_activity_log(user) # Uses created_at timestamp
79
+ User.add_to_performance_metrics(user) # Uses proc result (170)
77
80
 
78
81
  # Query collections
79
82
  User.leaderboard.score('user123') # => 85.0
80
- User.activity_log.range_by_score('-inf', '+inf') # All users by time
83
+ User.activity_log.rangebyscore('-inf', '+inf') # All users by time
81
84
  User.performance_metrics.rank('user123') # User's rank by performance
82
85
  ```
83
86
 
@@ -93,8 +96,7 @@ class Document < Familia::Horreum
93
96
  field :doc_id, :title, :content
94
97
 
95
98
  # Permission-based tracking with 8-bit encoding
96
- tracked_in :authorized_users, type: :sorted_set,
97
- score: :encode_permissions
99
+ class_tracked_in :authorized_users, score: :encode_permissions
98
100
 
99
101
  private
100
102
 
@@ -183,7 +185,7 @@ end
183
185
 
184
186
  ### Hash-Based Lookups
185
187
 
186
- The `indexed_by` relationship creates O(1) hash-based indexes for field values:
188
+ The `indexed_by` relationship creates O(1) hash-based indexes for field values. The `context` parameter determines index ownership and scope:
187
189
 
188
190
  ```ruby
189
191
  class User < Familia::Horreum
@@ -191,55 +193,102 @@ class User < Familia::Horreum
191
193
 
192
194
  field :email, :username, :department
193
195
 
194
- # Create indexes for fast lookups
195
- indexed_by :email_index, field: :email
196
- indexed_by :username_index, field: :username
197
- indexed_by :department_index, field: :department
196
+ # Global indexes for system-wide unique lookups
197
+ class_indexed_by :email, :email_index
198
+ class_indexed_by :username, :username_index
199
+
200
+ # Scoped indexes for values unique within a context
201
+ indexed_by :department, :department_index, parent: Organization
198
202
  end
199
203
 
200
- # Usage
204
+ # Usage for Global Context
201
205
  user = User.new(email: 'john@example.com', username: 'johndoe')
202
- User.add_to_email_index(user)
203
- User.add_to_username_index(user)
204
206
 
205
- # Fast O(1) lookups
207
+ # Add to global indexes (instance methods)
208
+ user.add_to_global_email_index
209
+ user.add_to_global_username_index
210
+
211
+ # Fast O(1) lookups (class methods)
206
212
  user_id = User.email_index.get('john@example.com') # => user.identifier
207
213
  user_id = User.username_index.get('johndoe') # => user.identifier
208
214
 
209
215
  # Batch operations
210
216
  users = [user1, user2, user3]
211
- users.each { |u| User.add_to_email_index(u) }
217
+ users.each { |u| u.add_to_global_email_index }
212
218
 
213
219
  # Check if indexed
214
220
  User.email_index.exists?('john@example.com') # => true
221
+
222
+ # Usage for Scoped Context
223
+ organization = Organization.new(org_id: 'acme_corp')
224
+ organization.find_by_department('engineering') # Find user by department within this org
215
225
  ```
216
226
 
217
- ### Multi-Field Indexing
227
+ ### Context Parameter Usage Patterns
228
+
229
+ Understanding when to use global vs class context:
218
230
 
219
231
  ```ruby
220
232
  class Product < Familia::Horreum
221
233
  feature :relationships
222
234
 
223
- field :category, :brand, :status
235
+ field :sku, :category, :brand
224
236
 
225
- # Composite indexing for complex queries
226
- indexed_by :category_brand_index, field: ->(product) {
227
- "#{product.category}:#{product.brand}"
228
- }
237
+ # Global context: SKUs must be unique system-wide
238
+ class_indexed_by :sku, :sku_index
229
239
 
230
- indexed_by :active_products, field: ->(product) {
231
- product.status == 'active' ? product.identifier : nil
232
- }
240
+ # Class context: Categories are unique per brand
241
+ indexed_by :category, :category_index, parent: Brand
233
242
  end
234
243
 
235
- # Usage
236
- product = Product.new(category: 'electronics', brand: 'apple', status: 'active')
237
- Product.add_to_category_brand_index(product)
238
- Product.add_to_active_products(product)
244
+ class Brand < Familia::Horreum
245
+ feature :relationships
246
+
247
+ identifier_field :brand_id
248
+ field :brand_id, :name
249
+ sorted_set :products
250
+ end
251
+
252
+ # Usage patterns:
253
+ product = Product.new(sku: 'ELEC001', category: 'laptops', brand: 'apple')
254
+
255
+ # Global indexing (system-wide unique SKUs)
256
+ product.add_to_global_sku_index
257
+ Product.sku_index.get('ELEC001') # => product.identifier
239
258
 
240
- # Query by composite key
241
- Product.category_brand_index.get('electronics:apple') # => product.identifier
242
- Product.active_products.exists?(product.identifier) # => true
259
+ # Scoped indexing (categories unique per brand)
260
+ brand = Brand.new(brand_id: 'apple', name: 'Apple Inc.')
261
+ brand.find_by_category('laptops') # Find products in this brand's laptop category
262
+ ```
263
+
264
+ ### Context Parameter Reference
265
+
266
+ The `context` parameter is a **required** architectural decision that determines index scope:
267
+
268
+ | Context Type | Usage | Redis Key Pattern | When to Use |
269
+ |--------------|--------|------------------|-------------|
270
+ | `:global` | `context: :global` | `global:index_name` | Field values unique system-wide (emails, usernames, API keys) |
271
+ | Class | `context: SomeClass` | `someclass:123:index_name` | Field values unique within parent object scope (project names per team) |
272
+
273
+ #### Generated Methods
274
+
275
+ **Global Context** (`context: :global`):
276
+ - **Instance methods**: `object.add_to_global_index_name`, `object.remove_from_global_index_name`
277
+ - **Class methods**: `Class.index_name` (returns hash), `Class.find_by_field`
278
+
279
+ **Class Context** (`context: Customer`):
280
+ - **Instance methods**: `object.add_to_customer_index_name(customer)`, `object.remove_from_customer_index_name(customer)`
281
+ - **Class methods on context**: `customer.find_by_field(value)`, `customer.find_all_by_field(values)`
282
+
283
+ #### Migration from Incorrect Syntax
284
+
285
+ ```ruby
286
+ # ❌ Old incorrect syntax (will cause ArgumentError)
287
+ indexed_by :email_lookup, field: :email
288
+
289
+ # ✅ New correct syntax
290
+ class_indexed_by :email, :email_lookup # Global scope
291
+ indexed_by :email, :customer_lookup, parent: Customer # Scoped per customer
243
292
  ```
244
293
 
245
294
  ## Member Of Relationships
@@ -444,8 +493,8 @@ class User < Familia::Horreum
444
493
 
445
494
  # Multi-tenant membership
446
495
  member_of Organization, :members, type: :set
447
- tracked_in :global_activity, type: :sorted_set
448
- indexed_by :email_lookup, field: :email
496
+ class_tracked_in :global_activity, score: :created_at
497
+ class_indexed_by :email, :email_lookup
449
498
  end
450
499
 
451
500
  class Project < Familia::Horreum
@@ -455,7 +504,7 @@ class Project < Familia::Horreum
455
504
  field :project_id, :name, :status
456
505
 
457
506
  member_of Organization, :projects, type: :set
458
- tracked_in :status_timeline, type: :sorted_set,
507
+ class_tracked_in :status_timeline,
459
508
  score: ->(proj) { "#{Time.now.to_i}.#{proj.status.hash}" }
460
509
  end
461
510
 
@@ -464,17 +513,21 @@ org = Organization.new(org_id: 'org123', name: 'Acme Corp')
464
513
  user = User.new(user_id: 'user456', email: 'john@acme.com')
465
514
  project = Project.new(project_id: 'proj789', name: 'Website')
466
515
 
467
- # Establish relationships
468
- user.add_to_organization_members(org.org_id)
469
- project.add_to_organization_projects(org.org_id)
516
+ # Establish relationships with clean syntax
517
+ org.members << user # Clean Ruby-like syntax
518
+ org.projects << project
519
+
520
+ # Save objects to trigger automatic indexing
521
+ user.save # Automatically added to class-level indexes
522
+ project.save # Automatically added to class-level tracking
470
523
 
471
524
  # Query organization structure
472
525
  org.members.size # Number of organization members
473
526
  org.projects.members # All project IDs in organization
474
527
 
475
- # Global indexes
476
- User.add_to_email_lookup(user)
528
+ # Automatic class-level indexing (no manual calls needed)
477
529
  user_id = User.email_lookup.get('john@acme.com') # Fast email lookup
530
+ found_user = User.find_by_email('john@acme.com') # Convenience method
478
531
  ```
479
532
 
480
533
  ### Analytics and Reporting
@@ -485,7 +538,7 @@ class AnalyticsService
485
538
  since = (Time.now - days.days).to_f.floor
486
539
 
487
540
  # Get all users active in time period
488
- active_users = User.global_activity.range_by_score(since, '+inf')
541
+ active_users = User.activity.range_by_score(since, '+inf')
489
542
 
490
543
  # Analyze permission levels
491
544
  permission_breakdown = Document.authorized_users
@@ -495,7 +548,7 @@ class AnalyticsService
495
548
  {
496
549
  total_active_users: active_users.size,
497
550
  permission_breakdown: permission_breakdown.transform_values(&:size),
498
- top_contributors: User.global_activity.range(0, 9, with_scores: true)
551
+ top_contributors: User.activity.range(0, 9, with_scores: true)
499
552
  }
500
553
  end
501
554