@arela/uploader 1.0.23 → 1.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.
Files changed (85) 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/scripts/scoring-compare.js +243 -0
  29. package/scripts/scoring-phase4-check.js +96 -0
  30. package/src/commands/IdentifyCommand.js +36 -0
  31. package/src/config/config.js +2 -2
  32. package/src/file-detection.js +71 -4
  33. package/src/scoring/db-matcher-adapter.js +98 -0
  34. package/src/scoring/matchers-seed.js +386 -0
  35. package/src/scoring/scoring-engine.js +246 -0
  36. package/src/services/ScanApiService.js +14 -0
  37. package/tests/unit/scoring-engine.test.js +221 -0
  38. package/.vscode/settings.json +0 -1
  39. package/coverage/IdentifyCommand.js.html +0 -1462
  40. package/coverage/PropagateCommand.js.html +0 -1507
  41. package/coverage/PushCommand.js.html +0 -1504
  42. package/coverage/ScanCommand.js.html +0 -1654
  43. package/coverage/UploadCommand.js.html +0 -1846
  44. package/coverage/WatchCommand.js.html +0 -4111
  45. package/coverage/base.css +0 -224
  46. package/coverage/block-navigation.js +0 -87
  47. package/coverage/favicon.png +0 -0
  48. package/coverage/index.html +0 -191
  49. package/coverage/lcov-report/IdentifyCommand.js.html +0 -1462
  50. package/coverage/lcov-report/PropagateCommand.js.html +0 -1507
  51. package/coverage/lcov-report/PushCommand.js.html +0 -1504
  52. package/coverage/lcov-report/ScanCommand.js.html +0 -1654
  53. package/coverage/lcov-report/UploadCommand.js.html +0 -1846
  54. package/coverage/lcov-report/WatchCommand.js.html +0 -4111
  55. package/coverage/lcov-report/base.css +0 -224
  56. package/coverage/lcov-report/block-navigation.js +0 -87
  57. package/coverage/lcov-report/favicon.png +0 -0
  58. package/coverage/lcov-report/index.html +0 -191
  59. package/coverage/lcov-report/prettify.css +0 -1
  60. package/coverage/lcov-report/prettify.js +0 -2
  61. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  62. package/coverage/lcov-report/sorter.js +0 -210
  63. package/coverage/lcov.info +0 -1937
  64. package/coverage/prettify.css +0 -1
  65. package/coverage/prettify.js +0 -2
  66. package/coverage/sort-arrow-sprite.png +0 -0
  67. package/coverage/sorter.js +0 -210
  68. package/docs/API_ENDPOINTS_FOR_DETECTION.md +0 -647
  69. package/docs/API_RETRY_MECHANISM.md +0 -338
  70. package/docs/ARELA_IDENTIFY_IMPLEMENTATION.md +0 -489
  71. package/docs/ARELA_IDENTIFY_QUICKREF.md +0 -186
  72. package/docs/ARELA_PROPAGATE_IMPLEMENTATION.md +0 -581
  73. package/docs/ARELA_PROPAGATE_QUICKREF.md +0 -272
  74. package/docs/ARELA_PUSH_IMPLEMENTATION.md +0 -577
  75. package/docs/ARELA_PUSH_QUICKREF.md +0 -322
  76. package/docs/ARELA_SCAN_IMPLEMENTATION.md +0 -373
  77. package/docs/ARELA_SCAN_QUICKREF.md +0 -139
  78. package/docs/CROSS_PLATFORM_PATH_HANDLING.md +0 -597
  79. package/docs/DETECTION_ATTEMPT_TRACKING.md +0 -414
  80. package/docs/MIGRATION_UPLOADER_TO_FILE_STATS.md +0 -1020
  81. package/docs/MULTI_LEVEL_DIRECTORY_SCANNING.md +0 -494
  82. package/docs/QUICK_REFERENCE_API_DETECTION.md +0 -264
  83. package/docs/REFACTORING_SUMMARY_DETECT_PEDIMENTOS.md +0 -200
  84. package/docs/STATS_COMMAND_SEQUENCE_DIAGRAM.md +0 -287
  85. package/docs/STATS_COMMAND_SIMPLE.md +0 -93
