@soulbatical/tetra-core 0.1.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.

Potentially problematic release.


This version of @soulbatical/tetra-core might be problematic. Click here for more details.

Files changed (181) hide show
  1. package/dist/core/SupabaseUserClient.d.ts +14 -0
  2. package/dist/core/SupabaseUserClient.d.ts.map +1 -0
  3. package/dist/core/SupabaseUserClient.js +49 -0
  4. package/dist/core/SupabaseUserClient.js.map +1 -0
  5. package/dist/core/adminDb.d.ts +21 -0
  6. package/dist/core/adminDb.d.ts.map +1 -0
  7. package/dist/core/adminDb.js +43 -0
  8. package/dist/core/adminDb.js.map +1 -0
  9. package/dist/core/publicDb.d.ts +19 -0
  10. package/dist/core/publicDb.d.ts.map +1 -0
  11. package/dist/core/publicDb.js +29 -0
  12. package/dist/core/publicDb.js.map +1 -0
  13. package/dist/core/superadminDb.d.ts +29 -0
  14. package/dist/core/superadminDb.d.ts.map +1 -0
  15. package/dist/core/superadminDb.js +53 -0
  16. package/dist/core/superadminDb.js.map +1 -0
  17. package/dist/core/systemDb.d.ts +34 -0
  18. package/dist/core/systemDb.d.ts.map +1 -0
  19. package/dist/core/systemDb.js +64 -0
  20. package/dist/core/systemDb.js.map +1 -0
  21. package/dist/core/userDb.d.ts +22 -0
  22. package/dist/core/userDb.d.ts.map +1 -0
  23. package/dist/core/userDb.js +36 -0
  24. package/dist/core/userDb.js.map +1 -0
  25. package/dist/core/webhookDb.d.ts +16 -0
  26. package/dist/core/webhookDb.d.ts.map +1 -0
  27. package/dist/core/webhookDb.js +26 -0
  28. package/dist/core/webhookDb.js.map +1 -0
  29. package/dist/frontend/components/FeatureFilters.d.ts +81 -0
  30. package/dist/frontend/components/FeatureFilters.d.ts.map +1 -0
  31. package/dist/frontend/components/FeatureFilters.js +257 -0
  32. package/dist/frontend/components/FeatureFilters.js.map +1 -0
  33. package/dist/frontend/components/FeatureTable.d.ts +96 -0
  34. package/dist/frontend/components/FeatureTable.d.ts.map +1 -0
  35. package/dist/frontend/components/FeatureTable.js +279 -0
  36. package/dist/frontend/components/FeatureTable.js.map +1 -0
  37. package/dist/frontend/hooks/useFeature.d.ts +108 -0
  38. package/dist/frontend/hooks/useFeature.d.ts.map +1 -0
  39. package/dist/frontend/hooks/useFeature.js +354 -0
  40. package/dist/frontend/hooks/useFeature.js.map +1 -0
  41. package/dist/frontend/index.d.ts +17 -0
  42. package/dist/frontend/index.d.ts.map +1 -0
  43. package/dist/frontend/index.js +14 -0
  44. package/dist/frontend/index.js.map +1 -0
  45. package/dist/index.d.ts +78 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +71 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/middleware/authMiddleware.d.ts +137 -0
  50. package/dist/middleware/authMiddleware.d.ts.map +1 -0
  51. package/dist/middleware/authMiddleware.js +292 -0
  52. package/dist/middleware/authMiddleware.js.map +1 -0
  53. package/dist/middleware/autoRegisterValidators.d.ts +31 -0
  54. package/dist/middleware/autoRegisterValidators.d.ts.map +1 -0
  55. package/dist/middleware/autoRegisterValidators.js +125 -0
  56. package/dist/middleware/autoRegisterValidators.js.map +1 -0
  57. package/dist/middleware/validateQueryParams.d.ts +62 -0
  58. package/dist/middleware/validateQueryParams.d.ts.map +1 -0
  59. package/dist/middleware/validateQueryParams.js +321 -0
  60. package/dist/middleware/validateQueryParams.js.map +1 -0
  61. package/dist/shared/controllers/BaseMutationController.d.ts +79 -0
  62. package/dist/shared/controllers/BaseMutationController.d.ts.map +1 -0
  63. package/dist/shared/controllers/BaseMutationController.js +241 -0
  64. package/dist/shared/controllers/BaseMutationController.js.map +1 -0
  65. package/dist/shared/controllers/BaseQueryController.d.ts +72 -0
  66. package/dist/shared/controllers/BaseQueryController.d.ts.map +1 -0
  67. package/dist/shared/controllers/BaseQueryController.js +375 -0
  68. package/dist/shared/controllers/BaseQueryController.js.map +1 -0
  69. package/dist/shared/controllers/FilterConfigController.d.ts +37 -0
  70. package/dist/shared/controllers/FilterConfigController.d.ts.map +1 -0
  71. package/dist/shared/controllers/FilterConfigController.js +94 -0
  72. package/dist/shared/controllers/FilterConfigController.js.map +1 -0
  73. package/dist/shared/controllers/index.d.ts +5 -0
  74. package/dist/shared/controllers/index.d.ts.map +1 -0
  75. package/dist/shared/controllers/index.js +4 -0
  76. package/dist/shared/controllers/index.js.map +1 -0
  77. package/dist/shared/controllers/types.d.ts +57 -0
  78. package/dist/shared/controllers/types.d.ts.map +1 -0
  79. package/dist/shared/controllers/types.js +2 -0
  80. package/dist/shared/controllers/types.js.map +1 -0
  81. package/dist/shared/factories/BatchRouteFactory.d.ts +33 -0
  82. package/dist/shared/factories/BatchRouteFactory.d.ts.map +1 -0
  83. package/dist/shared/factories/BatchRouteFactory.js +54 -0
  84. package/dist/shared/factories/BatchRouteFactory.js.map +1 -0
  85. package/dist/shared/factories/MutationRouteFactory.d.ts +27 -0
  86. package/dist/shared/factories/MutationRouteFactory.d.ts.map +1 -0
  87. package/dist/shared/factories/MutationRouteFactory.js +39 -0
  88. package/dist/shared/factories/MutationRouteFactory.js.map +1 -0
  89. package/dist/shared/factories/PhaseRouteFactory.d.ts +33 -0
  90. package/dist/shared/factories/PhaseRouteFactory.d.ts.map +1 -0
  91. package/dist/shared/factories/PhaseRouteFactory.js +67 -0
  92. package/dist/shared/factories/PhaseRouteFactory.js.map +1 -0
  93. package/dist/shared/factories/QueryRouteFactory.d.ts +37 -0
  94. package/dist/shared/factories/QueryRouteFactory.d.ts.map +1 -0
  95. package/dist/shared/factories/QueryRouteFactory.js +244 -0
  96. package/dist/shared/factories/QueryRouteFactory.js.map +1 -0
  97. package/dist/shared/factories/QueryServiceFactory.d.ts +282 -0
  98. package/dist/shared/factories/QueryServiceFactory.d.ts.map +1 -0
  99. package/dist/shared/factories/QueryServiceFactory.js +277 -0
  100. package/dist/shared/factories/QueryServiceFactory.js.map +1 -0
  101. package/dist/shared/factories/index.d.ts +8 -0
  102. package/dist/shared/factories/index.d.ts.map +1 -0
  103. package/dist/shared/factories/index.js +6 -0
  104. package/dist/shared/factories/index.js.map +1 -0
  105. package/dist/shared/factories/types.d.ts +98 -0
  106. package/dist/shared/factories/types.d.ts.map +1 -0
  107. package/dist/shared/factories/types.js +8 -0
  108. package/dist/shared/factories/types.js.map +1 -0
  109. package/dist/shared/ownership/types.d.ts +84 -0
  110. package/dist/shared/ownership/types.d.ts.map +1 -0
  111. package/dist/shared/ownership/types.js +8 -0
  112. package/dist/shared/ownership/types.js.map +1 -0
  113. package/dist/shared/rfc7807ErrorResponse.d.ts +54 -0
  114. package/dist/shared/rfc7807ErrorResponse.d.ts.map +1 -0
  115. package/dist/shared/rfc7807ErrorResponse.js +98 -0
  116. package/dist/shared/rfc7807ErrorResponse.js.map +1 -0
  117. package/dist/shared/services/BaseCronService.d.ts +171 -0
  118. package/dist/shared/services/BaseCronService.d.ts.map +1 -0
  119. package/dist/shared/services/BaseCronService.js +444 -0
  120. package/dist/shared/services/BaseCronService.js.map +1 -0
  121. package/dist/shared/services/BasePhaseService.d.ts +170 -0
  122. package/dist/shared/services/BasePhaseService.d.ts.map +1 -0
  123. package/dist/shared/services/BasePhaseService.js +409 -0
  124. package/dist/shared/services/BasePhaseService.js.map +1 -0
  125. package/dist/shared/services/CronRegistry.d.ts +67 -0
  126. package/dist/shared/services/CronRegistry.d.ts.map +1 -0
  127. package/dist/shared/services/CronRegistry.js +68 -0
  128. package/dist/shared/services/CronRegistry.js.map +1 -0
  129. package/dist/shared/services/SimpleRPCQueryService.d.ts +111 -0
  130. package/dist/shared/services/SimpleRPCQueryService.d.ts.map +1 -0
  131. package/dist/shared/services/SimpleRPCQueryService.js +265 -0
  132. package/dist/shared/services/SimpleRPCQueryService.js.map +1 -0
  133. package/dist/shared/types/feature-config.d.ts +611 -0
  134. package/dist/shared/types/feature-config.d.ts.map +1 -0
  135. package/dist/shared/types/feature-config.js +85 -0
  136. package/dist/shared/types/feature-config.js.map +1 -0
  137. package/dist/shared/types/query-config.d.ts +41 -0
  138. package/dist/shared/types/query-config.d.ts.map +1 -0
  139. package/dist/shared/types/query-config.js +6 -0
  140. package/dist/shared/types/query-config.js.map +1 -0
  141. package/dist/shared/utils/config-driven-filters.d.ts +215 -0
  142. package/dist/shared/utils/config-driven-filters.d.ts.map +1 -0
  143. package/dist/shared/utils/config-driven-filters.js +451 -0
  144. package/dist/shared/utils/config-driven-filters.js.map +1 -0
  145. package/dist/shared/utils/controllerErrorHandler.d.ts +44 -0
  146. package/dist/shared/utils/controllerErrorHandler.d.ts.map +1 -0
  147. package/dist/shared/utils/controllerErrorHandler.js +126 -0
  148. package/dist/shared/utils/controllerErrorHandler.js.map +1 -0
  149. package/dist/shared/utils/parseInclude.d.ts +14 -0
  150. package/dist/shared/utils/parseInclude.d.ts.map +1 -0
  151. package/dist/shared/utils/parseInclude.js +28 -0
  152. package/dist/shared/utils/parseInclude.js.map +1 -0
  153. package/dist/shared/utils/queryHelpers.d.ts +62 -0
  154. package/dist/shared/utils/queryHelpers.d.ts.map +1 -0
  155. package/dist/shared/utils/queryHelpers.js +61 -0
  156. package/dist/shared/utils/queryHelpers.js.map +1 -0
  157. package/dist/shared/utils/response-mapper.d.ts +42 -0
  158. package/dist/shared/utils/response-mapper.d.ts.map +1 -0
  159. package/dist/shared/utils/response-mapper.js +176 -0
  160. package/dist/shared/utils/response-mapper.js.map +1 -0
  161. package/dist/shared/utils/responseBuilder.d.ts +103 -0
  162. package/dist/shared/utils/responseBuilder.d.ts.map +1 -0
  163. package/dist/shared/utils/responseBuilder.js +131 -0
  164. package/dist/shared/utils/responseBuilder.js.map +1 -0
  165. package/dist/shared/validators/featureConfigValidator.d.ts +23 -0
  166. package/dist/shared/validators/featureConfigValidator.d.ts.map +1 -0
  167. package/dist/shared/validators/featureConfigValidator.js +143 -0
  168. package/dist/shared/validators/featureConfigValidator.js.map +1 -0
  169. package/dist/shared/validators/organizationValidator.d.ts +53 -0
  170. package/dist/shared/validators/organizationValidator.d.ts.map +1 -0
  171. package/dist/shared/validators/organizationValidator.js +69 -0
  172. package/dist/shared/validators/organizationValidator.js.map +1 -0
  173. package/dist/shared/validators/uuidValidator.d.ts +57 -0
  174. package/dist/shared/validators/uuidValidator.d.ts.map +1 -0
  175. package/dist/shared/validators/uuidValidator.js +77 -0
  176. package/dist/shared/validators/uuidValidator.js.map +1 -0
  177. package/dist/utils/logger.d.ts +40 -0
  178. package/dist/utils/logger.d.ts.map +1 -0
  179. package/dist/utils/logger.js +47 -0
  180. package/dist/utils/logger.js.map +1 -0
  181. package/package.json +80 -0
