@arela/uploader 1.0.24 → 1.1.1

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 (80) hide show
  1. package/docs/AUTO_PROCESSING_PIPELINE.md +258 -0
  2. package/docs/COMPLETE_USAGE_GUIDE.md +1363 -0
  3. package/docs/DATABASESERVICE_IMPROVEMENTS.md +546 -0
  4. package/docs/PASO_2_TEST_RESULTS.md +298 -0
  5. package/docs/PASO_3_PLAN.md +385 -0
  6. package/docs/PHASE_1_FILE_DETECTION.md +366 -0
  7. package/docs/PHASE_2_API_INTEGRATION.md +426 -0
  8. package/docs/PHASE_3_DATABASE_MANAGEMENT.md +480 -0
  9. package/docs/PHASE_4_FILE_OPERATIONS.md +448 -0
  10. package/docs/PHASE_5_WATCH_MODE.md +450 -0
  11. package/docs/PHASE_6_SIGNAL_HANDLING.md +472 -0
  12. package/docs/PHASE_7_ADVANCED_FEATURES.md +560 -0
  13. package/docs/PLAN_WATCH_FEATURE.md +417 -0
  14. package/docs/README.md +480 -0
  15. package/docs/SCHEMA_ALIGNMENT_SUMMARY.md +301 -0
  16. package/docs/SMARTWATCH_DATABASE_REFACTORING.md +181 -0
  17. package/docs/SMART_WATCH_DATABASE_CHANGES.md +502 -0
  18. package/docs/TESTING_WATCH_MODE.md +212 -0
  19. package/docs/WATCHER_API_IMPLEMENTATION.md +520 -0
  20. package/docs/WATCHER_API_INTEGRATION.md +562 -0
  21. package/docs/WATCHER_SETUP_GUIDE.md +614 -0
  22. package/docs/WATCH_ARCHITECTURE.md +395 -0
  23. package/docs/WATCH_AUTO_PIPELINE.md +334 -0
  24. package/docs/WATCH_CONFIGURATION.md +267 -0
  25. package/docs/WATCH_USAGE_GUIDE.md +567 -0
  26. package/docs/commands.md +14 -0
  27. package/package.json +1 -1
  28. package/src/commands/IdentifyCommand.js +11 -0
  29. package/src/config/config.js +2 -2
  30. package/src/file-detection.js +42 -1
  31. package/src/scoring/scoring-engine.js +40 -7
  32. package/src/services/LoggingService.js +5 -3
  33. package/.vscode/settings.json +0 -1
  34. package/coverage/IdentifyCommand.js.html +0 -1462
  35. package/coverage/PropagateCommand.js.html +0 -1507
  36. package/coverage/PushCommand.js.html +0 -1504
  37. package/coverage/ScanCommand.js.html +0 -1654
  38. package/coverage/UploadCommand.js.html +0 -1846
  39. package/coverage/WatchCommand.js.html +0 -4111
  40. package/coverage/base.css +0 -224
  41. package/coverage/block-navigation.js +0 -87
  42. package/coverage/favicon.png +0 -0
  43. package/coverage/index.html +0 -191
  44. package/coverage/lcov-report/IdentifyCommand.js.html +0 -1462
  45. package/coverage/lcov-report/PropagateCommand.js.html +0 -1507
  46. package/coverage/lcov-report/PushCommand.js.html +0 -1504
  47. package/coverage/lcov-report/ScanCommand.js.html +0 -1654
  48. package/coverage/lcov-report/UploadCommand.js.html +0 -1846
  49. package/coverage/lcov-report/WatchCommand.js.html +0 -4111
  50. package/coverage/lcov-report/base.css +0 -224
  51. package/coverage/lcov-report/block-navigation.js +0 -87
  52. package/coverage/lcov-report/favicon.png +0 -0
  53. package/coverage/lcov-report/index.html +0 -191
  54. package/coverage/lcov-report/prettify.css +0 -1
  55. package/coverage/lcov-report/prettify.js +0 -2
  56. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  57. package/coverage/lcov-report/sorter.js +0 -210
  58. package/coverage/lcov.info +0 -1937
  59. package/coverage/prettify.css +0 -1
  60. package/coverage/prettify.js +0 -2
  61. package/coverage/sort-arrow-sprite.png +0 -0
  62. package/coverage/sorter.js +0 -210
  63. package/docs/API_ENDPOINTS_FOR_DETECTION.md +0 -647
  64. package/docs/API_RETRY_MECHANISM.md +0 -338
  65. package/docs/ARELA_IDENTIFY_IMPLEMENTATION.md +0 -489
  66. package/docs/ARELA_IDENTIFY_QUICKREF.md +0 -186
  67. package/docs/ARELA_PROPAGATE_IMPLEMENTATION.md +0 -581
  68. package/docs/ARELA_PROPAGATE_QUICKREF.md +0 -272
  69. package/docs/ARELA_PUSH_IMPLEMENTATION.md +0 -577
  70. package/docs/ARELA_PUSH_QUICKREF.md +0 -322
  71. package/docs/ARELA_SCAN_IMPLEMENTATION.md +0 -373
  72. package/docs/ARELA_SCAN_QUICKREF.md +0 -139
  73. package/docs/CROSS_PLATFORM_PATH_HANDLING.md +0 -597
  74. package/docs/DETECTION_ATTEMPT_TRACKING.md +0 -414
  75. package/docs/MIGRATION_UPLOADER_TO_FILE_STATS.md +0 -1020
  76. package/docs/MULTI_LEVEL_DIRECTORY_SCANNING.md +0 -494
  77. package/docs/QUICK_REFERENCE_API_DETECTION.md +0 -264
  78. package/docs/REFACTORING_SUMMARY_DETECT_PEDIMENTOS.md +0 -200
  79. package/docs/STATS_COMMAND_SEQUENCE_DIAGRAM.md +0 -287
  80. package/docs/STATS_COMMAND_SIMPLE.md +0 -93
