## 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>
18 KiB
PRD: Bulk Receipt Upload & Auto-Processing
1. Introducere
Sistemul actual permite upload-ul și procesarea unui singur bon la un moment dat, cu intervenție manuală la editare/salvare. Această funcționalitate adaugă o pagină separată pentru upload multiple bonuri (PDF/PNG/JPG) care sunt procesate automat prin OCR și salvate direct în baza de date, fără intervenție manuală.
Context tehnic: Există deja infrastructura de job queue (SQLite) și worker pool pentru procesare paralelă OCR. Această funcționalitate va extinde sistemul existent.
2. Obiective
Obiectiv Principal
- Permiterea upload-ului bulk de bonuri (10-50 fișiere) cu procesare automată end-to-end
Obiective Secundare
- Reducerea timpului de introducere date cu 90%+ pentru batch-uri mari
- Vizibilitate în timp real asupra progresului procesării
- Separare clară între flow-ul manual (editare) și automat (bulk)
Metrici de Succes
- Timp mediu per bon < 10 secunde (vs. 2-3 minute manual)
- Rata de succes OCR > 80% (bonuri procesate fără erori)
- Upload batch 50 bonuri în < 10 minute
3. User Stories
US-001: Upload Multiple Fișiere
Ca utilizator data-entry Vreau să selectez/trag multiple fișiere (PDF/PNG/JPG) într-o zonă de upload Pentru că vreau să procesez un lot întreg de bonuri dintr-o dată
Acceptance Criteria:
- Drag & drop zone acceptă multiple fișiere simultan
- Click pe zonă deschide file picker cu multi-select activat
- Fișierele acceptate: PDF, PNG, JPG (max 10MB/fișier)
- Fișierele invalide sunt ignorate cu mesaj de avertizare
- Lista fișierelor selectate apare sub zona de upload
- Buton "Șterge" per fișier pentru eliminare din batch
- npm run typecheck passes
- Verify in browser that files appear in list after selection
- CSS: Drop zone folosește
var(--surface-card)background,var(--surface-border)border - CSS: Drop zone hover/active folosește
var(--blue-50)background - CSS: Spacing între elemente folosește tokens (
--space-md,--space-lg) - CSS: Testează în dark mode - drop zone vizibilă și contrastantă
US-002: Vizualizare Batch Înainte de Submit
Ca utilizator Vreau să văd lista fișierelor selectate cu preview Pentru că vreau să verific că am selectat fișierele corecte înainte de procesare
Acceptance Criteria:
- Lista arată: thumbnail (pentru imagini), nume fișier, mărime
- Pentru PDF-uri se arată icon generic PDF
- Counter total: "X fișiere selectate (Y MB)"
- Buton "Golește lista" pentru resetare completă
- Buton "Adaugă fișiere" pentru a adăuga la selecție existentă
- npm run typecheck passes
- Verify in browser that thumbnails render correctly
- CSS: Lista folosește pattern
.carddincards.css - CSS: Thumbnail cu
border-radius: var(--radius-md) - CSS: File size text cu
color: var(--color-text-secondary),font-size: var(--text-sm) - CSS: Butoane folosesc clasele
.btn .btn-secondaryși.btn .btn-primary - CSS: Testează în dark mode - thumbnails și text lizibile
US-003: Submit Batch pentru Procesare
Ca utilizator Vreau să trimit toate fișierele pentru procesare cu un singur click Pentru că vreau să declanșez procesarea automată a întregului lot
Acceptance Criteria:
- Buton "Procesează X bonuri" submit-ează batch-ul
- La submit, toate fișierele se uploadează și se creează câte un OCR job per fișier
- După submit, UI-ul trece în modul "progres" (nu mai permite adăugare fișiere)
- Dacă un upload individual eșuează (network error), se reîncearcă automat (max 3 retry)
- npm run typecheck passes
- Verify in browser that submit disables file addition
US-004: Progres Real-Time per Fișier
Ca utilizator Vreau să văd progresul fiecărui fișier în timp real Pentru că vreau să știu câte bonuri s-au procesat și câte mai sunt în așteptare
Acceptance Criteria:
- Fiecare fișier din listă arată status: "În așteptare" / "Se procesează..." / "Completat" / "Eroare"
- Status vizual diferențiat: badge/icon color-coded (gri/albastru/verde/roșu)
- La completare se arată confidence score overall (ex: "87% confidence")
- Progress bar global: "15/50 procesate"
- Timpul estimat rămas bazat pe average processing time
- npm run typecheck passes
- Verify in browser that status updates in real-time without page refresh
- CSS: Status badges folosesc culorile din tabel (vezi secțiunea 6):
- Pending:
background: var(--surface-hover),color: var(--color-text-secondary) - Processing:
background: var(--blue-50),color: var(--blue-600)+ spinner - Success:
background: var(--green-50),color: var(--green-600) - Error:
background: var(--red-50),color: var(--red-600)
- Pending:
- CSS: Progress bar folosește PrimeVue ProgressBar (stilizat global)
- CSS: Confidence score cu
font-family: var(--font-mono)pentru numere - CSS: Testează în dark mode - badges vizibile și contrastate
US-005: Salvare Automată a Bonurilor Procesate
Ca sistem Vreau să salvez automat bonurile procesate cu succes în baza de date Pentru că utilizatorul dorește procesare 100% automată fără intervenție
Acceptance Criteria:
- După OCR completat cu succes, se creează automat un receipt în DB
- Receipt-ul primește status "DRAFT" (poate fi editat ulterior dacă e nevoie)
- Se atașează automat fișierul original la receipt
- Se salvează toate câmpurile extrase: vendor, CUI, dată, sumă, TVA
- Se generează automat accounting entries (ca la flow-ul manual)
- npm run typecheck passes
- Verify that receipts appear in receipt list after bulk processing
US-006: Gestionare Erori OCR
Ca utilizator Vreau ca bonurile cu erori OCR să fie marcate pentru review manual Pentru că vreau să procesez restul batch-ului fără blocaj, dar să nu pierd bonurile problematice
Acceptance Criteria:
- La eroare OCR, fișierul primește status "Eroare" cu mesaj explicativ
- Bonurile cu erori rămân în lista vizibilă, nu sunt șterse
- Buton "Deschide în editor" pentru fiecare bon cu eroare (redirect la pagina de editare manuală)
- Procesarea celorlalte bonuri continuă independent
- La final se arată sumar: "45 procesate cu succes, 5 cu erori"
- npm run typecheck passes
- Verify in browser that error files show retry/edit options
- CSS: Error row cu
background: var(--red-50),border-left: 3px solid var(--red-500) - CSS: Error message cu
color: var(--red-600),font-size: var(--text-sm) - CSS: Action buttons în error row folosesc
.btn .btn-smpattern - CSS: Testează în dark mode - erori vizibile dar nu agresive
US-007: Rezumat Final Batch
Ca utilizator Vreau să văd un rezumat la finalul procesării batch-ului Pentru că vreau să știu câte bonuri s-au salvat și ce acțiuni mai am de făcut
Acceptance Criteria:
- Modal/panel de rezumat cu statistici: procesate OK, erori, total sumă
- Link direct la lista de receipts filtrat pe batch-ul curent (by date/user)
- Opțiune "Încarcă alt batch" pentru a începe de la zero
- Opțiune "Vezi bonurile cu erori" pentru review rapid
- npm run typecheck passes
- Verify in browser that summary modal shows correct counts
- CSS: Modal folosește PrimeVue Dialog (stilizat global) sau pattern
.card - CSS: Statistici success cu
color: var(--green-600), errors cucolor: var(--red-600) - CSS: Total sumă cu
font-size: var(--text-2xl),font-weight: var(--font-bold),font-family: var(--font-mono) - CSS: Spacing consistent:
padding: var(--space-lg),gap: var(--space-md) - CSS: Testează în dark mode - modal și conținut lizibile
US-008: Backend - Endpoint Batch Upload
Ca developer Vreau un endpoint optimizat pentru upload multiple fișiere Pentru că upload-ul secvențial ar fi prea lent pentru 50+ fișiere
Acceptance Criteria:
- POST
/api/data-entry/bulk/uploadacceptă multipart cu multiple fișiere - Returnează lista de job_id-uri pentru tracking
- Validare: max 100 fișiere per batch, max 10MB per fișier
- Jobs se creează atomic (toate sau niciunul)
- Returnează și un batch_id pentru grouping
- pytest tests pass
- API returns correct response schema
US-009: Backend - Auto-Save Receipt din OCR Result
Ca developer Vreau un service care creează automat receipt-uri din rezultatele OCR Pentru că flow-ul bulk trebuie să fie end-to-end fără intervenție UI
Acceptance Criteria:
ReceiptAutoCreateService.create_from_ocr_result(job_id, ocr_result, user)- Mapare completă OCR fields → Receipt fields
- Creare attachment cu fișierul original
- Generare accounting entries via existing logic
- Validare minimă: suma > 0, dată validă
- Return receipt_id sau error message
- pytest tests pass
US-010: Backend - Batch Status Endpoint
Ca developer Vreau un endpoint pentru status-ul întregului batch Pentru că frontend-ul trebuie să poll-eze eficient pentru toate fișierele
Acceptance Criteria:
- GET
/api/data-entry/bulk/batches/{batch_id}/status - Returnează status agregat: pending_count, processing_count, completed_count, failed_count
- Include lista de job_id + status pentru fiecare fișier
- Include receipt_id pentru jobs completate cu succes
- Suportă long-polling (wait param) pentru eficiență
- pytest tests pass
4. Cerințe Funcționale
- [REQ-001] Sistemul trebuie să accepte upload simultan de până la 100 fișiere
- [REQ-002] Fiecare fișier trebuie să fie max 10MB
- [REQ-003] Formatele acceptate: PDF, PNG, JPG, JPEG
- [REQ-004] Procesarea trebuie să fie paralelă (max N workers din config)
- [REQ-005] Bonurile procesate cu succes se salvează automat cu status DRAFT
- [REQ-006] Bonurile cu erori rămân disponibile pentru retry/editare manuală
- [REQ-007] Fișierele originale se atașează automat la receipt-uri
- [REQ-008] Se generează automat accounting entries pentru fiecare receipt
- [REQ-009] Batch-urile trebuie să fie tracked per user (nu se văd batch-urile altora)
- [REQ-010] Job files se curăță automat după 24h (cleanup existing)
5. Non-Goals (Ce NU facem)
- NU facem aprobare automată (bonurile rămân DRAFT, nu APPROVED)
- NU facem machine learning pentru îmbunătățirea OCR-ului
- NU facem procesare pe server extern (totul rămâne local)
- NU facem notificări (email/push) la finalizare batch
- NU facem preview/editare în bulk page - pentru asta există pagina individuală
- NU facem undo/rollback batch (bonurile create pot fi șterse individual)
- NU facem scheduling (procesare imediată, nu amânată)
- NU facem duplicate detection (poate fi adăugat ulterior)
6. Considerații Tehnice
Stack/Tehnologii
- Frontend: Vue 3 Composition API, PrimeVue (FileUpload, ProgressBar, DataTable)
- Backend: FastAPI, SQLite (job queue existent), SQLModel (receipts)
- State: Pinia store pentru batch progress tracking
Patterns de Urmat
- Folosește
OCRJobQueueexistent pentru job management - Extinde
job_worker.pypentru auto-save la completare - Folosește pattern-ul de polling din
OCRUploadZone.vueexistent
⚠️ REGULI CSS OBLIGATORII
CITEȘTE ÎNTÂI: docs/ONBOARDING_CSS.md și docs/DESIGN_TOKENS.md
Golden Rules
✅ Folosește DOAR design tokens - NICIODATĂ valori hardcodate
✅ Verifică CSS_PATTERNS.md înainte de a scrie CSS nou
✅ Testează în AMBELE teme (light + dark mode)
❌ NICIODATĂ :deep() în componente (PrimeVue → vendor/)
❌ NICIODATĂ duplicate CSS (write once, use everywhere)
Design Tokens Obligatorii
| Categorie | ❌ GREȘIT | ✅ CORECT |
|---|---|---|
| Spacing | padding: 8px |
padding: var(--space-sm) |
| Spacing | margin: 16px |
margin: var(--space-md) |
| Spacing | gap: 24px |
gap: var(--space-lg) |
| Font size | font-size: 14px |
font-size: var(--text-sm) |
| Font weight | font-weight: 500 |
font-weight: var(--font-medium) |
| Font weight | font-weight: 600 |
font-weight: var(--font-semibold) |
| Colors | color: #111827 |
color: var(--color-text) |
| Colors | color: #6b7280 |
color: var(--color-text-secondary) |
| Colors | background: #ffffff |
background: var(--surface-card) |
| Colors | background: #f0fdf4 |
background: var(--green-50) |
| Colors | border: #e5e7eb |
border-color: var(--surface-border) |
| Radius | border-radius: 8px |
border-radius: var(--radius-md) |
| Shadow | box-shadow: 0 4px 6px... |
box-shadow: var(--shadow-md) |
| Transition | transition: 0.2s |
transition: var(--transition-fast) |
Spacing Scale Reference
| Token | Value | Use Case |
|---|---|---|
--space-xs |
4px | Icon gaps, badges |
--space-sm |
8px | Between related items |
--space-md |
16px | Component padding |
--space-lg |
24px | Section padding, cards |
--space-xl |
32px | Page margins |
Status Colors (pentru progres/erori)
| Status | Background | Text/Icon |
|---|---|---|
| Pending | var(--surface-hover) |
var(--color-text-secondary) |
| Processing | var(--blue-50) |
var(--blue-600) |
| Success | var(--green-50) |
var(--green-600) |
| Error | var(--red-50) |
var(--red-600) |
| Warning | var(--yellow-50) |
var(--yellow-600) |
Dark Mode - OBLIGATORIU
- Folosește
--surface-*tokens pentru backgrounds (auto-switch în dark mode) - Testează cu theme toggle din header (auto → light → dark)
- NU folosi culori hardcodate care nu se schimbă în dark mode
Patterns Existente de Folosit
| Pattern | File | Use Case |
|---|---|---|
.card |
cards.css |
Container principal |
.btn, .btn-primary |
buttons.css |
Butoane |
.form-group, .form-label |
forms.css |
Formulare |
.spinner |
spinners.css |
Loading states |
.trend, .trend-up |
trends.css |
Indicators |
| Utility classes | utilities/ |
gap-md, text-center, etc. |
PrimeVue Components
- FileUpload, ProgressBar, DataTable, Tag, Badge - toate sunt stilizate global
- NU adăuga
:deep()în componente - Modificări PrimeVue →
src/assets/css/vendor/primevue-overrides.css
Dependențe
- Job Queue existent:
backend/modules/data_entry/services/ocr/job_queue.py - Worker Pool existent:
backend/modules/data_entry/services/ocr/ocr_worker_pool.py - Receipt CRUD:
backend/modules/data_entry/db/crud/receipt.py - Attachment CRUD:
backend/modules/data_entry/db/crud/attachment.py
Riscuri Tehnice
- Memory pressure: Upload simultan de 100 fișiere × 10MB = 1GB potențial
- Mitigare: Upload secvențial intern, buffer 5 fișiere max în memorie
- Queue overflow: 100 jobs noi pot încetini procesarea existentă
- Mitigare: Worker pool deja limitează concurența
- Browser crash: Tab închis pierde tracking progress
- Mitigare: Jobs persistă în DB, refresh poate recupera status
7. Considerații UI/UX
Layout
- Header: Titlu "Upload Bulk Bonuri" + link înapoi la lista principală
- Drop Zone: Mare, centrată, cu icon și text instructiv
- File List: Tabel/listă sub drop zone cu progres per fișier
- Actions Bar: Butoane "Procesează", "Golește lista" - sticky la bottom
Layout CSS Structure
.bulk-upload-page
├── .page-header (pattern existent)
│ └── h1 + breadcrumb
├── .card (drop zone container)
│ └── .upload-zone (dashed border, centered)
├── .card (file list container)
│ └── DataTable sau custom list
└── .form-actions (sticky footer cu butoane)
Stări UI cu CSS
| Stare | Background | Border | Elements |
|---|---|---|---|
| Empty | var(--surface-card) |
2px dashed var(--surface-border) |
Icon mare + text instructiv |
| Drag Over | var(--blue-50) |
2px dashed var(--blue-500) |
Border evidențiat |
| Files Selected | var(--surface-card) |
1px solid var(--surface-border) |
Lista + action buttons |
| Processing | var(--surface-card) |
- | Spinner global + per-file status |
| Complete | var(--green-50) subtle |
- | Summary card |
| Has Errors | - | - | Error items highlighted |
Status Badge Styles
/* Folosește PrimeVue Tag sau custom badges */
.status-pending { background: var(--surface-hover); color: var(--color-text-secondary); }
.status-processing { background: var(--blue-50); color: var(--blue-600); }
.status-success { background: var(--green-50); color: var(--green-600); }
.status-error { background: var(--red-50); color: var(--red-600); }
Accesibilitate
- Keyboard navigation pentru file list
- Screen reader announcements la status changes
- Focus management la modal rezumat
- WCAG contrast ratios respectate (toate token-urile sunt compliant)
8. Success Metrics
- Upload Success Rate: > 99% (fișierele ajung în queue)
- OCR Success Rate: > 80% (bonuri procesate fără erori)
- Average Processing Time: < 8 secunde/bon
- User Satisfaction: Reducere timp introducere date cu 90%
9. Open Questions
- Limita de 100 fișiere este suficientă sau trebuie mărită?
- Dorim să afișăm preview al datelor extrase înainte de save (ar contrazice "100% automat")?
- Ce facem cu bonurile duplicate detectate ulterior (același număr bon + dată)?
- Trebuie un "dry run" mode care procesează dar nu salvează?
10. Dependențe între User Stories
US-001 (Upload Files)
↓
US-002 (Preview List) ← independent
↓
US-003 (Submit Batch) → US-008 (Backend Upload Endpoint)
↓
US-004 (Progress) ← US-010 (Backend Status Endpoint)
↓
US-005 (Auto-Save) ← US-009 (Backend Auto-Create Service)
↓
US-006 (Error Handling)
↓
US-007 (Summary)
Ordine recomandată de implementare:
- US-008: Backend - Batch Upload Endpoint
- US-010: Backend - Batch Status Endpoint
- US-009: Backend - Auto-Save Service
- US-001: Frontend - Upload Zone
- US-002: Frontend - File Preview
- US-003: Frontend - Submit Batch
- US-004: Frontend - Progress Tracking
- US-005: Integration - Auto-Save Flow
- US-006: Frontend - Error Handling
- US-007: Frontend - Summary Modal
Last Updated: 2026-01-09 Author: Claude Code Status: Draft - Pending Review