# 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)
