opaque_id 1.3.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +136 -0
- data/README.md +62 -70
- data/docs/_config.yml +8 -17
- data/docs/algorithms.md +7 -4
- data/docs/alphabets.md +3 -0
- data/docs/api-reference.md +3 -0
- data/docs/assets/css/custom.scss +6 -53
- data/docs/configuration.md +3 -0
- data/docs/development.md +3 -0
- data/docs/getting-started.md +3 -0
- data/docs/index.md +6 -3
- data/docs/installation.md +3 -0
- data/docs/performance.md +6 -3
- data/docs/security.md +3 -0
- data/docs/usage.md +18 -15
- data/docs/use-cases.md +3 -0
- data/lib/opaque_id/version.rb +1 -1
- data/lib/opaque_id.rb +4 -1
- data/release-please-config.json +2 -1
- metadata +1 -9
- data/tasks/0001-prd-opaque-id-gem.md +0 -202
- data/tasks/0002-prd-publishing-release-automation.md +0 -206
- data/tasks/0003-prd-documentation-site.md +0 -191
- data/tasks/references/opaque_gem_requirements.md +0 -482
- data/tasks/references/original_identifiable_concern_and_nanoid.md +0 -110
- data/tasks/tasks-0001-prd-opaque-id-gem.md +0 -109
- data/tasks/tasks-0002-prd-publishing-release-automation.md +0 -177
- data/tasks/tasks-0003-prd-documentation-site.md +0 -84
data/docs/development.md
CHANGED
@@ -10,6 +10,9 @@ permalink: /development/
|
|
10
10
|
|
11
11
|
This guide covers development setup, guidelines, and contribution information for OpaqueId. Whether you're contributing to the project or developing applications that use OpaqueId, this guide will help you get started.
|
12
12
|
|
13
|
+
- TOC
|
14
|
+
{:toc}
|
15
|
+
|
13
16
|
## Prerequisites
|
14
17
|
|
15
18
|
Before you begin development, ensure you have the following installed:
|
data/docs/getting-started.md
CHANGED
@@ -10,6 +10,9 @@ permalink: /getting-started/
|
|
10
10
|
|
11
11
|
This guide will help you get up and running with OpaqueId in your Rails application. We'll cover installation, basic setup, and common usage patterns.
|
12
12
|
|
13
|
+
- TOC
|
14
|
+
{:toc}
|
15
|
+
|
13
16
|
## Prerequisites
|
14
17
|
|
15
18
|
Before you begin, ensure you have:
|
data/docs/index.md
CHANGED
@@ -12,7 +12,10 @@ permalink: /
|
|
12
12
|
[](https://github.com/rubocop/rubocop)
|
13
13
|
[](https://rubygems.org/gems/opaque_id)
|
14
14
|
|
15
|
-
A Ruby gem for generating
|
15
|
+
A simple Ruby gem for generating secure, opaque IDs for ActiveRecord models. OpaqueId provides a drop-in replacement for `nanoid.rb` using Ruby's built-in `SecureRandom` methods, with slug-like IDs as the default for optimal URL safety and user experience.
|
16
|
+
|
17
|
+
- TOC
|
18
|
+
{:toc}
|
16
19
|
|
17
20
|
## Features
|
18
21
|
|
@@ -54,10 +57,10 @@ end
|
|
54
57
|
|
55
58
|
# Create a user - opaque_id is automatically generated
|
56
59
|
user = User.create!(name: "John Doe")
|
57
|
-
puts user.opaque_id # => "
|
60
|
+
puts user.opaque_id # => "izkpm55j334u8x9y2"
|
58
61
|
|
59
62
|
# Find by opaque_id
|
60
|
-
user = User.find_by_opaque_id("
|
63
|
+
user = User.find_by_opaque_id("izkpm55j334u8x9y2")
|
61
64
|
```
|
62
65
|
|
63
66
|
## Why OpaqueId?
|
data/docs/installation.md
CHANGED
@@ -10,6 +10,9 @@ permalink: /installation/
|
|
10
10
|
|
11
11
|
This guide covers all installation methods for OpaqueId, from basic setup to advanced configurations.
|
12
12
|
|
13
|
+
- TOC
|
14
|
+
{:toc}
|
15
|
+
|
13
16
|
## Requirements
|
14
17
|
|
15
18
|
Before installing OpaqueId, ensure your environment meets these requirements:
|
data/docs/performance.md
CHANGED
@@ -8,17 +8,20 @@ permalink: /performance/
|
|
8
8
|
|
9
9
|
# Performance
|
10
10
|
|
11
|
-
OpaqueId is designed for
|
11
|
+
OpaqueId is designed for efficient ID generation with optimized algorithms and memory usage. This guide covers performance characteristics, optimization strategies, and scalability considerations.
|
12
|
+
|
13
|
+
- TOC
|
14
|
+
{:toc}
|
12
15
|
|
13
16
|
## Performance Characteristics
|
14
17
|
|
15
18
|
### Generation Speed
|
16
19
|
|
17
|
-
OpaqueId is designed for
|
20
|
+
OpaqueId is designed for efficient ID generation with optimized algorithms for different alphabet sizes and ID lengths.
|
18
21
|
|
19
22
|
#### Algorithm Performance
|
20
23
|
|
21
|
-
- **Fast Path (64-character alphabets)**: Uses bitwise operations for
|
24
|
+
- **Fast Path (64-character alphabets)**: Uses bitwise operations for efficient generation with no rejection sampling overhead
|
22
25
|
- **Unbiased Path (Other alphabets)**: Uses rejection sampling for unbiased distribution with slight performance overhead
|
23
26
|
- **Performance scales linearly** with ID length and batch size
|
24
27
|
|
data/docs/security.md
CHANGED
@@ -10,6 +10,9 @@ permalink: /security/
|
|
10
10
|
|
11
11
|
OpaqueId is designed with security as a primary concern, providing cryptographically secure ID generation with protection against various attack vectors. This guide covers security considerations, best practices, and threat model analysis.
|
12
12
|
|
13
|
+
- TOC
|
14
|
+
{:toc}
|
15
|
+
|
13
16
|
## Cryptographic Security
|
14
17
|
|
15
18
|
### SecureRandom Foundation
|
data/docs/usage.md
CHANGED
@@ -10,6 +10,9 @@ permalink: /usage/
|
|
10
10
|
|
11
11
|
This guide covers all usage patterns for OpaqueId, from basic standalone generation to advanced ActiveRecord integration.
|
12
12
|
|
13
|
+
- TOC
|
14
|
+
{:toc}
|
15
|
+
|
13
16
|
## Standalone ID Generation
|
14
17
|
|
15
18
|
OpaqueId can be used independently of ActiveRecord for generating secure, random IDs.
|
@@ -17,9 +20,9 @@ OpaqueId can be used independently of ActiveRecord for generating secure, random
|
|
17
20
|
### Basic Usage
|
18
21
|
|
19
22
|
```ruby
|
20
|
-
# Generate a default opaque ID (
|
23
|
+
# Generate a default opaque ID (18 characters, slug-like)
|
21
24
|
id = OpaqueId.generate
|
22
|
-
# => "
|
25
|
+
# => "izkpm55j334u8x9y2"
|
23
26
|
|
24
27
|
# Generate multiple IDs
|
25
28
|
ids = 5.times.map { OpaqueId.generate }
|
@@ -31,15 +34,15 @@ ids = 5.times.map { OpaqueId.generate }
|
|
31
34
|
```ruby
|
32
35
|
# Custom length
|
33
36
|
id = OpaqueId.generate(size: 10)
|
34
|
-
# => "
|
37
|
+
# => "izkpm55j334u"
|
35
38
|
|
36
39
|
# Custom alphabet
|
37
40
|
id = OpaqueId.generate(alphabet: OpaqueId::STANDARD_ALPHABET)
|
38
|
-
# => "
|
41
|
+
# => "izkpm55j334u8x9y2"
|
39
42
|
|
40
43
|
# Both custom length and alphabet
|
41
44
|
id = OpaqueId.generate(size: 15, alphabet: OpaqueId::STANDARD_ALPHABET)
|
42
|
-
# => "
|
45
|
+
# => "izkpm55j334u8x9y"
|
43
46
|
```
|
44
47
|
|
45
48
|
### Built-in Alphabets
|
@@ -47,11 +50,11 @@ id = OpaqueId.generate(size: 15, alphabet: OpaqueId::STANDARD_ALPHABET)
|
|
47
50
|
```ruby
|
48
51
|
# Alphanumeric alphabet (default) - A-Z, a-z, 0-9
|
49
52
|
id = OpaqueId.generate(alphabet: OpaqueId::ALPHANUMERIC_ALPHABET)
|
50
|
-
# => "
|
53
|
+
# => "izkpm55j334u8x9y2"
|
51
54
|
|
52
55
|
# Standard alphabet - A-Z, a-z, 0-9, -, _
|
53
56
|
id = OpaqueId.generate(alphabet: OpaqueId::STANDARD_ALPHABET)
|
54
|
-
# => "
|
57
|
+
# => "izkpm55j334u8x9y2"
|
55
58
|
```
|
56
59
|
|
57
60
|
### Custom Alphabets
|
@@ -70,7 +73,7 @@ id = OpaqueId.generate(size: 16, alphabet: hex_alphabet)
|
|
70
73
|
# URL-safe characters
|
71
74
|
url_safe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
72
75
|
id = OpaqueId.generate(size: 12, alphabet: url_safe)
|
73
|
-
# => "
|
76
|
+
# => "izkpm55j334u8x"
|
74
77
|
```
|
75
78
|
|
76
79
|
## ActiveRecord Integration
|
@@ -91,7 +94,7 @@ end
|
|
91
94
|
# Create a new user - opaque_id is automatically generated
|
92
95
|
user = User.create!(name: "John Doe", email: "john@example.com")
|
93
96
|
puts user.opaque_id
|
94
|
-
# => "
|
97
|
+
# => "izkpm55j334u8x9y2"
|
95
98
|
|
96
99
|
# The ID is generated before the record is saved
|
97
100
|
user = User.new(name: "Jane Smith")
|
@@ -107,10 +110,10 @@ puts user.opaque_id
|
|
107
110
|
|
108
111
|
```ruby
|
109
112
|
# Find by opaque_id (returns nil if not found)
|
110
|
-
user = User.find_by_opaque_id("
|
113
|
+
user = User.find_by_opaque_id("izkpm55j334u8x9y2")
|
111
114
|
|
112
115
|
# Find by opaque_id (raises exception if not found)
|
113
|
-
user = User.find_by_opaque_id!("
|
116
|
+
user = User.find_by_opaque_id!("izkpm55j334u8x9y2")
|
114
117
|
# => ActiveRecord::RecordNotFound if not found
|
115
118
|
|
116
119
|
# Use in scopes
|
@@ -120,7 +123,7 @@ class User < ApplicationRecord
|
|
120
123
|
scope :by_opaque_id, ->(id) { where(opaque_id: id) }
|
121
124
|
end
|
122
125
|
|
123
|
-
users = User.by_opaque_id("
|
126
|
+
users = User.by_opaque_id("izkpm55j334u8x9y2")
|
124
127
|
```
|
125
128
|
|
126
129
|
### Custom Column Names
|
@@ -136,7 +139,7 @@ end
|
|
136
139
|
# Now the methods use the custom column name
|
137
140
|
user = User.create!(name: "John Doe")
|
138
141
|
puts user.public_id
|
139
|
-
# => "
|
142
|
+
# => "izkpm55j334u8x9y2"
|
140
143
|
|
141
144
|
user = User.find_by_public_id("V1StGXR8_Z5jdHi6B-myT")
|
142
145
|
```
|
@@ -195,7 +198,7 @@ end
|
|
195
198
|
# Create an order
|
196
199
|
order = Order.create!(user_id: 1, total: 99.99)
|
197
200
|
puts order.opaque_id
|
198
|
-
# => "
|
201
|
+
# => "izkpm55j334u8x"
|
199
202
|
|
200
203
|
# Use in URLs
|
201
204
|
order_url(order.opaque_id)
|
@@ -256,7 +259,7 @@ end
|
|
256
259
|
# Create a user
|
257
260
|
user = User.create!(name: "John Doe", email: "john@example.com")
|
258
261
|
puts user.opaque_id
|
259
|
-
# => "
|
262
|
+
# => "izkpm55j334u8x9y2" (starts with letter)
|
260
263
|
|
261
264
|
# Use in user profiles
|
262
265
|
user_url(user.opaque_id)
|
data/docs/use-cases.md
CHANGED
@@ -10,6 +10,9 @@ permalink: /use-cases/
|
|
10
10
|
|
11
11
|
OpaqueId is designed for a wide range of applications where secure, unpredictable identifiers are needed. This guide covers real-world use cases with practical examples and implementation patterns.
|
12
12
|
|
13
|
+
- TOC
|
14
|
+
{:toc}
|
15
|
+
|
13
16
|
## E-Commerce Applications
|
14
17
|
|
15
18
|
### Order Management
|
data/lib/opaque_id/version.rb
CHANGED
data/lib/opaque_id.rb
CHANGED
@@ -9,6 +9,9 @@ module OpaqueId
|
|
9
9
|
class GenerationError < Error; end
|
10
10
|
class ConfigurationError < Error; end
|
11
11
|
|
12
|
+
# Slug-like alphabet for URL-safe, double-click selectable IDs (36 characters)
|
13
|
+
SLUG_LIKE_ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'
|
14
|
+
|
12
15
|
# Standard URL-safe alphabet (64 characters)
|
13
16
|
STANDARD_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'
|
14
17
|
|
@@ -17,7 +20,7 @@ module OpaqueId
|
|
17
20
|
|
18
21
|
class << self
|
19
22
|
# Generate a cryptographically secure random ID
|
20
|
-
def generate(size:
|
23
|
+
def generate(size: 18, alphabet: SLUG_LIKE_ALPHABET)
|
21
24
|
raise ConfigurationError, 'Size must be positive' unless size.positive?
|
22
25
|
raise ConfigurationError, 'Alphabet cannot be empty' if alphabet.nil? || alphabet.empty?
|
23
26
|
|
data/release-please-config.json
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opaque_id
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Nyaggah
|
@@ -156,14 +156,6 @@ files:
|
|
156
156
|
- lib/opaque_id/model.rb
|
157
157
|
- lib/opaque_id/version.rb
|
158
158
|
- release-please-config.json
|
159
|
-
- tasks/0001-prd-opaque-id-gem.md
|
160
|
-
- tasks/0002-prd-publishing-release-automation.md
|
161
|
-
- tasks/0003-prd-documentation-site.md
|
162
|
-
- tasks/references/opaque_gem_requirements.md
|
163
|
-
- tasks/references/original_identifiable_concern_and_nanoid.md
|
164
|
-
- tasks/tasks-0001-prd-opaque-id-gem.md
|
165
|
-
- tasks/tasks-0002-prd-publishing-release-automation.md
|
166
|
-
- tasks/tasks-0003-prd-documentation-site.md
|
167
159
|
homepage: https://github.com/nyaggah/opaque_id
|
168
160
|
licenses:
|
169
161
|
- MIT
|
@@ -1,202 +0,0 @@
|
|
1
|
-
# Product Requirements Document: OpaqueId Ruby Gem
|
2
|
-
|
3
|
-
## Introduction/Overview
|
4
|
-
|
5
|
-
The OpaqueId gem is a Ruby library that generates cryptographically secure, collision-free opaque identifiers for ActiveRecord models. This gem replaces the existing `nanoid.rb` dependency by implementing the same functionality using Ruby's built-in `SecureRandom` methods, eliminating external dependencies while maintaining the same security and performance characteristics.
|
6
|
-
|
7
|
-
The primary problem this gem solves is preventing the exposure of incremental database IDs in public URLs and APIs, which can reveal business metrics, enable enumeration attacks, and expose internal system architecture. Instead, it provides opaque, non-sequential identifiers that are URL-friendly and cryptographically secure.
|
8
|
-
|
9
|
-
## Goals
|
10
|
-
|
11
|
-
1. **Replace nanoid.rb dependency** - Implement equivalent functionality using Ruby's built-in SecureRandom
|
12
|
-
2. **Maintain security standards** - Provide cryptographically secure ID generation with unbiased distribution
|
13
|
-
3. **Ensure performance** - Achieve 1M+ IDs/sec for 64-character alphabets, 180K+ IDs/sec for 36-character alphabets
|
14
|
-
4. **Simplify integration** - Provide seamless ActiveRecord integration with minimal configuration
|
15
|
-
5. **Enable wide adoption** - Create comprehensive documentation accessible to all Rails developers
|
16
|
-
6. **Ensure reliability** - Implement robust collision detection and retry logic
|
17
|
-
7. **Maintain compatibility** - Support Rails 8.0+ and Ruby 3.2+ environments
|
18
|
-
|
19
|
-
## User Stories
|
20
|
-
|
21
|
-
### Primary Users: Rails Developers
|
22
|
-
|
23
|
-
**As a Rails developer**, I want to generate opaque IDs for my models so that I can expose public identifiers without revealing database structure.
|
24
|
-
|
25
|
-
**As a Rails developer**, I want to easily integrate opaque ID generation into my existing models so that I don't have to manually implement ID generation logic.
|
26
|
-
|
27
|
-
**As a Rails developer**, I want to configure ID generation parameters (length, alphabet, column name) so that I can customize the behavior for different use cases.
|
28
|
-
|
29
|
-
**As a Rails developer**, I want to find records by their opaque ID so that I can build public-facing APIs and URLs.
|
30
|
-
|
31
|
-
**As a Rails developer**, I want the gem to handle collision detection automatically so that I don't have to worry about duplicate IDs.
|
32
|
-
|
33
|
-
**As a Rails developer**, I want comprehensive documentation and examples so that I can quickly understand and implement the gem in my project.
|
34
|
-
|
35
|
-
### Secondary Users: Security-Conscious Teams
|
36
|
-
|
37
|
-
**As a security-conscious developer**, I want cryptographically secure ID generation so that my public identifiers cannot be predicted or enumerated.
|
38
|
-
|
39
|
-
**As a security-conscious developer**, I want unbiased character distribution so that my IDs have maximum entropy and cannot be analyzed for patterns.
|
40
|
-
|
41
|
-
## Functional Requirements
|
42
|
-
|
43
|
-
### Core ID Generation
|
44
|
-
|
45
|
-
1. The system must generate cryptographically secure random IDs using Ruby's `SecureRandom`
|
46
|
-
2. The system must implement rejection sampling algorithm to ensure unbiased character distribution
|
47
|
-
3. The system must provide optimized fast path for 64-character alphabets using bitwise operations
|
48
|
-
4. The system must support custom alphabet configurations
|
49
|
-
5. The system must support custom ID length configurations
|
50
|
-
6. The system must provide two predefined alphabets: ALPHANUMERIC_ALPHABET (36 chars) and STANDARD_ALPHABET (64 chars)
|
51
|
-
|
52
|
-
### ActiveRecord Integration
|
53
|
-
|
54
|
-
7. The system must provide `OpaqueId::Model` concern for easy ActiveRecord integration
|
55
|
-
8. The system must automatically generate opaque IDs on model creation via `before_create` callback
|
56
|
-
9. The system must provide `find_by_opaque_id` and `find_by_opaque_id!` class methods
|
57
|
-
10. The system must support custom column names via `opaque_id_column` configuration
|
58
|
-
11. The system must implement collision detection with configurable retry attempts
|
59
|
-
12. The system must raise appropriate errors when collision resolution fails
|
60
|
-
|
61
|
-
### Rails Generator (Optional Convenience Tool)
|
62
|
-
|
63
|
-
13. The system must provide optional Rails generator `opaque_id:install` for creating migrations and updating models
|
64
|
-
14. The system must generate migration files that add opaque_id column with unique index
|
65
|
-
15. The system must automatically add `include OpaqueId::Model` to the corresponding model file
|
66
|
-
16. The system must support custom column names via generator options
|
67
|
-
17. The system must require explicit table name argument and show clear usage instructions when run without arguments
|
68
|
-
18. The system must work with any existing table (new or existing models)
|
69
|
-
19. The system must handle edge cases gracefully (missing model file, already included, different class names)
|
70
|
-
|
71
|
-
### Configuration Options
|
72
|
-
|
73
|
-
20. The system must support `opaque_id_column` configuration (default: `:opaque_id`)
|
74
|
-
21. The system must support `opaque_id_length` configuration (default: `18`)
|
75
|
-
22. The system must support `opaque_id_alphabet` configuration (default: `ALPHANUMERIC_ALPHABET`)
|
76
|
-
23. The system must support `opaque_id_require_letter_start` configuration (default: `true`)
|
77
|
-
24. The system must support `opaque_id_purge_chars` configuration (default: `nil`)
|
78
|
-
25. The system must support `opaque_id_max_retry` configuration (default: `1000`)
|
79
|
-
|
80
|
-
### Error Handling
|
81
|
-
|
82
|
-
26. The system must raise `OpaqueId::ConfigurationError` for invalid size or empty alphabet
|
83
|
-
27. The system must raise `OpaqueId::GenerationError` when collision resolution fails
|
84
|
-
28. The system must provide clear error messages for debugging
|
85
|
-
|
86
|
-
### Standalone Usage
|
87
|
-
|
88
|
-
29. The system must provide `OpaqueId.generate` method for standalone ID generation
|
89
|
-
30. The system must support all configuration options in standalone generation
|
90
|
-
31. The system must maintain the same security and performance characteristics in standalone mode
|
91
|
-
|
92
|
-
## Non-Goals (Out of Scope)
|
93
|
-
|
94
|
-
1. **Other ORM Support** - Will not support Mongoid, Sequel, or other ORMs in initial release
|
95
|
-
2. **Non-Rails Usage** - Will not provide standalone Ruby usage without ActiveRecord dependency
|
96
|
-
3. **Custom Algorithms** - Will not implement alternative ID generation algorithms beyond rejection sampling
|
97
|
-
4. **Database Migrations** - Will not provide automatic database migration for existing records
|
98
|
-
5. **ID Validation** - Will not provide built-in ID format validation (users can implement their own)
|
99
|
-
6. **Bulk Generation** - Will not provide optimized bulk ID generation methods
|
100
|
-
7. **ID Prefixes/Suffixes** - Will not support adding prefixes or suffixes to generated IDs
|
101
|
-
8. **Custom Random Sources** - Will not support custom random number generators beyond SecureRandom
|
102
|
-
9. **Interactive Generator Mode** - Will not provide interactive prompts for generator arguments
|
103
|
-
10. **Backward Compatibility** - Will not maintain compatibility with existing `public_id` implementations
|
104
|
-
|
105
|
-
## Design Considerations
|
106
|
-
|
107
|
-
### API Design
|
108
|
-
|
109
|
-
- Follow Rails conventions for ActiveRecord concerns and generators
|
110
|
-
- Use descriptive method names that clearly indicate functionality
|
111
|
-
- Provide both safe (`find_by_opaque_id`) and unsafe (`find_by_opaque_id!`) lookup methods
|
112
|
-
- Use class-level configuration options for easy customization
|
113
|
-
- Follow Devise-style generator pattern for seamless integration
|
114
|
-
|
115
|
-
### Performance Optimization
|
116
|
-
|
117
|
-
- Implement fast path for 64-character alphabets using bitwise operations (`byte & 63`)
|
118
|
-
- Use rejection sampling with optimal mask calculation for unbiased distribution
|
119
|
-
- Pre-allocate string capacity to avoid memory reallocation during generation
|
120
|
-
- Batch random byte generation to minimize SecureRandom calls
|
121
|
-
|
122
|
-
### Security Considerations
|
123
|
-
|
124
|
-
- Use only cryptographically secure random number generation
|
125
|
-
- Implement proper rejection sampling to avoid modulo bias
|
126
|
-
- Provide sufficient entropy through configurable alphabet sizes
|
127
|
-
- Ensure IDs cannot be predicted or enumerated
|
128
|
-
|
129
|
-
## Technical Considerations
|
130
|
-
|
131
|
-
### Dependencies
|
132
|
-
|
133
|
-
- **ActiveRecord**: >= 6.0 (targeting Rails 8.0+ compatibility)
|
134
|
-
- **ActiveSupport**: >= 6.0 (for concern functionality)
|
135
|
-
- **Ruby**: >= 3.2 (for modern Ruby features and performance)
|
136
|
-
|
137
|
-
### Testing Framework
|
138
|
-
|
139
|
-
- Use **Minitest** instead of RSpec for consistency with Rails conventions
|
140
|
-
- Implement comprehensive unit tests for all public methods
|
141
|
-
- Include statistical tests for character distribution uniformity
|
142
|
-
- Add performance benchmarks to ensure performance requirements are met
|
143
|
-
- Test edge cases including collision scenarios and error conditions
|
144
|
-
|
145
|
-
### File Structure
|
146
|
-
|
147
|
-
```
|
148
|
-
lib/
|
149
|
-
├── opaque_id.rb # Main module with generator
|
150
|
-
├── opaque_id/
|
151
|
-
│ ├── version.rb # Version constant
|
152
|
-
│ └── model.rb # ActiveRecord concern
|
153
|
-
└── generators/
|
154
|
-
└── opaque_id/
|
155
|
-
├── install_generator.rb # Migration generator
|
156
|
-
└── templates/
|
157
|
-
└── migration.rb.tt # Migration template
|
158
|
-
```
|
159
|
-
|
160
|
-
### Error Classes
|
161
|
-
|
162
|
-
- `OpaqueId::Error` - Base error class
|
163
|
-
- `OpaqueId::GenerationError` - ID generation failures
|
164
|
-
- `OpaqueId::ConfigurationError` - Invalid configuration
|
165
|
-
|
166
|
-
## Success Metrics
|
167
|
-
|
168
|
-
### Performance Metrics
|
169
|
-
|
170
|
-
- **Standard alphabet (64 chars)**: Achieve ~1.2M IDs/sec generation rate
|
171
|
-
- **Alphanumeric alphabet (36 chars)**: Achieve ~180K IDs/sec generation rate
|
172
|
-
- **Custom alphabet (20 chars)**: Achieve ~150K IDs/sec generation rate
|
173
|
-
|
174
|
-
### Quality Metrics
|
175
|
-
|
176
|
-
- **Test Coverage**: Achieve 95%+ code coverage
|
177
|
-
- **Documentation**: Provide comprehensive README with examples
|
178
|
-
- **Error Handling**: All error conditions properly tested and documented
|
179
|
-
|
180
|
-
### Adoption Metrics
|
181
|
-
|
182
|
-
- **Gem Downloads**: Target 1000+ downloads in first month
|
183
|
-
- **GitHub Stars**: Target 50+ stars within 6 months
|
184
|
-
- **Community Feedback**: Positive reception from Rails community
|
185
|
-
|
186
|
-
## Open Questions
|
187
|
-
|
188
|
-
1. **Version Strategy**: Should we follow semantic versioning strictly, or use a different versioning strategy for a utility gem?
|
189
|
-
|
190
|
-
2. **Backward Compatibility**: How should we handle potential breaking changes in future versions, especially regarding default configurations?
|
191
|
-
|
192
|
-
3. **Performance Testing**: Should we include automated performance regression testing in CI/CD, or rely on manual benchmarking?
|
193
|
-
|
194
|
-
4. **Documentation Hosting**: Should we create a dedicated documentation site, or rely on GitHub README and inline documentation?
|
195
|
-
|
196
|
-
5. **Community Contributions**: What level of community contribution should we expect, and how should we structure the project to encourage contributions?
|
197
|
-
|
198
|
-
6. **Integration Testing**: Should we test against multiple Rails versions in CI, or focus on the target Rails 8.0+ range?
|
199
|
-
|
200
|
-
7. **Security Auditing**: Should we implement any security auditing tools or processes for the random number generation?
|
201
|
-
|
202
|
-
8. **Migration Path**: How should we help users migrate from nanoid.rb to opaque_id, if at all?
|