@@ -0,0 +1,502 @@
1
+ # Smart Watch Database Service Changes
2
+
3
+ ## 📋 Resumen de Cambios
4
+
5
+ Se han agregado **13 nuevos métodos** al `DatabaseService.js` para soportar la cola inteligente de procesamiento (Smart Watch Queue).
6
+
7
+ ### ✅ Métodos Agregados
8
+
9
+ #### 1. `insertFileToUploader(filePath, options)`
10
+ Inserta un archivo con estado inicial PENDING o READY_TO_UPLOAD.
11
+
12
+ **Parámetros:**
13
+ - `filePath` (string): Ruta completa del archivo
14
+ - `options` (object):
15
+ - `processingStatus` (string): 'PENDING' o 'READY_TO_UPLOAD' (default: 'PENDING')
16
+ - `dependsOnPath` (string): Ruta del directorio padre
17
+ - `documentType` (string): Tipo de documento
18
+ - `size` (number): Tamaño del archivo en bytes
19
+ - `fileExtension` (string): Extensión del archivo
20
+
21
+ **Ejemplo:**
22
+ ```javascript
23
+ const file = await databaseService.insertFileToUploader('/path/to/file.pdf', {
24
+ processingStatus: 'PENDING',
25
+ dependsOnPath: '../../Documents/2023',
26
+ size: 1024,
27
+ fileExtension: 'pdf'
28
+ });
29
+ ```
30
+
31
+ #### 2. `getPendingFilesInDirectory(dirPath)`
32
+ Obtiene archivos que esperan por un pedimento simplificado.
33
+
34
+ **Parámetros:**
35
+ - `dirPath` (string): Ruta del directorio
36
+
37
+ **Retorna:** Array de archivos con status PENDING
38
+
39
+ **Ejemplo:**
40
+ ```javascript
41
+ const pendingFiles = await databaseService.getPendingFilesInDirectory(
42
+ '../../Documents/2023'
43
+ );
44
+ console.log(`${pendingFiles.length} files waiting for pedimento`);
45
+ ```
46
+
47
+ #### 3. `getFilesWithStatus(statuses, limit)`
48
+ Obtiene archivos con ciertos status.
49
+
50
+ **Parámetros:**
51
+ - `statuses` (array): Array de status a buscar
52
+ - `limit` (number): Máximo de resultados (default: 10)
53
+
54
+ **Ejemplo:**
55
+ ```javascript
56
+ const ready = await databaseService.getFilesWithStatus(
57
+ ['READY_TO_UPLOAD', 'PROCESSING'],
58
+ 10
59
+ );
60
+ ```
61
+
62
+ #### 4. `updateFileStatus(filePath, updates)`
63
+ Actualiza el estado y otros campos de un archivo.
64
+
65
+ **Parámetros:**
66
+ - `filePath` (string): Ruta original del archivo
67
+ - `updates` (object): Campos a actualizar
68
+
69
+ **Ejemplo:**
70
+ ```javascript
71
+ await databaseService.updateFileStatus(filePath, {
72
+ processing_status: 'UPLOADED',
73
+ upload_attempts: 1
74
+ });
75
+ ```
76
+
77
+ #### 5. `markPedimentoDetected(dirPath, pedimentoPath)`
78
+ Marca un pedimento como detectado y actualiza archivos pendientes automáticamente.
79
+
80
+ **Parámetros:**
81
+ - `dirPath` (string): Ruta del directorio
82
+ - `pedimentoPath` (string): Ruta del archivo pedimento
83
+
84
+ **Comportamiento Automático:**
85
+ - Marca el pedimento como READY_TO_UPLOAD
86
+ - Obtiene todos los PENDING en `dirPath`
87
+ - Actualiza todos los PENDING a READY_TO_UPLOAD
88
+ - Registra el timestamp de detección
89
+
90
+ **Ejemplo:**
91
+ ```javascript
92
+ await databaseService.markPedimentoDetected(
93
+ '../../Documents/2023',
94
+ '../../Documents/2023/3429-07-23021611-Simplif.pdf'
95
+ );
96
+ // Automáticamente marca todos los PENDING como READY_TO_UPLOAD
97
+ ```
98
+
99
+ #### 6. `getExpiredWaitingFiles(maxWaitTimeSeconds)`
100
+ Obtiene archivos que esperan demasiado sin pedimento (archivos huérfanos).
101
+
102
+ **Parámetros:**
103
+ - `maxWaitTimeSeconds` (number): Tiempo máximo de espera en segundos
104
+
105
+ **Ejemplo:**
106
+ ```javascript
107
+ const expired = await databaseService.getExpiredWaitingFiles(300); // 5 minutos
108
+ if (expired.length > 0) {
109
+ console.log(`Found ${expired.length} orphaned files`);
110
+ }
111
+ ```
112
+
113
+ #### 7. `getProcessingStats()`
114
+ Obtiene estadísticas generales de la cola.
115
+
116
+ **Retorna:** Object con conteos por status
117
+
118
+ **Ejemplo:**
119
+ ```javascript
120
+ const stats = await databaseService.getProcessingStats();
121
+ console.log(`
122
+ Pending: ${stats.pending}
123
+ Ready: ${stats.readyToUpload}
124
+ Processing: ${stats.processing}
125
+ Uploaded: ${stats.uploaded}
126
+ Failed: ${stats.failed}
127
+ Total: ${stats.total}
128
+ `);
129
+ ```
130
+
131
+ #### 8. `getFailedFilesForRetry(maxAttempts)`
132
+ Obtiene archivos fallidos listos para reintentar.
133
+
134
+ **Parámetros:**
135
+ - `maxAttempts` (number): Máximo número de intentos permitidos (default: 3)
136
+
137
+ **Ejemplo:**
138
+ ```javascript
139
+ const toRetry = await databaseService.getFailedFilesForRetry(3);
140
+ console.log(`${toRetry.length} files ready for retry`);
141
+ ```
142
+
143
+ #### 9. `retryFile(filePath)`
144
+ Reinicia un archivo fallido individual.
145
+
146
+ **Parámetros:**
147
+ - `filePath` (string): Ruta del archivo
148
+
149
+ **Comportamiento:**
150
+ - Cambia status a READY_TO_UPLOAD
151
+ - Reinicia upload_attempts a 0
152
+ - Limpia last_error
153
+
154
+ **Ejemplo:**
155
+ ```javascript
156
+ const retried = await databaseService.retryFile('../../Documents/2023/file.pdf');
157
+ console.log(`File retried: ${retried.filename}`);
158
+ ```
159
+
160
+ #### 10. `retryFailedFiles(limit, maxAttempts)`
161
+ Reinicia múltiples archivos fallidos de forma eficiente.
162
+
163
+ **Parámetros:**
164
+ - `limit` (number): Cantidad máxima a reintentar (default: 10)
165
+ - `maxAttempts` (number): Máximo número de intentos (default: 3)
166
+
167
+ **Retorna:** Object con `{ retried, skipped, files }`
168
+
169
+ **Ejemplo:**
170
+ ```javascript
171
+ const result = await databaseService.retryFailedFiles(10, 3);
172
+ console.log(`✅ Retried: ${result.retried}, ❌ Skipped: ${result.skipped}`);
173
+ ```
174
+
175
+ #### 11. `getOverallProgress()`
176
+ Obtiene progreso general con estimación de tiempo.
177
+
178
+ **Retorna:** Object con:
179
+ - `totalFiles`: Total de archivos
180
+ - `processedFiles`: Archivos subidos exitosamente
181
+ - `failedFiles`: Archivos con error
182
+ - `pendingFiles`: Archivos pendientes/procesando
183
+ - `percentComplete`: Porcentaje completado
184
+ - `estimatedTimeRemaining`: ETA estimada
185
+ - `avgProcessingTimeMs`: Tiempo promedio de procesamiento
186
+
187
+ **Ejemplo:**
188
+ ```javascript
189
+ const progress = await databaseService.getOverallProgress();
190
+ console.log(`Progress: ${progress.percentComplete}%`);
191
+ console.log(`ETA: ${progress.estimatedTimeRemaining}`);
192
+ console.log(`Success rate: ${
193
+ (progress.processedFiles / progress.totalFiles * 100).toFixed(2)
194
+ }%`);
195
+ ```
196
+
197
+ #### 12. `getFileDetails(filePath)`
198
+ Obtiene detalles completos de un archivo.
199
+
200
+ **Parámetros:**
201
+ - `filePath` (string): Ruta del archivo
202
+
203
+ **Retorna:** Object con todos los campos + información adicional
204
+
205
+ **Ejemplo:**
206
+ ```javascript
207
+ const details = await databaseService.getFileDetails(filePath);
208
+ console.log(`
209
+ Filename: ${details.filename}
210
+ Status: ${details.processing_status}
211
+ Time in queue: ${details.timeInQueue}
212
+ Attempts: ${details.attempts}
213
+ Has error: ${details.hasError}
214
+ `);
215
+ ```
216
+
217
+ #### 13. `searchFiles(filters)`
218
+ Busca archivos por múltiples criterios.
219
+
220
+ **Parámetros:**
221
+ - `filters` (object):
222
+ - `status` (string): Status a buscar
223
+ - `rfc` (string): RFC del remitente
224
+ - `year` (number): Año
225
+ - `dirPath` (string): Ruta del directorio
226
+ - `numPedimento` (string): Número de pedimento (búsqueda parcial)
227
+ - `limit` (number): Máximo de resultados (default: 50)
228
+
229
+ **Ejemplo:**
230
+ ```javascript
231
+ const results = await databaseService.searchFiles({
232
+ status: 'FAILED',
233
+ rfc: 'AUM9207011CA',
234
+ year: 2023,
235
+ limit: 50
236
+ });
237
+ ```
238
+
239
+ ## 🔄 Flujo de Procesamiento
240
+
241
+ ### Escenario Típico
242
+
243
+ ```javascript
244
+ // 1. Archivo nuevo detectado en el directorio
245
+ const file = await databaseService.insertFileToUploader(
246
+ filePath,
247
+ {
248
+ processingStatus: 'PENDING',
249
+ dependsOnPath: dirPath
250
+ }
251
+ );
252
+ console.log(`✅ Archivo registrado: ${file.filename}`);
253
+
254
+ // 2. Esperando pedimento simplificado
255
+ const pending = await databaseService.getPendingFilesInDirectory(dirPath);
256
+ console.log(`⏳ Esperando: ${pending.length} archivos`);
257
+
258
+ // 3. Se detecta pedimento simplificado
259
+ await databaseService.markPedimentoDetected(dirPath, pedimentoPath);
260
+ // ↓ Automáticamente marca PENDING → READY_TO_UPLOAD
261
+
262
+ // 4. Obtener archivos listos para procesar
263
+ const ready = await databaseService.getFilesWithStatus(['READY_TO_UPLOAD'], 10);
264
+ console.log(`✅ Listos: ${ready.length} archivos`);
265
+
266
+ // 5. Actualizar a PROCESSING
267
+ await databaseService.updateFileStatus(filePath, {
268
+ processing_status: 'PROCESSING'
269
+ });
270
+
271
+ // 6. Actualizar a UPLOADED (éxito)
272
+ await databaseService.updateFileStatus(filePath, {
273
+ processing_status: 'UPLOADED',
274
+ upload_attempts: 1
275
+ });
276
+ console.log(`✅ Subido: ${filePath}`);
277
+
278
+ // 7. Si hay error → FAILED
279
+ await databaseService.updateFileStatus(filePath, {
280
+ processing_status: 'FAILED',
281
+ last_error: 'Timeout uploading to server',
282
+ upload_attempts: 1
283
+ });
284
+
285
+ // 8. Reintentar más tarde
286
+ const retried = await databaseService.retryFile(filePath);
287
+ console.log(`🔄 Reintentando: ${filePath}`);
288
+ ```
289
+
290
+ ## 📊 Estados de Archivo
291
+
292
+ ```
293
+ ┌─────────┐
294
+ │ PENDING │ ← Archivo nuevo, esperando pedimento simplificado
295
+ └────┬────┘
296
+
297
+ │ [Pedimento detectado → markPedimentoDetected()]
298
+
299
+ ┌──────────────────┐
300
+ │ READY_TO_UPLOAD │ ← Listo para procesar
301
+ └────┬─────────────┘
302
+
303
+ │ [Comienza procesamiento → updateFileStatus('PROCESSING')]
304
+
305
+ ┌────────────┐
306
+ │ PROCESSING │ ← Siendo procesado
307
+ └────┬───────┘
308
+
309
+ ├─→ [Éxito] ┌──────────┐
310
+ │ │ UPLOADED │ ✅ Completado
311
+ │ └──────────┘
312
+
313
+ └─→ [Error] ┌────────┐
314
+ │ FAILED │ ❌ Con error
315
+ └───┬────┘
316
+
317
+ │ [Reintentar → retryFile()]
318
+
319
+ READY_TO_UPLOAD (reinicio del ciclo)
320
+ ```
321
+
322
+ ## 🛡️ Manejo de Errores
323
+
324
+ Todos los métodos incluyen:
325
+ - **Retry lógico** con exponential backoff (hasta 30 segundos)
326
+ - **Error logging** detallado con contexto
327
+ - **Transacciones seguras** (no hay datos parciales)
328
+ - **Validaciones** de parámetros
329
+ - **Recuperación automática** en caso de timeout
330
+
331
+ ## 📈 Casos de Uso
332
+
333
+ ### Monitoreo en Tiempo Real
334
+ ```javascript
335
+ setInterval(async () => {
336
+ const stats = await databaseService.getProcessingStats();
337
+ const progress = await databaseService.getOverallProgress();
338
+
339
+ console.log(`📊 Stats:`);
340
+ console.log(` Progreso: ${progress.percentComplete}%`);
341
+ console.log(` ETA: ${progress.estimatedTimeRemaining}`);
342
+ console.log(` Pendientes: ${progress.pendingFiles}`);
343
+ console.log(` Fallidos: ${progress.failedFiles}`);
344
+ }, 5000); // Cada 5 segundos
345
+ ```
346
+
347
+ ### Limpieza de Archivos Huérfanos (Orfanage Cleanup)
348
+ ```javascript
349
+ // Ejecutar cada 30 minutos
350
+ setInterval(async () => {
351
+ const expired = await databaseService.getExpiredWaitingFiles(1800); // 30 minutos
352
+
353
+ if (expired.length > 0) {
354
+ console.log(`🗑️ Limpiando ${expired.length} archivos huérfanos...`);
355
+
356
+ for (const file of expired) {
357
+ await databaseService.updateFileStatus(file.original_path, {
358
+ processing_status: 'FAILED',
359
+ last_error: 'Expired waiting for pedimento (30 minutes)'
360
+ });
361
+ }
362
+ }
363
+ }, 1800000); // 30 minutos
364
+ ```
365
+
366
+ ### Reintentos Automáticos
367
+ ```javascript
368
+ // Ejecutar cada 10 minutos
369
+ setInterval(async () => {
370
+ const result = await databaseService.retryFailedFiles(10, 3);
371
+
372
+ if (result.retried > 0) {
373
+ console.log(`🔄 Retrying ${result.retried} files...`);
374
+ }
375
+ }, 600000); // 10 minutos
376
+ ```
377
+
378
+ ### Búsqueda Avanzada
379
+ ```javascript
380
+ // Buscar todos los archivos fallidos de un RFC en 2023
381
+ const files = await databaseService.searchFiles({
382
+ rfc: 'AUM9207011CA',
383
+ year: 2023,
384
+ status: 'FAILED'
385
+ });
386
+
387
+ console.log(`Found ${files.length} failed files for RFC ${rfc}`);
388
+ files.forEach(f => {
389
+ console.log(`- ${f.filename}: ${f.last_error}`);
390
+ });
391
+ ```
392
+
393
+ ### Dashboard con Estadísticas
394
+ ```javascript
395
+ async function getDashboardData() {
396
+ const [stats, progress, failedFiles] = await Promise.all([
397
+ databaseService.getProcessingStats(),
398
+ databaseService.getOverallProgress(),
399
+ databaseService.getFailedFilesForRetry()
400
+ ]);
401
+
402
+ return {
403
+ stats,
404
+ progress,
405
+ failedCount: failedFiles.length,
406
+ successRate: (
407
+ progress.processedFiles / progress.totalFiles * 100
408
+ ).toFixed(2) + '%'
409
+ };
410
+ }
411
+ ```
412
+
413
+ ## 🔗 Integración con SmartWatchService
414
+
415
+ El DatabaseService se usa desde SmartWatchService:
416
+
417
+ ```javascript
418
+ // En SmartWatchService.js
419
+ class SmartWatchService {
420
+ async handleNewFile(filePath) {
421
+ const isPedimento = await this.#isPedimentoSimplificado(filePath);
422
+ const parentDir = path.dirname(filePath);
423
+
424
+ if (isPedimento) {
425
+ // Insertar pedimento y marcar dependientes como READY
426
+ await this.databaseService.markPedimentoDetected(parentDir, filePath);
427
+ logger.info(`✅ Pedimento detected, ${pending.length} files ready`);
428
+ } else {
429
+ // Insertar archivo como PENDING
430
+ await this.databaseService.insertFileToUploader(filePath, {
431
+ processingStatus: 'PENDING',
432
+ dependsOnPath: parentDir,
433
+ size: fs.statSync(filePath).size,
434
+ fileExtension: path.extname(filePath).slice(1)
435
+ });
436
+ logger.info(`⏳ File registered as PENDING`);
437
+ }
438
+ }
439
+
440
+ async processReadyFiles() {
441
+ const ready = await this.databaseService.getFilesWithStatus(
442
+ ['READY_TO_UPLOAD'],
443
+ 10
444
+ );
445
+
446
+ for (const file of ready) {
447
+ try {
448
+ await this.databaseService.updateFileStatus(file.original_path, {
449
+ processing_status: 'PROCESSING'
450
+ });
451
+
452
+ const result = await this.uploadService.upload(file);
453
+
454
+ await this.databaseService.updateFileStatus(file.original_path, {
455
+ processing_status: 'UPLOADED',
456
+ upload_attempts: (file.upload_attempts || 0) + 1
457
+ });
458
+ } catch (error) {
459
+ await this.databaseService.updateFileStatus(file.original_path, {
460
+ processing_status: 'FAILED',
461
+ last_error: error.message,
462
+ upload_attempts: (file.upload_attempts || 0) + 1
463
+ });
464
+ }
465
+ }
466
+ }
467
+ }
468
+ ```
469
+
470
+ ## 📚 Tablas y Campos Soportados
471
+
472
+ ### Tabla: `uploader`
473
+
474
+ **Campos utilizados por Smart Watch:**
475
+ - `original_path` (varchar): Ruta completa del archivo
476
+ - `filename` (varchar): Nombre del archivo
477
+ - `file_extension` (varchar): Extensión (.pdf, .xml, etc.)
478
+ - `size` (bigint): Tamaño en bytes
479
+ - `document_type` (varchar): Tipo de documento
480
+ - `processing_status` (varchar): PENDING | READY_TO_UPLOAD | PROCESSING | UPLOADED | FAILED
481
+ - `depends_on_path` (varchar): Referencia al directorio del pedimento
482
+ - `pedimento_detected_at` (timestamp): Cuándo se detectó el pedimento
483
+ - `upload_attempts` (integer): Número de intentos
484
+ - `last_error` (text): Último mensaje de error
485
+ - `created_at` (timestamp): Fecha de creación
486
+ - `updated_at` (timestamp): Última actualización
487
+ - `status` (varchar): Legacy field (pendiente, en_progreso, completado, fallido)
488
+
489
+ ## ✅ Validación
490
+
491
+ - Todos los métodos pasan validación de sintaxis Node.js
492
+ - Incluyen error handling robusto con retry logic
493
+ - Compatible con Supabase JS client (v1.x y v2.x)
494
+ - Logs detallados para debugging
495
+ - No hay breaking changes en métodos existentes
496
+
497
+ ## 🚀 Próximos Pasos
498
+
499
+ 1. **Integración con SmartWatchService** - Usar estos métodos en el watch service
500
+ 2. **Estadísticas en API** - Exponer endpoints REST para las estadísticas
501
+ 3. **Dashboard** - Crear UI para monitoreo en tiempo real
502
+ 4. **Alertas** - Notificaciones cuando hay archivos expirados o con errores
@@ -0,0 +1,212 @@
1
+ # 🧪 Testing Manual: Watch Mode - Fase 2
2
+
3
+ ## Preparación del Entorno
4
+
5
+ ```bash
6
+ # Crear directorio de prueba
7
+ mkdir -p /tmp/watch-test
8
+ cd /tmp/watch-test
9
+
10
+ # Crear archivo inicial
11
+ echo "Test document" > test-document.txt
12
+ ```
13
+
14
+ ## Test 1: Watch Mode Básico (Strategy: batch)
15
+
16
+ ```bash
17
+ # Terminal 1: Iniciar watch mode
18
+ cd /Users/jjfigueroa/gitRepos/arela-uploader
19
+ node src/index.js watch --directories /tmp/watch-test --strategy batch --debounce 500 --verbose
20
+
21
+ # Terminal 2: Crear archivos de prueba
22
+ cd /tmp/watch-test
23
+
24
+ # Crear un archivo nuevo
25
+ echo "New file content" > new-file.txt
26
+
27
+ # Esperar a ver el evento procesado en Terminal 1
28
+
29
+ # Crear otro archivo
30
+ echo "Another file" > another-file.txt
31
+
32
+ # Modificar archivo existente
33
+ echo "Modified content" >> new-file.txt
34
+
35
+ # Esperar a ver eventos en Terminal 1
36
+ ```
37
+
38
+ ## Test 2: Strategy Individual
39
+
40
+ ```bash
41
+ # Terminal 1: Iniciar con strategy individual
42
+ cd /Users/jjfigueroa/gitRepos/arela-uploader
43
+ node src/index.js watch --directories /tmp/watch-test --strategy individual --debounce 500 --verbose
44
+
45
+ # Terminal 2: Crear archivo
46
+ cd /tmp/watch-test
47
+ echo "Single file test" > single-test.txt
48
+
49
+ # Esperar a ver que SOLO este archivo se procesa
50
+ ```
51
+
52
+ ## Test 3: Strategy Full-Structure
53
+
54
+ ```bash
55
+ # Crear estructura de directorios
56
+ mkdir -p /tmp/watch-test/documents/folder1
57
+ mkdir -p /tmp/watch-test/documents/folder2
58
+
59
+ echo "File 1" > /tmp/watch-test/documents/folder1/file1.txt
60
+ echo "File 2" > /tmp/watch-test/documents/folder2/file2.txt
61
+
62
+ # Terminal 1: Iniciar con strategy full-structure
63
+ cd /Users/jjfigueroa/gitRepos/arela-uploader
64
+ node src/index.js watch --directories /tmp/watch-test/documents --strategy full-structure --debounce 1000 --verbose
65
+
66
+ # Terminal 2: Crear un nuevo archivo en subfolder
67
+ cd /tmp/watch-test/documents/folder1
68
+ echo "New test file" > test-new.txt
69
+
70
+ # Esperar a ver que TODA la estructura se procesa
71
+ ```
72
+
73
+ ## Test 4: Multiple Directories
74
+
75
+ ```bash
76
+ # Crear más directorio de prueba
77
+ mkdir -p /tmp/watch-test2
78
+ echo "Test" > /tmp/watch-test2/test.txt
79
+
80
+ # Terminal 1: Watch múltiples directorios
81
+ cd /Users/jjfigueroa/gitRepos/arela-uploader
82
+ node src/index.js watch --directories /tmp/watch-test,/tmp/watch-test2 --strategy batch --verbose
83
+
84
+ # Terminal 2: Crear archivos en ambas carpetas
85
+ echo "File in test1" > /tmp/watch-test/file1.txt
86
+ echo "File in test2" > /tmp/watch-test2/file2.txt
87
+
88
+ # Esperar a ver eventos de ambos directorios
89
+ ```
90
+
91
+ ## Test 5: Dry-Run Mode
92
+
93
+ ```bash
94
+ # Terminal 1: Iniciar en modo dry-run
95
+ cd /Users/jjfigueroa/gitRepos/arela-uploader
96
+ node src/index.js watch --directories /tmp/watch-test --strategy batch --dry-run --verbose
97
+
98
+ # Terminal 2: Crear archivo
99
+ cd /tmp/watch-test
100
+ echo "Dry run test" > dry-test.txt
101
+
102
+ # Esperar a ver "[DRY RUN]" en los logs - no debe hacer upload real
103
+ ```
104
+
105
+ ## Test 6: Debouncing (Verificar que agrupa eventos)
106
+
107
+ ```bash
108
+ # Terminal 1: Iniciar watch con debounce de 2 segundos
109
+ cd /Users/jjfigueroa/gitRepos/arela-uploader
110
+ node src/index.js watch --directories /tmp/watch-test --strategy batch --debounce 2000 --verbose
111
+
112
+ # Terminal 2: Crear múltiples archivos rápidamente
113
+ cd /tmp/watch-test
114
+ for i in {1..5}; do
115
+ echo "File $i" > test-$i.txt
116
+ sleep 0.2 # 200ms entre archivos
117
+ done
118
+
119
+ # Esperar 2 segundos
120
+ # Debería ver un ÚNICO evento que agrupa los 5 archivos
121
+ ```
122
+
123
+ ## Test 7: Graceful Shutdown
124
+
125
+ ```bash
126
+ # Terminal 1: Iniciar watch mode
127
+ cd /Users/jjfigueroa/gitRepos/arela-uploader
128
+ node src/index.js watch --directories /tmp/watch-test --verbose
129
+
130
+ # Terminal 2: Crear archivo mientras está corriendo
131
+ cd /tmp/watch-test
132
+ echo "Test" > test.txt
133
+
134
+ # Terminal 1: Presionar Ctrl+C
135
+
136
+ # Esperar a ver:
137
+ # - "🛑 Received SIGINT, shutting down gracefully..."
138
+ # - "🔴 Stopping WatchService..."
139
+ # - "✅ WatchService stopped"
140
+ # - Resumen final con estadísticas
141
+ ```
142
+
143
+ ## Test 8: Ignorar Patrones
144
+
145
+ ```bash
146
+ # Terminal 1: Iniciar watch ignorando archivos .tmp
147
+ cd /Users/jjfigueroa/gitRepos/arela-uploader
148
+ node src/index.js watch --directories /tmp/watch-test --ignore "*.tmp,*.bak" --verbose
149
+
150
+ # Terminal 2: Crear archivos para ignorar
151
+ cd /tmp/watch-test
152
+ echo "Should be ignored" > file.tmp
153
+ echo "Also ignored" > file.bak
154
+ echo "Should be captured" > file.txt
155
+
156
+ # Esperar: solo file.txt debe generar evento
157
+ ```
158
+
159
+ ## Puntos a Verificar en los Tests
160
+
161
+ ### Logs Esperados:
162
+ - ✅ "🟢 WATCH MODE STARTED"
163
+ - ✅ "📁 Watching X director(y/ies):"
164
+ - ✅ "⚡ Processing event:"
165
+ - ✅ "📤 [STRATEGY] Upload triggered by:"
166
+ - ✅ "✅ Files queued for upload"
167
+ - ✅ "📊 Stats:"
168
+
169
+ ### Eventos Esperados:
170
+ - `add` - Cuando se crea un archivo nuevo
171
+ - `change` - Cuando se modifica un archivo
172
+ - `unlink` - Cuando se elimina un archivo (debería ignorarse)
173
+
174
+ ### Debouncing:
175
+ - Múltiples cambios rápidos = 1 evento procesado
176
+ - Esperar = nuevo evento procesado
177
+
178
+ ### Graceful Shutdown:
179
+ - Ctrl+C debería cerrar cleanly
180
+ - Ver resumen final con estadísticas
181
+ - Sin errores no capturados
182
+
183
+ ## Comandos Útiles para Limpieza
184
+
185
+ ```bash
186
+ # Limpiar directorio de prueba
187
+ rm -rf /tmp/watch-test
188
+ rm -rf /tmp/watch-test2
189
+
190
+ # Ver archivos siendo creados en tiempo real
191
+ ls -la /tmp/watch-test
192
+
193
+ # Monitorear cambios de archivos en otra terminal
194
+ fswatch /tmp/watch-test # Requiere 'brew install fswatch' en macOS
195
+ ```
196
+
197
+ ## Comandos para Desarrollar
198
+
199
+ ```bash
200
+ # Ejecutar linter
201
+ npm run format
202
+
203
+ # Ver logs en detalle
204
+ node src/index.js watch --directories /tmp/watch-test --verbose --clear-log
205
+
206
+ # Ver solo directorios siendo observados
207
+ node src/index.js watch --directories /tmp/watch-test --verbose | grep "📁"
208
+ ```
209
+
210
+ ---
211
+
212
+ **Nota**: Los tests pueden ejecutarse en serie o en paralelo según sea necesario. Cada test es independiente pero usa los mismos directorios (/tmp/watch-test) que pueden necesitar cleanup entre tests.