@@ -0,0 +1,409 @@
1
+ import { createLogger } from '../../utils/logger.js';
2
+ const logger = createLogger('service:phase:base');
3
+ /**
4
+ * Abstract base class for all Phase Services
5
+ * Provides 95% of batch update logic shared across:
6
+ * - OrderPhaseService
7
+ * - BookPhaseService (via BookPhaseCacheService)
8
+ * - ProductionPhaseService
9
+ * - ProductionItemPhaseService
10
+ * - OrderItemPhaseService
11
+ *
12
+ * Pattern:
13
+ * 1. Batch fetch entities using RPC (200 per chunk)
14
+ * 2. Calculate phases in batch (avoiding N+1)
15
+ * 3. Batch update (100 per chunk with Promise.allSettled)
16
+ * 4. Progress logging & error tracking
17
+ */
18
+ export class BasePhaseService {
19
+ supabase;
20
+ config; // FeatureConfig
21
+ constructor(supabase) {
22
+ this.supabase = supabase;
23
+ }
24
+ /**
25
+ * Get the RPC function name for batch fetching (v3.0 - results pattern)
26
+ * Uses config.resultsRpcName automatically
27
+ *
28
+ * @deprecated Override getFeatureConfig() instead - this method is auto-generated
29
+ */
30
+ getRpcFunctionName() {
31
+ if (!this.config) {
32
+ this.config = this.getFeatureConfig();
33
+ }
34
+ if (!this.config?.resultsRpcName) {
35
+ throw new Error(`Missing resultsRpcName in feature config for ${this.getTableName()}. ` +
36
+ `Add 'resultsRpcName: "get_${this.getTableName()}_results"' to the config.`);
37
+ }
38
+ return this.config.resultsRpcName;
39
+ }
40
+ /**
41
+ * Get the batch size for updates (default: 100)
42
+ * Override if needed (e.g., Productions uses 20)
43
+ */
44
+ getUpdateBatchSize() {
45
+ return 100;
46
+ }
47
+ /**
48
+ * Prepare update data from entity and phases
49
+ * Override if entity needs custom fields (e.g., phase_conflict_details)
50
+ */
51
+ prepareUpdateData(entity, phases, now) {
52
+ return {
53
+ current_phase: phases[0],
54
+ phase_updated_at: now
55
+ };
56
+ }
57
+ /**
58
+ * CONCRETE METHODS - Shared 95% logic
59
+ */
60
+ /**
61
+ * Batch fetch entities using RPC
62
+ * Handles chunking if > 200 IDs
63
+ */
64
+ async batchFetchEntities(ids) {
65
+ if (ids.length === 0)
66
+ return [];
67
+ const SAFE_BATCH_SIZE = 200;
68
+ const entities = [];
69
+ const rpcFunction = this.getRpcFunctionName();
70
+ const entityType = this.getEntityTypeName();
71
+ if (ids.length > SAFE_BATCH_SIZE) {
72
+ logger.info(`📦 Processing ${ids.length} ${entityType} in batches of ${SAFE_BATCH_SIZE}...`);
73
+ for (let i = 0; i < ids.length; i += SAFE_BATCH_SIZE) {
74
+ const batchIds = ids.slice(i, i + SAFE_BATCH_SIZE);
75
+ const batchNumber = Math.floor(i / SAFE_BATCH_SIZE) + 1;
76
+ const totalBatches = Math.ceil(ids.length / SAFE_BATCH_SIZE);
77
+ logger.info(`📦 Fetching batch ${batchNumber}/${totalBatches} (${batchIds.length} ${entityType})...`);
78
+ // Modern pattern: get_*_results with p_ids parameter
79
+ // No p_org_id for system-wide cron jobs (NULL = all orgs)
80
+ const { data, error } = await this.supabase
81
+ .rpc(rpcFunction, {
82
+ p_org_id: null, // NULL = system-wide (all organizations)
83
+ p_ids: batchIds,
84
+ p_limit: 10000 // High limit to fetch all requested IDs
85
+ });
86
+ if (error) {
87
+ logger.error({ error, batchNumber }, `❌ Batch ${batchNumber} failed`);
88
+ throw error;
89
+ }
90
+ else if (data && data.length > 0) {
91
+ // Extract data from rows (get_*_results returns {data: jsonb, total_count: bigint}[])
92
+ const extractedData = data.map((row) => row.data);
93
+ entities.push(...extractedData);
94
+ logger.info(`✅ Batch ${batchNumber} successful: ${extractedData.length} ${entityType} fetched`);
95
+ }
96
+ }
97
+ }
98
+ else {
99
+ // Small enough to fetch in one go
100
+ const { data, error } = await this.supabase
101
+ .rpc(rpcFunction, {
102
+ p_org_id: null, // NULL = system-wide (all organizations)
103
+ p_ids: ids,
104
+ p_limit: 10000 // High limit to fetch all requested IDs
105
+ });
106
+ if (error) {
107
+ logger.error({ error }, `Error fetching ${entityType} for batch update`);
108
+ throw error;
109
+ }
110
+ // Extract data from rows (get_*_results returns {data: jsonb, total_count: bigint}[])
111
+ if (data && data.length > 0) {
112
+ const extractedData = data.map((row) => row.data);
113
+ entities.push(...extractedData);
114
+ }
115
+ }
116
+ return entities;
117
+ }
118
+ // REMOVED: getRpcParameterName() - No longer needed
119
+ // Modern pattern uses standardized p_ids parameter in get_*_results functions
120
+ /**
121
+ * Generic method to batch fetch related entities via RPC
122
+ * Handles error logging and groups results by key
123
+ *
124
+ * @param rpcName - Name of the RPC function to call
125
+ * @param params - Parameters to pass to the RPC function
126
+ * @param groupByKey - Key to group results by (e.g., 'orderid', 'productionid')
127
+ * @returns Map of grouped results by the specified key
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * const orderItemsMap = await this.batchFetchRelated<OrderItem>(
132
+ * 'get_orderitems_for_orders',
133
+ * { order_ids: orderIds },
134
+ * 'orderid'
135
+ * );
136
+ * ```
137
+ */
138
+ async batchFetchRelated(rpcName, params, groupByKey) {
139
+ // Return empty map if no params or all params are empty
140
+ if (!params || Object.values(params).every(v => !v || (Array.isArray(v) && v.length === 0))) {
141
+ return new Map();
142
+ }
143
+ try {
144
+ const { data, error } = await this.supabase.rpc(rpcName, params);
145
+ if (error) {
146
+ logger.error({ error, rpcName, params }, `Failed to batch fetch related entities via ${rpcName}`);
147
+ return new Map();
148
+ }
149
+ return this.groupByKey(data || [], groupByKey);
150
+ }
151
+ catch (error) {
152
+ logger.error({ error, rpcName, params }, `Exception during batch fetch via ${rpcName}`);
153
+ return new Map();
154
+ }
155
+ }
156
+ /**
157
+ * Helper method to group array of items by a specific key
158
+ *
159
+ * @param items - Array of items to group
160
+ * @param key - Property name to group by
161
+ * @returns Map where key is the grouping value and value is array of items
162
+ *
163
+ * @example
164
+ * ```typescript
165
+ * const itemsByOrder = this.groupByKey<OrderItem>(orderItems, 'orderid');
166
+ * ```
167
+ */
168
+ groupByKey(items, key) {
169
+ const map = new Map();
170
+ for (const item of items) {
171
+ const keyValue = item[key];
172
+ if (!map.has(keyValue)) {
173
+ map.set(keyValue, []);
174
+ }
175
+ map.get(keyValue).push(item);
176
+ }
177
+ return map;
178
+ }
179
+ /**
180
+ * Batch update entities with phases
181
+ * Uses Promise.allSettled for parallel updates with error tracking
182
+ */
183
+ async batchUpdateEntities(updateData, results) {
184
+ if (updateData.length === 0)
185
+ return;
186
+ const BATCH_SIZE = this.getUpdateBatchSize();
187
+ const now = new Date().toISOString();
188
+ const tableName = this.getTableName();
189
+ const entityType = this.getEntityTypeName();
190
+ logger.info(`📝 Updating ${updateData.length} ${entityType} in batches of ${BATCH_SIZE}...`);
191
+ for (let i = 0; i < updateData.length; i += BATCH_SIZE) {
192
+ const batch = updateData.slice(i, i + BATCH_SIZE);
193
+ // Use Promise.allSettled to update all entities in batch concurrently
194
+ const batchResults = await Promise.allSettled(batch.map(update => {
195
+ // Prepare update data using overridable method
196
+ const updateFields = this.prepareUpdateData(update, [update.current_phase], now);
197
+ return this.supabase
198
+ .from(tableName)
199
+ .update(updateFields)
200
+ .eq('id', update.id);
201
+ }));
202
+ // Process results
203
+ batchResults.forEach((result, idx) => {
204
+ const update = batch[idx];
205
+ if (result.status === 'fulfilled' && !result.value.error) {
206
+ results.success++;
207
+ }
208
+ else {
209
+ results.failed++;
210
+ const error = result.status === 'rejected'
211
+ ? result.reason
212
+ : result.value.error;
213
+ // Better error formatting
214
+ let errorMessage = 'Unknown error';
215
+ if (typeof error === 'string') {
216
+ errorMessage = error;
217
+ }
218
+ else if (error?.message) {
219
+ errorMessage = error.message;
220
+ }
221
+ else if (error?.code) {
222
+ errorMessage = `Error code: ${error.code}${error.details ? ' - ' + error.details : ''}`;
223
+ }
224
+ else if (error) {
225
+ errorMessage = JSON.stringify(error);
226
+ }
227
+ results.errors.push({
228
+ entityId: update.id,
229
+ error: errorMessage
230
+ });
231
+ }
232
+ });
233
+ // Log progress
234
+ const processed = Math.min(i + BATCH_SIZE, updateData.length);
235
+ const percentage = Math.round((processed / updateData.length) * 100);
236
+ logger.info(`📝 Updated ${processed}/${updateData.length} ${entityType} (${percentage}%)`);
237
+ }
238
+ }
239
+ /**
240
+ * Main batch update method
241
+ * This is the SINGLE SOURCE OF TRUTH for batch phase updates
242
+ *
243
+ * Pattern:
244
+ * 1. Batch fetch entities (200 per chunk)
245
+ * 2. Calculate phases in batch (avoiding N+1)
246
+ * 3. Prepare update data
247
+ * 4. Batch update (100 per chunk with error tracking)
248
+ */
249
+ async updateCachedPhasesBatch(ids) {
250
+ const results = {
251
+ success: 0,
252
+ failed: 0,
253
+ errors: [],
254
+ changedIds: [] // Track which IDs actually changed
255
+ };
256
+ if (ids.length === 0) {
257
+ return results;
258
+ }
259
+ const entityType = this.getEntityTypeName();
260
+ logger.info(`🚀 Starting REAL batch phase update for ${ids.length} ${entityType}`);
261
+ const startTime = Date.now();
262
+ try {
263
+ // STEP 1: Batch fetch all entities using RPC
264
+ const entities = await this.batchFetchEntities(ids);
265
+ if (entities.length === 0) {
266
+ logger.warn(`No ${entityType} found for batch update`);
267
+ results.failed = ids.length;
268
+ ids.forEach(id => results.errors.push({ entityId: id, error: 'Entity not found' }));
269
+ return results;
270
+ }
271
+ // STEP 2: Calculate phases for ALL entities in ONE batch call (efficient!)
272
+ const allPhasesMap = await this.determineAllPhasesForEntities(entities);
273
+ // STEP 3: Prepare update data
274
+ const updateData = [];
275
+ for (const entity of entities) {
276
+ const entityId = entity.id;
277
+ const phases = allPhasesMap.get(entityId) || [];
278
+ if (phases.length === 0) {
279
+ results.failed++;
280
+ results.errors.push({ entityId, error: 'No phases determined' });
281
+ continue;
282
+ }
283
+ const newPhase = phases[0];
284
+ const previousPhase = entity.current_phase;
285
+ updateData.push({
286
+ id: entityId,
287
+ current_phase: newPhase,
288
+ previous_phase: previousPhase,
289
+ phase_details: {
290
+ all_phases: phases,
291
+ timestamp: new Date().toISOString()
292
+ }
293
+ });
294
+ // Track if phase actually changed
295
+ if (newPhase !== previousPhase) {
296
+ results.changedIds.push(entityId);
297
+ }
298
+ }
299
+ // STEP 4: Batch update all entities
300
+ await this.batchUpdateEntities(updateData, results);
301
+ const duration = Math.round((Date.now() - startTime) / 1000);
302
+ logger.info({
303
+ [`total_${entityType.replace(/ /g, '_')}`]: ids.length,
304
+ success: results.success,
305
+ failed: results.failed,
306
+ changed: results.changedIds.length,
307
+ unchanged: results.success - results.changedIds.length,
308
+ duration
309
+ }, `✅ Batch phase update completed in ${duration}s`);
310
+ }
311
+ catch (error) {
312
+ // Better error logging
313
+ const errorDetails = error instanceof Error
314
+ ? { message: error.message, stack: error.stack, name: error.name }
315
+ : { error: String(error) };
316
+ logger.error({
317
+ error: errorDetails,
318
+ entityCount: ids.length,
319
+ successSoFar: results.success,
320
+ failedSoFar: results.failed
321
+ }, `❌ Critical error in batch phase update for ${entityType}`);
322
+ // Mark remaining as failed
323
+ const remainingIds = ids.slice(results.success + results.failed);
324
+ results.failed += remainingIds.length;
325
+ // Better error message
326
+ let errorMessage = 'Unknown error';
327
+ if (error instanceof Error) {
328
+ errorMessage = error.message;
329
+ }
330
+ else if (typeof error === 'string') {
331
+ errorMessage = error;
332
+ }
333
+ else if (error) {
334
+ errorMessage = JSON.stringify(error);
335
+ }
336
+ remainingIds.forEach(id => {
337
+ results.errors.push({
338
+ entityId: id,
339
+ error: errorMessage
340
+ });
341
+ });
342
+ }
343
+ return results;
344
+ }
345
+ /**
346
+ * Update cached phase for a single entity
347
+ * Default implementation that delegates to batch method
348
+ *
349
+ * Services can override this if they need custom behavior (e.g., extra metadata)
350
+ *
351
+ * @param entityId - ID of entity to update
352
+ * @returns UNIFORM PhaseUpdateResult with all phase information
353
+ */
354
+ async updateCachedPhase(entityId) {
355
+ const entityType = this.getEntityTypeName();
356
+ logger.debug({ entityId }, `Updating cached phase for single ${entityType.slice(0, -1)}`);
357
+ try {
358
+ // Get current phase before update
359
+ const entitiesBefore = await this.batchFetchEntities([entityId]);
360
+ const previousPhase = entitiesBefore[0] ? entitiesBefore[0].current_phase : undefined;
361
+ // Use batch method for consistency and code reuse
362
+ const results = await this.updateCachedPhasesBatch([entityId]);
363
+ if (results.success > 0) {
364
+ // Success - get the updated entity with all phase info
365
+ const entitiesAfter = await this.batchFetchEntities([entityId]);
366
+ const entity = entitiesAfter[0];
367
+ if (!entity) {
368
+ return {
369
+ success: false,
370
+ error: 'Entity not found after update'
371
+ };
372
+ }
373
+ const currentPhase = entity.current_phase;
374
+ const phaseDetails = entity.phase_conflict_details;
375
+ const allPhases = phaseDetails?.all_phases || (currentPhase ? [currentPhase] : []);
376
+ const hasConflict = phaseDetails?.phases?.length > 1 || false;
377
+ const changed = results.changedIds?.includes(entityId) || false;
378
+ return {
379
+ success: true,
380
+ phase: currentPhase,
381
+ previousPhase,
382
+ allPhases,
383
+ hasConflict,
384
+ metadata: {
385
+ changed,
386
+ timestamp: new Date().toISOString()
387
+ }
388
+ };
389
+ }
390
+ else {
391
+ // Failed - return error from batch results
392
+ const error = results.errors.find(e => e.entityId === entityId);
393
+ return {
394
+ success: false,
395
+ previousPhase,
396
+ error: error?.error || 'Update failed'
397
+ };
398
+ }
399
+ }
400
+ catch (error) {
401
+ logger.error({ error, entityId }, `Error updating cached phase for ${entityType.slice(0, -1)}`);
402
+ return {
403
+ success: false,
404
+ error: error instanceof Error ? error.message : 'Unknown error'
405
+ };
406
+ }
407
+ }
408
+ }
409
+ //# sourceMappingURL=BasePhaseService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BasePhaseService.js","sourceRoot":"","sources":["../../../src/shared/services/BasePhaseService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Configuration for a cron service
3
+ * Used to register cron services for auto-discovery
4
+ */
5
+ export interface CronServiceConfig {
6
+ /** Unique identifier (e.g., 'order-item-phases') */
7
+ id: string;
8
+ /** Display name (e.g., 'OrderItem Phases') */
9
+ name: string;
10
+ /** Human-readable description of what this cron job does */
11
+ description: string;
12
+ /** Human-readable schedule (e.g., 'Every 30 min (:06, :36)') */
13
+ schedule: string;
14
+ /** API endpoint for manual triggering */
15
+ endpoint: string;
16
+ /** Dynamic import function that returns the service class */
17
+ serviceImport: () => Promise<any>;
18
+ }
19
+ /**
20
+ * Registry for all cron services in the application
21
+ *
22
+ * Provides:
23
+ * - Auto-discovery of cron services
24
+ * - Centralized configuration
25
+ * - Type-safe service registration
26
+ *
27
+ * Usage:
28
+ * 1. Export cronConfig from your cron service file
29
+ * 2. Register it: CronRegistry.register(cronConfig)
30
+ * 3. Access via CronRegistry.getAll() or CronRegistry.get(id)
31
+ */
32
+ export declare class CronRegistry {
33
+ private static services;
34
+ /**
35
+ * Register a cron service
36
+ * @param config - Cron service configuration
37
+ * @throws Error if service with same ID already registered
38
+ */
39
+ static register(config: CronServiceConfig): void;
40
+ /**
41
+ * Get all registered cron services
42
+ * @returns Array of all registered cron service configs
43
+ */
44
+ static getAll(): CronServiceConfig[];
45
+ /**
46
+ * Get a specific cron service by ID
47
+ * @param id - Service ID
48
+ * @returns Service config or undefined if not found
49
+ */
50
+ static get(id: string): CronServiceConfig | undefined;
51
+ /**
52
+ * Check if a cron service is registered
53
+ * @param id - Service ID
54
+ * @returns True if service is registered
55
+ */
56
+ static has(id: string): boolean;
57
+ /**
58
+ * Get count of registered services
59
+ * @returns Number of registered services
60
+ */
61
+ static count(): number;
62
+ /**
63
+ * Clear all registered services (for testing)
64
+ */
65
+ static clear(): void;
66
+ }
67
+ //# sourceMappingURL=CronRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CronRegistry.d.ts","sourceRoot":"","sources":["../../../src/shared/services/CronRegistry.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IAEX,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IAEb,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IAEpB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IAEjB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IAEjB,6DAA6D;IAC7D,aAAa,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;CACnC;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAwC;IAE/D;;;;OAIG;IACH,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAShD;;;OAGG;IACH,MAAM,CAAC,MAAM,IAAI,iBAAiB,EAAE;IAIpC;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAIrD;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAI/B;;;OAGG;IACH,MAAM,CAAC,KAAK,IAAI,MAAM;IAItB;;OAEG;IACH,MAAM,CAAC,KAAK,IAAI,IAAI;CAIrB"}
@@ -0,0 +1,68 @@
1
+ import { createLogger } from '../../utils/logger.js';
2
+ const logger = createLogger('system:cron:registry');
3
+ /**
4
+ * Registry for all cron services in the application
5
+ *
6
+ * Provides:
7
+ * - Auto-discovery of cron services
8
+ * - Centralized configuration
9
+ * - Type-safe service registration
10
+ *
11
+ * Usage:
12
+ * 1. Export cronConfig from your cron service file
13
+ * 2. Register it: CronRegistry.register(cronConfig)
14
+ * 3. Access via CronRegistry.getAll() or CronRegistry.get(id)
15
+ */
16
+ export class CronRegistry {
17
+ static services = new Map();
18
+ /**
19
+ * Register a cron service
20
+ * @param config - Cron service configuration
21
+ * @throws Error if service with same ID already registered
22
+ */
23
+ static register(config) {
24
+ if (this.services.has(config.id)) {
25
+ logger.warn({ serviceId: config.id }, '⚠️ Cron service already registered, overwriting');
26
+ }
27
+ this.services.set(config.id, config);
28
+ logger.debug({ serviceId: config.id, name: config.name }, '✅ Cron service registered');
29
+ }
30
+ /**
31
+ * Get all registered cron services
32
+ * @returns Array of all registered cron service configs
33
+ */
34
+ static getAll() {
35
+ return Array.from(this.services.values());
36
+ }
37
+ /**
38
+ * Get a specific cron service by ID
39
+ * @param id - Service ID
40
+ * @returns Service config or undefined if not found
41
+ */
42
+ static get(id) {
43
+ return this.services.get(id);
44
+ }
45
+ /**
46
+ * Check if a cron service is registered
47
+ * @param id - Service ID
48
+ * @returns True if service is registered
49
+ */
50
+ static has(id) {
51
+ return this.services.has(id);
52
+ }
53
+ /**
54
+ * Get count of registered services
55
+ * @returns Number of registered services
56
+ */
57
+ static count() {
58
+ return this.services.size;
59
+ }
60
+ /**
61
+ * Clear all registered services (for testing)
62
+ */
63
+ static clear() {
64
+ this.services.clear();
65
+ logger.debug('🧹 All cron services unregistered');
66
+ }
67
+ }
68
+ //# sourceMappingURL=CronRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CronRegistry.js","sourceRoot":"","sources":["../../../src/shared/services/CronRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,MAAM,GAAG,YAAY,CAAC,sBAAsB,CAAC,CAAC;AA0BpD;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,YAAY;IACf,MAAM,CAAC,QAAQ,GAAG,IAAI,GAAG,EAA6B,CAAC;IAE/D;;;;OAIG;IACH,MAAM,CAAC,QAAQ,CAAC,MAAyB;QACvC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YACjC,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,kDAAkD,CAAC,CAAC;QAC5F,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,2BAA2B,CAAC,CAAC;IACzF,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,MAAM;QACX,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,EAAU;QACnB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,EAAU;QACnB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,KAAK;QACV,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK;QACV,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACpD,CAAC"}