cmdx 1.7.5 → 1.9.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.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/.cursor/prompts/docs.md +3 -3
  4. data/.cursor/prompts/llms.md +1 -3
  5. data/.cursor/prompts/rspec.md +1 -1
  6. data/.irbrc +14 -2
  7. data/CHANGELOG.md +62 -29
  8. data/LLM.md +203 -78
  9. data/README.md +23 -85
  10. data/docs/.DS_Store +0 -0
  11. data/docs/assets/favicon.ico +0 -0
  12. data/docs/assets/favicon.svg +1 -0
  13. data/docs/attributes/coercions.md +19 -29
  14. data/docs/attributes/defaults.md +3 -16
  15. data/docs/attributes/definitions.md +29 -39
  16. data/docs/attributes/naming.md +3 -13
  17. data/docs/attributes/transformations.md +63 -0
  18. data/docs/attributes/validations.md +23 -40
  19. data/docs/basics/chain.md +14 -23
  20. data/docs/basics/context.md +13 -22
  21. data/docs/basics/execution.md +8 -26
  22. data/docs/basics/setup.md +8 -19
  23. data/docs/callbacks.md +19 -32
  24. data/docs/deprecation.md +8 -25
  25. data/docs/getting_started.md +101 -77
  26. data/docs/index.md +120 -0
  27. data/docs/internationalization.md +6 -18
  28. data/docs/interruptions/exceptions.md +10 -16
  29. data/docs/interruptions/faults.md +8 -25
  30. data/docs/interruptions/halt.md +31 -25
  31. data/docs/logging.md +7 -17
  32. data/docs/middlewares.md +13 -29
  33. data/docs/outcomes/result.md +21 -38
  34. data/docs/outcomes/states.md +8 -22
  35. data/docs/outcomes/statuses.md +10 -21
  36. data/docs/stylesheets/extra.css +42 -0
  37. data/docs/tips_and_tricks.md +7 -46
  38. data/docs/workflows.md +23 -38
  39. data/examples/active_record_query_tagging.md +46 -0
  40. data/examples/paper_trail_whatdunnit.md +39 -0
  41. data/lib/cmdx/attribute.rb +9 -2
  42. data/lib/cmdx/attribute_value.rb +31 -10
  43. data/lib/cmdx/callback_registry.rb +12 -2
  44. data/lib/cmdx/coercions/hash.rb +6 -1
  45. data/lib/cmdx/configuration.rb +10 -2
  46. data/lib/cmdx/deprecator.rb +3 -3
  47. data/lib/cmdx/errors.rb +1 -1
  48. data/lib/cmdx/executor.rb +97 -9
  49. data/lib/cmdx/log_formatters/logstash.rb +4 -4
  50. data/lib/cmdx/pipeline.rb +4 -4
  51. data/lib/cmdx/railtie.rb +9 -0
  52. data/lib/cmdx/result.rb +10 -1
  53. data/lib/cmdx/task.rb +12 -7
  54. data/lib/cmdx/version.rb +1 -1
  55. data/lib/cmdx.rb +1 -0
  56. data/lib/generators/cmdx/templates/install.rb +9 -0
  57. data/lib/locales/af.yml +2 -2
  58. data/lib/locales/ar.yml +2 -2
  59. data/lib/locales/az.yml +2 -2
  60. data/lib/locales/be.yml +2 -2
  61. data/lib/locales/bg.yml +2 -2
  62. data/lib/locales/bn.yml +2 -2
  63. data/lib/locales/bs.yml +2 -2
  64. data/lib/locales/ca.yml +2 -2
  65. data/lib/locales/cnr.yml +2 -2
  66. data/lib/locales/cs.yml +2 -2
  67. data/lib/locales/cy.yml +2 -2
  68. data/lib/locales/da.yml +2 -2
  69. data/lib/locales/de.yml +2 -2
  70. data/lib/locales/dz.yml +2 -2
  71. data/lib/locales/el.yml +2 -2
  72. data/lib/locales/en.yml +2 -2
  73. data/lib/locales/eo.yml +2 -2
  74. data/lib/locales/es.yml +2 -2
  75. data/lib/locales/et.yml +2 -2
  76. data/lib/locales/eu.yml +2 -2
  77. data/lib/locales/fa.yml +2 -2
  78. data/lib/locales/fi.yml +2 -2
  79. data/lib/locales/fr.yml +2 -2
  80. data/lib/locales/fy.yml +2 -2
  81. data/lib/locales/gd.yml +2 -2
  82. data/lib/locales/gl.yml +2 -2
  83. data/lib/locales/he.yml +2 -2
  84. data/lib/locales/hi.yml +2 -2
  85. data/lib/locales/hr.yml +2 -2
  86. data/lib/locales/hu.yml +2 -2
  87. data/lib/locales/hy.yml +2 -2
  88. data/lib/locales/id.yml +2 -2
  89. data/lib/locales/is.yml +2 -2
  90. data/lib/locales/it.yml +2 -2
  91. data/lib/locales/ja.yml +2 -2
  92. data/lib/locales/ka.yml +2 -2
  93. data/lib/locales/kk.yml +2 -2
  94. data/lib/locales/km.yml +2 -2
  95. data/lib/locales/kn.yml +2 -2
  96. data/lib/locales/ko.yml +2 -2
  97. data/lib/locales/lb.yml +2 -2
  98. data/lib/locales/lo.yml +2 -2
  99. data/lib/locales/lt.yml +2 -2
  100. data/lib/locales/lv.yml +2 -2
  101. data/lib/locales/mg.yml +2 -2
  102. data/lib/locales/mk.yml +2 -2
  103. data/lib/locales/ml.yml +2 -2
  104. data/lib/locales/mn.yml +2 -2
  105. data/lib/locales/mr-IN.yml +2 -2
  106. data/lib/locales/ms.yml +2 -2
  107. data/lib/locales/nb.yml +2 -2
  108. data/lib/locales/ne.yml +2 -2
  109. data/lib/locales/nl.yml +2 -2
  110. data/lib/locales/nn.yml +2 -2
  111. data/lib/locales/oc.yml +2 -2
  112. data/lib/locales/or.yml +2 -2
  113. data/lib/locales/pa.yml +2 -2
  114. data/lib/locales/pl.yml +2 -2
  115. data/lib/locales/pt.yml +2 -2
  116. data/lib/locales/rm.yml +2 -2
  117. data/lib/locales/ro.yml +2 -2
  118. data/lib/locales/ru.yml +2 -2
  119. data/lib/locales/sc.yml +2 -2
  120. data/lib/locales/sk.yml +2 -2
  121. data/lib/locales/sl.yml +2 -2
  122. data/lib/locales/sq.yml +2 -2
  123. data/lib/locales/sr.yml +2 -2
  124. data/lib/locales/st.yml +2 -2
  125. data/lib/locales/sv.yml +2 -2
  126. data/lib/locales/sw.yml +2 -2
  127. data/lib/locales/ta.yml +2 -2
  128. data/lib/locales/te.yml +2 -2
  129. data/lib/locales/th.yml +2 -2
  130. data/lib/locales/tl.yml +2 -2
  131. data/lib/locales/tr.yml +2 -2
  132. data/lib/locales/tt.yml +2 -2
  133. data/lib/locales/ug.yml +2 -2
  134. data/lib/locales/uk.yml +2 -2
  135. data/lib/locales/ur.yml +2 -2
  136. data/lib/locales/uz.yml +2 -2
  137. data/lib/locales/vi.yml +2 -2
  138. data/lib/locales/wo.yml +2 -2
  139. data/lib/locales/zh-CN.yml +2 -2
  140. data/lib/locales/zh-HK.yml +2 -2
  141. data/lib/locales/zh-TW.yml +2 -2
  142. data/lib/locales/zh-YUE.yml +2 -2
  143. data/mkdocs.yml +122 -0
  144. data/src/cmdx-dark-logo.png +0 -0
  145. data/src/cmdx-favicon.svg +1 -0
  146. data/src/cmdx-light-logo.png +0 -0
  147. data/src/cmdx-logo.svg +1 -0
  148. metadata +15 -4
  149. data/lib/cmdx/freezer.rb +0 -51
  150. data/src/cmdx-logo.png +0 -0
