@arela/uploader 1.0.2 → 1.0.4
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.
- package/.env.local +316 -0
- package/.env.template +70 -0
- package/coverage/IdentifyCommand.js.html +1462 -0
- package/coverage/PropagateCommand.js.html +1507 -0
- package/coverage/PushCommand.js.html +1504 -0
- package/coverage/ScanCommand.js.html +1654 -0
- package/coverage/UploadCommand.js.html +1846 -0
- package/coverage/WatchCommand.js.html +4111 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +191 -0
- package/coverage/lcov-report/IdentifyCommand.js.html +1462 -0
- package/coverage/lcov-report/PropagateCommand.js.html +1507 -0
- package/coverage/lcov-report/PushCommand.js.html +1504 -0
- package/coverage/lcov-report/ScanCommand.js.html +1654 -0
- package/coverage/lcov-report/UploadCommand.js.html +1846 -0
- package/coverage/lcov-report/WatchCommand.js.html +4111 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +191 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +1937 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/docs/API_RETRY_MECHANISM.md +338 -0
- package/docs/ARELA_IDENTIFY_IMPLEMENTATION.md +489 -0
- package/docs/ARELA_IDENTIFY_QUICKREF.md +186 -0
- package/docs/ARELA_PROPAGATE_IMPLEMENTATION.md +581 -0
- package/docs/ARELA_PROPAGATE_QUICKREF.md +272 -0
- package/docs/ARELA_PUSH_IMPLEMENTATION.md +577 -0
- package/docs/ARELA_PUSH_QUICKREF.md +322 -0
- package/docs/ARELA_SCAN_IMPLEMENTATION.md +373 -0
- package/docs/ARELA_SCAN_QUICKREF.md +139 -0
- package/docs/CROSS_PLATFORM_PATH_HANDLING.md +593 -0
- package/docs/DETECTION_ATTEMPT_TRACKING.md +414 -0
- package/docs/MIGRATION_UPLOADER_TO_FILE_STATS.md +1020 -0
- package/docs/MULTI_LEVEL_DIRECTORY_SCANNING.md +494 -0
- package/docs/STATS_COMMAND_SEQUENCE_DIAGRAM.md +287 -0
- package/docs/STATS_COMMAND_SIMPLE.md +93 -0
- package/package.json +31 -3
- package/src/commands/IdentifyCommand.js +459 -0
- package/src/commands/PropagateCommand.js +474 -0
- package/src/commands/PushCommand.js +473 -0
- package/src/commands/ScanCommand.js +523 -0
- package/src/config/config.js +154 -7
- package/src/file-detection.js +9 -10
- package/src/index.js +150 -0
- package/src/services/ScanApiService.js +645 -0
- package/src/utils/PathNormalizer.js +220 -0
- package/tests/commands/IdentifyCommand.test.js +570 -0
- package/tests/commands/PropagateCommand.test.js +568 -0
- package/tests/commands/PushCommand.test.js +754 -0
- package/tests/commands/ScanCommand.test.js +382 -0
- package/tests/unit/PathAndTableNameGeneration.test.js +1211 -0
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
# Arela Push Command Implementation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `arela push` command is an optimized replacement for the legacy `upload --upload-by-rfc` command. It uploads files with `arela_path` to the storage API, tracking upload attempts and providing real-time progress feedback.
|
|
6
|
+
|
|
7
|
+
## Key Improvements Over Legacy Command
|
|
8
|
+
|
|
9
|
+
### 1. **Architecture**
|
|
10
|
+
- **Legacy**: Mixed logic with stats collection and detection
|
|
11
|
+
- **New**: Dedicated command focused only on file uploads
|
|
12
|
+
|
|
13
|
+
### 2. **Query Optimization**
|
|
14
|
+
- **Legacy**: Uses LIKE patterns and regex for filtering
|
|
15
|
+
- **New**: Uses exact match on `rfc` and `detected_pedimento_year` columns
|
|
16
|
+
|
|
17
|
+
### 3. **Attempt Tracking**
|
|
18
|
+
- **Legacy**: No tracking, processes same files repeatedly
|
|
19
|
+
- **New**: Tracks `upload_attempts`, respects `max_upload_attempts`
|
|
20
|
+
|
|
21
|
+
### 4. **Cross-Tenant Support**
|
|
22
|
+
- **Legacy**: Single API target
|
|
23
|
+
- **New**: Can read from one API, upload to another
|
|
24
|
+
|
|
25
|
+
### 5. **Progress Monitoring**
|
|
26
|
+
- **Legacy**: Basic percentage display
|
|
27
|
+
- **New**: Real-time throughput with files/sec metrics
|
|
28
|
+
|
|
29
|
+
## Database Schema Updates
|
|
30
|
+
|
|
31
|
+
### New Columns in file_stats_* Tables
|
|
32
|
+
|
|
33
|
+
```sql
|
|
34
|
+
-- Upload tracking fields
|
|
35
|
+
upload_attempted_at TIMESTAMP,
|
|
36
|
+
upload_attempts INTEGER DEFAULT 0,
|
|
37
|
+
max_upload_attempts INTEGER DEFAULT 3,
|
|
38
|
+
upload_error TEXT,
|
|
39
|
+
uploaded_at TIMESTAMP,
|
|
40
|
+
uploaded_to_storage_id UUID, -- Reference to storage.storage table
|
|
41
|
+
upload_path TEXT -- Final path where file was uploaded
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Optimized Indexes
|
|
45
|
+
|
|
46
|
+
```sql
|
|
47
|
+
-- Pending upload index (most selective filters first)
|
|
48
|
+
CREATE INDEX idx_<table>_upload_pending
|
|
49
|
+
ON cli.<table>(rfc, detected_pedimento_year, arela_path, upload_attempts, max_upload_attempts)
|
|
50
|
+
WHERE arela_path IS NOT NULL
|
|
51
|
+
AND uploaded_at IS NULL
|
|
52
|
+
AND (upload_attempts < max_upload_attempts OR upload_attempts IS NULL);
|
|
53
|
+
|
|
54
|
+
-- RFC and year filtering
|
|
55
|
+
CREATE INDEX idx_<table>_rfc_year_upload
|
|
56
|
+
ON cli.<table>(rfc, detected_pedimento_year, uploaded_at)
|
|
57
|
+
WHERE rfc IS NOT NULL;
|
|
58
|
+
|
|
59
|
+
-- Upload error tracking
|
|
60
|
+
CREATE INDEX idx_<table>_upload_errors
|
|
61
|
+
ON cli.<table>(upload_error, upload_attempts)
|
|
62
|
+
WHERE upload_error IS NOT NULL;
|
|
63
|
+
|
|
64
|
+
-- Uploaded files index
|
|
65
|
+
CREATE INDEX idx_<table>_uploaded
|
|
66
|
+
ON cli.<table>(uploaded_at, rfc)
|
|
67
|
+
WHERE uploaded_at IS NOT NULL;
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Backend Implementation
|
|
71
|
+
|
|
72
|
+
### 1. FileStatsTableManagerService
|
|
73
|
+
|
|
74
|
+
**File**: `arela-api/src/uploader/services/file-stats-table-manager.service.ts`
|
|
75
|
+
|
|
76
|
+
**New Methods**:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// Fetch files ready for upload
|
|
80
|
+
async fetchFilesForPush(
|
|
81
|
+
tableName: string,
|
|
82
|
+
options: {
|
|
83
|
+
rfcs?: string[];
|
|
84
|
+
years?: number[];
|
|
85
|
+
offset?: number;
|
|
86
|
+
limit?: number;
|
|
87
|
+
}
|
|
88
|
+
): Promise<Array<FileForPush>>
|
|
89
|
+
|
|
90
|
+
// Batch update upload results
|
|
91
|
+
async batchUpdateUpload(
|
|
92
|
+
tableName: string,
|
|
93
|
+
updates: Array<UploadUpdate>
|
|
94
|
+
): Promise<{ updated: number; errors: number }>
|
|
95
|
+
|
|
96
|
+
// Get push statistics
|
|
97
|
+
async getPushStats(
|
|
98
|
+
tableName: string
|
|
99
|
+
): Promise<PushStats>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Key Optimizations**:
|
|
103
|
+
|
|
104
|
+
1. **Exact Match Queries**: Uses `WHERE rfc = ANY($1)` instead of LIKE patterns
|
|
105
|
+
2. **Indexed Filtering**: Query patterns match index definitions for fast lookups
|
|
106
|
+
3. **Batch Processing**: Updates multiple files per transaction
|
|
107
|
+
4. **Attempt Tracking**: Skips files that reached max_upload_attempts
|
|
108
|
+
|
|
109
|
+
### 2. UploaderController Endpoints
|
|
110
|
+
|
|
111
|
+
**File**: `arela-api/src/uploader/controllers/uploader.controller.ts`
|
|
112
|
+
|
|
113
|
+
**New Endpoints**:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
GET /api/uploader/scan/files-for-push?tableName=X&rfcs=...&years=...&offset=0&limit=100
|
|
117
|
+
→ Fetch files ready for upload with optional RFC/year filtering
|
|
118
|
+
|
|
119
|
+
PATCH /api/uploader/scan/batch-update-upload?tableName=X
|
|
120
|
+
→ Update upload results for batch of files
|
|
121
|
+
|
|
122
|
+
GET /api/uploader/scan/push-stats?tableName=X
|
|
123
|
+
→ Get upload statistics
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## CLI Implementation
|
|
127
|
+
|
|
128
|
+
### 1. PushCommand
|
|
129
|
+
|
|
130
|
+
**File**: `arela-uploader/src/commands/PushCommand.js`
|
|
131
|
+
|
|
132
|
+
**Workflow**:
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
1. Validate configuration → Ensure same config as scan/identify/propagate
|
|
136
|
+
2. Show initial stats → Display current upload status
|
|
137
|
+
3. Set API targets → Configure scan and push APIs
|
|
138
|
+
4. Fetch files in batches → Get files with arela_path (with RFC/year filters)
|
|
139
|
+
5. For each batch:
|
|
140
|
+
a. Upload files concurrently (upload_batch_size)
|
|
141
|
+
b. Update results in database
|
|
142
|
+
c. Update progress bar
|
|
143
|
+
6. Show final stats → Display results
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Key Features**:
|
|
147
|
+
|
|
148
|
+
- **Real-time Progress**: Shows files uploaded, errors, and files/sec
|
|
149
|
+
- **Batch Processing**: Configurable fetch and upload batch sizes
|
|
150
|
+
- **Error Handling**: Tracks and reports upload errors
|
|
151
|
+
- **Cross-Tenant**: Can read from one API, upload to another
|
|
152
|
+
|
|
153
|
+
### 2. ScanApiService Updates
|
|
154
|
+
|
|
155
|
+
**File**: `arela-uploader/src/services/ScanApiService.js`
|
|
156
|
+
|
|
157
|
+
**New Methods**:
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
async fetchFilesForPush(tableName, options)
|
|
161
|
+
→ GET /api/uploader/scan/files-for-push
|
|
162
|
+
|
|
163
|
+
async batchUpdateUpload(tableName, updates)
|
|
164
|
+
→ PATCH /api/uploader/scan/batch-update-upload
|
|
165
|
+
|
|
166
|
+
async getPushStats(tableName)
|
|
167
|
+
→ GET /api/uploader/scan/push-stats
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 3. Configuration Updates
|
|
171
|
+
|
|
172
|
+
**File**: `arela-uploader/src/config/config.js`
|
|
173
|
+
|
|
174
|
+
**New Configuration Section**:
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
push: {
|
|
178
|
+
rfcs: [], // From PUSH_RFCS env var
|
|
179
|
+
years: [], // From PUSH_YEARS env var
|
|
180
|
+
batchSize: 100, // From PUSH_BATCH_SIZE
|
|
181
|
+
uploadBatchSize: 10, // From PUSH_UPLOAD_BATCH_SIZE
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Usage
|
|
186
|
+
|
|
187
|
+
### Basic Push
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# Upload all files with arela_path
|
|
191
|
+
arela push
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### With RFC Filter
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# Upload only specific RFCs
|
|
198
|
+
arela push --rfcs RFC123456ABC,RFC789012DEF
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### With Year Filter
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
# Upload only specific years
|
|
205
|
+
arela push --years 2023,2024
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Cross-Tenant Mode
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
# Read file_stats from agencia API, upload files to cliente API
|
|
212
|
+
arela push --scan-api agencia --push-api cliente
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Custom Batch Sizes
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
# Increase throughput
|
|
219
|
+
arela push --batch-size 200 --upload-batch-size 20
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Configuration Requirements
|
|
223
|
+
|
|
224
|
+
Same configuration as `arela scan`, `arela identify`, and `arela propagate`:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
# Required
|
|
228
|
+
ARELA_COMPANY_SLUG=your_company
|
|
229
|
+
ARELA_SERVER_ID=server01
|
|
230
|
+
UPLOAD_BASE_PATH=/path/to/files
|
|
231
|
+
UPLOAD_SOURCES=2023|2024|2025
|
|
232
|
+
|
|
233
|
+
# Optional - Push filters
|
|
234
|
+
PUSH_RFCS=RFC123456ABC|RFC789012DEF
|
|
235
|
+
PUSH_YEARS=2023|2024|2025
|
|
236
|
+
PUSH_BATCH_SIZE=100
|
|
237
|
+
PUSH_UPLOAD_BATCH_SIZE=10
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Performance Characteristics
|
|
241
|
+
|
|
242
|
+
### Query Efficiency
|
|
243
|
+
|
|
244
|
+
**Legacy Approach**:
|
|
245
|
+
```sql
|
|
246
|
+
-- LIKE pattern matching (SLOW)
|
|
247
|
+
WHERE arela_path LIKE 'RFC123456ABC/%'
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**New Approach**:
|
|
251
|
+
```sql
|
|
252
|
+
-- Exact match with index (FAST)
|
|
253
|
+
WHERE rfc = ANY($1) AND detected_pedimento_year = ANY($2)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Result**: 10-100x faster queries
|
|
257
|
+
|
|
258
|
+
### Memory Usage
|
|
259
|
+
|
|
260
|
+
- **Memory**: O(batch_size) - Only current batch in memory
|
|
261
|
+
- **Network**: Minimal - batch updates reduce API calls
|
|
262
|
+
- **Database**: Indexed queries for instant lookups
|
|
263
|
+
|
|
264
|
+
### Upload Throughput
|
|
265
|
+
|
|
266
|
+
**Dataset**: 650 files, average size 500KB, 10 concurrent uploads
|
|
267
|
+
|
|
268
|
+
| Metric | Value |
|
|
269
|
+
|--------|-------|
|
|
270
|
+
| Total Time | 12-15 seconds |
|
|
271
|
+
| Throughput | 40-55 files/sec |
|
|
272
|
+
| Memory Usage | ~150-200 MB |
|
|
273
|
+
| API Calls | ~10 (100 files per fetch batch) |
|
|
274
|
+
|
|
275
|
+
## Progress Display
|
|
276
|
+
|
|
277
|
+
### Default Mode
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
📤 Uploading |████████████████████░░░░░░░░| 67% | 435/650 files | 45 files/sec | ✓ 410 ✗ 25
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Shows:
|
|
284
|
+
- Progress bar
|
|
285
|
+
- Percentage complete
|
|
286
|
+
- Files processed / total files
|
|
287
|
+
- Real-time throughput (files/sec)
|
|
288
|
+
- Files uploaded (✓) vs errors (✗)
|
|
289
|
+
|
|
290
|
+
### Final Output
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
✅ Push Complete!
|
|
294
|
+
|
|
295
|
+
📊 Results:
|
|
296
|
+
Files Processed: 650
|
|
297
|
+
Uploaded: 600
|
|
298
|
+
Errors: 50
|
|
299
|
+
Duration: 14.4s
|
|
300
|
+
Speed: 45 files/sec
|
|
301
|
+
|
|
302
|
+
📈 Final Status:
|
|
303
|
+
Total with arela_path: 3500
|
|
304
|
+
Uploaded: 3400
|
|
305
|
+
Pending: 50
|
|
306
|
+
Errors: 50
|
|
307
|
+
|
|
308
|
+
📊 Top RFCs:
|
|
309
|
+
PED781129JT6: 150/150 (100.0%)
|
|
310
|
+
ABC123456XYZ: 100/100 (100.0%)
|
|
311
|
+
DEF789012MNO: 195/200 (97.5%)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Upload Logic
|
|
315
|
+
|
|
316
|
+
### Phase 1: Fetch Files
|
|
317
|
+
|
|
318
|
+
```sql
|
|
319
|
+
-- Get files ready for upload with filters
|
|
320
|
+
SELECT id, file_name, absolute_path, arela_path, rfc, detected_pedimento_year
|
|
321
|
+
FROM cli.file_stats_X
|
|
322
|
+
WHERE arela_path IS NOT NULL
|
|
323
|
+
AND uploaded_at IS NULL
|
|
324
|
+
AND (upload_attempts < max_upload_attempts OR upload_attempts IS NULL)
|
|
325
|
+
AND rfc = ANY($1) -- Optional RFC filter
|
|
326
|
+
AND detected_pedimento_year = ANY($2) -- Optional year filter
|
|
327
|
+
ORDER BY rfc, detected_pedimento_year, arela_path, file_name
|
|
328
|
+
LIMIT 100 OFFSET 0;
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Phase 2: Upload Files
|
|
332
|
+
|
|
333
|
+
For each file:
|
|
334
|
+
1. Check file exists on filesystem
|
|
335
|
+
2. Construct upload path: `{arela_path}{file_name}`
|
|
336
|
+
3. Upload to storage API via `POST /api/storage/detect-and-upload-file`
|
|
337
|
+
4. Track success or error
|
|
338
|
+
|
|
339
|
+
### Phase 3: Update Results
|
|
340
|
+
|
|
341
|
+
```sql
|
|
342
|
+
-- Update upload results in batch
|
|
343
|
+
UPDATE cli.file_stats_X
|
|
344
|
+
SET
|
|
345
|
+
upload_path = $1,
|
|
346
|
+
uploaded_to_storage_id = $2,
|
|
347
|
+
uploaded_at = CASE WHEN $3 = true THEN NOW() ELSE NULL END,
|
|
348
|
+
upload_attempted_at = NOW(),
|
|
349
|
+
upload_attempts = COALESCE(upload_attempts, 0) + 1,
|
|
350
|
+
upload_error = $4
|
|
351
|
+
WHERE id = $5;
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Error Handling
|
|
355
|
+
|
|
356
|
+
### Common Errors
|
|
357
|
+
|
|
358
|
+
**1. Configuration Missing**
|
|
359
|
+
|
|
360
|
+
```
|
|
361
|
+
Error: Configuration errors:
|
|
362
|
+
- ARELA_COMPANY_SLUG is required
|
|
363
|
+
- ARELA_SERVER_ID is required
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Solution**: Set environment variables in `.env`
|
|
367
|
+
|
|
368
|
+
**2. Table Not Found**
|
|
369
|
+
|
|
370
|
+
```
|
|
371
|
+
Error: Table 'file_stats_...' not found in CLI registry
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**Solution**: Run `arela scan` first to create the table
|
|
375
|
+
|
|
376
|
+
**3. No Files Ready**
|
|
377
|
+
|
|
378
|
+
```
|
|
379
|
+
✅ No files pending upload!
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Cause**: No files have `arela_path` set
|
|
383
|
+
**Solution**: Run `arela identify` and `arela propagate` first
|
|
384
|
+
|
|
385
|
+
**4. File Not Found**
|
|
386
|
+
|
|
387
|
+
Upload result:
|
|
388
|
+
```json
|
|
389
|
+
{
|
|
390
|
+
"uploadError": "FILE_NOT_FOUND: File does not exist on filesystem"
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
**Cause**: File was deleted after scan
|
|
395
|
+
**Solution**: Rescan the directory
|
|
396
|
+
|
|
397
|
+
**5. Upload Failed**
|
|
398
|
+
|
|
399
|
+
```json
|
|
400
|
+
{
|
|
401
|
+
"uploadError": "UPLOAD_FAILED: HTTP 500: Internal Server Error"
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
**Cause**: Storage API error
|
|
406
|
+
**Solution**: Check storage API logs and connectivity
|
|
407
|
+
|
|
408
|
+
## Cross-Tenant Architecture
|
|
409
|
+
|
|
410
|
+
### Use Case: Multi-Region Deployment
|
|
411
|
+
|
|
412
|
+
**Scenario**:
|
|
413
|
+
- File stats stored in Mexico API
|
|
414
|
+
- Files uploaded to US API for better performance
|
|
415
|
+
|
|
416
|
+
**Configuration**:
|
|
417
|
+
```bash
|
|
418
|
+
arela push --scan-api default --push-api us-region
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
**Environment**:
|
|
422
|
+
```bash
|
|
423
|
+
# Default API (Mexico) - for file_stats
|
|
424
|
+
ARELA_API_URL=https://api-mx.arela.com
|
|
425
|
+
ARELA_API_TOKEN=token-mx
|
|
426
|
+
|
|
427
|
+
# US Region API - for file uploads
|
|
428
|
+
ARELA_API_US_REGION_URL=https://api-us.arela.com
|
|
429
|
+
ARELA_API_US_REGION_TOKEN=token-us
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Integration with Storage API
|
|
433
|
+
|
|
434
|
+
### Upload Endpoint
|
|
435
|
+
|
|
436
|
+
**Endpoint**: `POST /api/storage/detect-and-upload-file`
|
|
437
|
+
|
|
438
|
+
**Request**:
|
|
439
|
+
```
|
|
440
|
+
multipart/form-data:
|
|
441
|
+
- file: File stream
|
|
442
|
+
- Path: Directory path (from arela_path)
|
|
443
|
+
- name: File name
|
|
444
|
+
- Bucket: "archivos"
|
|
445
|
+
- body: JSON metadata (rfc, year, originalPath)
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
**Response**:
|
|
449
|
+
```json
|
|
450
|
+
{
|
|
451
|
+
"id": "uuid-of-storage-record",
|
|
452
|
+
"public_url": "https://...",
|
|
453
|
+
"detected_type": "pedimento_simplificado",
|
|
454
|
+
...
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
## Monitoring and Observability
|
|
459
|
+
|
|
460
|
+
### Key Metrics
|
|
461
|
+
|
|
462
|
+
1. **Upload Success Rate**: `uploaded / (uploaded + errors)`
|
|
463
|
+
2. **Average Throughput**: `files / duration`
|
|
464
|
+
3. **Error Rate by RFC**: Track which RFCs have most errors
|
|
465
|
+
4. **Retry Rate**: Files reaching max attempts
|
|
466
|
+
|
|
467
|
+
### Monitoring Queries
|
|
468
|
+
|
|
469
|
+
```sql
|
|
470
|
+
-- Daily upload stats
|
|
471
|
+
SELECT
|
|
472
|
+
DATE(uploaded_at) as date,
|
|
473
|
+
COUNT(*) as uploaded,
|
|
474
|
+
COUNT(DISTINCT rfc) as rfcs_processed
|
|
475
|
+
FROM cli.file_stats_<company>_<server>_<path>
|
|
476
|
+
WHERE uploaded_at >= NOW() - INTERVAL '7 days'
|
|
477
|
+
GROUP BY DATE(uploaded_at)
|
|
478
|
+
ORDER BY date DESC;
|
|
479
|
+
|
|
480
|
+
-- Error breakdown
|
|
481
|
+
SELECT
|
|
482
|
+
SUBSTRING(upload_error FROM 1 FOR 50) as error_type,
|
|
483
|
+
COUNT(*) as count
|
|
484
|
+
FROM cli.file_stats_<company>_<server>_<path>
|
|
485
|
+
WHERE upload_error IS NOT NULL
|
|
486
|
+
GROUP BY error_type
|
|
487
|
+
ORDER BY count DESC;
|
|
488
|
+
|
|
489
|
+
-- Slow uploads (multiple attempts)
|
|
490
|
+
SELECT
|
|
491
|
+
rfc,
|
|
492
|
+
file_name,
|
|
493
|
+
upload_attempts,
|
|
494
|
+
upload_error
|
|
495
|
+
FROM cli.file_stats_<company>_<server>_<path>
|
|
496
|
+
WHERE upload_attempts > 1
|
|
497
|
+
ORDER BY upload_attempts DESC
|
|
498
|
+
LIMIT 100;
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
## Comparison: Legacy vs Optimized
|
|
502
|
+
|
|
503
|
+
| Feature | Legacy (upload --upload-by-rfc) | New (push) |
|
|
504
|
+
|---------|----------------------------------|------------|
|
|
505
|
+
| Table | Global `uploader` | Dynamic `file_stats_*` |
|
|
506
|
+
| API | Single target | Configurable scan + push APIs |
|
|
507
|
+
| Query Strategy | LIKE patterns | Exact match on RFC/year |
|
|
508
|
+
| Progress | Percentage | Throughput (files/sec) |
|
|
509
|
+
| Indexes | Basic | Optimized for upload queries |
|
|
510
|
+
| Attempt Tracking | No | Yes (max 3 attempts) |
|
|
511
|
+
| Error Handling | Basic | Categorized with tracking |
|
|
512
|
+
| Cross-Tenant | No | Yes |
|
|
513
|
+
|
|
514
|
+
## Next Steps
|
|
515
|
+
|
|
516
|
+
After push, files are uploaded and indexed in the storage system. You can:
|
|
517
|
+
|
|
518
|
+
1. **Verify uploads**: Check storage.storage table for uploaded files
|
|
519
|
+
2. **Monitor errors**: Review files that failed upload
|
|
520
|
+
3. **Retry failures**: Reset upload_attempts and run push again
|
|
521
|
+
4. **Archive processed files**: Move uploaded files to archive directory
|
|
522
|
+
|
|
523
|
+
## Testing
|
|
524
|
+
|
|
525
|
+
### Unit Tests (Backend)
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
// file-stats-table-manager.service.spec.ts
|
|
529
|
+
describe('fetchFilesForPush', () => {
|
|
530
|
+
it('should fetch files with arela_path', async () => {
|
|
531
|
+
const files = await service.fetchFilesForPush('test_table', {
|
|
532
|
+
limit: 10,
|
|
533
|
+
});
|
|
534
|
+
expect(files).toBeDefined();
|
|
535
|
+
expect(files.every(f => f.arela_path !== null)).toBe(true);
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
it('should filter by RFC', async () => {
|
|
539
|
+
const files = await service.fetchFilesForPush('test_table', {
|
|
540
|
+
rfcs: ['RFC123'],
|
|
541
|
+
limit: 10,
|
|
542
|
+
});
|
|
543
|
+
expect(files.every(f => f.rfc === 'RFC123')).toBe(true);
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Integration Tests (CLI)
|
|
549
|
+
|
|
550
|
+
```bash
|
|
551
|
+
# Test basic push
|
|
552
|
+
npm test -- PushCommand.test.js
|
|
553
|
+
|
|
554
|
+
# Test with filters
|
|
555
|
+
PUSH_RFCS=RFC123 npm test -- PushCommand.test.js
|
|
556
|
+
|
|
557
|
+
# Test cross-tenant
|
|
558
|
+
npm test -- PushCommand.crossTenant.test.js
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
## Files Modified/Created
|
|
562
|
+
|
|
563
|
+
### Backend
|
|
564
|
+
- ✅ `src/uploader/services/file-stats-table-manager.service.ts` - Added push methods
|
|
565
|
+
- ✅ `src/uploader/services/uploader.service.ts` - Added push wrappers
|
|
566
|
+
- ✅ `src/uploader/controllers/uploader.controller.ts` - Added push endpoints
|
|
567
|
+
|
|
568
|
+
### CLI
|
|
569
|
+
- ✅ `src/commands/PushCommand.js` - New command
|
|
570
|
+
- ✅ `src/services/ScanApiService.js` - Added push methods
|
|
571
|
+
- ✅ `src/config/config.js` - Added push configuration
|
|
572
|
+
- ✅ `src/index.js` - Registered push command
|
|
573
|
+
- ✅ `.env.template` - Added push environment variables
|
|
574
|
+
|
|
575
|
+
### Documentation
|
|
576
|
+
- ✅ `docs/ARELA_PUSH_IMPLEMENTATION.md` - This file
|
|
577
|
+
- ✅ `docs/ARELA_PUSH_QUICKREF.md` - Quick reference guide
|