## Funcționalități Principale ### Bulk Upload & Processing - Drag & drop pentru upload bonuri multiple oriunde pe pagină - Batch processing cu job queue și worker pool - Real-time updates via SSE (Server-Sent Events) cu fallback polling - Duplicate detection via SHA-256 file hash - Auto-retry pentru job-uri failed - Cancel individual jobs sau batch complet ### Mobile UX - Android Native Style - Top bar fixă cu hamburger, titlu centrat, acțiuni (search/filter) - Bottom navigation cu 4 tab-uri (Bonuri, Upload, Rapoarte, Setări) - FAB (Floating Action Button) cu hide/show on scroll - Filter chips orizontal scrollabile - Selecție multiplă prin long-press (500ms) - Select All + Bulk Delete cu confirmare - Layout Android pentru Create/Edit/View bon (Gmail compose style) ### Bug Fixes - Refresh individual via SSE în loc de refresh total pagină - Bonurile cu eroare OCR rămân vizibile pentru editare manuală - Afișare nume fișier original pentru toate bonurile - Upload stabil pe mobil (fix race condition File API) - Păstrare ordine bonuri la refresh (nu se reordonează) ### Backend - SSE endpoint pentru status updates real-time - Bulk delete endpoint cu partial success - Auto-cleanup bonuri failed după 7 zile - Batch model cu tracking complet ### Testing - E2E tests cu Playwright - Unit tests pentru bulk upload, auto-create, cleanup ## Commits Squashed: 43 user stories (US-001 → US-043) ## Branch: ralph/bulk-receipt-upload ## Timp dezvoltare: ~3 zile (Ralph autonomous) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
14 KiB
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
- [REQ-001] Sistemul trebuie să creeze rânduri vizuale în tabel imediat după upload, înainte de procesare OCR
- [REQ-002] Fiecare fișier încărcat trebuie să aibă vizibil: nume fișier, status procesare, acțiune cancel
- [REQ-003] Status-ul trebuie să se actualizeze în timp real via long-polling existent
- [REQ-004] Utilizatorul poate anula fișiere individuale sau tot batch-ul
- [REQ-005] Anularea afectează doar fișierele pending/processing, nu cele deja procesate
- [REQ-006] Rândurile pentru fișiere neprocesate au coloane de date goale ('-')
- [REQ-007] Checkbox-urile sunt disabled pentru fișiere în procesare
- [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.mdpentru 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ă
- US-007 - Backend endpoints pentru cancel (independent)
- US-008 - Store actions pentru cancel (depinde de US-007)
- US-009 - Componenta row pentru jobs (independent)
- US-001 - Afișare fișiere în tabel (depinde de US-009)
- US-002 - Actualizare status real-time (depinde de US-001)
- US-010 - Sincronizare job→receipt (depinde de US-002)
- US-003 - Animații tranziție (depinde de US-002)
- US-004 - Cancel individual (depinde de US-008)
- US-005 - Cancel batch (depinde de US-008)
- US-006 - Checkbox disabled (depinde de US-009)