data/docs/logging.md CHANGED
@@ -1,16 +1,10 @@
1
1
  # Logging
2
2
 
3
- CMDx provides comprehensive automatic logging for task execution with structured data, customizable formatters, and intelligent severity mapping. All task results are logged after completion with rich metadata for debugging and monitoring.
4
-
5
- ## Table of Contents
6
-
7
- - [Formatters](#formatters)
8
- - [Structure](#structure)
9
- - [Usage](#usage)
3
+ CMDx automatically logs every task execution with structured data, making debugging and monitoring effortless. Choose from multiple formatters to match your logging infrastructure.
10
4
 
11
5
  ## Formatters
12
6
 
13
- CMDx supports multiple log formatters to integrate with various logging systems:
7
+ Choose the format that works best for your logging system:
14
8
 
15
9
  | Formatter | Use Case | Output Style |
16
10
  |-----------|----------|--------------|
@@ -40,12 +34,13 @@ E, [2022-07-17T18:43:15.000000 #3784] ERROR -- BillingWorkflow:
40
34
  index=3 chain_id="018c2b95-b764-7615-a924-cc5b910ed1e5" type="Task" class="BillingWorkflow" state="interrupted" status="failed" caused_failure={index: 2, class: "CalculateTax", status: "failed"} threw_failure={index: 1, class: "ValidateCustomer", status: "failed"}
41
35
  ```
42
36
 
43
- > [!TIP]
44
- > Logging can be used as low-level eventing system, ingesting all tasks performed within a small action or long running request. This ie where correlation is especially handy.
37
+ !!! tip
38
+
39
+ Use logging as a low-level event stream to track all tasks in a request. Combine with correlation for powerful distributed tracing.
45
40
 
46
41
  ## Structure
47
42
 
48
- All log entries include comprehensive execution metadata. Field availability depends on execution context and outcome.
43
+ Every log entry includes rich metadata. Available fields depend on execution context and outcome.
49
44
 
50
45
  ### Core Fields
51
46
 
@@ -86,7 +81,7 @@ All log entries include comprehensive execution metadata. Field availability dep
86
81
 
87
82
  ## Usage
88
83
 
89
- Tasks have access to the frameworks logger.
84
+ Access the framework logger directly within tasks:
90
85
 
91
86
  ```ruby
92
87
  class ProcessSubscription < CMDx::Task
@@ -97,8 +92,3 @@ class ProcessSubscription < CMDx::Task
97
92
  end
98
93
  end
99
94
  ```
100
-
101
- ---
102
-
103
- - **Prev:** [Middlewares](middlewares.md)
104
- - **Next:** [Internationalization (i18n)](internationalization.md)
data/docs/middlewares.md CHANGED
@@ -1,27 +1,16 @@
1
1
  # Middlewares
2
2
 
3
- Middleware provides Rack-style wrappers around task execution for cross-cutting concerns like authentication, logging, caching, and error handling.
3
+ Wrap task execution with middleware for cross-cutting concerns like authentication, caching, timeouts, and monitoring. Think Rack middleware, but for your business logic.
4
4
 
5
- Check out the [Getting Started](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#middlewares) docs for global configuration.
5
+ See [Global Configuration](getting_started.md#middlewares) for framework-wide setup.
6
6
 
7
- ## Table of Contents
7
+ ## Execution Order
8
8
 
9
- - [Order](#order)
10
- - [Declarations](#declarations)
11
- - [Proc or Lambda](#proc-or-lambda)
12
- - [Class or Module](#class-or-module)
13
- - [Removals](#removals)
14
- - [Built-in](#built-in)
15
- - [Timeout](#timeout)
16
- - [Correlate](#correlate)
17
- - [Runtime](#runtime)
9
+ Middleware wraps task execution in layers, like an onion:
18
10
 
19
- ## Order
11
+ !!! note
20
12
 
21
- Middleware executes in a nested fashion, creating an onion-like execution pattern:
22
-
23
- > [!NOTE]
24
- > Middleware executes in the order they are registered, with the first registered middleware being the outermost wrapper.
13
+ First registered = outermost wrapper. They execute in registration order.
25
14
 
26
15
  ```ruby
27
16
  class ProcessCampaign < CMDx::Task
@@ -97,10 +86,11 @@ end
97
86
 
98
87
  ## Removals
99
88
 
100
- Class and Module based declarations can be removed at a global and task level.
89
+ Remove class or module-based middleware globally or per-task:
90
+
91
+ !!! warning
101
92
 
102
- > [!WARNING]
103
- > Only one removal operation is allowed per `deregister` call. Multiple removals require separate calls.
93
+ Each `deregister` call removes one middleware. Use multiple calls for batch removals.
104
94
 
105
95
  ```ruby
106
96
  class ProcessCampaign < CMDx::Task
@@ -113,7 +103,7 @@ end
113
103
 
114
104
  ### Timeout
115
105
 
116
- Ensures task execution doesn't exceed a specified time limit:
106
+ Prevent tasks from running too long:
117
107
 
118
108
  ```ruby
119
109
  class ProcessReport < CMDx::Task
@@ -149,7 +139,7 @@ result.metadata #=> { limit: 3 }
149
139
 
150
140
  ### Correlate
151
141
 
152
- Tags tasks with a global correlation ID for distributed tracing:
142
+ Add correlation IDs for distributed tracing and request tracking:
153
143
 
154
144
  ```ruby
155
145
  class ProcessExport < CMDx::Task
@@ -179,8 +169,7 @@ result.metadata #=> { correlation_id: "550e8400-e29b-41d4-a716-446655440000" }
179
169
 
180
170
  ### Runtime
181
171
 
182
- The runtime middleware tags tasks with how long it took to execute the task.
183
- The calculation uses a monotonic clock and the time is returned in milliseconds.
172
+ Track task execution time in milliseconds using a monotonic clock:
184
173
 
185
174
  ```ruby
186
175
  class PerformanceMonitoringCheck
@@ -200,8 +189,3 @@ end
200
189
  result = ProcessExport.execute
201
190
  result.metadata #=> { runtime: 1247 } (ms)
202
191
  ```
203
-
204
- ---
205
-
206
- - **Prev:** [Callbacks](callbacks.md)
207
- - **Next:** [Logging](logging.md)
@@ -1,27 +1,14 @@
1
1
  # Outcomes - Result
2
2
 
3
- The result object is the comprehensive return value of task execution, providing complete information about the execution outcome, state, timing, and any data produced during the task lifecycle. Results serve as the primary interface for inspecting task execution outcomes and chaining task operations.
4
-
5
- ## Table of Contents
6
-
7
- - [Result Attributes](#result-attributes)
8
- - [Lifecycle Information](#lifecycle-information)
9
- - [Outcome Analysis](#outcome-analysis)
10
- - [Chain Analysis](#chain-analysis)
11
- - [Index and Position](#index-and-position)
12
- - [Block Yield](#block-yield)
13
- - [Handlers](#handlers)
14
- - [Pattern Matching](#pattern-matching)
15
- - [Array Pattern](#array-pattern)
16
- - [Hash Pattern](#hash-pattern)
17
- - [Pattern Guards](#pattern-guards)
3
+ Results are your window into task execution. They expose everything: outcome, state, timing, context, and metadata.
18
4
 
19
5
  ## Result Attributes
20
6
 
21
- Every result provides access to essential execution information:
7
+ Access essential execution information:
22
8
 
23
- > [!IMPORTANT]
24
- > Result objects are immutable after task execution completes and reflect the final state.
9
+ !!! warning "Important"
10
+
11
+ Results are immutable after execution completes.
25
12
 
26
13
  ```ruby
27
14
  result = BuildApplication.execute(version: "1.2.3")
@@ -43,7 +30,7 @@ result.metadata #=> { error_code: "BUILD_TOOL.NOT_FOUND" }
43
30
 
44
31
  ## Lifecycle Information
45
32
 
46
- Results provide comprehensive methods for checking execution state and status:
33
+ Check execution state and status with predicate methods:
47
34
 
48
35
  ```ruby
49
36
  result = BuildApplication.execute(version: "1.2.3")
@@ -65,7 +52,7 @@ result.bad? #=> false (skipped or failed)
65
52
 
66
53
  ## Outcome Analysis
67
54
 
68
- Results provide unified outcome determination depending on the fault causal chain:
55
+ Get a unified outcome string combining state and status:
69
56
 
70
57
  ```ruby
71
58
  result = BuildApplication.execute(version: "1.2.3")
@@ -75,7 +62,7 @@ result.outcome #=> "success" (state and status)
75
62
 
76
63
  ## Chain Analysis
77
64
 
78
- Use these methods to trace the root cause of faults or trace the cause points.
65
+ Trace fault origins and propagation:
79
66
 
80
67
  ```ruby
81
68
  result = DeploymentWorkflow.execute(app_name: "webapp")
@@ -116,7 +103,7 @@ result.chain.results[result.index] == result #=> true
116
103
 
117
104
  ## Block Yield
118
105
 
119
- Implement conditional logic using a block expression that yields a result for complete encapsulation.
106
+ Execute code with direct result access:
120
107
 
121
108
  ```ruby
122
109
  BuildApplication.execute(version: "1.2.3") do |result|
@@ -132,34 +119,35 @@ end
132
119
 
133
120
  ## Handlers
134
121
 
135
- Use result handlers for clean, functional-style conditional logic. Handlers return the result object, enabling method chaining and fluent interfaces.
122
+ Handle outcomes with functional-style methods. Handlers return the result for chaining:
136
123
 
137
124
  ```ruby
138
125
  result = BuildApplication.execute(version: "1.2.3")
139
126
 
140
127
  # Status-based handlers
141
128
  result
142
- .on_success { |result| notify_deployment_ready(result) }
143
- .on_failed { |result| handle_build_failure(result) }
144
- .on_skipped { |result| log_skip_reason(result) }
129
+ .handle_success { |result| notify_deployment_ready(result) }
130
+ .handle_failed { |result| handle_build_failure(result) }
131
+ .handle_skipped { |result| log_skip_reason(result) }
145
132
 
146
133
  # State-based handlers
147
134
  result
148
- .on_complete { |result| update_build_status(result) }
149
- .on_interrupted { |result| cleanup_partial_artifacts(result) }
135
+ .handle_complete { |result| update_build_status(result) }
136
+ .handle_interrupted { |result| cleanup_partial_artifacts(result) }
150
137
 
151
138
  # Outcome-based handlers
152
139
  result
153
- .on_good { |result| increment_success_counter(result) }
154
- .on_bad { |result| alert_operations_team(result) }
140
+ .handle_good { |result| increment_success_counter(result) }
141
+ .handle_bad { |result| alert_operations_team(result) }
155
142
  ```
156
143
 
157
144
  ## Pattern Matching
158
145
 
159
- Results support Ruby's pattern matching through array and hash deconstruction:
146
+ Use Ruby 3.0+ pattern matching for elegant outcome handling:
147
+
148
+ !!! warning "Important"
160
149
 
161
- > [!IMPORTANT]
162
- > Pattern matching requires Ruby 3.0+
150
+ Pattern matching works with both array and hash deconstruction.
163
151
 
164
152
  ### Array Pattern
165
153
 
@@ -203,8 +191,3 @@ in { runtime: time } if time > performance_threshold
203
191
  investigate_build_performance(result)
204
192
  end
205
193
  ```
206
-
207
- ---
208
-
209
- - **Prev:** [Interruptions - Exceptions](../interruptions/exceptions.md)
210
- - **Next:** [Outcomes - States](states.md)
@@ -1,16 +1,6 @@
1
1
  # Outcomes - States
2
2
 
3
- States represent the execution lifecycle condition of task execution, tracking
4
- the progress of tasks through their complete execution journey. States provide
5
- insight into where a task is in its lifecycle and enable lifecycle-based
6
- decision making and monitoring.
7
-
8
- ## Table of Contents
9
-
10
- - [Definitions](#definitions)
11
- - [Transitions](#transitions)
12
- - [Predicates](#predicates)
13
- - [Handlers](#handlers)
3
+ States track where a task is in its execution lifecycle—from creation through completion or interruption.
14
4
 
15
5
  ## Definitions
16
6
 
@@ -34,8 +24,9 @@ State-Status combinations:
34
24
 
35
25
  ## Transitions
36
26
 
37
- > [!CAUTION]
38
- > States are automatically managed during task execution and should **never** be modified manually. State transitions are handled internally by the CMDx framework.
27
+ !!! danger "Caution"
28
+
29
+ States are managed automatically—never modify them manually.
39
30
 
40
31
  ```ruby
41
32
  # Valid state transition flow
@@ -62,19 +53,14 @@ result.executed? #=> true (complete OR interrupted)
62
53
 
63
54
  ## Handlers
64
55
 
65
- Use state-based handlers for lifecycle event handling. The `on_executed` handler is particularly useful for cleanup operations that should run regardless of success, skipped, or failure.
56
+ Handle lifecycle events with state-based handlers. Use `handle_executed` for cleanup that runs regardless of outcome:
66
57
 
67
58
  ```ruby
68
59
  result = ProcessVideoUpload.execute
69
60
 
70
61
  # Individual state handlers
71
62
  result
72
- .on_complete { |result| send_upload_notification(result) }
73
- .on_interrupted { |result| cleanup_temp_files(result) }
74
- .on_executed { |result| log_upload_metrics(result) }
63
+ .handle_complete { |result| send_upload_notification(result) }
64
+ .handle_interrupted { |result| cleanup_temp_files(result) }
65
+ .handle_executed { |result| log_upload_metrics(result) }
75
66
  ```
76
-
77
- ---
78
-
79
- - **Prev:** [Outcomes - Result](result.md)
80
- - **Next:** [Outcomes - Statuses](statuses.md)
@@ -1,13 +1,6 @@
1
1
  # Outcomes - Statuses
2
2
 
3
- Statuses represent the business outcome of task execution logic, indicating how the task's business logic concluded. Statuses differ from execution states by focusing on the business outcome rather than the technical execution lifecycle. Understanding statuses is crucial for implementing proper business logic branching and error handling.
4
-
5
- ## Table of Contents
6
-
7
- - [Definitions](#definitions)
8
- - [Transitions](#transitions)
9
- - [Predicates](#predicates)
10
- - [Handlers](#handlers)
3
+ Statuses represent the business outcome—did the task succeed, skip, or fail? This differs from state, which tracks the execution lifecycle.
11
4
 
12
5
  ## Definitions
13
6
 
@@ -19,8 +12,9 @@ Statuses represent the business outcome of task execution logic, indicating how
19
12
 
20
13
  ## Transitions
21
14
 
22
- > [!IMPORTANT]
23
- > Status transitions are unidirectional and final. Once a task is marked as skipped or failed, it cannot return to success status. Design your business logic accordingly.
15
+ !!! warning "Important"
16
+
17
+ Status transitions are final and unidirectional. Once skipped or failed, tasks can't return to success.
24
18
 
25
19
  ```ruby
26
20
  # Valid status transitions
@@ -53,24 +47,19 @@ result.bad? #=> true if skipped OR failed (not success)
53
47
 
54
48
  ## Handlers
55
49
 
56
- Use status-based handlers for business logic branching. The `on_good` and `on_bad` handlers are particularly useful for handling success/skip vs failed outcomes respectively.
50
+ Branch business logic with status-based handlers. Use `handle_good` and `handle_bad` for success/skip vs failed outcomes:
57
51
 
58
52
  ```ruby
59
53
  result = ProcessNotification.execute
60
54
 
61
55
  # Individual status handlers
62
56
  result
63
- .on_success { |result| mark_notification_sent(result) }
64
- .on_skipped { |result| log_notification_skipped(result) }
65
- .on_failed { |result| queue_retry_notification(result) }
57
+ .handle_success { |result| mark_notification_sent(result) }
58
+ .handle_skipped { |result| log_notification_skipped(result) }
59
+ .handle_failed { |result| queue_retry_notification(result) }
66
60
 
67
61
  # Outcome-based handlers
68
62
  result
69
- .on_good { |result| update_message_stats(result) }
70
- .on_bad { |result| track_delivery_failure(result) }
63
+ .handle_good { |result| update_message_stats(result) }
64
+ .handle_bad { |result| track_delivery_failure(result) }
71
65
  ```
72
-
73
- ---
74
-
75
- - **Prev:** [Outcomes - States](states.md)
76
- - **Next:** [Attributes - Definitions](../attributes/definitions.md)
@@ -0,0 +1,42 @@
1
+ :root > * {
2
+ /* Primary color shades */
3
+ --md-primary-fg-color: #fe1817;
4
+ --md-primary-fg-color--light: #fe1817;
5
+ --md-primary-fg-color--dark: #fe1817;
6
+
7
+ /* Accent color shades */
8
+ --md-accent-fg-color: hsla(#{hex2hsl(#fe1817)}, 1);
9
+ --md-accent-fg-color--transparent: hsla(#{hex2hsl(#fe1817)}, 0.1);
10
+ }
11
+
12
+ /* Atom One Light Pro syntax highlighting */
13
+ [data-md-color-scheme="default"] {
14
+ --md-code-hl-color: #2c3036;
15
+ --md-code-hl-keyword-color: #a626a4;
16
+ --md-code-hl-string-color: #50a14f;
17
+ --md-code-hl-name-color: #e4564a;
18
+ --md-code-hl-function-color: #4078f2;
19
+ --md-code-hl-number-color: #ca7601;
20
+ --md-code-hl-constant-color: #c18401;
21
+ --md-code-hl-comment-color: #9ca0a4;
22
+ --md-code-hl-operator-color: #0184bc;
23
+ --md-code-hl-punctuation-color:#383a42;
24
+ --md-code-hl-variable-color: #e4564a;
25
+ --md-code-hl-generic-color: #e4564a;
26
+ }
27
+
28
+ /* Atom One Dark Pro syntax highlighting */
29
+ [data-md-color-scheme="slate"] {
30
+ --md-code-hl-color: #e5e5e6;
31
+ --md-code-hl-keyword-color: #c678dd;
32
+ --md-code-hl-string-color: #98c379;
33
+ --md-code-hl-name-color: #e06c75;
34
+ --md-code-hl-function-color: #61afef;
35
+ --md-code-hl-number-color: #d19a66;
36
+ --md-code-hl-constant-color: #d19a66;
37
+ --md-code-hl-comment-color: #7f848e;
38
+ --md-code-hl-operator-color: #56b6c2;
39
+ --md-code-hl-punctuation-color:#abb2bf;
40
+ --md-code-hl-variable-color: #e06c75;
41
+ --md-code-hl-generic-color: #e06c75;
42
+ }
@@ -1,16 +1,6 @@
1
1
  # Tips and Tricks
2
2
 
3
- This guide covers advanced patterns and optimization techniques for getting the most out of CMDx in production applications.
4
-
5
- ## Table of Contents
6
-
7
- - [Project Organization](#project-organization)
8
- - [Directory Structure](#directory-structure)
9
- - [Naming Conventions](#naming-conventions)
10
- - [Story Telling](#story-telling)
11
- - [Style Guide](#style-guide)
12
- - [Attribute Options](#attribute-options)
13
- - [ActiveRecord Query Tagging](#activerecord-query-tagging)
3
+ Best practices, patterns, and techniques to build maintainable CMDx applications.
14
4
 
15
5
  ## Project Organization
16
6
 
@@ -54,7 +44,7 @@ class TokenGeneration < CMDx::Task; end # ❌ Avoid
54
44
 
55
45
  ### Story Telling
56
46
 
57
- Consider using descriptive methods to express the task’s flow, rather than concentrating all logic inside the `work` method.
47
+ Break down complex logic into descriptive methods that read like a narrative:
58
48
 
59
49
  ```ruby
60
50
  class ProcessOrder < CMDx::Task
@@ -86,7 +76,7 @@ end
86
76
 
87
77
  ### Style Guide
88
78
 
89
- Follow a style pattern for consistent task design:
79
+ Follow this order for consistent, readable tasks:
90
80
 
91
81
  ```ruby
92
82
  class ExportReport < CMDx::Task
@@ -129,7 +119,7 @@ end
129
119
 
130
120
  ## Attribute Options
131
121
 
132
- Use Rails `with_options` to reduce duplication and improve readability:
122
+ Use `with_options` to reduce duplication:
133
123
 
134
124
  ```ruby
135
125
  class ConfigureCompany < CMDx::Task
@@ -155,36 +145,7 @@ class ConfigureCompany < CMDx::Task
155
145
  end
156
146
  ```
157
147
 
158
- ## ActiveRecord Query Tagging
159
-
160
- Automatically tag SQL queries for better debugging:
161
-
162
- ```ruby
163
- # config/application.rb
164
- config.active_record.query_log_tags_enabled = true
165
- config.active_record.query_log_tags << :cmdx_task_class
166
- config.active_record.query_log_tags << :cmdx_chain_id
167
-
168
- # app/tasks/application_task.rb
169
- class ApplicationTask < CMDx::Task
170
- before_execution :set_execution_context
171
-
172
- private
173
-
174
- def set_execution_context
175
- # NOTE: This could easily be made into a middleware
176
- ActiveSupport::ExecutionContext.set(
177
- cmdx_task_class: self.class.name,
178
- cmdx_chain_id: chain.id
179
- )
180
- end
181
- end
182
-
183
- # SQL queries will now include comments like:
184
- # /*cmdx_task_class:ExportReportTask,cmdx_chain_id:018c2b95-b764-7615*/ SELECT * FROM reports WHERE id = 1
185
- ```
186
-
187
- ---
148
+ ## Advanced Examples
188
149
 
189
- - **Prev:** [Workflows](workflows.md)
190
- - **Next:** [Getting Started](getting_started.md)
150
+ - [Active Record Query Tagging](https://github.com/drexed/cmdx/blob/main/examples/active_record_query_tagging.md)
151
+ - [Paper Trail Whatdunnit](https://github.com/drexed/cmdx/blob/main/examples/paper_trail_whatdunnit.md)
data/docs/workflows.md CHANGED
@@ -1,26 +1,14 @@
1
1
  # Workflows
2
2
 
3
- Workflow orchestrates sequential execution of multiple tasks in a linear pipeline. Workflows provide a declarative DSL for composing complex business logic from individual task components, with support for conditional execution, context propagation, and configurable halt behavior.
4
-
5
- ## Table of Contents
6
-
7
- - [Declarations](#declarations)
8
- - [Task](#task)
9
- - [Group](#group)
10
- - [Conditionals](#conditionals)
11
- - [Halt Behavior](#halt-behavior)
12
- - [Task Configuration](#task-configuration)
13
- - [Group Configuration](#group-configuration)
14
- - [Nested Workflows](#nested-workflows)
15
- - [Parallel Execution](#parallel-execution)
16
- - [Task Generator](#task-generator)
3
+ Compose multiple tasks into powerful, sequential pipelines. Workflows provide a declarative way to build complex business processes with conditional execution, shared context, and flexible error handling.
17
4
 
18
5
  ## Declarations
19
6
 
20
- Tasks execute sequentially in declaration order (FIFO). The workflow context propagates to each task, allowing access to data from previous executions.
7
+ Tasks run in declaration order (FIFO), sharing a common context across the pipeline.
21
8
 
22
- > [!IMPORTANT]
23
- > Do **NOT** define a `work` method in workflow tasks. The included module automatically provides the execution logic.
9
+ !!! warning
10
+
11
+ Don't define a `work` method in workflows—the module handles execution automatically.
24
12
 
25
13
  ### Task
26
14
 
@@ -35,15 +23,17 @@ class OnboardingWorkflow < CMDx::Task
35
23
  end
36
24
  ```
37
25
 
38
- > [!TIP]
39
- > Execute tasks in parallel via the [cmdx-parallel](https://github.com/drexed/cmdx-parallel) gem.
26
+ !!! tip
27
+
28
+ Execute tasks in parallel via the [cmdx-parallel](https://github.com/drexed/cmdx-parallel) gem.
40
29
 
41
30
  ### Group
42
31
 
43
- Group related tasks for better organization and shared configuration:
32
+ Group related tasks to share configuration:
44
33
 
45
- > [!IMPORTANT]
46
- > Settings and conditionals for a group apply to all tasks within that group.
34
+ !!! warning "Important"
35
+
36
+ Settings and conditionals apply to all tasks in the group.
47
37
 
48
38
  ```ruby
49
39
  class ContentModerationWorkflow < CMDx::Task
@@ -78,10 +68,10 @@ class OnboardingWorkflow < CMDx::Task
78
68
  task SendWelcomeEmail, if: :email_configured?, unless: :email_disabled?
79
69
 
80
70
  # Proc
81
- task SendWelcomeEmail, if: ->(workflow) { Rails.env.production? && workflow.class.name.include?("Premium") }
71
+ task SendWelcomeEmail, if: -> { Rails.env.production? && self.class.name.include?("Premium") }
82
72
 
83
73
  # Lambda
84
- task SendWelcomeEmail, if: proc { |workflow| workflow.context.features_enabled? }
74
+ task SendWelcomeEmail, if: proc { context.features_enabled? }
85
75
 
86
76
  # Class or Module
87
77
  task SendWelcomeEmail, unless: ContentAccessCheck
@@ -95,7 +85,7 @@ class OnboardingWorkflow < CMDx::Task
95
85
  private
96
86
 
97
87
  def email_configured?
98
- context.user.email_address.present?
88
+ context.user.email_address == true
99
89
  end
100
90
 
101
91
  def email_disabled?
@@ -106,9 +96,7 @@ end
106
96
 
107
97
  ## Halt Behavior
108
98
 
109
- By default skipped tasks are considered no-op executions and does not stop workflow execution.
110
- This is configurable via global and task level breakpoint settings. Task and group configurations
111
- can be used together within a workflow.
99
+ By default, skipped tasks don't stop the workflow—they're treated as no-ops. Configure breakpoints globally or per-task to customize this behavior.
112
100
 
113
101
  ```ruby
114
102
  class AnalyticsWorkflow < CMDx::Task
@@ -164,7 +152,7 @@ end
164
152
 
165
153
  ## Nested Workflows
166
154
 
167
- Workflows can task other workflows for hierarchical composition:
155
+ Build hierarchical workflows by composing workflows within workflows:
168
156
 
169
157
  ```ruby
170
158
  class EmailPreparationWorkflow < CMDx::Task
@@ -191,10 +179,11 @@ end
191
179
 
192
180
  ## Parallel Execution
193
181
 
194
- Parallel task execution leverages the [Parallel](https://github.com/grosser/parallel) gem, which automatically detects the number of available processors to maximize concurrent task execution.
182
+ Run tasks concurrently using the [Parallel](https://github.com/grosser/parallel) gem. It automatically uses all available processors for maximum throughput.
183
+
184
+ !!! warning
195
185
 
196
- > [!IMPORTANT]
197
- > Context cannot be modified during parallel execution. Ensure that all required data is preloaded into the context before parallelization begins.
186
+ Context is read-only during parallel execution. Load all required data beforehand.
198
187
 
199
188
  ```ruby
200
189
  class SendWelcomeNotifications < CMDx::Task
@@ -232,10 +221,6 @@ class SendNotifications < CMDx::Task
232
221
  end
233
222
  ```
234
223
 
235
- > [!TIP]
236
- > Use **present tense verbs + pluralized noun** for workflow task names, eg: `SendNotifications`, `DownloadFiles`, `ValidateDocuments`
237
-
238
- ---
224
+ !!! tip
239
225
 
240
- - **Prev:** [Deprecation](deprecation.md)
241
- - **Next:** [Tips and Tricks](tips_and_tricks.md)
226
+ Use **present tense verbs + pluralized noun** for workflow task names, eg: `SendNotifications`, `DownloadFiles`, `ValidateDocuments`
@@ -0,0 +1,46 @@
1
+ # Active Record Query Tagging
2
+
3
+ Add a comment to every query indicating some context to help you track down where that query came from, eg:
4
+
5
+ ```sh
6
+ /*cmdx_task_class:ExportReportTask,cmdx_chain_id:018c2b95-b764-7615*/ SELECT * FROM reports WHERE id = 1
7
+ ```
8
+
9
+ ### Setup
10
+
11
+ ```ruby
12
+ # config/application.rb
13
+ config.active_record.query_log_tags_enabled = true
14
+ config.active_record.query_log_tags += [
15
+ :cmdx_correlation_id,
16
+ :cmdx_chain_id,
17
+ :cmdx_task_class,
18
+ :cmdx_task_id
19
+ ]
20
+
21
+ # lib/cmdx_query_tagging_middleware.rb
22
+ class CmdxQueryTaggingMiddleware
23
+ def self.call(task, **options, &)
24
+ ActiveSupport::ExecutionContext.set(
25
+ cmdx_correlation_id: task.result.metadata[:correlation_id],
26
+ cmdx_chain_id: task.chain.id,
27
+ cmdx_task_class: task.class.name,
28
+ cmdx_task_id: task.id,
29
+ &
30
+ )
31
+ end
32
+ end
33
+ ```
34
+
35
+ ### Usage
36
+
37
+ ```ruby
38
+ class MyTask < CMDx::Task
39
+ register :middleware, CmdxQueryTaggingMiddleware
40
+
41
+ def work
42
+ # Do work...
43
+ end
44
+
45
+ end
46
+ ```