@@ -0,0 +1,562 @@
1
+ # Integración del Watcher con arela-api
2
+
3
+ ## 📋 Resumen
4
+ Este documento describe cómo exponer la información del WatchService a través de endpoints REST en la arela-api para que el frontend pueda monitorear en tiempo real el estado del uploader en modo watch.
5
+
6
+ ## 🎯 Objetivos
7
+ - Permitir que el frontend vea el estado en tiempo real del watcher
8
+ - Exponer estadísticas de archivos pendientes, listos para subir, procesando, etc.
9
+ - Permitir control remoto del watcher (start/stop/enable-disable auto-processing)
10
+ - Proporcionar información de progreso del pipeline automático
11
+
12
+ ---
13
+
14
+ ## 📡 Endpoints Necesarios
15
+
16
+ ### 1. GET `/api/watcher/status`
17
+ **Descripción:** Obtener estado actual del watcher
18
+
19
+ **Respuesta:**
20
+ ```json
21
+ {
22
+ "isRunning": true,
23
+ "autoProcessingEnabled": true,
24
+ "watchedDirectories": 3,
25
+ "activeWatchers": 3,
26
+ "lastUpdated": "2025-11-17T22:30:00.000Z",
27
+ "stats": {
28
+ "filesAdded": 145,
29
+ "filesModified": 23,
30
+ "filesRemoved": 5,
31
+ "uploadsTriggered": 12,
32
+ "pipelinesTriggered": 12,
33
+ "errorsEncountered": 0
34
+ }
35
+ }
36
+ ```
37
+
38
+ ---
39
+
40
+ ### 2. GET `/api/watcher/queue-stats`
41
+ **Descripción:** Obtener estadísticas de la cola de procesamiento
42
+
43
+ **Respuesta:**
44
+ ```json
45
+ {
46
+ "queue": {
47
+ "pending": 25,
48
+ "readyToUpload": 8,
49
+ "processing": 2,
50
+ "uploaded": 156,
51
+ "failed": 0,
52
+ "total": 191
53
+ },
54
+ "progress": {
55
+ "percentComplete": 82.2,
56
+ "estimatedTimeRemaining": "5 minutes",
57
+ "avgProcessingTimeMs": 3400
58
+ },
59
+ "timestamp": "2025-11-17T22:30:00.000Z"
60
+ }
61
+ ```
62
+
63
+ ---
64
+
65
+ ### 3. GET `/api/watcher/directories`
66
+ **Descripción:** Obtener lista de directorios siendo monitoreados
67
+
68
+ **Respuesta:**
69
+ ```json
70
+ {
71
+ "directories": [
72
+ {
73
+ "path": "/Users/jjfigueroa/Documents/2023",
74
+ "isReady": true,
75
+ "fileCount": 65,
76
+ "folderStructure": "arela"
77
+ },
78
+ {
79
+ "path": "/Users/jjfigueroa/Documents/2024",
80
+ "isReady": true,
81
+ "fileCount": 89,
82
+ "folderStructure": "arela"
83
+ },
84
+ {
85
+ "path": "/Users/jjfigueroa/Downloads",
86
+ "isReady": false,
87
+ "fileCount": 37,
88
+ "folderStructure": "arela"
89
+ }
90
+ ],
91
+ "totalDirectories": 3
92
+ }
93
+ ```
94
+
95
+ ---
96
+
97
+ ### 4. POST `/api/watcher/start`
98
+ **Descripción:** Iniciar el watcher
99
+
100
+ **Body (opcional):**
101
+ ```json
102
+ {
103
+ "directories": ["/path/to/dir1", "/path/to/dir2"],
104
+ "autoProcessing": true,
105
+ "folderStructure": "arela"
106
+ }
107
+ ```
108
+
109
+ **Respuesta:**
110
+ ```json
111
+ {
112
+ "success": true,
113
+ "message": "Watcher started successfully",
114
+ "stats": { /* ver GET /api/watcher/status */ }
115
+ }
116
+ ```
117
+
118
+ ---
119
+
120
+ ### 5. POST `/api/watcher/stop`
121
+ **Descripción:** Detener el watcher
122
+
123
+ **Respuesta:**
124
+ ```json
125
+ {
126
+ "success": true,
127
+ "message": "Watcher stopped successfully",
128
+ "finalStats": { /* estadísticas finales */ }
129
+ }
130
+ ```
131
+
132
+ ---
133
+
134
+ ### 6. POST `/api/watcher/enable-auto-processing`
135
+ **Descripción:** Habilitar procesamiento automático
136
+
137
+ **Body:**
138
+ ```json
139
+ {
140
+ "batchSize": 10,
141
+ "timeout": 30000
142
+ }
143
+ ```
144
+
145
+ **Respuesta:**
146
+ ```json
147
+ {
148
+ "success": true,
149
+ "autoProcessingEnabled": true
150
+ }
151
+ ```
152
+
153
+ ---
154
+
155
+ ### 7. POST `/api/watcher/disable-auto-processing`
156
+ **Descripción:** Deshabilitar procesamiento automático
157
+
158
+ **Respuesta:**
159
+ ```json
160
+ {
161
+ "success": true,
162
+ "autoProcessingEnabled": false
163
+ }
164
+ ```
165
+
166
+ ---
167
+
168
+ ### 8. GET `/api/watcher/pipeline-status`
169
+ **Descripción:** Obtener estado de los pipelines en ejecución
170
+
171
+ **Respuesta:**
172
+ ```json
173
+ {
174
+ "isProcessing": false,
175
+ "activePipelines": 0,
176
+ "recentPipelines": [
177
+ {
178
+ "id": "pipeline-1763418030418-ml4dcsgw3",
179
+ "file": "3429-07-23009203-Simplif.pdf",
180
+ "directory": "/Users/jjfigueroa/Documents/2023/230734293009203",
181
+ "startTime": "2025-11-17T22:20:30.000Z",
182
+ "duration": 653,
183
+ "status": "success",
184
+ "steps": {
185
+ "statsOnly": "success",
186
+ "detectPdfs": "success",
187
+ "propagateArelaPath": "success",
188
+ "uploadByRfc": "success"
189
+ }
190
+ }
191
+ ]
192
+ }
193
+ ```
194
+
195
+ ---
196
+
197
+ ## 🔧 Implementación en arela-api
198
+
199
+ ### Archivo: `routes/watcher.routes.js`
200
+
201
+ ```javascript
202
+ import express from 'express';
203
+ import watchService from '../services/WatchService.js'; // Import desde arela-uploader
204
+ import logger from '../services/LoggingService.js';
205
+
206
+ const router = express.Router();
207
+
208
+ /**
209
+ * GET /api/watcher/status
210
+ * Get watcher status and stats
211
+ */
212
+ router.get('/status', (req, res) => {
213
+ try {
214
+ const stats = watchService.getStats();
215
+ res.json({
216
+ isRunning: stats.isRunning,
217
+ autoProcessingEnabled: stats.autoProcessingEnabled,
218
+ watchedDirectories: stats.watchedDirectories,
219
+ activeWatchers: stats.activeWatchers,
220
+ lastUpdated: new Date().toISOString(),
221
+ stats: {
222
+ filesAdded: stats.filesAdded,
223
+ filesModified: stats.filesModified,
224
+ filesRemoved: stats.filesRemoved,
225
+ uploadsTriggered: stats.uploadsTriggered,
226
+ pipelinesTriggered: stats.pipelinesTriggered,
227
+ errorsEncountered: stats.errorsEncountered,
228
+ },
229
+ });
230
+ } catch (error) {
231
+ logger.error(`Error getting watcher status: ${error.message}`);
232
+ res.status(500).json({ error: error.message });
233
+ }
234
+ });
235
+
236
+ /**
237
+ * GET /api/watcher/queue-stats
238
+ * Get queue statistics
239
+ */
240
+ router.get('/queue-stats', async (req, res) => {
241
+ try {
242
+ const queueStats = await watchService.getQueueStats();
243
+ if (!queueStats) {
244
+ return res.status(500).json({ error: 'Could not fetch queue stats' });
245
+ }
246
+ res.json(queueStats);
247
+ } catch (error) {
248
+ logger.error(`Error getting queue stats: ${error.message}`);
249
+ res.status(500).json({ error: error.message });
250
+ }
251
+ });
252
+
253
+ /**
254
+ * GET /api/watcher/directories
255
+ * Get watched directories info
256
+ */
257
+ router.get('/directories', (req, res) => {
258
+ try {
259
+ const directories = Array.from(watchService.watchedDirs).map((dir) => {
260
+ const config = watchService.directoryConfigs.get(dir);
261
+ const isReady = watchService.watcherReady.get(dir) === true;
262
+
263
+ return {
264
+ path: dir,
265
+ isReady,
266
+ folderStructure: config?.folderStructure || 'default',
267
+ };
268
+ });
269
+
270
+ res.json({
271
+ directories,
272
+ totalDirectories: directories.length,
273
+ });
274
+ } catch (error) {
275
+ logger.error(`Error getting watched directories: ${error.message}`);
276
+ res.status(500).json({ error: error.message });
277
+ }
278
+ });
279
+
280
+ /**
281
+ * POST /api/watcher/start
282
+ * Start the watcher
283
+ */
284
+ router.post('/start', async (req, res) => {
285
+ try {
286
+ const { directories, autoProcessing = true, folderStructure = 'arela' } =
287
+ req.body;
288
+
289
+ if (!directories || directories.length === 0) {
290
+ return res.status(400).json({ error: 'No directories specified' });
291
+ }
292
+
293
+ // Add watchers for each directory
294
+ for (const dir of directories) {
295
+ await watchService.addWatcher(dir, {}, { folderStructure });
296
+ }
297
+
298
+ // Enable auto-processing if requested
299
+ if (autoProcessing) {
300
+ watchService.enableAutoProcessing({ batchSize: 10 });
301
+ }
302
+
303
+ // Start watching
304
+ await watchService.start();
305
+
306
+ res.json({
307
+ success: true,
308
+ message: 'Watcher started successfully',
309
+ stats: watchService.getStats(),
310
+ });
311
+ } catch (error) {
312
+ logger.error(`Error starting watcher: ${error.message}`);
313
+ res.status(500).json({ error: error.message });
314
+ }
315
+ });
316
+
317
+ /**
318
+ * POST /api/watcher/stop
319
+ * Stop the watcher
320
+ */
321
+ router.post('/stop', async (req, res) => {
322
+ try {
323
+ const finalStats = watchService.getStats();
324
+ await watchService.stop('API request');
325
+
326
+ res.json({
327
+ success: true,
328
+ message: 'Watcher stopped successfully',
329
+ finalStats,
330
+ });
331
+ } catch (error) {
332
+ logger.error(`Error stopping watcher: ${error.message}`);
333
+ res.status(500).json({ error: error.message });
334
+ }
335
+ });
336
+
337
+ /**
338
+ * POST /api/watcher/enable-auto-processing
339
+ * Enable automatic processing pipeline
340
+ */
341
+ router.post('/enable-auto-processing', (req, res) => {
342
+ try {
343
+ const { batchSize = 10 } = req.body;
344
+
345
+ watchService.enableAutoProcessing({ batchSize });
346
+
347
+ res.json({
348
+ success: true,
349
+ autoProcessingEnabled: watchService.isAutoProcessingEnabled(),
350
+ });
351
+ } catch (error) {
352
+ logger.error(`Error enabling auto-processing: ${error.message}`);
353
+ res.status(500).json({ error: error.message });
354
+ }
355
+ });
356
+
357
+ /**
358
+ * POST /api/watcher/disable-auto-processing
359
+ * Disable automatic processing pipeline
360
+ */
361
+ router.post('/disable-auto-processing', (req, res) => {
362
+ try {
363
+ watchService.disableAutoProcessing();
364
+
365
+ res.json({
366
+ success: true,
367
+ autoProcessingEnabled: watchService.isAutoProcessingEnabled(),
368
+ });
369
+ } catch (error) {
370
+ logger.error(`Error disabling auto-processing: ${error.message}`);
371
+ res.status(500).json({ error: error.message });
372
+ }
373
+ });
374
+
375
+ export default router;
376
+ ```
377
+
378
+ ---
379
+
380
+ ## 🖥️ Integración en arela-api Express App
381
+
382
+ ### Archivo: `app.js` o `index.js`
383
+
384
+ ```javascript
385
+ import express from 'express';
386
+ import watcherRoutes from './routes/watcher.routes.js';
387
+
388
+ const app = express();
389
+
390
+ // ... other middleware ...
391
+
392
+ // Mount watcher routes
393
+ app.use('/api/watcher', watcherRoutes);
394
+
395
+ // ... rest of app ...
396
+ ```
397
+
398
+ ---
399
+
400
+ ## 📦 Importación de WatchService
401
+
402
+ Para que arela-api pueda acceder a WatchService desde arela-uploader, hay dos opciones:
403
+
404
+ ### Opción 1: Exportar como módulo NPM (Recomendado)
405
+ 1. En `arela-uploader/package.json`:
406
+ ```json
407
+ {
408
+ "name": "@arela/uploader",
409
+ "exports": {
410
+ "./services": "./src/services/index.js"
411
+ }
412
+ }
413
+ ```
414
+
415
+ 2. En `arela-uploader/src/services/index.js`:
416
+ ```javascript
417
+ export { default as watchService } from './WatchService.js';
418
+ export { default as databaseService } from './DatabaseService.js';
419
+ export { default as autoProcessingService } from './AutoProcessingService.js';
420
+ ```
421
+
422
+ 3. En arela-api:
423
+ ```bash
424
+ npm install /path/to/arela-uploader
425
+ # o si está publicado en npm
426
+ npm install @arela/uploader
427
+ ```
428
+
429
+ 4. Usar en arela-api:
430
+ ```javascript
431
+ import { watchService } from '@arela/uploader/services';
432
+ ```
433
+
434
+ ### Opción 2: Compartir código vía monorepo
435
+ Usar Lerna o Yarn Workspaces para mantener ambos proyectos en el mismo workspace.
436
+
437
+ ---
438
+
439
+ ## 🎨 Ejemplo de Interfaz Frontend
440
+
441
+ ```javascript
442
+ // hooks/useWatcher.js
443
+ import { useState, useEffect } from 'react';
444
+
445
+ export const useWatcher = () => {
446
+ const [status, setStatus] = useState(null);
447
+ const [queue, setQueue] = useState(null);
448
+ const [loading, setLoading] = useState(false);
449
+ const [error, setError] = useState(null);
450
+
451
+ useEffect(() => {
452
+ const interval = setInterval(async () => {
453
+ try {
454
+ setLoading(true);
455
+ const [statusRes, queueRes] = await Promise.all([
456
+ fetch('/api/watcher/status'),
457
+ fetch('/api/watcher/queue-stats'),
458
+ ]);
459
+
460
+ const statusData = await statusRes.json();
461
+ const queueData = await queueRes.json();
462
+
463
+ setStatus(statusData);
464
+ setQueue(queueData);
465
+ setError(null);
466
+ } catch (err) {
467
+ setError(err.message);
468
+ } finally {
469
+ setLoading(false);
470
+ }
471
+ }, 5000); // Refrescar cada 5 segundos
472
+
473
+ return () => clearInterval(interval);
474
+ }, []);
475
+
476
+ const startWatcher = async (directories) => {
477
+ const res = await fetch('/api/watcher/start', {
478
+ method: 'POST',
479
+ headers: { 'Content-Type': 'application/json' },
480
+ body: JSON.stringify({ directories, autoProcessing: true }),
481
+ });
482
+ return res.json();
483
+ };
484
+
485
+ const stopWatcher = async () => {
486
+ const res = await fetch('/api/watcher/stop', { method: 'POST' });
487
+ return res.json();
488
+ };
489
+
490
+ return {
491
+ status,
492
+ queue,
493
+ loading,
494
+ error,
495
+ startWatcher,
496
+ stopWatcher,
497
+ };
498
+ };
499
+ ```
500
+
501
+ ---
502
+
503
+ ## 🔐 Consideraciones de Seguridad
504
+
505
+ 1. **Autenticación**: Todos los endpoints deben requerir autenticación JWT o similar
506
+ 2. **Autorización**: Solo usuarios con rol `admin` o `uploader` pueden controlar el watcher
507
+ 3. **Rate Limiting**: Implementar rate limiting en los endpoints de control (start/stop)
508
+ 4. **Auditoría**: Registrar todas las acciones de control del watcher
509
+
510
+ Ejemplo con middleware de autenticación:
511
+ ```javascript
512
+ import { verifyAuth } from '../middleware/auth.js';
513
+
514
+ router.get('/status', verifyAuth, (req, res) => {
515
+ // ... endpoint
516
+ });
517
+
518
+ router.post('/start', verifyAuth, requireRole('admin'), async (req, res) => {
519
+ // ... endpoint
520
+ });
521
+ ```
522
+
523
+ ---
524
+
525
+ ## 📊 WebSocket para actualizaciones en tiempo real (Opcional)
526
+
527
+ Para mayor eficiencia, implementar WebSocket en lugar de polling:
528
+
529
+ ```javascript
530
+ // socket.io integration
531
+ io.on('connection', (socket) => {
532
+ socket.on('subscribe-watcher', async () => {
533
+ // Enviar status inicial
534
+ socket.emit('watcher:status', watchService.getStats());
535
+
536
+ // Actualizar cada 5 segundos
537
+ const interval = setInterval(async () => {
538
+ socket.emit('watcher:status', watchService.getStats());
539
+ socket.emit('watcher:queue', await watchService.getQueueStats());
540
+ }, 5000);
541
+
542
+ socket.on('disconnect', () => clearInterval(interval));
543
+ });
544
+ });
545
+ ```
546
+
547
+ ---
548
+
549
+ ## ✅ Checklist de Implementación
550
+
551
+ - [ ] Crear archivo `routes/watcher.routes.js` con endpoints
552
+ - [ ] Integrar rutas en `app.js`
553
+ - [ ] Exportar WatchService desde arela-uploader
554
+ - [ ] Importar en arela-api
555
+ - [ ] Agregar autenticación a endpoints
556
+ - [ ] Agregar validación de inputs
557
+ - [ ] Agregar logging y error handling
558
+ - [ ] Implementar caché en frontend (SWR, React Query)
559
+ - [ ] Agregar WebSocket para actualizaciones real-time (opcional)
560
+ - [ ] Documentar endpoints en OpenAPI/Swagger
561
+ - [ ] Crear tests de integración
562
+