# PRD: Bulk Upload - Progres Real-Time în Listă ## 1. Introducere Sistemul actual de bulk upload afișează fișierele în lista de bonuri **doar după** ce procesarea OCR se finalizează. Utilizatorul nu poate vedea ce fișiere a încărcat și în ce stadiu se află fiecare. Această funcționalitate va afișa toate fișierele imediat după upload, direct în tabelul de bonuri, cu actualizare în timp real a statusului pe măsură ce sunt procesate. ### Context Dezvoltare | Aspect | Valoare | |--------|---------| | **Branch** | `ralph/bulk-receipt-upload` (continuare branch existent) | | **Bază** | Sistemul bulk upload implementat anterior (US-001 → US-013) | | **NU crea branch nou** | Toate modificările se fac în branch-ul existent | ## 2. Obiective ### Obiectiv Principal - Vizibilitate completă a tuturor fișierelor încărcate, de la momentul upload-ului până la finalizare ### Obiective Secundare - Feedback vizual clar pentru progresul procesării - Posibilitatea de a anula fișiere individuale sau întreg batch-ul - Identificarea rapidă a fișierelor cu erori ### Metrici de Succes - Utilizatorul vede fișierele în tabel în <2 secunde de la upload - Status-ul se actualizează în timp real fără refresh manual - Rata de abandon a bulk upload scade (utilizatorii înțeleg ce se întâmplă) ## 3. User Stories ### US-001: Afișare Fișiere Imediat După Upload **Ca** utilizator care încarcă bonuri în bulk **Vreau** să văd toate fișierele selectate în tabel imediat după upload **Pentru că** vreau să știu că fișierele mele au fost primite și sunt în procesare **Acceptance Criteria:** - [ ] După drag-drop sau selectare fișiere, rândurile apar în tabel în <2 secunde - [ ] Fiecare fișier are un rând propriu în tabelul de bonuri - [ ] Rândurile sunt grupate în batch-ul corespunzător (BatchGroupHeader) - [ ] Coloanele de date (Data, Sumă, Furnizor, Tip) afișează '-' pentru fișiere neprocesate - [ ] Coloana "Fișier" afișează numele fișierului original - [ ] Coloana "Status Procesare" afișează "În așteptare" (pending) - [ ] npm run typecheck passes - [ ] Verify in browser: upload 3 fișiere și confirmă că apar instant în tabel ### US-002: Actualizare Status în Timp Real **Ca** utilizator **Vreau** să văd statusul fiecărui fișier actualizându-se automat **Pentru că** vreau să urmăresc progresul fără să dau refresh **Acceptance Criteria:** - [ ] Statusul se schimbă de la "În așteptare" → "Se procesează..." → "Procesat" / "Eroare" - [ ] Tranziția status include animație fade subtilă (CSS transition 300ms) - [ ] Badge-ul "Se procesează..." include spinner animat - [ ] Când procesarea se termină cu succes, coloanele se populează cu date extrase (Data, Sumă, etc.) - [ ] Când procesarea eșuează, coloana Status afișează "Eroare" cu tooltip pentru mesajul de eroare - [ ] Rândul rămâne în aceeași poziție în grup (nu se mută) - [ ] npm run typecheck passes - [ ] Verify in browser: urmărește un fișier din pending → processing → completed ### US-003: Animație la Schimbarea Statusului **Ca** utilizator **Vreau** o indicație vizuală când un fișier își schimbă statusul **Pentru că** vreau să observ ușor progresul când am multe fișiere **Acceptance Criteria:** - [ ] Badge-ul de status se schimbă cu CSS transition (opacity fade) - [ ] Când trece la "Procesat", rândul primește un highlight verde subtil pentru 2s - [ ] Când trece la "Eroare", rândul primește un highlight roșu subtil pentru 2s - [ ] Animațiile folosesc design tokens (`--green-50`, `--red-50`) - [ ] Animațiile nu sunt distragătoare (subtile, nu flashy) - [ ] npm run typecheck passes - [ ] Verify in browser: testează tranziția vizuală pentru success și error ### US-004: Cancel Fișier Individual **Ca** utilizator **Vreau** să pot anula procesarea unui singur fișier **Pentru că** poate am încărcat din greșeală un fișier **Acceptance Criteria:** - [ ] Fișierele cu status "În așteptare" sau "Se procesează" au buton/icon Cancel (×) - [ ] Click pe Cancel afișează confirmare: "Anulezi procesarea pentru {filename}?" - [ ] După confirmare, fișierul este eliminat din coadă și dispare din tabel - [ ] Fișierele deja procesate NU au buton Cancel (sunt bonuri valide) - [ ] Fișierele cu eroare au buton Retry, nu Cancel - [ ] Cancel individual nu afectează alte fișiere din batch - [ ] npm run typecheck passes - [ ] Verify in browser: anulează un fișier pending și confirmă că dispare ### US-005: Cancel Tot Batch-ul **Ca** utilizator **Vreau** să pot anula toate fișierele dintr-un batch **Pentru că** poate am încărcat batch-ul greșit **Acceptance Criteria:** - [ ] BatchGroupHeader pentru batch-uri în procesare are buton "Anulează tot" - [ ] Click pe "Anulează tot" afișează confirmare cu numărul de fișiere afectate - [ ] Confirmarea menționează că fișierele deja procesate rămân ca bonuri - [ ] După confirmare, toate fișierele pending/processing sunt eliminate - [ ] Fișierele deja procesate (completed) rămân în sistem ca bonuri valide - [ ] Dacă toate fișierele sunt completed/failed, butonul nu apare - [ ] npm run typecheck passes - [ ] Verify in browser: anulează un batch și confirmă că doar pending/processing dispar ### US-006: Checkbox Disabled pentru Fișiere în Procesare **Ca** utilizator **Vreau** să nu pot selecta fișierele în procesare pentru acțiuni bulk **Pentru că** nu are sens să validez/șterg un fișier care nu e încă procesat **Acceptance Criteria:** - [ ] Checkbox-ul este disabled pentru rânduri cu status pending/processing - [ ] Hover pe checkbox disabled afișează tooltip: "Fișierul se procesează" - [ ] "Select All" nu include fișierele în procesare - [ ] Acțiunile bulk (Validează, Șterge) funcționează doar pe fișiere completed/failed - [ ] npm run typecheck passes - [ ] Verify in browser: încearcă să selectezi un fișier pending - checkbox disabled ### US-007: Backend - Endpoint pentru Cancel Job **Ca** sistem **Vreau** un endpoint API pentru anularea job-urilor de procesare **Pentru că** frontend-ul trebuie să poată cancela fișiere **Acceptance Criteria:** - [ ] POST /api/data-entry/bulk/cancel/{job_id} - anulează un job specific - [ ] POST /api/data-entry/bulk/cancel-batch/{batch_id} - anulează tot batch-ul (pending/processing) - [ ] Endpoint-urile returnează lista de job-uri anulate - [ ] Job-urile cu status completed/failed nu pot fi anulate (return 400) - [ ] Dacă receipt-ul a fost deja creat, nu se șterge (rămâne în sistem) - [ ] Endpoint-urile actualizează status în job_queue la 'cancelled' - [ ] npm run typecheck passes (Python) - [ ] Testează cu curl: cancel job pending returnează 200 ### US-008: Frontend - Integrare Store pentru Cancel **Ca** dezvoltator **Vreau** acțiuni în store pentru cancel **Pentru că** componentele trebuie să poată apela cancel **Acceptance Criteria:** - [ ] batchProgressStore.cancelJob(jobId) - apelează endpoint cancel individual - [ ] batchProgressStore.cancelBatch(batchId) - apelează endpoint cancel batch - [ ] După cancel, job-ul dispare din Map-ul de jobs - [ ] După cancel batch, toate job-urile pending/processing dispar - [ ] Polling-ul continuă pentru job-urile rămase (completed) - [ ] Erori la cancel sunt afișate utilizatorului (toast) - [ ] npm run typecheck passes - [ ] Verify in browser: cancel + verifică că store se actualizează ### US-009: Afișare Fișiere în Tabel - Componenta Row **Ca** dezvoltator **Vreau** să pot randa un rând pentru un job neprocesar încă **Pentru că** trebuie să afișez fișierele înainte de a deveni Receipt-uri **Acceptance Criteria:** - [ ] Tabelul poate randa atât Receipt-uri cât și BatchJob-uri (pending files) - [ ] Pentru BatchJob: afișează filename în coloana Fișier - [ ] Pentru BatchJob: coloanele Data, Sumă, Furnizor, Tip afișează '-' - [ ] Pentru BatchJob: ProcessingStatusCell afișează status corect - [ ] Pentru BatchJob: acțiunile din meniu sunt disabled (doar Cancel disponibil) - [ ] Stilul rândului indică vizual că e în procesare (ușor muted/opacity) - [ ] npm run typecheck passes - [ ] Verify in browser: rândul pentru job pending arată corect ### US-010: Sincronizare Job Status cu Receipt **Ca** sistem **Vreau** să asociez job-urile cu receipt-urile create **Pentru că** când OCR termină, rândul trebuie să se transforme în receipt **Acceptance Criteria:** - [ ] Când OCR termină cu succes, job-ul primește receipt_id - [ ] Frontend-ul detectează receipt_id și înlocuiește rândul de job cu receipt-ul real - [ ] Coloanele se populează cu datele din receipt (Data, Sumă, Furnizor) - [ ] Tranziția e smooth - nu dispare/reapare rândul - [ ] Dacă OCR eșuează, job-ul rămâne cu status 'failed' și error_message - [ ] npm run typecheck passes - [ ] Verify in browser: urmărește un fișier cum devine receipt cu date populate ## 4. Cerințe Funcționale 1. **[REQ-001]** Sistemul trebuie să creeze rânduri vizuale în tabel imediat după upload, înainte de procesare OCR 2. **[REQ-002]** Fiecare fișier încărcat trebuie să aibă vizibil: nume fișier, status procesare, acțiune cancel 3. **[REQ-003]** Status-ul trebuie să se actualizeze în timp real via long-polling existent 4. **[REQ-004]** Utilizatorul poate anula fișiere individuale sau tot batch-ul 5. **[REQ-005]** Anularea afectează doar fișierele pending/processing, nu cele deja procesate 6. **[REQ-006]** Rândurile pentru fișiere neprocesate au coloane de date goale ('-') 7. **[REQ-007]** Checkbox-urile sunt disabled pentru fișiere în procesare 8. **[REQ-008]** Animațiile de tranziție folosesc design tokens CSS ## 5. Non-Goals (Ce NU facem) - **NU** implementăm preview/thumbnail pentru fișiere - doar nume + status - **NU** implementăm progress bar procentual per fișier - doar status discret - **NU** implementăm reordonare/prioritizare a cozii de procesare - **NU** implementăm pause/resume pentru procesare - **NU** ștergem receipt-urile deja create când se anulează un batch - **NU** permitem editarea fișierelor în timpul procesării ## 6. Considerații Tehnice ### Git Branch - **Branch:** `ralph/bulk-receipt-upload` - **CONTINUĂ în acest branch** - **NU crea branch nou** - această funcționalitate extinde bulk upload-ul existent - Commit messages: `feat(bulk-upload-realtime): US-XXX - Descriere` ### Stack/Tehnologii - **Frontend:** Vue 3, Pinia stores, PrimeVue components - **Backend:** FastAPI, SQLite (data-entry module), job_queue table - **Polling:** Long-polling existent în batchProgressStore ### Patterns de Urmat - ProcessingStatusCell pentru afișare status (extinde pentru cancel) - BatchGroupHeader pentru grupare (adaugă buton cancel all) - batchProgressStore pentru state management (adaugă cancel actions) - Design tokens din `docs/DESIGN_TOKENS.md` pentru culori/spacing ### Dependențe - Sistemul de bulk upload existent (US-001 până la US-013 anterioare) - Long-polling pentru status updates - BatchJob model din backend ### Riscuri Tehnice - **Race condition:** Job poate termina între request cancel și procesare - handle gracefully - **Performance:** Multe rânduri în tabel cu polling - optimizează re-renders cu Vue keys - **UX:** Rânduri care "dispar" pot fi confuze - animație clear pentru cancel ## 7. Considerații UI/UX ### Layout și Flow ``` ┌─────────────────────────────────────────────────────────────────────┐ │ BatchGroupHeader: "Batch B-abc123" - 5 fișiere [Anulează tot] │ ├─────────────────────────────────────────────────────────────────────┤ │ □ │ bon1.pdf │ - │ - │ - │ În așteptare │ [×] │ │ □ │ bon2.pdf │ - │ - │ - │ Se procesează...│ [×] │ │ ☑ │ bon3.pdf │ 15 Ian │ 125.50 │ LIDL │ ✓ Procesat │ │ │ □ │ bon4.pdf │ - │ - │ - │ ✗ Eroare │ [↻] │ │ ☑ │ bon5.pdf │ 15 Ian │ 89.00 │ Mega │ ✓ Procesat │ │ └─────────────────────────────────────────────────────────────────────┘ ``` ### Stări (loading, error, empty, success) - **Pending:** Badge gri "În așteptare", checkbox disabled, buton Cancel - **Processing:** Badge albastru cu spinner "Se procesează...", checkbox disabled, buton Cancel - **Completed:** Badge verde "✓ Procesat", checkbox enabled, fără Cancel - **Failed:** Badge roșu "✗ Eroare" cu tooltip, checkbox disabled, buton Retry - **Cancelled:** Rândul dispare cu animație fade-out ### Accesibilitate - Buton Cancel are aria-label descriptiv - Tooltip-urile de eroare sunt accesibile cu keyboard - Animațiile respectă `prefers-reduced-motion` ## 8. Success Metrics - **Time to visibility:** Fișierele apar în tabel în <2s de la upload - **Real-time accuracy:** Status-ul reflectă starea reală în <1s de la schimbare - **Cancel success rate:** 100% din cancel-uri pentru pending jobs funcționează - **User satisfaction:** Utilizatorii înțeleg ce se întâmplă cu fișierele lor ## 9. Open Questions - [ ] Dacă utilizatorul navighează away și revine, cum se restaurează rândurile pentru jobs pending? (Probabil din localStorage + API call) - [ ] Limită maximă de fișiere afișate simultan în tabel? (Performance consideration) - [ ] Notificare sonoră/vizuală când tot batch-ul e procesat? --- ## Appendix: Ordine Implementare Recomandată 1. **US-007** - Backend endpoints pentru cancel (independent) 2. **US-008** - Store actions pentru cancel (depinde de US-007) 3. **US-009** - Componenta row pentru jobs (independent) 4. **US-001** - Afișare fișiere în tabel (depinde de US-009) 5. **US-002** - Actualizare status real-time (depinde de US-001) 6. **US-010** - Sincronizare job→receipt (depinde de US-002) 7. **US-003** - Animații tranziție (depinde de US-002) 8. **US-004** - Cancel individual (depinde de US-008) 9. **US-005** - Cancel batch (depinde de US-008) 10. **US-006** - Checkbox disabled (depinde de US-009)