curatare
This commit is contained in:
@@ -1,300 +0,0 @@
|
||||
# PRD: Bulk Actions & SSE Real-time Status Updates
|
||||
|
||||
## Branch de lucru
|
||||
|
||||
> **IMPORTANT**: Toate implementările din acest PRD trebuie făcute în branch-ul existent:
|
||||
> `ralph/bulk-receipt-upload`
|
||||
|
||||
---
|
||||
|
||||
## 1. Introducere
|
||||
|
||||
Pagina de listă bonuri fiscale (`ReceiptsListView.vue`) are deja funcționalitate de selecție multiplă (select all și individual), dar lipsesc acțiunile bulk (în special ștergerea). De asemenea, actualizarea statusului bonurilor la bulk import se face prin polling periodic care reîncarcă toată lista, ceea ce creează o experiență vizuală neplăcută (flicker, pierdere scroll, etc.).
|
||||
|
||||
Acest PRD adresează:
|
||||
1. **Bulk Delete** - posibilitatea de a șterge mai multe bonuri odată
|
||||
2. **SSE Real-time Updates** - actualizări incrementale ale statusului în loc de refresh total
|
||||
|
||||
---
|
||||
|
||||
## 2. Obiective
|
||||
|
||||
### Obiectiv Principal
|
||||
- Permiterea ștergerii în masă a bonurilor selectate cu UX fluid
|
||||
|
||||
### Obiective Secundare
|
||||
- Eliminarea refresh-ului total al paginii la actualizarea statusului bonurilor
|
||||
- Actualizări real-time via SSE pentru starea bonurilor în procesare
|
||||
- Experiență vizuală smooth fără flicker
|
||||
|
||||
### Metrici de Succes
|
||||
- Ștergerea a 10+ bonuri să dureze <2s
|
||||
- Nicio reîncărcare completă a listei la update status
|
||||
- SSE să reducă request-urile de polling cu 80%+
|
||||
|
||||
---
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
### US-001: Buton Șterge în Bulk Actions Bar
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd un buton "Șterge" când am selecții
|
||||
**Pentru că** vreau să pot șterge mai multe bonuri odată
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Butonul "Șterge" apare în bulk actions bar când `selectedReceipts.length > 0`
|
||||
- [ ] Butonul e vizibil lângă "Validează selectate" și "Deselectează" în header inline
|
||||
- [ ] Butonul are icon `pi-trash` și severity `danger`
|
||||
- [ ] Bonurile în procesare (pending/processing) NU sunt selectabile (deja implementat - verifică că funcționează)
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: butonul apare doar când există selecții
|
||||
|
||||
---
|
||||
|
||||
### US-002: Dialog Confirmare Ștergere Bulk
|
||||
**Ca** utilizator
|
||||
**Vreau** o confirmare simplă înainte de ștergere
|
||||
**Pentru că** vreau să evit ștergeri accidentale
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] La click pe "Șterge", apare dialog cu mesaj: "Ești sigur că vrei să ștergi {N} bonuri?"
|
||||
- [ ] Dialog-ul are 2 butoane: "Anulează" (secondary) și "Șterge" (danger)
|
||||
- [ ] Dialog-ul folosește componenta PrimeVue `ConfirmDialog` sau `Dialog`
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: dialogul apare cu numărul corect de bonuri
|
||||
|
||||
---
|
||||
|
||||
### US-003: Backend Endpoint Bulk Delete
|
||||
**Ca** frontend
|
||||
**Vreau** să pot trimite o listă de ID-uri pentru ștergere
|
||||
**Pentru că** e mai eficient decât request-uri individuale
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Endpoint `DELETE /api/data-entry/receipts/bulk` acceptă body: `{ "ids": [1, 2, 3] }`
|
||||
- [ ] Validează că fiecare bon e în status DRAFT și creat de user-ul curent
|
||||
- [ ] Returnează partial success: `{ "deleted": [1, 2], "failed": [{"id": 3, "error": "..."}] }`
|
||||
- [ ] Șterge atașamentele și înregistrările contabile asociate
|
||||
- [ ] Bonurile în procesare nu pot fi șterse - returnează eroare specifică
|
||||
- [ ] npm run typecheck passes (pentru Python: ruff check)
|
||||
|
||||
---
|
||||
|
||||
### US-004: Frontend Bulk Delete cu Partial Success
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd rezultatul ștergerii
|
||||
**Pentru că** vreau să știu dacă toate bonurile au fost șterse
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] După ștergere, toast arată rezultatul: "X bonuri șterse" sau "X din Y șterse, Z au eșuat"
|
||||
- [ ] Bonurile șterse dispar instant din listă (fără animație per specificații)
|
||||
- [ ] Lista se actualizează local (nu re-fetch complet dacă nu e necesar)
|
||||
- [ ] Stats se actualizează după ștergere
|
||||
- [ ] Selecția se golește după ștergere
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: bonurile dispar instant, toast corect
|
||||
|
||||
---
|
||||
|
||||
### US-005: Navigare la Pagina Anterioară când Lista Devine Goală
|
||||
**Ca** utilizator
|
||||
**Vreau** să fiu redirecționat automat la pagina anterioară
|
||||
**Pentru că** nu vreau să văd o pagină goală
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] După bulk delete, dacă pagina curentă devine goală și există pagini anterioare, navighează la pagina anterioară
|
||||
- [ ] Dacă eram pe pagina 1 și devine goală, afișează empty state
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: navigare automată funcționează
|
||||
|
||||
---
|
||||
|
||||
### US-006: Backend SSE Endpoint pentru Status Updates
|
||||
**Ca** frontend
|
||||
**Vreau** să primesc notificări real-time despre schimbări de status
|
||||
**Pentru că** vreau să actualizez UI-ul fără polling
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Endpoint `GET /api/data-entry/receipts/sse/status` returnează Server-Sent Events
|
||||
- [ ] Conexiunea e persistent și trimite evenimente la schimbări de status
|
||||
- [ ] Format eveniment: `data: {"receipt_id": 123, "status": "completed", "processing_status": "completed"}`
|
||||
- [ ] Suport pentru filtrare pe batch_id (query param)
|
||||
- [ ] Include timeout handling și reconnect hints
|
||||
- [ ] ruff check passes
|
||||
|
||||
---
|
||||
|
||||
### US-007: Frontend SSE Client pentru Status Updates
|
||||
**Ca** frontend
|
||||
**Vreau** să mă conectez la SSE și să actualizez rândurile individual
|
||||
**Pentru că** vreau actualizări smooth fără reload
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Creează serviciu SSE în `src/modules/data-entry/services/sseService.js`
|
||||
- [ ] Conectare automată când există bonuri în procesare în listă
|
||||
- [ ] La primire eveniment, actualizează doar rândul afectat (nu toată lista)
|
||||
- [ ] Deconectare automată când nu mai sunt bonuri în procesare
|
||||
- [ ] Retry logic cu exponential backoff la disconnect
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: statusul se actualizează în timp real fără flicker
|
||||
|
||||
---
|
||||
|
||||
### US-008: Înlocuire Polling cu SSE
|
||||
**Ca** frontend
|
||||
**Vreau** să folosesc SSE în loc de polling interval
|
||||
**Pentru că** e mai eficient și mai smooth
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Elimină `setInterval` pentru auto-refresh când SSE e activ
|
||||
- [ ] Fallback la polling dacă SSE nu e disponibil (WebSocket blocked, etc.)
|
||||
- [ ] Când toate bonurile din batch sunt procesate, închide conexiunea SSE
|
||||
- [ ] Logging pentru debug (console.log la conectare/deconectare/evenimente)
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: consola arată evenimente SSE, nu polling requests
|
||||
|
||||
---
|
||||
|
||||
### US-009: Update Row Individual fără Re-render Lista
|
||||
**Ca** frontend
|
||||
**Vreau** să actualizez un singur rând fără să re-renderez toată lista
|
||||
**Pentru că** vreau performanță și stabilitate vizuală
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Creează metodă `updateReceiptInPlace(receiptId, updates)` în store
|
||||
- [ ] Metoda modifică doar obiectul specific din array, nu înlocuiește array-ul
|
||||
- [ ] Vue reactivity detectează schimbarea și actualizează doar rândul afectat
|
||||
- [ ] Stats se actualizează separat (poate necesita re-fetch stats)
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: DevTools Performance - doar un rând se re-renderează
|
||||
|
||||
---
|
||||
|
||||
### US-010: Graceful Degradation la SSE Failure
|
||||
**Ca** utilizator
|
||||
**Vreau** ca aplicația să funcționeze și fără SSE
|
||||
**Pentru că** pot avea probleme de rețea sau proxy
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Dacă SSE fail la connect, fallback la polling clasic (interval 5s)
|
||||
- [ ] Mesaj discret în consolă (nu toast pentru user)
|
||||
- [ ] Retry SSE periodic (la 30s) pentru a vedea dacă funcționează din nou
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: deconectează SSE, verifică că polling-ul preia
|
||||
|
||||
---
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
|
||||
1. [REQ-001] Butonul "Șterge" trebuie să fie roșu (severity danger) cu icon trash
|
||||
2. [REQ-002] Bonurile cu `processing_status` în `pending` sau `processing` nu pot fi șterse
|
||||
3. [REQ-003] Ștergerea bulk trebuie să șteargă și atașamentele și înregistrările contabile asociate
|
||||
4. [REQ-004] SSE trebuie să trimită evenimente pentru: status change, processing_status change
|
||||
5. [REQ-005] Frontend trebuie să mențină conexiunea SSE doar când există bonuri în procesare
|
||||
6. [REQ-006] La ștergerea ultimului bon de pe pagină, navighează automat la pagina anterioară
|
||||
|
||||
---
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
|
||||
- ❌ Bulk edit (modificare date pe mai multe bonuri) - poate fi un alt PRD
|
||||
- ❌ Animații fade/slide la ștergere - utilizatorul a cerut instant remove
|
||||
- ❌ Undo pentru ștergere - nu e în scope
|
||||
- ❌ WebSocket în loc de SSE - SSE e mai simplu și suficient
|
||||
- ❌ Notificări push/toast pentru statusuri - doar actualizare în tabel
|
||||
|
||||
---
|
||||
|
||||
## 6. Considerații Tehnice
|
||||
|
||||
### Stack/Tehnologii
|
||||
- **Backend**: FastAPI cu SSE support (StreamingResponse)
|
||||
- **Frontend**: Vue 3 Composition API, Pinia store
|
||||
- **SSE**: Native EventSource API (bun suport browser)
|
||||
|
||||
### Patterns de Urmat
|
||||
- Service pattern în backend (nu logică în router)
|
||||
- Store actions în frontend pentru mutații
|
||||
- `@cached` decorator DOAR pentru reads, nu pentru deletes
|
||||
|
||||
### Dependențe
|
||||
- PrimeVue ConfirmDialog sau Dialog pentru confirmare
|
||||
- FastAPI `StreamingResponse` pentru SSE
|
||||
- Deja există: bulk actions bar, selection logic, checkbox disable pentru processing
|
||||
|
||||
### Riscuri Tehnice
|
||||
- SSE poate fi blocat de proxy/firewall - mitigat cu fallback la polling
|
||||
- Concurrency la delete bulk - poate conflicta cu procesare - mitigat cu check status
|
||||
|
||||
### Structură Fișiere Noi
|
||||
```
|
||||
backend/modules/data_entry/
|
||||
├── routers/
|
||||
│ └── receipts.py # Adaugă DELETE /bulk și GET /sse/status
|
||||
├── services/
|
||||
│ └── sse_service.py # NOU: SSE broadcaster
|
||||
└── schemas/
|
||||
└── receipt.py # Adaugă BulkDeleteRequest, BulkDeleteResponse
|
||||
|
||||
src/modules/data-entry/
|
||||
├── services/
|
||||
│ └── sseService.js # NOU: SSE client
|
||||
├── stores/
|
||||
│ └── receiptsStore.js # Adaugă updateReceiptInPlace
|
||||
└── views/receipts/
|
||||
└── ReceiptsListView.vue # Adaugă buton Șterge, integrare SSE
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Considerații UI/UX
|
||||
|
||||
### Layout
|
||||
- Butonul Șterge: în bulk actions bar, header inline, lângă celelalte butoane
|
||||
- Dialog confirmare: centered modal, compact
|
||||
|
||||
### Stări
|
||||
- **Loading delete**: butonul Șterge arată spinner
|
||||
- **Success**: toast verde "X bonuri șterse"
|
||||
- **Partial fail**: toast warning "X din Y șterse, Z au eșuat"
|
||||
- **SSE connected**: indicator vizual opțional (poate în devtools)
|
||||
|
||||
### Accesibilitate
|
||||
- Dialog accesibil (focus trap, escape to close)
|
||||
- Buton cu label clear
|
||||
|
||||
---
|
||||
|
||||
## 8. Success Metrics
|
||||
|
||||
- Bulk delete 10 bonuri: < 2 secunde end-to-end
|
||||
- Zero full page refreshes la status updates
|
||||
- SSE latency: < 500ms de la schimbare status la UI update
|
||||
- Fallback polling activat în < 5s dacă SSE eșuează
|
||||
|
||||
---
|
||||
|
||||
## 9. Open Questions
|
||||
|
||||
- [x] Confirmare: simplă cu count ✓
|
||||
- [x] Bonuri în procesare: exclude automat ✓
|
||||
- [x] Polling: SSE ✓
|
||||
- [x] Error handling: partial success ✓
|
||||
- [x] Bara acțiuni: header inline ✓
|
||||
- [x] Animații: instant remove ✓
|
||||
- [x] Pagină goală: du la pagina anterioară ✓
|
||||
|
||||
---
|
||||
|
||||
## 10. Ordine Implementare Recomandată
|
||||
|
||||
1. **US-003** - Backend bulk delete (fundație)
|
||||
2. **US-001** - Buton Șterge în UI
|
||||
3. **US-002** - Dialog confirmare
|
||||
4. **US-004** - Frontend bulk delete cu toast
|
||||
5. **US-005** - Navigare pagină anterioară
|
||||
6. **US-009** - Update row in place (pregătire pentru SSE)
|
||||
7. **US-006** - Backend SSE endpoint
|
||||
8. **US-007** - Frontend SSE client
|
||||
9. **US-008** - Înlocuire polling cu SSE
|
||||
10. **US-010** - Graceful degradation
|
||||
@@ -1,406 +0,0 @@
|
||||
# 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 `.card` din `cards.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)`
|
||||
- [ ] **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-sm` pattern
|
||||
- [ ] **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 cu `color: 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/upload` acceptă 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
|
||||
|
||||
1. [REQ-001] Sistemul trebuie să accepte upload simultan de până la 100 fișiere
|
||||
2. [REQ-002] Fiecare fișier trebuie să fie max 10MB
|
||||
3. [REQ-003] Formatele acceptate: PDF, PNG, JPG, JPEG
|
||||
4. [REQ-004] Procesarea trebuie să fie paralelă (max N workers din config)
|
||||
5. [REQ-005] Bonurile procesate cu succes se salvează automat cu status DRAFT
|
||||
6. [REQ-006] Bonurile cu erori rămân disponibile pentru retry/editare manuală
|
||||
7. [REQ-007] Fișierele originale se atașează automat la receipt-uri
|
||||
8. [REQ-008] Se generează automat accounting entries pentru fiecare receipt
|
||||
9. [REQ-009] Batch-urile trebuie să fie tracked per user (nu se văd batch-urile altora)
|
||||
10. [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 `OCRJobQueue` existent pentru job management
|
||||
- Extinde `job_worker.py` pentru auto-save la completare
|
||||
- Folosește pattern-ul de polling din `OCRUploadZone.vue` existent
|
||||
|
||||
### ⚠️ 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
|
||||
1. **Header:** Titlu "Upload Bulk Bonuri" + link înapoi la lista principală
|
||||
2. **Drop Zone:** Mare, centrată, cu icon și text instructiv
|
||||
3. **File List:** Tabel/listă sub drop zone cu progres per fișier
|
||||
4. **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
|
||||
```css
|
||||
/* 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:**
|
||||
1. US-008: Backend - Batch Upload Endpoint
|
||||
2. US-010: Backend - Batch Status Endpoint
|
||||
3. US-009: Backend - Auto-Save Service
|
||||
4. US-001: Frontend - Upload Zone
|
||||
5. US-002: Frontend - File Preview
|
||||
6. US-003: Frontend - Submit Batch
|
||||
7. US-004: Frontend - Progress Tracking
|
||||
8. US-005: Integration - Auto-Save Flow
|
||||
9. US-006: Frontend - Error Handling
|
||||
10. US-007: Frontend - Summary Modal
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2026-01-09
|
||||
**Author:** Claude Code
|
||||
**Status:** Draft - Pending Review
|
||||
@@ -1,499 +0,0 @@
|
||||
# PRD: Bulk Upload Integration in Receipts List
|
||||
|
||||
## 1. Introducere
|
||||
|
||||
Funcționalitatea actuală de bulk upload există într-o pagină separată (`BulkUploadView.vue`). Când un fișier dă eroare la procesare, utilizatorul nu îl mai regăsește - acesta "dispare" din UI. Această funcționalitate integrează bulk upload direct în lista principală de bonuri, permițând vizibilitatea completă a tuturor bonurilor: în curs de upload, în procesare, procesate cu succes și cu erori.
|
||||
|
||||
**Problema de rezolvat:** Bonurile cu erori din bulk upload se pierd și nu mai pot fi regăsite. Utilizatorul nu are vizibilitate asupra batch-ului după ce părăsește pagina de bulk upload.
|
||||
|
||||
**Soluția:** Integrare completă în lista de bonuri cu:
|
||||
- Row grouping vizual per batch
|
||||
- Coloană pentru batch ID și status procesare
|
||||
- Mesaje de eroare vizibile în listă
|
||||
- Drag & drop overlay pe toată pagina
|
||||
- Quick filter chips pentru statusuri de procesare
|
||||
|
||||
## 2. Obiective
|
||||
|
||||
### Obiectiv Principal
|
||||
- Vizibilitate completă a tuturor bonurilor din bulk upload direct în lista principală
|
||||
|
||||
### Obiective Secundare
|
||||
- Eliminarea paginii separate de bulk upload (consolidare UX)
|
||||
- Recuperarea bonurilor cu erori fără a le pierde
|
||||
- Persistență: bonurile rămân vizibile chiar și după refresh/revenire
|
||||
|
||||
### Metrici de Succes
|
||||
- 0 bonuri "pierdute" după erori OCR
|
||||
- 100% tracking vizibil pentru toate batch-urile
|
||||
- Timp de onboarding pentru bulk upload < 30 secunde
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
### US-001: Drag Anywhere pentru Upload
|
||||
**Ca** utilizator data-entry
|
||||
**Vreau** să pot trage fișiere oriunde pe pagina de bonuri
|
||||
**Pentru că** vreau un flow natural fără să caut zona specifică de upload
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Tragerea unui fișier oriunde pe pagina de bonuri activează un overlay fullscreen
|
||||
- [ ] Overlay-ul arată: icon upload + text "Eliberează pentru a încărca X fișiere"
|
||||
- [ ] La eliberare, fișierele se validează și se uploadează
|
||||
- [ ] Fișierele invalide se afișează în toast cu motivul
|
||||
- [ ] Overlay dispare dacă utilizatorul trage fișierele în afara paginii
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser that overlay appears on drag
|
||||
|
||||
**Detalii tehnice:**
|
||||
- Global event listeners pe `window`: `dragenter`, `dragover`, `dragleave`, `drop`
|
||||
- Cleanup listeners în `onUnmounted` pentru a evita memory leaks
|
||||
- `e.preventDefault()` pe toate evenimentele pentru a preveni deschiderea fișierelor în browser
|
||||
|
||||
### US-002: Row Grouping per Batch în DataTable
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd bonurile din același batch grupate vizual
|
||||
**Pentru că** vreau să identific rapid care bonuri aparțin aceluiași upload
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Bonurile cu același `batch_id` apar grupate în tabel
|
||||
- [ ] Header de grup expandabil: "Batch B-001 • 12 Jan 2026 • 15 fișiere"
|
||||
- [ ] Click pe header expandează/colapsează grupul
|
||||
- [ ] Bonurile fără batch (create manual) apar în grupul "Alte bonuri"
|
||||
- [ ] Grupurile sunt sortate după timestamp (cel mai recent sus)
|
||||
- [ ] Grupul în procesare este automat expandat
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser that groups expand/collapse correctly
|
||||
|
||||
**Detalii tehnice:**
|
||||
- PrimeVue DataTable cu `rowGroupMode="subheader"` și `groupRowsBy="batch_id"`
|
||||
- Custom header slot pentru styling
|
||||
- State local pentru expanded groups
|
||||
|
||||
### US-003: Coloană Status Batch în Tabel
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd statusul fiecărui bon din batch într-o coloană dedicată
|
||||
**Pentru că** vreau să știu rapid care bonuri au reușit și care au erori
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Coloană nouă "Procesare" după coloana "Status" existentă
|
||||
- [ ] Valori posibile:
|
||||
- `pending` - "În așteptare" (gri)
|
||||
- `processing` - "Se procesează..." + spinner (albastru)
|
||||
- `completed` - "✓ Procesat" (verde)
|
||||
- `failed` - "✗ Eroare" (roșu) cu expand pentru mesaj
|
||||
- [ ] Bonurile manuale (fără batch) arată "-" în această coloană
|
||||
- [ ] Click pe "✗ Eroare" deschide tooltip/popover cu mesajul complet
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser that status updates in real-time
|
||||
|
||||
**CSS Design Tokens:**
|
||||
```css
|
||||
.processing-pending { background: var(--surface-hover); color: var(--text-color-secondary); }
|
||||
.processing-active { background: var(--blue-50); color: var(--blue-600); }
|
||||
.processing-success { background: var(--green-50); color: var(--green-600); }
|
||||
.processing-failed { background: var(--red-50); color: var(--red-600); }
|
||||
```
|
||||
|
||||
### US-004: Mesaj Eroare Vizibil în Listă
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd mesajul de eroare direct în listă (prescurtat)
|
||||
**Pentru că** vreau să înțeleg problema fără să deschid detalii
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Pentru bonuri cu `status=failed`, se afișează primele 50 caractere din mesaj
|
||||
- [ ] Mesajul e trunchiat cu "..." dacă depășește 50 caractere
|
||||
- [ ] Hover/click arată mesajul complet într-un tooltip
|
||||
- [ ] Mesajul e afișat sub rândul principal (inline expand) sau în popover
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser that full error message is accessible
|
||||
|
||||
**Exemple de mesaje:**
|
||||
- "OCR failed: format nerecunoscut pentru bon"
|
||||
- "Duplicate: bon similar existent (ID: 123)"
|
||||
- "Validare: suma totală nu poate fi 0"
|
||||
|
||||
### US-005: Quick Filter Chips pentru Statusuri Procesare
|
||||
**Ca** utilizator
|
||||
**Vreau** filtre rapide pentru a vedea doar bonurile cu erori sau în procesare
|
||||
**Pentru că** vreau să mă concentrez pe ce necesită atenție
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Chips noi în rândul de statusuri existente:
|
||||
- "În procesare (3)" - bonuri cu processing_status='processing' sau 'pending'
|
||||
- "Cu erori (2)" - bonuri cu processing_status='failed'
|
||||
- [ ] Chips apar doar când există batch-uri active (count > 0)
|
||||
- [ ] Click pe chip filtrează lista
|
||||
- [ ] Chips sunt colorat conform statusului (albastru/roșu)
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser that filtering works correctly
|
||||
|
||||
### US-006: Retry Individual și Retry All Failed
|
||||
**Ca** utilizator
|
||||
**Vreau** să pot re-procesa bonurile cu erori
|
||||
**Pentru că** unele erori pot fi temporare sau vreau să încerc din nou
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Buton "Reîncercă" pe fiecare rând cu eroare
|
||||
- [ ] Buton "Reîncercă toate erorile" în header-ul grupului de batch
|
||||
- [ ] La retry, statusul revine la "pending" și se re-uploadează fișierul
|
||||
- [ ] Retry păstrează batch_id original
|
||||
- [ ] Dacă fișierul original nu mai există, se afișează eroare
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser that retry updates status correctly
|
||||
|
||||
**Detalii tehnice:**
|
||||
- Fișierele originale trebuie păstrate în storage până la cleanup (7 zile)
|
||||
- Retry apelează același endpoint de upload cu job_id existent
|
||||
|
||||
### US-007: Reject Automat pentru Duplicate (File Hash)
|
||||
**Ca** sistem
|
||||
**Vreau** să detectez și să reject fișierele duplicate la upload
|
||||
**Pentru că** utilizatorul nu trebuie să proceseze același bon de două ori
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] La upload, se calculează SHA-256 hash al fișierului
|
||||
- [ ] Dacă hash-ul există deja în DB, upload-ul e respins
|
||||
- [ ] Mesaj: "Fișier duplicat - există deja ca bon #123"
|
||||
- [ ] Link direct către bonul existent
|
||||
- [ ] Verificarea se face înainte de a crea job-ul OCR
|
||||
- [ ] pytest tests pass
|
||||
- [ ] API returns correct error schema for duplicates
|
||||
|
||||
### US-008: Auto-Cleanup Erori După 7 Zile
|
||||
**Ca** sistem
|
||||
**Vreau** să șterg automat bonurile cu erori după 7 zile
|
||||
**Pentru că** vreau să păstrez lista curată fără intervenție manuală
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Background job zilnic verifică bonurile cu `processing_status='failed'`
|
||||
- [ ] Bonurile mai vechi de 7 zile se șterg automat
|
||||
- [ ] Fișierele atașate se șterg și ele
|
||||
- [ ] Notificare toast la login: "3 bonuri cu erori au fost șterse (expirate)"
|
||||
- [ ] Utilizatorul poate vedea/extinde TTL în setări (opțional, nice-to-have)
|
||||
- [ ] pytest tests pass
|
||||
|
||||
### US-009: Auto-Resume Polling la Refresh/Revenire
|
||||
**Ca** utilizator
|
||||
**Vreau** ca procesarea să continue și să văd statusul actualizat automat când revin
|
||||
**Pentru că** nu vreau să pierd progresul sau să fac acțiuni manuale
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Procesarea OCR pe backend CONTINUĂ indiferent de starea browser-ului
|
||||
- [ ] La refresh/revenire, frontend detectează batch-uri incomplete și reia polling automat
|
||||
- [ ] Starea se stochează în localStorage: `active_batch_ids`
|
||||
- [ ] La completare, se curăță din localStorage
|
||||
- [ ] Dacă utilizatorul revine după ce procesarea s-a terminat, vede statusul final corect
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser that progress resumes after refresh
|
||||
|
||||
**Detalii tehnice:**
|
||||
- Backend worker pool procesează independent de frontend
|
||||
- La `onMounted`, verifică localStorage pentru batch-uri active
|
||||
- Query backend pentru status curent al fiecărui batch
|
||||
- Reia polling doar pentru batch-uri care încă nu sunt complete
|
||||
- Afișează toast: "Procesare în curs detectată, se actualizează..."
|
||||
|
||||
### US-010: Lock Row în Procesare (Read-Only)
|
||||
**Ca** utilizator
|
||||
**Vreau** ca bonurile în procesare să fie read-only
|
||||
**Pentru că** nu are sens să editez un bon care încă nu e complet
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Bonuri cu `processing_status='pending'` sau `'processing'` au butoanele dezactivate
|
||||
- [ ] Visual: row are opacity 0.7 sau border-left albastru
|
||||
- [ ] Tooltip pe butoane: "Bonul se procesează, vă rugăm așteptați"
|
||||
- [ ] După completare, row-ul devine interactiv normal
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser that buttons are disabled during processing
|
||||
|
||||
### US-011: Backend - Stocare Batch și Processing Status
|
||||
**Ca** developer
|
||||
**Vreau** să extind schema Receipt pentru a stoca informații de batch
|
||||
**Pentru că** am nevoie de persistență pentru tracking
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Câmpuri noi în tabelul `receipts`:
|
||||
- `batch_id` (string, nullable) - UUID batch
|
||||
- `processing_status` (enum: pending/processing/completed/failed, nullable)
|
||||
- `processing_error` (text, nullable) - mesaj eroare complet
|
||||
- `file_hash` (string, nullable) - SHA-256 pentru duplicate detection
|
||||
- `processing_started_at` (datetime, nullable)
|
||||
- `processing_completed_at` (datetime, nullable)
|
||||
- [ ] Index pe `batch_id` pentru query-uri eficiente
|
||||
- [ ] Index pe `file_hash` pentru duplicate detection
|
||||
- [ ] Migration reversibilă
|
||||
- [ ] pytest tests pass
|
||||
- [ ] Alembic migration works
|
||||
|
||||
### US-012: Backend - Endpoint List cu Batch Info
|
||||
**Ca** developer
|
||||
**Vreau** să extind endpoint-ul GET /receipts pentru a include info de batch
|
||||
**Pentru că** frontend-ul are nevoie de toate datele într-un singur request
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Response include câmpurile noi pentru fiecare receipt
|
||||
- [ ] Filtrare pe `processing_status` funcționează
|
||||
- [ ] Filtrare pe `batch_id` funcționează
|
||||
- [ ] Sorting pe `processing_started_at` funcționează
|
||||
- [ ] Include count-uri pentru fiecare processing_status în response (pentru chips)
|
||||
- [ ] pytest tests pass
|
||||
|
||||
### US-013: Eliminare Pagină Separată Bulk Upload
|
||||
**Ca** developer
|
||||
**Vreau** să elimin pagina separată de bulk upload
|
||||
**Pentru că** funcționalitatea e acum integrată în lista principală
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Șterge `/data-entry/bulk-upload` route
|
||||
- [ ] Șterge `BulkUploadView.vue`
|
||||
- [ ] Redirect de la vechea rută la `/data-entry` (pentru bookmarks)
|
||||
- [ ] Actualizare meniu/navigație să nu mai arate link-ul separat
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser that old route redirects correctly
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
|
||||
1. [REQ-001] Drag & drop pe toată pagina de bonuri activează upload overlay
|
||||
2. [REQ-002] Bonurile din batch-uri sunt grupate vizual în tabel
|
||||
3. [REQ-003] Coloană dedicată pentru status procesare (pending/processing/success/failed)
|
||||
4. [REQ-004] Mesajele de eroare sunt vizibile direct în listă
|
||||
5. [REQ-005] Fișierele duplicate (același hash) sunt respinse automat
|
||||
6. [REQ-006] Retry disponibil per bon și per batch pentru erori
|
||||
7. [REQ-007] Bonurile cu erori se șterg automat după 7 zile
|
||||
8. [REQ-008] Starea procesării persistă la refresh
|
||||
9. [REQ-009] Bonurile în procesare sunt read-only (locked)
|
||||
10. [REQ-010] Procesarea folosește configurația existentă din .env pentru workers paraleli
|
||||
11. [REQ-011] Procesarea backend continuă independent de browser; polling se reia automat la revenire
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
|
||||
- **NU** implementăm WebSocket pentru status updates (rămânem pe long-polling existent)
|
||||
- **NU** adăugăm suport pentru editare inline în listă
|
||||
- **NU** implementăm preview imagine în row (poate fi adăugat ulterior)
|
||||
- **NU** facem grouping recursiv (batch în batch)
|
||||
- **NU** implementăm undo pentru retry
|
||||
- **NU** adăugăm notificări push/email la completare batch
|
||||
- **NU** facem drag & drop pentru reordonare (doar upload)
|
||||
|
||||
## 6. Considerații Tehnice
|
||||
|
||||
### Schema DB Extinsă
|
||||
|
||||
```sql
|
||||
ALTER TABLE receipts ADD COLUMN batch_id VARCHAR(36);
|
||||
ALTER TABLE receipts ADD COLUMN processing_status VARCHAR(20)
|
||||
CHECK (processing_status IN ('pending', 'processing', 'completed', 'failed'));
|
||||
ALTER TABLE receipts ADD COLUMN processing_error TEXT;
|
||||
ALTER TABLE receipts ADD COLUMN file_hash VARCHAR(64);
|
||||
ALTER TABLE receipts ADD COLUMN processing_started_at TIMESTAMP;
|
||||
ALTER TABLE receipts ADD COLUMN processing_completed_at TIMESTAMP;
|
||||
|
||||
CREATE INDEX idx_receipts_batch_id ON receipts(batch_id);
|
||||
CREATE INDEX idx_receipts_file_hash ON receipts(file_hash);
|
||||
CREATE INDEX idx_receipts_processing_status ON receipts(processing_status);
|
||||
```
|
||||
|
||||
### Component Architecture
|
||||
|
||||
```
|
||||
ReceiptsListView.vue (enhanced)
|
||||
├── DragDropOverlay.vue (new - fullscreen overlay)
|
||||
├── BatchGroupHeader.vue (new - expandable group header)
|
||||
├── ProcessingStatusCell.vue (new - status + error display)
|
||||
├── QuickFilterChips.vue (enhanced - add processing filters)
|
||||
└── DataTable (PrimeVue with row grouping)
|
||||
```
|
||||
|
||||
### Store Changes
|
||||
|
||||
```javascript
|
||||
// receiptsStore.js - extended
|
||||
state: {
|
||||
// ... existing
|
||||
processingStats: {
|
||||
pending_count: 0,
|
||||
processing_count: 0,
|
||||
failed_count: 0
|
||||
},
|
||||
activeBatchIds: [] // for localStorage persistence
|
||||
}
|
||||
|
||||
// batchProgressStore.js - reuse existing
|
||||
// Just connect to receiptsStore for updates
|
||||
```
|
||||
|
||||
### ⚠️ REGULI CSS OBLIGATORII
|
||||
|
||||
**CITEȘTE ÎNTÂI:** `docs/ONBOARDING_CSS.md` și `docs/DESIGN_TOKENS.md`
|
||||
|
||||
#### Processing Status Colors
|
||||
| Status | Background | Text/Icon | Border |
|
||||
|--------|------------|-----------|--------|
|
||||
| Pending | `var(--surface-hover)` | `var(--text-color-secondary)` | - |
|
||||
| Processing | `var(--blue-50)` | `var(--blue-600)` | `var(--blue-500)` |
|
||||
| Success | `var(--green-50)` | `var(--green-600)` | - |
|
||||
| Failed | `var(--red-50)` | `var(--red-600)` | `var(--red-500)` |
|
||||
|
||||
#### Drag Overlay
|
||||
```css
|
||||
.drag-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.drag-overlay-content {
|
||||
background: var(--surface-card);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-xl);
|
||||
text-align: center;
|
||||
border: 3px dashed var(--primary-500);
|
||||
}
|
||||
```
|
||||
|
||||
#### Row Grouping Header
|
||||
```css
|
||||
.batch-group-header {
|
||||
background: var(--surface-ground);
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
font-weight: var(--font-semibold);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.batch-group-header:hover {
|
||||
background: var(--surface-hover);
|
||||
}
|
||||
```
|
||||
|
||||
### Dependențe
|
||||
|
||||
- Refolosește `batchProgressStore.js` existent
|
||||
- Refolosește componente din `components/bulk/` unde posibil
|
||||
- Extinde `receiptsStore.js` cu câmpuri noi
|
||||
|
||||
### Riscuri Tehnice
|
||||
|
||||
- **Row grouping performance:** Pentru liste mari (>500 bonuri), grouping poate fi lent
|
||||
- Mitigare: Virtualizare sau paginare strictă
|
||||
- **LocalStorage limits:** Dacă sunt multe batch-uri active
|
||||
- Mitigare: Stochează doar ID-uri, nu date complete
|
||||
- **Race condition la retry:** Dacă utilizatorul face retry în timp ce procesarea originală se termină
|
||||
- Mitigare: Check status înainte de retry, abort dacă deja completat
|
||||
|
||||
## 7. Considerații UI/UX
|
||||
|
||||
### Layout Update
|
||||
|
||||
```
|
||||
ReceiptsListView.vue
|
||||
├── PageHeader
|
||||
├── QuickFilterChips (enhanced: + Processing | Erori)
|
||||
├── FiltersRow (existing)
|
||||
├── DragDropOverlay (fullscreen, hidden until drag)
|
||||
└── DataTable
|
||||
├── BatchGroupHeader (expandable)
|
||||
│ └── Receipt rows (with new Processing column)
|
||||
├── BatchGroupHeader
|
||||
│ └── Receipt rows
|
||||
└── "Alte bonuri" group (receipts fără batch)
|
||||
```
|
||||
|
||||
### Stări UI
|
||||
|
||||
| Stare | Visual |
|
||||
|-------|--------|
|
||||
| **Idle** | Pagină normală, fără overlay |
|
||||
| **Dragging** | Overlay fullscreen cu drop zone |
|
||||
| **Uploading** | Toast progress + batch nou apare în listă |
|
||||
| **Processing** | Rows cu spinner, read-only |
|
||||
| **Complete** | Rows normale, toast success |
|
||||
| **Has Errors** | Rows roșii cu mesaj, buton retry |
|
||||
|
||||
### Mobile Considerations
|
||||
|
||||
- Drag & drop nu funcționează pe mobile - oferă buton "Upload" explicit
|
||||
- Row grouping se transformă în cards grupate
|
||||
- Error messages în accordion expandabil
|
||||
|
||||
## 8. Success Metrics
|
||||
|
||||
- **Zero bonuri pierdute:** 100% vizibilitate pentru toate fișierele uploadate
|
||||
- **Retry success rate:** > 50% dintre erorile retry-uite să reușească
|
||||
- **Auto-cleanup:** < 100 bonuri cu erori la orice moment (TTL 7 zile)
|
||||
- **User satisfaction:** Reducere support tickets pentru "nu găsesc bonul"
|
||||
|
||||
## 9. Open Questions
|
||||
|
||||
- [x] Comportament la refresh → **Backend continuă procesarea, frontend reia polling automat la revenire**
|
||||
- [x] Auto-cleanup după 7 zile → **Confirmat**
|
||||
- [x] Retry individual + batch → **Confirmat ambele**
|
||||
- [x] Row complet blocat în procesare → **Confirmat**
|
||||
- [x] Grupare vizuală per batch → **Confirmat, row grouping**
|
||||
- [x] Mesaj eroare prescurtat → **Confirmat, 50 caractere**
|
||||
- [x] Drag anywhere → **Confirmat, overlay fullscreen**
|
||||
- [x] Quick filter chips → **Confirmat**
|
||||
- [x] Reject duplicate (hash) → **Confirmat**
|
||||
- [x] Batch info permanent → **Confirmat, rămâne în DB**
|
||||
- [x] Workers paraleli → **Configurabil din .env, existent**
|
||||
|
||||
---
|
||||
|
||||
## 10. Dependențe între User Stories
|
||||
|
||||
```
|
||||
US-011 (DB Schema) ─────────────────────────────────────────┐
|
||||
↓ │
|
||||
US-012 (API List + Batch Info) ─────────────────────────────┤
|
||||
↓ │
|
||||
US-007 (Duplicate Detection) ←───────────────────────────────┤
|
||||
↓ │
|
||||
US-001 (Drag Anywhere) ─────────────────────────────────────┤
|
||||
↓ │
|
||||
US-002 (Row Grouping) ←──────────────────────────────────────┤
|
||||
↓ │
|
||||
US-003 (Processing Status Column) ←──────────────────────────┤
|
||||
↓ │
|
||||
US-004 (Error Message Display) ←─────────────────────────────┤
|
||||
↓ │
|
||||
US-005 (Quick Filter Chips) │
|
||||
↓ │
|
||||
US-010 (Lock Row Processing) ←───────────────────────────────┤
|
||||
↓ │
|
||||
US-006 (Retry Individual + All) │
|
||||
↓ │
|
||||
US-009 (Persistence at Refresh) │
|
||||
↓ │
|
||||
US-008 (Auto-Cleanup 7 Days) │
|
||||
↓ │
|
||||
US-013 (Remove Old Bulk Page) │
|
||||
```
|
||||
|
||||
**Ordine recomandată de implementare:**
|
||||
|
||||
1. **US-011:** Backend - Extindere schema DB
|
||||
2. **US-012:** Backend - Endpoint list cu batch info
|
||||
3. **US-007:** Backend - Duplicate detection (file hash)
|
||||
4. **US-001:** Frontend - Drag Anywhere Overlay
|
||||
5. **US-002:** Frontend - Row Grouping per Batch
|
||||
6. **US-003:** Frontend - Processing Status Column
|
||||
7. **US-004:** Frontend - Error Message Display
|
||||
8. **US-005:** Frontend - Quick Filter Chips
|
||||
9. **US-010:** Frontend - Lock Row în Procesare
|
||||
10. **US-006:** Frontend - Retry Individual + All
|
||||
11. **US-009:** Frontend - Persistence at Refresh
|
||||
12. **US-008:** Backend - Auto-Cleanup Job
|
||||
13. **US-013:** Cleanup - Remove Old Bulk Page
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2026-01-11
|
||||
**Author:** Claude Code
|
||||
**Status:** Draft - Pending Review
|
||||
**Predecessor:** `prd-bulk-receipt-upload.md` (implementat)
|
||||
@@ -1,279 +0,0 @@
|
||||
# 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)
|
||||
@@ -1,213 +0,0 @@
|
||||
# PRD: Dashboard Desktop Cleanup - Eliminare Duplicate și Reorganizare Layout
|
||||
|
||||
## 1. Introducere
|
||||
|
||||
Dashboard-ul desktop afișează în prezent carduri duplicate pentru Trezorerie, Clienți și Furnizori. Există `SolduriCompactCard` (în secțiunea `desktop-solduri-section`) și `CollapsibleCard` cu grafice (în secțiunea `metrics-row`). Scopul este eliminarea duplicatelor, păstrând doar `CollapsibleCard`-urile cu grafice, dar reorganizate astfel încât textul cu valorile să apară ÎNAINTE de grafice pentru vizibilitate mai bună.
|
||||
|
||||
## 2. Obiective
|
||||
|
||||
### Obiectiv Principal
|
||||
- Eliminarea cardurilor duplicate de pe dashboard-ul desktop, păstrând doar `CollapsibleCard`-urile cu conținut reorganizat (text → grafice)
|
||||
|
||||
### Obiective Secundare
|
||||
- Îmbunătățirea vizibilității valorilor principale (afișate înaintea graficelor)
|
||||
- Menținerea unui layout compact și informativ
|
||||
- Păstrarea funcționalității mobile neschimbată
|
||||
|
||||
### Metrici de Succes
|
||||
- Zero carduri duplicate pe dashboard desktop
|
||||
- Valorile principale vizibile fără scroll
|
||||
- Același număr de informații disponibile ca înainte
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
### US-001: Eliminare SolduriCompactCard de pe Desktop
|
||||
**Ca** utilizator desktop
|
||||
**Vreau** să văd doar un set de carduri pentru fiecare metric
|
||||
**Pentru că** duplicatele creează confuzie și ocupă spațiu inutil
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Secțiunea `desktop-solduri-section` este eliminată din `DashboardView.vue` pentru desktop
|
||||
- [ ] Rămân doar cele 4 `CollapsibleCard`-uri: Trezorerie, Cash Flow, Clienți, Furnizori
|
||||
- [ ] Layout-ul grid 2x2 din `metrics-row` rămâne neschimbat
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser că pe desktop nu mai există duplicate
|
||||
|
||||
### US-002: Eliminare Icoane din Header-ul CollapsibleCard
|
||||
**Ca** utilizator
|
||||
**Vreau** un header curat, fără icoane/emoji-uri
|
||||
**Pentru că** vreau un design minimalist și profesional
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Prop-ul `icon` nu mai este transmis către `CollapsibleCard` în `DashboardView.vue`
|
||||
- [ ] Header-ul afișează doar: "Label Valoare ▼" (ex: "Trezorerie 125.500 RON ▼")
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser că header-urile nu au icoane
|
||||
|
||||
### US-003: Reorganizare TreasuryDualCard - Text Înainte de Grafice
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd valorile Casa/Bancă și breakdown-ul ÎNAINTE de grafice
|
||||
**Pentru că** textul cu valorile este mai important decât graficele
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] În `TreasuryDualCard.vue`, secțiunea `breakdown-section` se mută ÎNAINTE de `sparkline-dual-container`
|
||||
- [ ] Ordinea în body devine: values-section → breakdown-section → sparkline-dual-container
|
||||
- [ ] Breakdown-ul Casa/Bancă cu sub-conturi rămâne expandabil
|
||||
- [ ] Graficele apar la sfârșit
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser că textul apare înainte de grafice
|
||||
|
||||
### US-004: Reorganizare ClientiBalanceCard - Text Înainte de Grafice
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd breakdown-ul (În termen/Restant) ÎNAINTE de grafic
|
||||
**Pentru că** valorile text sunt prioritare față de grafic
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] În `ClientiBalanceCard.vue`, secțiunea `breakdown-section` se mută ÎNAINTE de `metric-sparkline`
|
||||
- [ ] Ordinea în body devine: value-section → breakdown-section → metric-sparkline
|
||||
- [ ] Breakdown-ul În termen/Restant cu perioade rămâne expandabil
|
||||
- [ ] Graficul apare la sfârșit
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser că textul apare înainte de grafic
|
||||
|
||||
### US-005: Reorganizare FurnizoriBalanceCard - Text Înainte de Grafice
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd breakdown-ul (În termen/Restant) ÎNAINTE de grafic
|
||||
**Pentru că** consistență cu celelalte carduri
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] În `FurnizoriBalanceCard.vue`, secțiunea `breakdown-section` se mută ÎNAINTE de `metric-sparkline`
|
||||
- [ ] Ordinea în body devine: value-section → breakdown-section → metric-sparkline
|
||||
- [ ] Breakdown-ul În termen/Restant cu perioade rămâne expandabil
|
||||
- [ ] Graficul apare la sfârșit
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser că textul apare înainte de grafic
|
||||
|
||||
### US-006: Păstrare Layout Mobile Neschimbat
|
||||
**Ca** utilizator mobile
|
||||
**Vreau** ca experiența pe mobil să rămână neschimbată
|
||||
**Pentru că** layout-ul mobile este deja optimizat
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] `SwipeableCards` pe mobile rămâne identic
|
||||
- [ ] Prima pagină cu `solduri-grid-2x2` (4x `SolduriCompactCard`) rămâne pe mobile
|
||||
- [ ] Paginile 2-5 cu carduri grafice rămân neschimbate pe mobile
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser (mobile viewport) că experiența nu s-a schimbat
|
||||
|
||||
### US-007: Grafice Colapsabile și Colapsate Implicit
|
||||
**Ca** utilizator desktop
|
||||
**Vreau** să pot expanda/colasa graficele separat
|
||||
**Pentru că** vreau să văd rapid valorile fără să scrollez peste grafice
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Secțiunea cu grafice are un header clickabil: "Grafice evoluție ▶" (collapsed) / "▼" (expanded)
|
||||
- [ ] Graficele sunt COLAPSATE implicit (`chartsExpanded = false`)
|
||||
- [ ] La click pe header, graficele se expandează la dimensiunea lor completă (150px height fiecare)
|
||||
- [ ] Se folosește `v-show` pentru toggle (păstrează Chart.js instances în memorie)
|
||||
- [ ] Header-ul graficelor are styling consistent cu breakdown headers (font, culoare, spacing)
|
||||
- [ ] Implementat în: `TreasuryDualCard.vue`, `ClientiBalanceCard.vue`, `FurnizoriBalanceCard.vue`
|
||||
- [ ] `CashFlowMetricCard.vue` primește același treatment (grafic colapsabil)
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser că graficele sunt collapsed implicit și se expandează corect la click
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
|
||||
1. [REQ-001] Pe desktop (`!isMobile`), secțiunea `desktop-solduri-section` nu trebuie să se mai afișeze
|
||||
2. [REQ-002] Prop-ul `icon` trebuie eliminat din toate utilizările `CollapsibleCard` în `DashboardView.vue`
|
||||
3. [REQ-003] În cardurile cu grafice (Treasury, Clienti, Furnizori, CashFlow), ordinea secțiunilor trebuie să fie: Header → Text/Breakdown → Grafice (colapsabile)
|
||||
4. [REQ-004] Breakdown-urile (Casa/Bancă, În termen/Restant) rămân expandabile cu click
|
||||
5. [REQ-005] Pe mobile, nimic nu se schimbă - condiția `isMobile` protejează codul existent
|
||||
6. [REQ-006] Graficele din toate cardurile trebuie să fie colapsabile și COLAPSATE implicit, cu header clickabil pentru expand
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
|
||||
- NU modificăm componentele `SolduriCompactCard` - doar le ascundem pe desktop
|
||||
- NU schimbăm layout-ul mobile
|
||||
- NU modificăm stilul/dimensiunea graficelor - doar adăugăm collapse toggle
|
||||
- NU modificăm `CollapsibleCard.vue` component-ul shared
|
||||
- NU modificăm logica de date/calcul din carduri
|
||||
|
||||
## 6. Considerații Tehnice
|
||||
|
||||
### Stack/Tehnologii
|
||||
- Vue 3 Composition API
|
||||
- Chart.js pentru grafice
|
||||
- CSS cu design tokens existente
|
||||
|
||||
### Patterns de Urmat
|
||||
- Utilizare `v-if="!isMobile"` pentru condiții desktop
|
||||
- Utilizare `v-show` pentru grafice colapsabile (păstrează Chart.js instances)
|
||||
- Design tokens din `DESIGN_TOKENS.md`
|
||||
- BEM naming convention pentru CSS
|
||||
|
||||
### Fișiere Afectate
|
||||
- `src/modules/reports/views/DashboardView.vue` - eliminare secțiune și icoane
|
||||
- `src/modules/reports/components/dashboard/cards/TreasuryDualCard.vue` - reordonare secțiuni + grafice colapsabile
|
||||
- `src/modules/reports/components/dashboard/cards/ClientiBalanceCard.vue` - reordonare secțiuni + grafice colapsabile
|
||||
- `src/modules/reports/components/dashboard/cards/FurnizoriBalanceCard.vue` - reordonare secțiuni + grafice colapsabile
|
||||
- `src/modules/reports/components/dashboard/cards/CashFlowMetricCard.vue` - grafice colapsabile
|
||||
|
||||
### Dependențe
|
||||
- Nicio dependență nouă necesară
|
||||
|
||||
### Riscuri Tehnice
|
||||
- ~~Chart.js poate avea probleme dacă canvas-ul nu este vizibil la render~~ → Rezolvat cu `v-show` care păstrează DOM-ul
|
||||
- Chart.js instances rămân în memorie când graficele sunt colapsate - acceptabil pentru 4 carduri
|
||||
|
||||
## 7. Considerații UI/UX
|
||||
|
||||
### Layout Nou (Desktop) - Stare Implicită (Collapsed)
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ Trezorerie 125.500 RON ▼│ ← Header card (fără icoane)
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Casa 35.500 RON │ ← Valori principale (vizibile)
|
||||
│ Bancă 90.000 RON │
|
||||
│ ▶ Casa breakdown (click expand) │ ← Detalii conturi (expandabile)
|
||||
│ ▶ Bancă breakdown (click expand) │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ▶ Grafice evoluție │ ← COLLAPSED IMPLICIT
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Layout Nou (Desktop) - Grafice Expandate
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ Trezorerie 125.500 RON ▼│
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Casa 35.500 RON │
|
||||
│ Bancă 90.000 RON │
|
||||
│ ▶ Casa breakdown │
|
||||
│ ▶ Bancă breakdown │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ▼ Grafice evoluție │ ← EXPANDED (click toggle)
|
||||
│ ┌─────────────────────────────────────────┐ │
|
||||
│ │ 📈 [Grafic Casa - 150px height] │ │ ← Full size charts
|
||||
│ │ 📈 [Grafic Bancă - 150px height] │ │
|
||||
│ └─────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Dark Mode
|
||||
- Toate componentele folosesc deja design tokens compatibile dark mode
|
||||
- Nu necesită modificări suplimentare
|
||||
|
||||
### Accesibilitate
|
||||
- Header-ul CollapsibleCard are deja `role="button"` și `tabindex="0"`
|
||||
- Breakdown-urile au keyboard support pentru expand/collapse
|
||||
|
||||
## 8. Success Metrics
|
||||
|
||||
- **Eliminare duplicate**: 100% (3 carduri duplicate eliminate)
|
||||
- **Timp de scanare**: valorile principale vizibile în primele 2 secunde
|
||||
- **Funcționalitate păstrată**: 100% (aceleași date disponibile, doar reorganizate)
|
||||
|
||||
## 9. Open Questions
|
||||
|
||||
- [x] Confirmat: Se elimină complet `desktop-solduri-section` pe desktop
|
||||
- [x] Confirmat: Header fără icoane
|
||||
- [x] Confirmat: Text/breakdown înainte de grafice
|
||||
- [x] Confirmat: Layout grid 2x2 rămâne
|
||||
- [x] Confirmat: Mobile neschimbat
|
||||
- [x] Confirmat: Grafice colapsabile și colapsate implicit (cu `v-show`)
|
||||
@@ -1,176 +0,0 @@
|
||||
# PRD: Dashboard cu Solduri - Versiunea 2 (Corectă)
|
||||
|
||||
## 1. Introducere
|
||||
Adăugare secțiune Solduri în Dashboard păstrând paginile originale cu grafice. Pe mobil, soldurile sunt prima pagină din swipe (grid 2x2), iar graficele sunt paginile 2-5 (ca în main). Pe desktop, două secțiuni separate: Solduri sus, Grafice jos.
|
||||
|
||||
## 2. Obiective
|
||||
|
||||
### Obiectiv Principal
|
||||
- Prima pagină din swipe pe mobil = 4 carduri compacte cu solduri
|
||||
- Paginile 2-5 din swipe = cardurile originale cu grafice (păstrate exact ca în main)
|
||||
|
||||
### Obiective Secundare
|
||||
- Desktop: Secțiune Solduri + Secțiune Grafice (fără titluri vizibile)
|
||||
- Eliminare MaturityAndDetailsCard de pe Dashboard
|
||||
- Carduri solduri compacte cu expand pentru detalii
|
||||
|
||||
### Metrici de Succes
|
||||
- Mobil: 5 pagini de swipe (Solduri + 4 grafice)
|
||||
- Desktop: 2 secțiuni vizual separate
|
||||
- Cardurile grafice rămân IDENTICE cu cele din main
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
### US-2001: Creare componentă SolduriCompactCard (reutilizabilă)
|
||||
**Ca** dezvoltator
|
||||
**Vreau** o componentă card compactă pentru solduri
|
||||
**Pentru că** o voi folosi în grid 2x2 pe mobil și desktop
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Creează SolduriCompactCard.vue în src/modules/reports/components/solduri/
|
||||
- [ ] Props: type (trezorerie|clienti|furnizori|tva), total, breakdown (object)
|
||||
- [ ] Afișează: icon + label + valoare principală
|
||||
- [ ] Click expandează/colapsează breakdown-ul (conturi, buckets)
|
||||
- [ ] Folosește design tokens pentru culori și spațiere
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-2002: Grid 2x2 Solduri pentru prima pagină swipe pe mobil
|
||||
**Ca** utilizator pe mobil
|
||||
**Vreau** prima pagină din swipe să fie un grid 2x2 cu 4 carduri solduri
|
||||
**Pentru că** văd toate soldurile dintr-o privire
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Prima pagină din SwipeableCards conține un grid 2x2
|
||||
- [ ] Ordinea: Trezorerie | Clienți / Furnizori | TVA
|
||||
- [ ] Fiecare card e SolduriCompactCard cu props corecte
|
||||
- [ ] Touch target minim 44x44px
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser mobil că prima pagină e grid-ul cu solduri
|
||||
|
||||
### US-2003: Păstrare carduri grafice originale pe paginile 2-5 mobil
|
||||
**Ca** utilizator pe mobil
|
||||
**Vreau** paginile 2-5 din swipe să fie cardurile cu grafice originale
|
||||
**Pentru că** vreau să le văd individual cu toate detaliile
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Pagina 2: TreasuryDualCard (exact ca în main)
|
||||
- [ ] Pagina 3: CashFlowMetricCard (exact ca în main)
|
||||
- [ ] Pagina 4: ClientiBalanceCard (exact ca în main)
|
||||
- [ ] Pagina 5: FurnizoriBalanceCard (exact ca în main)
|
||||
- [ ] SwipeableCards folosește totalCards=5 sau similar
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify în browser că swipe funcționează între toate 5 paginile
|
||||
|
||||
### US-2004: Secțiune Solduri pe Desktop (grid 2x2 sau 4 în linie)
|
||||
**Ca** utilizator pe desktop
|
||||
**Vreau** să văd soldurile într-o secțiune separată sus
|
||||
**Pentru că** sunt cele mai importante informații
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Secțiune Solduri în partea de sus a Dashboard-ului
|
||||
- [ ] Fără titlu vizibil (doar layout)
|
||||
- [ ] 4 SolduriCompactCard în grid responsive (2x2 sau 4 în linie pe ecran lat)
|
||||
- [ ] Sub solduri: cardurile originale cu grafice
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify în browser desktop că ambele secțiuni sunt vizibile
|
||||
|
||||
### US-2005: Eliminare MaturityAndDetailsCard de pe Dashboard
|
||||
**Ca** utilizator
|
||||
**Vreau** Dashboard-ul să nu mai aibă tabelul detaliat de scadențe
|
||||
**Pentru că** există deja pagina Maturity Analysis separată
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Șterge MaturityAndDetailsCard din DashboardView.vue
|
||||
- [ ] Șterge div-ul .comparison-row
|
||||
- [ ] Șterge importul componentei
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify: Dashboard nu mai are tabel
|
||||
|
||||
### US-2006: Integrare date Solduri din dashboardStore
|
||||
**Ca** dezvoltator
|
||||
**Vreau** cardurile solduri să folosească datele existente din store
|
||||
**Pentru că** nu vreau request-uri API duplicate
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Trezorerie: dashboardStore.treasuryData (casa.total, banca.total, items)
|
||||
- [ ] Clienți: dashboardStore.netBalanceData.clienti_total + breakdown
|
||||
- [ ] Furnizori: dashboardStore.netBalanceData.furnizori_total + breakdown
|
||||
- [ ] TVA: dashboardStore (calculat din summary sau endpoint)
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-2007: Indicatori vizuali pentru starea financiară
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd indicatori de avertizare pe carduri
|
||||
**Pentru că** identific rapid problemele
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Indicator roșu pe Clienți/Furnizori dacă restanță > 20%
|
||||
- [ ] TVA roșu dacă e de plată, verde dacă e de recuperat
|
||||
- [ ] Folosește var(--red-500), var(--green-500)
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-2008: Buton Refresh în header Dashboard
|
||||
**Ca** utilizator
|
||||
**Vreau** un buton de refresh în header
|
||||
**Pentru că** vreau să actualizez manual datele
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Pe mobil: icon refresh în MobileTopBar actions
|
||||
- [ ] Pe desktop: buton lângă titlu Dashboard
|
||||
- [ ] Animație spinner în timpul încărcării
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
1. [REQ-001] Cardurile grafice rămân IDENTICE cu cele din main
|
||||
2. [REQ-002] Swipe pe mobil funcționează fluid între toate 5 paginile
|
||||
3. [REQ-003] Desktop layout responsive (secțiunile se adaptează la lățime)
|
||||
4. [REQ-004] Funcționează în dark mode
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
- NU modificăm cardurile cu grafice (TreasuryDualCard, etc.)
|
||||
- NU adăugăm funcționalități noi de analiză
|
||||
- NU schimbăm API-ul backend
|
||||
- NU facem KPIStrip (bandă compactă) - facem carduri individuale
|
||||
|
||||
## 6. Layout Vizual
|
||||
|
||||
### MOBIL (5 pagini swipe):
|
||||
```
|
||||
[Pagina 1 - Solduri Grid 2x2]
|
||||
┌──────────┬──────────┐
|
||||
│TREZORERIE│ CLIENȚI │
|
||||
│ 150.000 │ 89.000 │
|
||||
│[expand] │[expand] │
|
||||
├──────────┼──────────┤
|
||||
│FURNIZORI │ TVA │
|
||||
│ 45.000 │ +15.000 │
|
||||
│[expand] │[expand] │
|
||||
└──────────┴──────────┘
|
||||
• ○ ○ ○ ○ (dot indicator)
|
||||
|
||||
[Pagina 2] TreasuryDualCard (grafice)
|
||||
[Pagina 3] CashFlowMetricCard (grafice)
|
||||
[Pagina 4] ClientiBalanceCard (grafice)
|
||||
[Pagina 5] FurnizoriBalanceCard (grafice)
|
||||
```
|
||||
|
||||
### DESKTOP:
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Dashboard [↻ Refresh] │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │TREZORERIE│ │ CLIENȚI │ │FURNIZORI│ │ TVA │ ← Solduri │
|
||||
│ │ 150.000 │ │ 89.000 ●│ │ 45.000 │ │+15.000 │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ ┌───────────────────┐ ┌───────────────────┐ │
|
||||
│ │ Treasury Trend │ │ Cash Flow │ ← Grafice │
|
||||
│ │ [sparkline] │ │ [sparkline] │ │
|
||||
│ └───────────────────┘ └───────────────────┘ │
|
||||
│ ┌───────────────────┐ ┌───────────────────┐ │
|
||||
│ │ Clienți Balance │ │ Furnizori Balance │ │
|
||||
│ │ [sparkline] │ │ [sparkline] │ │
|
||||
│ └───────────────────┘ └───────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
@@ -1,325 +0,0 @@
|
||||
# PRD: Card Indicatori Financiari în Dashboard Solduri
|
||||
|
||||
## 1. Introducere
|
||||
|
||||
Adăugarea unui card nou în dashboard-ul solduri cu indicatori financiari esențiali pentru evaluare bancară/creditare și analiză sănătate financiară a firmei. Indicatorii vor include rate de lichiditate, eficiență, risc, și scorul Altman Z-Score pentru predicția falimentului - aceiași indicatori pe care îi folosesc băncile și evaluatorii pentru acordarea de credite.
|
||||
|
||||
## 2. Obiective
|
||||
|
||||
### Obiectiv Principal
|
||||
- Oferirea unei viziuni complete asupra sănătății financiare a firmei într-un singur card, cu indicatori calculați automat din datele contabile
|
||||
|
||||
### Obiective Secundare
|
||||
- Vizualizarea evoluției indicatorilor pe 12 luni (sparklines)
|
||||
- Comparație Year-over-Year pentru fiecare indicator
|
||||
- Alertare vizuală (cod culoare) pentru valori în afara pragurilor recomandate
|
||||
- Calculul scorului Altman Z-Score pentru evaluarea riscului de faliment
|
||||
|
||||
### Metrici de Succes
|
||||
- Toți cei 22+ indicatori sunt calculați corect și afișați
|
||||
- Sparklines afișează evoluția corectă pe 12 luni
|
||||
- Cod culoare (verde/galben/roșu) corespunde pragurilor standard
|
||||
- Timpul de încărcare < 2 secunde (cu cache)
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
### US-001: Backend - Serviciu Agregare Conturi Balanță
|
||||
**Ca** dezvoltator backend
|
||||
**Vreau** un serviciu care agregă soldurile din balanța de verificare (VBAL) pe clase de conturi
|
||||
**Pentru că** am nevoie de date agregate pentru calculul indicatorilor de bilanț și Altman Z-Score
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Creat `backend/modules/reports/services/financial_indicators_service.py`
|
||||
- [ ] Metoda `get_balance_sheet_aggregates()` returnează solduri agregate pentru: active_imobilizate, stocuri, creante, disponibilitati, capital_propriu, rezultat, datorii_termen_lung, datorii_curente, venituri, cheltuieli_operationale
|
||||
- [ ] Query-ul folosește VBAL view cu LIKE pentru prefixe conturi (ex: `cont LIKE '20%'`)
|
||||
- [ ] Cache implementat cu TTL 30 minute
|
||||
- [ ] Unit test verifică structura răspunsului
|
||||
|
||||
### US-002: Backend - Calcul Indicatori Lichiditate
|
||||
**Ca** utilizator al dashboard-ului
|
||||
**Vreau** să văd indicatorii de lichiditate calculați automat
|
||||
**Pentru că** vreau să știu dacă firma poate plăti datoriile pe termen scurt
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Calculat `lichiditate_curenta` = Active Curente / Datorii Curente
|
||||
- [ ] Calculat `lichiditate_imediata` (Quick Ratio) = (Trezorerie + Creanțe) / Datorii Curente
|
||||
- [ ] Calculat `lichiditate_vedere` (Cash Ratio) = Trezorerie / Datorii Curente
|
||||
- [ ] Fiecare indicator include: valoare, status (good/warning/danger), prag_min, prag_max
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-003: Backend - Calcul Indicatori Eficiență
|
||||
**Ca** utilizator al dashboard-ului
|
||||
**Vreau** să văd indicatorii de eficiență (DSO, DPO, rate)
|
||||
**Pentru că** vreau să știu cât de repede convertesc resursele în bani
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Calculat `dso` (Durata Încasare) = (Sold Clienți / Facturări Lunare) × 30 zile
|
||||
- [ ] Calculat `dpo` (Durata Plată) = (Sold Furnizori / Achiziții Lunare) × 30 zile
|
||||
- [ ] Calculat `cash_conversion_cycle` = DSO - DPO
|
||||
- [ ] Calculat `rata_incasare` = Încasări / Facturări × 100
|
||||
- [ ] Calculat `rata_plata` = Plăți / Achiziții × 100
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-004: Backend - Calcul Indicatori Risc și Aging
|
||||
**Ca** utilizator al dashboard-ului
|
||||
**Vreau** să văd indicatorii de risc și aging creanțe/datorii
|
||||
**Pentru că** vreau să știu cât de sănătos este portofoliul de creanțe
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Calculat `creante_restante_pct` = Creanțe Restante / Creanțe Total × 100
|
||||
- [ ] Calculat `creante_90plus_pct` = Creanțe 90+ zile / Creanțe Total × 100
|
||||
- [ ] Calculat `datorii_restante_pct` = Datorii Restante / Datorii Total × 100
|
||||
- [ ] Calculat `raport_datorii_trezorerie` = Datorii Furnizori / Trezorerie
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-005: Backend - Calcul Indicatori Cash Flow
|
||||
**Ca** utilizator al dashboard-ului
|
||||
**Vreau** să văd indicatorii de cash flow
|
||||
**Pentru că** vreau să știu dacă firma generează sau consumă numerar
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Calculat `flux_net_lunar` = Încasări - Plăți (luna curentă)
|
||||
- [ ] Calculat `cash_flow_ytd` = Suma fluxurilor de la ianuarie
|
||||
- [ ] Calculat `flux_net_yoy_pct` = (CF_curent - CF_anterior) / CF_anterior × 100
|
||||
- [ ] Calculat `acoperire_cash_flow` = Cash Flow / Datorii Restante
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-006: Backend - Calcul Indicatori Dinamică
|
||||
**Ca** utilizator al dashboard-ului
|
||||
**Vreau** să văd evoluția vânzărilor și achizițiilor
|
||||
**Pentru că** vreau să știu dacă afacerea crește sau scade
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Calculat `crestere_vanzari_yoy` = (Vânzări_curent - Vânzări_anterior) / Vânzări_anterior × 100
|
||||
- [ ] Calculat `crestere_achizitii_yoy` = similar
|
||||
- [ ] Calculat `marja_implicita` = (Vânzări - Achiziții) / Vânzări × 100
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-007: Backend - Calcul Altman Z-Score
|
||||
**Ca** utilizator al dashboard-ului
|
||||
**Vreau** să văd scorul Altman Z-Score calculat automat
|
||||
**Pentru că** vreau să știu riscul de faliment al firmei conform standardelor internaționale
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Calculat X1 = Working Capital / Total Assets
|
||||
- [ ] Calculat X2 = Retained Earnings (cont 117) / Total Assets
|
||||
- [ ] Calculat X3 = EBIT (Cl.7 - Cl.6 fără 66x) / Total Assets
|
||||
- [ ] Calculat X4 = Equity (Cl.1 capital) / Total Liabilities
|
||||
- [ ] Calculat Z'' = 6.56×X1 + 3.26×X2 + 6.72×X3 + 1.05×X4
|
||||
- [ ] Status: "Zonă Sigură" (>2.60), "Zonă Gri" (1.10-2.60), "Zonă Risc" (<1.10)
|
||||
- [ ] Răspunsul include și componentele individuale (X1-X4) pentru transparență
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-008: Backend - Endpoint API Financial Indicators
|
||||
**Ca** frontend developer
|
||||
**Vreau** un endpoint API care returnează toți indicatorii calculați
|
||||
**Pentru că** am nevoie să afișez datele în UI
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Endpoint `GET /api/reports/dashboard/financial-indicators`
|
||||
- [ ] Parametri: company (required), luna (optional), an (optional)
|
||||
- [ ] Răspuns JSON cu structura: { lichiditate: {...}, eficienta: {...}, risc: {...}, cash_flow: {...}, dinamica: {...}, altman_zscore: {...} }
|
||||
- [ ] Fiecare indicator include: value, status, threshold_min, threshold_max, sparkline_data (array 12 valori)
|
||||
- [ ] Cache 30 minute implementat
|
||||
- [ ] Response time < 500ms (cu cache)
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-009: Backend - Date Istorice pentru Sparklines
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd evoluția fiecărui indicator pe 12 luni
|
||||
**Pentru că** vreau să înțeleg trendul, nu doar valoarea curentă
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Fiecare indicator include câmp `sparkline_data` cu array de 12 valori (ultimele 12 luni)
|
||||
- [ ] Include și `sparkline_labels` cu etichetele lunilor (ex: ["Feb 24", "Mar 24", ...])
|
||||
- [ ] Datele sunt calculate pentru fiecare lună din ultimele 12
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-010: Frontend - Component FinancialIndicatorsCard
|
||||
**Ca** utilizator al dashboard-ului
|
||||
**Vreau** un card vizual care afișează indicatorii financiari
|
||||
**Pentru că** vreau să văd rapid starea financiară a firmei
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Creat `src/modules/reports/components/dashboard/cards/FinancialIndicatorsCard.vue`
|
||||
- [ ] Header cu titlu "Indicatori Financiari" și selector perioadă
|
||||
- [ ] Tabs pentru categorii: Lichiditate, Eficiență, Risc, Z-Score
|
||||
- [ ] Grid 2x2 sau 2x3 pentru indicatori în fiecare tab
|
||||
- [ ] Folosește design tokens din `docs/DESIGN_TOKENS.md`
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser that card-ul se afișează corect
|
||||
|
||||
### US-011: Frontend - Component IndicatorItem cu Sparkline
|
||||
**Ca** utilizator
|
||||
**Vreau** fiecare indicator să aibă o mini-diagramă de evoluție
|
||||
**Pentru că** vreau să văd trendul vizual
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Creat sub-component pentru afișarea unui indicator individual
|
||||
- [ ] Afișează: nume, valoare curentă, status (icon + culoare), sparkline
|
||||
- [ ] Cod culoare: verde (good), galben (warning), roșu (danger)
|
||||
- [ ] Sparkline folosește array-ul de 12 valori
|
||||
- [ ] Hover pe sparkline arată valoarea lunii
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser that sparkline-urile se afișează corect
|
||||
|
||||
### US-012: Frontend - Expand pentru Detalii Complete
|
||||
**Ca** utilizator
|
||||
**Vreau** să pot expanda cardul pentru a vedea toți indicatorii
|
||||
**Pentru că** unii indicatori sunt mai puțin importanți dar vreau acces la ei
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Buton/chevron pentru expand/collapse
|
||||
- [ ] Starea collapsed arată 4-6 indicatori principali
|
||||
- [ ] Starea expanded arată toți 22+ indicatori în format tabel
|
||||
- [ ] Animație smooth la expand/collapse
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser that expand/collapse funcționează
|
||||
|
||||
### US-013: Frontend - Store Integration
|
||||
**Ca** frontend developer
|
||||
**Vreau** să integrez datele în Pinia store
|
||||
**Pentru că** am nevoie de state management pentru indicatori
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Adăugat metodă `loadFinancialIndicators(companyId, luna, an)` în `dashboard.js` store
|
||||
- [ ] State pentru `financialIndicators` cu loading, error, data
|
||||
- [ ] Computed properties pentru fiecare categorie de indicatori
|
||||
- [ ] Reîncărcare automată când se schimbă compania sau perioada
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-014: Frontend - Integrare în DashboardView Desktop
|
||||
**Ca** utilizator pe desktop
|
||||
**Vreau** să văd cardul de indicatori în dashboard
|
||||
**Pentru că** vreau acces rapid la informații
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Import `FinancialIndicatorsCard` în `DashboardView.vue`
|
||||
- [ ] Adăugat în grid-ul desktop (rând nou sub metric cards)
|
||||
- [ ] Card ocupă full width sau 2 coloane
|
||||
- [ ] Se încarcă împreună cu restul dashboard-ului
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser (desktop) that cardul apare corect în layout
|
||||
|
||||
### US-015: Frontend - Integrare în DashboardView Mobile
|
||||
**Ca** utilizator pe mobil
|
||||
**Vreau** să văd cardul de indicatori în carusel
|
||||
**Pentru că** vreau acces la informații și pe telefon
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Adăugat pagină nouă (Page 6) în `SwipeableCards` carousel
|
||||
- [ ] Layout adaptat pentru ecran mic (1 coloană sau 2x2 mai mic)
|
||||
- [ ] Touch-friendly (tap pentru expand, swipe pentru navigare)
|
||||
- [ ] Respectă padding pentru MobileTopBar și MobileBottomNav
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser (mobile viewport) that cardul funcționează corect
|
||||
|
||||
### US-016: Frontend - Dark Mode Support
|
||||
**Ca** utilizator
|
||||
**Vreau** cardul să arate bine în dark mode
|
||||
**Pentru că** folosesc aplicația și seara
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Culorile de status funcționează în ambele teme
|
||||
- [ ] Sparklines au contrast suficient
|
||||
- [ ] Textul e lizibil în dark mode
|
||||
- [ ] Folosește variabile CSS pentru culori (nu hardcodate)
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser (dark mode) that totul e vizibil și lizibil
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
|
||||
1. [REQ-001] Sistemul trebuie să calculeze toți cei 22 indicatori financiari definiți
|
||||
2. [REQ-002] Utilizatorul poate vedea valoarea curentă și evoluția pe 12 luni pentru fiecare indicator
|
||||
3. [REQ-003] Sistemul trebuie să afișeze cod culoare pentru status (verde/galben/roșu) bazat pe praguri standard
|
||||
4. [REQ-004] Când se schimbă compania sau perioada, indicatorii se recalculează automat
|
||||
5. [REQ-005] Altman Z-Score trebuie calculat conform formulei Z'' pentru firme private non-manufacturiere
|
||||
6. [REQ-006] Sistemul trebuie să cacheze rezultatele pentru 30 minute
|
||||
7. [REQ-007] Datele se încarcă în paralel cu restul dashboard-ului (nu secvențial)
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
|
||||
- **NU** implementăm export PDF/Excel al indicatorilor (poate fi adăugat ulterior)
|
||||
- **NU** implementăm alerte email când indicatorii depășesc praguri
|
||||
- **NU** implementăm comparație între multiple firme
|
||||
- **NU** implementăm indicatori care necesită date care nu sunt în sistemul contabil (ex: prețul acțiunilor pentru Z-Score original)
|
||||
- **NU** modificăm indicatorii existenți din cardurile solduri (Trezorerie, Clienți, Furnizori, TVA)
|
||||
|
||||
## 6. Considerații Tehnice
|
||||
|
||||
### Stack/Tehnologii
|
||||
- **Backend**: Python, FastAPI, python-oracledb, Pydantic
|
||||
- **Frontend**: Vue.js 3, Pinia, PrimeVue, CSS Variables
|
||||
- **Database**: Oracle (view VBAL pentru balanță)
|
||||
|
||||
### Patterns de Urmat
|
||||
- Backend service pattern cu `@cached` decorator (vezi `dashboard_service.py`)
|
||||
- Frontend component pattern cu props pentru configurare (vezi `SolduriCompactCard.vue`)
|
||||
- CSS design tokens (vezi `docs/DESIGN_TOKENS.md`)
|
||||
|
||||
### Conturi VBAL Necesare
|
||||
```python
|
||||
ACCOUNT_GROUPS = {
|
||||
'active_imobilizate': ['20%', '21%', '22%', '23%', '24%', '25%', '26%', '27%', '28%'],
|
||||
'stocuri': ['30%', '31%', '32%', '33%', '34%', '35%', '36%', '37%', '38%', '39%'],
|
||||
'creante': ['41%', '44%', '45%', '46%', '47%'],
|
||||
'disponibilitati': ['51%', '53%'],
|
||||
'capital_propriu': ['101', '102', '103', '104', '105', '106', '107', '108', '109'],
|
||||
'rezultat': ['117', '121', '129'],
|
||||
'datorii_termen_lung': ['161', '162', '163', '164', '165', '166', '167', '168', '169'],
|
||||
'datorii_curente': ['401', '403', '404', '405', '408', '419', '421', '423', '424', ...],
|
||||
'venituri': ['70%', '71%', '72%', '74%', '75%', '78%'],
|
||||
'cheltuieli_operationale': ['60%', '61%', '62%', '63%', '64%', '65%', '68%'],
|
||||
}
|
||||
```
|
||||
|
||||
### Dependențe
|
||||
- Depinde de endpoint-urile existente `/dashboard/summary` și `/dashboard/trends`
|
||||
- Depinde de view-ul Oracle VBAL din schema companiei
|
||||
|
||||
### Riscuri Tehnice
|
||||
- **R1**: Unele firme pot să nu aibă toate conturile populate (soluție: returnăm null/N/A pentru indicatorii care nu pot fi calculați)
|
||||
- **R2**: Query-ul VBAL cu multe LIKE poate fi lent (soluție: cache agresiv 30min)
|
||||
- **R3**: Valorile Z-Score pot fi distorsionate pentru firme foarte mici (soluție: afișăm disclaimer)
|
||||
|
||||
## 7. Considerații UI/UX
|
||||
|
||||
### Layout Card (Desktop)
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 📊 INDICATORI FINANCIARI Ianuarie 2025 ▼ │
|
||||
├──────────────┬──────────────┬──────────────┬───────────────────┤
|
||||
│ LICHIDITATE │ EFICIENȚĂ │ RISC │ ALTMAN Z │
|
||||
├──────────────┴──────────────┴──────────────┴───────────────────┤
|
||||
│ Quick Ratio DSO Creanțe Rest. Z-Score │
|
||||
│ 1.85x 32 zile 15.2% 2.45 │
|
||||
│ ✅ >1.0 ⚠️ <45 ✅ <20% ⚠️ Zonă Gri │
|
||||
│ ▁▂▃▄▅▆▇█▇▆▅ ▇▆▅▄▃▂▁▂▃▄▅▆ ▁▁▂▂▃▃▄▄▅▅▆▆ ▃▄▄▅▅▆▆▇▇███ │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ ▼ Mai multe indicatori Refresh ↻ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Stări UI
|
||||
- **Loading**: Skeleton/shimmer pentru card
|
||||
- **Error**: Mesaj de eroare cu buton retry
|
||||
- **Empty**: "Datele nu sunt disponibile pentru această perioadă"
|
||||
- **Success**: Afișare indicatori cu cod culoare
|
||||
|
||||
### Cod Culoare Status
|
||||
- 🟢 **Verde** (--green-600): Valoare în zona optimă
|
||||
- 🟡 **Galben** (--yellow-600): Valoare acceptabilă, de urmărit
|
||||
- 🔴 **Roșu** (--red-600): Valoare critică, necesită atenție
|
||||
|
||||
## 8. Success Metrics
|
||||
|
||||
- **Completitudine**: 22/22 indicatori calculați și afișați
|
||||
- **Performanță**: Response time API < 500ms (cached)
|
||||
- **UX**: Card încărcat complet în < 2 secunde
|
||||
- **Acuratețe**: Z-Score calculat corect conform formula standard
|
||||
|
||||
## 9. Open Questions
|
||||
|
||||
- [x] Care indicatori să fie vizibili implicit vs la expand? → 4-6 principali vizibili, restul la expand
|
||||
- [x] Vrem tab-uri sau scroll vertical pentru categorii? → Tabs pentru categorii
|
||||
- [ ] Pragurile pentru cod culoare să fie configurabile per firmă sau fixe? → Fixe pentru MVP
|
||||
@@ -1,400 +0,0 @@
|
||||
# PRD: Mobile Navigation Fixes - Phase 3
|
||||
|
||||
## 1. Introducere
|
||||
|
||||
Acest PRD continuă îmbunătățirile mobile din fazele anterioare, adresând bugfix-uri și ajustări identificate în testare. Scopul este corectarea navigării, restaurarea funcționalităților lipsă și restructurarea meniului footer pentru o experiență consistentă.
|
||||
|
||||
**Branch de lucru:** `ralph/unified-mobile-md` (continuare)
|
||||
|
||||
## 2. Obiective
|
||||
|
||||
### Obiectiv Principal
|
||||
- **Corectare navigare**: Buton Înapoi funcțional, footer nav consistent pe toate paginile
|
||||
|
||||
### Obiective Secundare
|
||||
- Restaurare butoane export/filtrare pe paginile de rapoarte
|
||||
- Restructurare footer: Dashboard, Bonuri, Facturi, Setări
|
||||
- Tab-uri Clienți/Furnizori în Facturi și Scadențe
|
||||
- Upload doar în butonul + pe pagina Bonuri
|
||||
|
||||
### Metrici de Succes
|
||||
- 100% pagini mobile au footer nav funcțional
|
||||
- Buton Înapoi pe toate paginile de editare/vizualizare
|
||||
- Export/Filtrare disponibile pe toate rapoartele
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
---
|
||||
|
||||
### US-301: Buton Înapoi în Creare/Editare/Vizualizare Bon
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** buton ← Înapoi în MobileTopBar pe pagina de bon
|
||||
**Pentru că** acum nu pot reveni la lista de bonuri fără hamburger menu
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] ReceiptCreateUnifiedView.vue are MobileTopBar cu showBack=true
|
||||
- [ ] Click pe ← navighează la /data-entry (lista bonuri)
|
||||
- [ ] Funcționează în toate modurile: create, edit, view
|
||||
- [ ] Verify in browser: butonul apare și funcționează
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-302: Footer Nav pe toate Paginile de Setări
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** MobileBottomNav pe toate paginile din secțiunea Setări
|
||||
**Pentru că** unele pagini (OCR Metrics, Cache Stats, Loguri) nu au footer
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] OCRMetricsView.vue include MobileBottomNav
|
||||
- [ ] CacheStatsView.vue include MobileBottomNav
|
||||
- [ ] ServerLogsView.vue include MobileBottomNav
|
||||
- [ ] TelegramAdminView.vue include MobileBottomNav (dacă există)
|
||||
- [ ] SettingsHubView.vue include MobileBottomNav (verificare)
|
||||
- [ ] Setări activ/highlighted în footer pe aceste pagini
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-303: Mutare Upload din Footer în Butonul + pe Bonuri
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** funcția Upload să fie în butonul FAB (+) pe pagina Bonuri
|
||||
**Pentru că** Upload nu are sens în footer pe alte pagini
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MobileBottomNav NU mai are link/buton Upload
|
||||
- [ ] ReceiptsListView.vue are buton FAB (+) în colțul dreapta-jos
|
||||
- [ ] Click pe FAB deschide meniu: "Bon Nou" | "Upload Bulk"
|
||||
- [ ] FAB poziționat deasupra MobileBottomNav (bottom: 72px)
|
||||
- [ ] Verify in browser: FAB apare doar pe pagina Bonuri
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-304: Tab-uri Clienți/Furnizori în Facturi
|
||||
**Ca** utilizator
|
||||
**Vreau** pagina Facturi să aibă tab-uri pentru Clienți și Furnizori
|
||||
**Pentru că** vreau să comut rapid între cele două perspective
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] InvoicesView.vue modificat cu tab-uri: "Clienți" | "Furnizori"
|
||||
- [ ] Tab-uri în MobileTopBar sau sub el (design Material)
|
||||
- [ ] Switch între tab-uri păstrează filtrele active
|
||||
- [ ] Default: primul tab activ (Clienți)
|
||||
- [ ] URL query param pentru tab activ (?tab=suppliers)
|
||||
- [ ] MobileTopBar cu title "Facturi"
|
||||
- [ ] MobileBottomNav activ (Facturi highlighted)
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-305: Tab-uri Clienți/Furnizori în Scadențe
|
||||
**Ca** utilizator
|
||||
**Vreau** pagina Scadențe să aibă tab-uri pentru Clienți și Furnizori
|
||||
**Pentru că** vreau să comut rapid între cele două perspective
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MaturityAnalysisView.vue modificat cu tab-uri: "Clienți" | "Furnizori"
|
||||
- [ ] Tab-uri în MobileTopBar sau sub el (design Material)
|
||||
- [ ] Switch între tab-uri păstrează filtrele active
|
||||
- [ ] Default: primul tab activ (Clienți)
|
||||
- [ ] URL query param pentru tab activ (?tab=suppliers)
|
||||
- [ ] MobileTopBar cu title "Scadențe"
|
||||
- [ ] MobileBottomNav activ (Rapoarte în hamburger menu)
|
||||
- [ ] Buton ← Înapoi în MobileTopBar
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-306: Restaurare Butoane Export și Filtrare pe Rapoarte (Mobil)
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** butoane de export și filtrare pe Facturi, Balanță, Casa/Banca, Lista Bonuri
|
||||
**Pentru că** aceste funcționalități au dispărut în implementarea anterioară
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] InvoicesView.vue: buton Export în MobileTopBar actions
|
||||
- [ ] InvoicesView.vue: buton Filtrare care deschide BottomSheet
|
||||
- [ ] TrialBalanceView.vue: buton Export în MobileTopBar actions
|
||||
- [ ] TrialBalanceView.vue: buton Filtrare care deschide BottomSheet
|
||||
- [ ] BankCashRegisterView.vue: buton Export în MobileTopBar actions
|
||||
- [ ] BankCashRegisterView.vue: buton Filtrare care deschide BottomSheet
|
||||
- [ ] ReceiptsListView.vue: buton Export în MobileTopBar actions
|
||||
- [ ] ReceiptsListView.vue: buton Filtrare care deschide BottomSheet
|
||||
- [ ] MaturityAnalysisView.vue: buton Export în MobileTopBar actions
|
||||
- [ ] MaturityAnalysisView.vue: buton Filtrare care deschide BottomSheet
|
||||
- [ ] Icons: pi-download (export), pi-filter (filtre)
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-307: Restructurare Footer Nav (4 butoane noi)
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** footer navigation cu: Dashboard | Bonuri | Facturi | Setări
|
||||
**Pentru că** vreau acces rapid la cele mai folosite secțiuni
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MobileBottomNav cu 4 butoane: Dashboard, Bonuri, Facturi, Setări
|
||||
- [ ] Dashboard: icon pi-home sau pi-chart-bar, route /dashboard
|
||||
- [ ] Bonuri: icon pi-receipt, route /data-entry
|
||||
- [ ] Facturi: icon pi-file-edit, route /reports/invoices
|
||||
- [ ] Setări: icon pi-cog, route /settings
|
||||
- [ ] Active state corect pe fiecare pagină
|
||||
- [ ] Ștergere link Upload din footer (mutat în FAB)
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-308: Actualizare Hamburger Menu - Grupat pe Categorii
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** meniul hamburger organizat pe categorii clare
|
||||
**Pentru că** vreau să găsesc rapid paginile de care am nevoie
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MobileDrawerMenu.vue restructurat cu secțiuni:
|
||||
- [ ] Secțiune "PRINCIPALE":
|
||||
- [ ] Dashboard → /dashboard
|
||||
- [ ] Bonuri → /data-entry
|
||||
- [ ] Secțiune "RAPOARTE":
|
||||
- [ ] Facturi → /reports/invoices
|
||||
- [ ] Balanță → /reports/trial-balance
|
||||
- [ ] Casa și Banca → /reports/bank-cash
|
||||
- [ ] Secțiune "ANALIZE":
|
||||
- [ ] Scadențe → /reports/maturity-analysis
|
||||
- [ ] Facturi Detaliate → /reports/detailed-invoices
|
||||
- [ ] Secțiune "SETĂRI":
|
||||
- [ ] Setări → /settings (hub)
|
||||
- [ ] Separatori vizuali între secțiuni
|
||||
- [ ] Header cu logo
|
||||
- [ ] Footer cu profil utilizator și logout
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-309: Cleanup Dashboard Mobile
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** Dashboard-ul să afișeze doar KPIs fără quick-links
|
||||
**Pentru că** navigarea se face din footer și hamburger menu
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] DashboardView.vue pe mobil: ștergere quick-link cards (dacă există)
|
||||
- [ ] Doar SwipeableCards cu KPIs pe mobil
|
||||
- [ ] Desktop rămâne neschimbat
|
||||
- [ ] MobileTopBar cu title "Dashboard"
|
||||
- [ ] MobileBottomNav cu Dashboard activ
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-310: Actualizare Router cu Modificările
|
||||
**Ca** developer
|
||||
**Vreau** router-ul actualizat pentru noile pagini și modificări
|
||||
**Pentru că** navigarea trebuie să funcționeze corect
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Rută /reports/invoices → InvoicesView (cu tab-uri)
|
||||
- [ ] Rută /reports/maturity-analysis → MaturityAnalysisView (cu tab-uri)
|
||||
- [ ] Rutele existente păstrate: /reports/trial-balance, /reports/bank-cash
|
||||
- [ ] Rutele /reports/detailed-invoices funcționale
|
||||
- [ ] Cleanup rute nefolosite (dacă există)
|
||||
- [ ] Toate rutele lazy loaded
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-311: Actualizare Documentație MOBILE_PATTERNS.md
|
||||
**Ca** developer viitor
|
||||
**Vreau** documentația actualizată cu modificările din Phase 3
|
||||
**Pentru că** pattern-urile s-au schimbat
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Secțiune actualizată: Footer Navigation (Dashboard, Bonuri, Facturi, Setări)
|
||||
- [ ] Secțiune nouă: FAB Pattern pentru acțiuni contextuale
|
||||
- [ ] Secțiune nouă: Tab Pattern pentru switch Clienți/Furnizori
|
||||
- [ ] Secțiune actualizată: Hamburger Menu grupat pe categorii
|
||||
- [ ] Diagrame ASCII actualizate cu noua structură navigare
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
|
||||
1. [REQ-001] Toate paginile de editare/vizualizare au buton Înapoi în MobileTopBar
|
||||
2. [REQ-002] Footer nav are exact 4 butoane: Dashboard, Bonuri, Facturi, Setări
|
||||
3. [REQ-003] Upload accesibil DOAR din FAB pe pagina Bonuri
|
||||
4. [REQ-004] Facturi cu tab-uri Clienți/Furnizori
|
||||
5. [REQ-005] Scadențe cu tab-uri Clienți/Furnizori
|
||||
6. [REQ-006] Toate rapoartele au butoane Export și Filtrare pe mobil
|
||||
7. [REQ-007] Hamburger menu organizat pe categorii: Principale, Rapoarte, Analize, Setări
|
||||
8. [REQ-008] Dashboard afișează doar KPIs pe mobil
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
|
||||
- ❌ Nu modificăm layout-ul desktop
|
||||
- ❌ Nu adăugăm funcționalități noi în backend
|
||||
- ❌ Nu schimbăm logica de business
|
||||
- ❌ Nu modificăm stilurile cardurilor existente
|
||||
- ❌ Nu implementăm notificări sau animații complexe
|
||||
- ❌ Nu creăm pagini separate pentru Clienți/Furnizori (folosim tab-uri)
|
||||
|
||||
## 6. Considerații Tehnice
|
||||
|
||||
### Stack/Tehnologii
|
||||
- Vue 3 Composition API
|
||||
- Vue Router pentru navigare
|
||||
- Componente existente: MobileTopBar, MobileBottomNav, BottomSheet, MobileDrawerMenu
|
||||
- PrimeVue TabView sau custom tabs pentru Clienți/Furnizori
|
||||
|
||||
### Patterns de Urmat
|
||||
- Tab Pattern pentru switch între perspective
|
||||
- FAB Pattern pentru acțiuni contextuale
|
||||
- BottomSheet pentru filtre pe mobil
|
||||
|
||||
### Dependențe
|
||||
- US-307 trebuie făcut primul (footer restructurare)
|
||||
- US-304 și US-305 pot fi făcute în paralel (tab-uri)
|
||||
- US-308 poate fi făcut independent (hamburger menu)
|
||||
|
||||
### Riscuri Tehnice
|
||||
- **Risc scăzut**: Tab-uri în pagini existente pot necesita refactoring
|
||||
- Mitigare: Folosire PrimeVue TabView sau custom component simplu
|
||||
|
||||
## 7. Considerații UI/UX
|
||||
|
||||
### Structură Footer Navigation Nouă
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ MOBILE BOTTOM NAV (4 butoane) │
|
||||
├───────────┬───────────┬───────────┬─────────┤
|
||||
│ Dashboard │ Bonuri │ Facturi │ Setări │
|
||||
│ 🏠 │ 🧾 │ 📄 │ ⚙️ │
|
||||
│/dashboard │/data-entry│ /reports/ │/settings│
|
||||
│ │ │ invoices │ │
|
||||
└───────────┴───────────┴───────────┴─────────┘
|
||||
```
|
||||
|
||||
### FAB pe Pagina Bonuri
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ Lista Bonuri 🔍 📥 ☰ │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ [Bon 1] │
|
||||
│ [Bon 2] │
|
||||
│ [Bon 3] │
|
||||
│ ┌───┐ │
|
||||
│ │ + │ │ ← FAB
|
||||
│ └───┘ │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Dashboard │ Bonuri │ Facturi │ Setări │
|
||||
└─────────────────────────────────────────────┘
|
||||
|
||||
Click pe FAB →
|
||||
┌─────────────────┐
|
||||
│ 📝 Bon Nou │
|
||||
│ 📤 Upload Bulk │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
### Pagina Facturi cu Tab-uri
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ Facturi 🔍 📥 ☰ │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ┌─────────────┬─────────────┐ │
|
||||
│ │ Clienți │ Furnizori │ ← Tab-uri │
|
||||
│ └─────────────┴─────────────┘ │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ [Factură 1] │
|
||||
│ [Factură 2] │
|
||||
│ [Factură 3] │
|
||||
│ │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Dashboard │ Bonuri │ Facturi │ Setări │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Pagina Scadențe cu Tab-uri
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ ← Scadențe 🔍 📥 ☰ │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ┌─────────────┬─────────────┐ │
|
||||
│ │ Clienți │ Furnizori │ ← Tab-uri │
|
||||
│ └─────────────┴─────────────┘ │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ [Scadență 1] │
|
||||
│ [Scadență 2] │
|
||||
│ [Scadență 3] │
|
||||
│ │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Dashboard │ Bonuri │ Facturi │ Setări │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Hamburger Menu Actualizat (Grupat pe Categorii)
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ [Logo ROA2WEB] │
|
||||
│─────────────────────────────────────────────│
|
||||
│ PRINCIPALE │
|
||||
│ 🏠 Dashboard │
|
||||
│ 🧾 Bonuri │
|
||||
│─────────────────────────────────────────────│
|
||||
│ RAPOARTE │
|
||||
│ 📄 Facturi │
|
||||
│ 📊 Balanță │
|
||||
│ 💰 Casa și Banca │
|
||||
│─────────────────────────────────────────────│
|
||||
│ ANALIZE │
|
||||
│ ⏰ Scadențe │
|
||||
│ 📋 Facturi Detaliate │
|
||||
│─────────────────────────────────────────────│
|
||||
│ ADMINISTRARE │
|
||||
│ ⚙️ Setări │
|
||||
│─────────────────────────────────────────────│
|
||||
│ 👤 [Username] │
|
||||
│ [Logout] │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 8. Success Metrics
|
||||
|
||||
- **Navigare**: 100% pagini cu footer nav funcțional
|
||||
- **Consistență**: Tab-uri identice în Facturi și Scadențe
|
||||
- **UX**: Max 2 tap-uri pentru orice destinație
|
||||
- **Funcționalitate**: Export/Filtre disponibile pe toate rapoartele
|
||||
|
||||
## 9. Open Questions
|
||||
|
||||
- [x] Footer: Dashboard, Bonuri, Facturi, Setări - DA
|
||||
- [x] Hamburger: Grupat pe categorii - DA
|
||||
- [x] Facturi/Scadențe: Tab-uri Clienți/Furnizori - DA
|
||||
|
||||
---
|
||||
|
||||
## Implementare Sugerată (Ordinea User Stories)
|
||||
|
||||
### Faza 1: Infrastructură Navigare
|
||||
1. US-307: Restructurare Footer Nav (4 butoane noi)
|
||||
2. US-308: Actualizare Hamburger Menu - Grupat pe Categorii
|
||||
|
||||
### Faza 2: Tab-uri Clienți/Furnizori
|
||||
3. US-304: Tab-uri în Facturi
|
||||
4. US-305: Tab-uri în Scadențe
|
||||
|
||||
### Faza 3: Corectări Navigare
|
||||
5. US-301: Buton Înapoi în editare bon
|
||||
6. US-302: Footer Nav pe paginile de setări
|
||||
7. US-303: FAB pe pagina Bonuri (mutare Upload)
|
||||
|
||||
### Faza 4: Restaurare Funcționalități
|
||||
8. US-306: Restaurare Export și Filtrare pe rapoarte
|
||||
|
||||
### Faza 5: Cleanup
|
||||
9. US-309: Cleanup Dashboard Mobile
|
||||
10. US-310: Actualizare Router
|
||||
|
||||
### Faza 6: Documentație
|
||||
11. US-311: Update MOBILE_PATTERNS.md
|
||||
@@ -1,188 +0,0 @@
|
||||
# PRD: Mobile Fixes Phase 4 - Layout & State Issues
|
||||
|
||||
## 1. Introducere
|
||||
|
||||
După completarea Phase 3 (11/11 stories), au fost identificate probleme critice în modul mobil prin testare Playwright. Cauza principală este că layout-ul desktop (AppHeader + sidebar) rămâne vizibil pe viewport mobil, acoperind componentele mobile (MobileTopBar, MobileDrawerMenu). În plus, există probleme cu persistența bonurilor cu eroare la upload.
|
||||
|
||||
## 2. Obiective
|
||||
|
||||
### Obiectiv Principal
|
||||
- Corectarea layout-ului mobil pentru a afișa DOAR componentele mobile pe viewport < 768px
|
||||
|
||||
### Obiective Secundare
|
||||
- Restaurarea corectă a bonurilor cu eroare după refresh
|
||||
- Permiterea editării bonurilor cu eroare pentru corectare
|
||||
|
||||
### Metrici de Succes
|
||||
- Playwright test: Header desktop ASCUNS pe viewport 375px
|
||||
- Playwright test: MobileTopBar cu butoane filter/export VIZIBILE
|
||||
- Playwright test: MobileDrawerMenu afișează secțiunea ANALIZE
|
||||
- Playwright test: Bonuri cu eroare rămân vizibile după refresh
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
### US-401: Fix Layout Principal - Ascundere Header Desktop pe Mobil
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** să văd doar MobileTopBar și MobileBottomNav
|
||||
**Pentru că** header-ul desktop ocupă spațiu și acoperă butoanele mobile
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] AppHeader.vue are `v-if="!isMobile"` pentru a se ascunde pe mobil
|
||||
- [ ] Sidebar-ul desktop (navigation cu Rapoarte/Introduceri Date/Sistem) este ascuns pe mobil
|
||||
- [ ] MobileTopBar este singurul header vizibil pe viewport < 768px
|
||||
- [ ] Nu există suprapunere între header desktop și MobileTopBar
|
||||
- [ ] npm run build passes
|
||||
- [ ] Verify in browser (375x667): Header desktop NU este vizibil
|
||||
|
||||
### US-402: Fix MobileTopBar - Butoane Filter/Export Vizibile
|
||||
**Ca** utilizator mobil pe pagina Facturi/Bonuri
|
||||
**Vreau** să văd butoanele de filtrare și export în header
|
||||
**Pentru că** acum sunt ascunse/acoperite de header-ul desktop
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Pe InvoicesView.vue, butoanele Filter/Refresh/Export sunt vizibile în MobileTopBar
|
||||
- [ ] Pe ReceiptsListView.vue, butoanele Filter/Export/More sunt vizibile în MobileTopBar
|
||||
- [ ] Click pe butonul Filter deschide BottomSheet cu filtre
|
||||
- [ ] Click pe butonul Export declanșează descărcarea
|
||||
- [ ] npm run build passes
|
||||
- [ ] Verify in browser (375x667): Butoanele sunt vizibile și funcționale pe pagina Facturi
|
||||
|
||||
### US-403: Fix MobileDrawerMenu - Secțiunea ANALIZE Vizibilă
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** să văd secțiunea ANALIZE în hamburger menu
|
||||
**Pentru că** acum se deschide sidebar-ul desktop în loc de MobileDrawerMenu
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Click pe butonul Meniu din MobileTopBar deschide MobileDrawerMenu (nu sidebar desktop)
|
||||
- [ ] MobileDrawerMenu afișează secțiunile: PRINCIPALE, RAPOARTE, ANALIZE, ADMINISTRARE
|
||||
- [ ] Secțiunea ANALIZE conține: Scadențe, Facturi Detaliate
|
||||
- [ ] Link-urile din ANALIZE navighează corect
|
||||
- [ ] npm run build passes
|
||||
- [ ] Verify in browser (375x667): Click pe Meniu → apare drawer cu secțiunea ANALIZE
|
||||
|
||||
### US-404: Fix Spațiu Blank - Padding Corect pentru Mobile
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** ca paginile să nu aibă spațiu blank excesiv în partea de sus
|
||||
**Pentru că** acum există ~120px spațiu gol unde ar fi header-ul desktop
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Paginile de rapoarte au padding-top corect pentru MobileTopBar (56px)
|
||||
- [ ] Nu există spațiu blank între MobileTopBar și conținut
|
||||
- [ ] Tab-urile Clienți/Furnizori sunt imediat sub MobileTopBar
|
||||
- [ ] npm run build passes
|
||||
- [ ] Verify in browser (375x667): Nu există spațiu blank excesiv pe pagina Facturi
|
||||
|
||||
### US-405: Fix batchProgressStore - Restaurare Joburi Failed
|
||||
**Ca** utilizator care a uploadat bonuri cu erori OCR
|
||||
**Vreau** ca bonurile cu eroare să rămână vizibile după refresh
|
||||
**Pentru că** acum dispar și nu pot fi editate
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] `restoreJobsFromBatch()` în batchProgressStore.js include joburi cu status 'failed'
|
||||
- [ ] Batch-ul NU este șters din localStorage dacă are joburi failed
|
||||
- [ ] După refresh, bonurile cu eroare sunt afișate cu status vizual "Eroare"
|
||||
- [ ] `unifiedItems` computed include joburile failed pentru afișare
|
||||
- [ ] npm run build passes
|
||||
- [ ] Verify in browser: Upload bon cu eroare → Refresh → Bonul cu eroare rămâne vizibil
|
||||
|
||||
### US-406: Fix UI Bonuri cu Eroare - Afișare Corectă pe Mobil
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** să văd clar că un bon are eroare (nu "în procesare")
|
||||
**Pentru că** acum bonurile failed arată ca și cum ar fi încă în procesare
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Bonurile cu status 'failed' afișează chip/badge "Eroare" (roșu)
|
||||
- [ ] NU afișează "În procesare" pentru bonuri failed
|
||||
- [ ] Mesajul de eroare este vizibil (truncat dacă e prea lung)
|
||||
- [ ] npm run build passes
|
||||
- [ ] Verify in browser (375x667): Bon cu eroare arată "Eroare" nu "În procesare"
|
||||
|
||||
### US-407: Fix Editare Bonuri cu Eroare
|
||||
**Ca** utilizator care are un bon cu eroare OCR
|
||||
**Vreau** să pot edita bonul pentru a corecta erorile manual
|
||||
**Pentru că** acum nu pot salva modificările sau re-trimite pe workflow
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Click pe bon cu eroare deschide formularul de editare
|
||||
- [ ] La salvare, `processing_status` este resetat la NULL
|
||||
- [ ] După salvare, bonul poate fi trimis pe workflow (Submit for Approval)
|
||||
- [ ] Backend endpoint PATCH /receipts/{id} resetează processing_status
|
||||
- [ ] npm run build passes
|
||||
- [ ] Verify in browser: Editează bon cu eroare → Salvează → Poate fi trimis pe workflow
|
||||
|
||||
### US-408: Verificare Finală cu Playwright
|
||||
**Ca** developer
|
||||
**Vreau** verificare automată a tuturor fix-urilor
|
||||
**Pentru că** trebuie confirmate toate scenariile înainte de merge
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Test 1: Viewport 375x667 → Header desktop ASCUNS
|
||||
- [ ] Test 2: Viewport 375x667 → MobileTopBar cu butoane VIZIBILE
|
||||
- [ ] Test 3: Click Meniu → MobileDrawerMenu cu ANALIZE
|
||||
- [ ] Test 4: Pagina Facturi → Tab-uri + butoane imediat vizibile (fără blank)
|
||||
- [ ] Test 5: Upload bon cu eroare → Arată "Eroare" nu "În procesare"
|
||||
- [ ] Test 6: Refresh → Bonul cu eroare rămâne
|
||||
- [ ] npm run build passes
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
|
||||
1. [REQ-001] Pe viewport < 768px, AppHeader și sidebar desktop trebuie ascunse complet
|
||||
2. [REQ-002] MobileTopBar trebuie să fie singurul header vizibil pe mobil
|
||||
3. [REQ-003] MobileDrawerMenu trebuie să se deschidă la click pe butonul Meniu din MobileTopBar
|
||||
4. [REQ-004] Butoanele actions din MobileTopBar trebuie să fie vizibile și funcționale
|
||||
5. [REQ-005] batchProgressStore trebuie să restaureze și să afișeze joburi cu status 'failed'
|
||||
6. [REQ-006] Editarea unui bon cu eroare trebuie să reseteze processing_status pentru re-workflow
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
|
||||
- NU modificăm layout-ul desktop (rămâne neschimbat)
|
||||
- NU adăugăm funcționalități noi (doar fix-uri)
|
||||
- NU modificăm stilurile cardurilor de bonuri
|
||||
- NU schimbăm structura hamburger menu (doar ne asigurăm că se deschide corect)
|
||||
|
||||
## 6. Considerații Tehnice
|
||||
|
||||
### Stack/Tehnologii
|
||||
- Vue 3 Composition API
|
||||
- PrimeVue components
|
||||
- Pinia stores (batchProgressStore)
|
||||
- CSS media queries / v-if cu isMobile computed
|
||||
|
||||
### Patterns de Urmat
|
||||
- `isMobile` computed bazat pe `window.innerWidth < 768`
|
||||
- `v-if="!isMobile"` pentru componente desktop-only
|
||||
- `v-if="isMobile"` pentru componente mobile-only
|
||||
|
||||
### Fișiere Cheie de Modificat
|
||||
| Fișier | Modificare |
|
||||
|--------|------------|
|
||||
| `src/App.vue` sau layout component | v-if pentru AppHeader/sidebar |
|
||||
| `src/shared/components/layout/AppHeader.vue` | Verificare isMobile |
|
||||
| `src/modules/reports/views/InvoicesView.vue` | CSS padding-top |
|
||||
| `src/modules/data-entry/views/ReceiptsListView.vue` | CSS padding-top |
|
||||
| `src/stores/batchProgressStore.js` | Include 'failed' în restore |
|
||||
| `backend/modules/data_entry/routers/receipts.py` | Reset processing_status |
|
||||
|
||||
### Riscuri Tehnice
|
||||
- Modificarea layout-ului principal poate afecta toate paginile - testare completă necesară
|
||||
- isMobile computed trebuie să fie reactiv la resize
|
||||
|
||||
## 7. Considerații UI/UX
|
||||
|
||||
- Mobile layout trebuie să fie curat, fără suprapuneri
|
||||
- Butoanele touch target minim 48px
|
||||
- Feedback vizual clar pentru starea bonurilor (Eroare vs În procesare)
|
||||
- Tranziție smooth pentru MobileDrawerMenu
|
||||
|
||||
## 8. Success Metrics
|
||||
|
||||
- 100% teste Playwright trec
|
||||
- 0 suprapuneri vizuale pe viewport mobil
|
||||
- Bonuri cu eroare persistent după refresh
|
||||
- Timp de încărcare pagină neschimbat
|
||||
|
||||
## 9. Open Questions
|
||||
|
||||
- [x] Cauza exactă a problemei? → Header desktop nu este ascuns pe mobil (confirmat prin Playwright)
|
||||
- [x] isMobile computed există? → Trebuie verificat în layout principal
|
||||
- [ ] Există alte pagini afectate de layout? → De verificat după fix
|
||||
@@ -1,380 +0,0 @@
|
||||
# PRD: Mobile Navigation & Dashboard Split Improvements
|
||||
|
||||
## 1. Introducere
|
||||
|
||||
Acest PRD extinde implementarea Material Design mobilă anterioară (`ralph/unified-mobile-md`) cu îmbunătățiri ale navigării și restructurarea Dashboard-ului. Scopul este o experiență de navigare mai intuitivă pe mobil, cu pagini dedicate pentru secțiunile complexe ale Dashboard-ului și un sistem de meniuri consistent.
|
||||
|
||||
**Branch de lucru:** `ralph/unified-mobile-md` (continuare)
|
||||
|
||||
## 2. Obiective
|
||||
|
||||
### Obiectiv Principal
|
||||
- **Navigare intuitivă**: Footer nav activ pe toate paginile, hamburger menu Material Design, acces facil la setări
|
||||
|
||||
### Obiective Secundare
|
||||
- Dashboard split în 3 pagini pentru performanță și claritate
|
||||
- Butoane context-aware pentru editare/vizualizare bonuri
|
||||
- Pagină hub pentru setări
|
||||
- Profil utilizator în hamburger menu
|
||||
|
||||
### Metrici de Succes
|
||||
- 100% pagini cu MobileBottomNav activ
|
||||
- Navigare către orice pagină în max 2 tap-uri
|
||||
- Dashboard load time redus cu 30% (doar KPIs pe pagina principală)
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
---
|
||||
|
||||
### US-201: MobileBottomNav activ pe Dashboard
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** să văd footer navigation și pe Dashboard
|
||||
**Pentru că** acum Dashboard-ul nu are MobileBottomNav și nu pot naviga ușor
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] DashboardView.vue include MobileBottomNav component
|
||||
- [ ] Link-ul "Rapoarte" din nav este activ/highlighted pe Dashboard
|
||||
- [ ] MobileTopBar adăugat cu title "Dashboard"
|
||||
- [ ] Verify in browser: navigarea funcționează din Dashboard
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-202: Hamburger Menu Material Design cu Profil
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** meniul hamburger să aibă design Material cu secțiune profil
|
||||
**Pentru că** actualul meniu (Sidebar) nu se integrează vizual cu restul interfeței
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Componentă `MobileDrawerMenu.vue` creată în src/shared/components/mobile/
|
||||
- [ ] Secțiuni: Header cu logo, Navigare principală, Profil utilizator (nume + logout)
|
||||
- [ ] Link-uri navigare: Dashboard, Bonuri, Facturi, Balanță, Trezorerie, Setări
|
||||
- [ ] Active state pe link-ul curent (bazat pe route)
|
||||
- [ ] Animație slide-in de la stânga
|
||||
- [ ] Close pe tap outside sau pe link click
|
||||
- [ ] Dark mode support
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-203: Dashboard KPIs Only View
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** Dashboard-ul principal să arate doar KPI cards
|
||||
**Pentru că** încărcarea completă e lentă și vreau acces rapid la overview
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] DashboardView.vue pe mobil afișează DOAR: SwipeableCards cu KPIs
|
||||
- [ ] Adăugare 2 carduri quick-link: "Analiză Scadențe →" și "Facturi Detaliate →"
|
||||
- [ ] Click pe quick-link navighează la pagina dedicată
|
||||
- [ ] Desktop rămâne neschimbat (toate secțiunile)
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-204: Creare Pagină Analiză Scadențe
|
||||
**Ca** utilizator
|
||||
**Vreau** o pagină dedicată pentru analiza scadențelor clienți/furnizori
|
||||
**Pentru că** e o secțiune complexă care merită pagină separată
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] View nou: `src/modules/reports/views/MaturityAnalysisView.vue`
|
||||
- [ ] Route: `/reports/maturity-analysis`
|
||||
- [ ] Conține componenta MaturityAndDetailsCard (partea de analiză)
|
||||
- [ ] MobileTopBar cu title "Analiză Scadențe" și buton ← Înapoi la Dashboard
|
||||
- [ ] MobileBottomNav activ
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-205: Creare Pagină Facturi Detaliate
|
||||
**Ca** utilizator
|
||||
**Vreau** o pagină dedicată pentru tabelul facturilor detaliate
|
||||
**Pentru că** tabelul detaliat e complex și merită pagină separată
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] View nou: `src/modules/reports/views/DetailedInvoicesView.vue`
|
||||
- [ ] Route: `/reports/detailed-invoices`
|
||||
- [ ] Conține componenta/partea de tabel detaliat din MaturityAndDetailsCard
|
||||
- [ ] MobileTopBar cu title "Facturi Detaliate" și buton ← Înapoi
|
||||
- [ ] MobileBottomNav activ
|
||||
- [ ] Filtre în BottomSheet pe mobil
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-206: Creare Pagină Hub Setări
|
||||
**Ca** utilizator
|
||||
**Vreau** o pagină centrală cu toate opțiunile de setări
|
||||
**Pentru că** butonul Setări din footer trebuie să ducă undeva util
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] View nou: `src/modules/reports/views/SettingsHubView.vue`
|
||||
- [ ] Route: `/settings`
|
||||
- [ ] Carduri pentru: OCR Setări, Cache Stats, Loguri Server, Telegram (dacă admin)
|
||||
- [ ] MobileTopBar cu title "Setări"
|
||||
- [ ] MobileBottomNav cu Setări activ
|
||||
- [ ] Click pe card navighează la pagina respectivă
|
||||
- [ ] Design responsive (grid 2x2 pe mobil, 4 columns pe desktop)
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-207: Actualizare MobileBottomNav cu link Setări
|
||||
**Ca** utilizator
|
||||
**Vreau** butonul Setări din footer să ducă la Hub Setări
|
||||
**Pentru că** acum duce direct la OCR Metrics
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MobileBottomNav: link Setări → `/settings` (nu `/data-entry/ocr-metrics`)
|
||||
- [ ] Icon: pi-cog
|
||||
- [ ] Active state când pe `/settings` sau `/settings/*` sau pagini admin
|
||||
- [ ] Actualizare în toate paginile care folosesc MobileBottomNav
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-208: Actualizare Router cu noile rute
|
||||
**Ca** developer
|
||||
**Vreau** router-ul configurat pentru noile pagini
|
||||
**Pentru că** navigarea trebuie să funcționeze
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Rută `/reports/maturity-analysis` → MaturityAnalysisView
|
||||
- [ ] Rută `/reports/detailed-invoices` → DetailedInvoicesView
|
||||
- [ ] Rută `/settings` → SettingsHubView
|
||||
- [ ] Lazy loading pentru toate view-urile noi
|
||||
- [ ] Redirect `/data-entry/ocr-metrics` accesibil din Settings Hub
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-209: Butoane Context-Aware în Editare Bon
|
||||
**Ca** utilizator
|
||||
**Vreau** butoanele din editare bon să se schimbe în funcție de starea bonului
|
||||
**Pentru că** acțiunile disponibile diferă pentru draft/pending/approved
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] ReceiptCreateUnifiedView detectează starea bonului (draft/pending/approved/rejected)
|
||||
- [ ] **Draft**: Salvează | Submit pentru Aprobare | Șterge
|
||||
- [ ] **Pending**: Salvează | Aprobă | Respinge (dacă are permisiuni)
|
||||
- [ ] **Approved**: doar vizualizare (butoane disabled sau ascunse)
|
||||
- [ ] **Rejected**: Salvează (re-edit) | Re-submit
|
||||
- [ ] Butoane în MobileActionBar fix jos pe mobil
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-210: Creare MobileActionBar Component
|
||||
**Ca** developer
|
||||
**Vreau** componentă reutilizabilă pentru butoane de acțiune pe mobil
|
||||
**Pentru că** avem nevoie de bar fix jos cu butoane în mai multe pagini
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Componentă `MobileActionBar.vue` în src/shared/components/mobile/
|
||||
- [ ] Props: actions (array of {label, icon, severity, handler, disabled})
|
||||
- [ ] Layout: butoane full-width sau side-by-side (2 butoane)
|
||||
- [ ] Position: fixed bottom, above MobileBottomNav
|
||||
- [ ] Animație: slide-up la mount
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-211: Integrare MobileActionBar în ReceiptCreateUnifiedView
|
||||
**Ca** utilizator
|
||||
**Vreau** butoanele de acțiune pentru bon să fie în action bar pe mobil
|
||||
**Pentru că** butoanele actuale sunt în form și nu sunt ușor accesibile
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] ReceiptCreateUnifiedView folosește MobileActionBar pe mobil
|
||||
- [ ] Desktop păstrează butoanele în form
|
||||
- [ ] Buton Înapoi în MobileTopBar (deja există din US-105)
|
||||
- [ ] Action bar dispare când se deschide BottomSheet sau alte overlay-uri
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-212: Quick Links în Dashboard Mobile
|
||||
**Ca** utilizator
|
||||
**Vreau** carduri clickabile în Dashboard pentru a ajunge la Scadențe și Facturi
|
||||
**Pentru că** trebuie să știu unde găsesc datele detaliate
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] După SwipeableCards, 2 carduri: "Analiză Scadențe" și "Facturi Detaliate"
|
||||
- [ ] Design: icon + titlu + săgeată dreaptă (→)
|
||||
- [ ] Click navighează la pagina respectivă
|
||||
- [ ] Doar pe mobil (desktop are totul în aceeași pagină)
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-213: Actualizare Hamburger Menu în toate paginile
|
||||
**Ca** utilizator
|
||||
**Vreau** hamburger menu-ul să funcționeze uniform în toată aplicația
|
||||
**Pentru că** acum unele pagini au Sidebar, altele nu au
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Toate paginile cu MobileTopBar: click pe ☰ deschide MobileDrawerMenu
|
||||
- [ ] MobileDrawerMenu înlocuiește vechiul Sidebar pe mobil
|
||||
- [ ] Desktop păstrează navigarea existentă
|
||||
- [ ] npm run build passes
|
||||
|
||||
---
|
||||
|
||||
### US-214: Actualizare Documentație MOBILE_PATTERNS.md
|
||||
**Ca** developer viitor
|
||||
**Vreau** documentația actualizată cu noile componente și pattern-uri
|
||||
**Pentru că** altfel nu voi ști cum să le folosesc
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Secțiune nouă: MobileDrawerMenu (usage, props)
|
||||
- [ ] Secțiune nouă: MobileActionBar (usage, props)
|
||||
- [ ] Secțiune actualizată: Navigation patterns (footer → settings hub)
|
||||
- [ ] Diagrame ASCII actualizate cu noile rute
|
||||
- [ ] npm run build passes (doar pentru validare că nu s-a stricat nimic)
|
||||
|
||||
---
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
|
||||
1. [REQ-001] Toate paginile mobile TREBUIE să aibă MobileBottomNav vizibil
|
||||
2. [REQ-002] Hamburger menu TREBUIE să fie MobileDrawerMenu pe mobil
|
||||
3. [REQ-003] Dashboard mobil afișează DOAR KPIs + quick links
|
||||
4. [REQ-004] Setări din footer navighează la Settings Hub
|
||||
5. [REQ-005] Editare bon are butoane context-aware bazate pe status
|
||||
6. [REQ-006] Noile pagini (Scadențe, Facturi, Settings) au MobileTopBar + MobileBottomNav
|
||||
7. [REQ-007] Navigare către orice pagină în max 2 tap-uri
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
|
||||
- ❌ Nu schimbăm layout-ul desktop (doar mobile)
|
||||
- ❌ Nu adăugăm funcționalități noi în backend
|
||||
- ❌ Nu modificăm logica de business pentru bonuri
|
||||
- ❌ Nu schimbăm stilul cardurilor KPI (sunt deja bune)
|
||||
- ❌ Nu implementăm gesture navigation (swipe back)
|
||||
- ❌ Nu adăugăm notificări push
|
||||
|
||||
## 6. Considerații Tehnice
|
||||
|
||||
### Stack/Tehnologii
|
||||
- Vue 3 Composition API
|
||||
- Vue Router pentru navigare
|
||||
- Componente existente: MobileTopBar, MobileBottomNav, BottomSheet
|
||||
- PrimeVue pentru UI elements
|
||||
|
||||
### Patterns de Urmat
|
||||
- Pattern din ReceiptsListView pentru MobileTopBar + MobileBottomNav
|
||||
- BottomSheet pentru filtre pe mobil
|
||||
- isMobile composable pentru condiționare
|
||||
|
||||
### Dependențe
|
||||
- US-201, US-202 trebuie făcute înaintea celorlalte (componente de bază)
|
||||
- US-208 (router) trebuie făcut înainte de US-204, US-205, US-206
|
||||
- US-210 trebuie făcut înainte de US-211
|
||||
|
||||
### Riscuri Tehnice
|
||||
- **Risc mediu**: MaturityAndDetailsCard e complex, split-ul poate fi dificil
|
||||
- Mitigare: Extrage logica în composable reutilizabil
|
||||
- **Risc scăzut**: Schimbarea navigării poate afecta deep links
|
||||
- Mitigare: Păstrăm rutele vechi funcționale (redirect)
|
||||
|
||||
## 7. Considerații UI/UX
|
||||
|
||||
### Structură Navigare Nouă
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ HAMBURGER MENU (MobileDrawerMenu) │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ [Logo ROA2WEB] │
|
||||
│─────────────────────────────────────────────│
|
||||
│ 📊 Dashboard │
|
||||
│ 🧾 Bonuri │
|
||||
│ 📄 Facturi │
|
||||
│ 📈 Balanță │
|
||||
│ 💰 Trezorerie │
|
||||
│ ⚙️ Setări │
|
||||
│─────────────────────────────────────────────│
|
||||
│ 👤 Marius M. │
|
||||
│ [Logout] │
|
||||
└─────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ SETTINGS HUB │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ 🔍 OCR │ │ 📊 Cache │ │
|
||||
│ │ Setări │ │ Stats │ │
|
||||
│ └──────────┘ └──────────┘ │
|
||||
│ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ 📋 Loguri│ │ 📱Telegram│ │
|
||||
│ │ Server │ │ Bot │ │
|
||||
│ └──────────┘ └──────────┘ │
|
||||
└─────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ MOBILE ACTION BAR (Editare Bon) │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Status: DRAFT │
|
||||
│ ┌─────────────────────────────────────────┐ │
|
||||
│ │ [Salvează] [Submit Aprobare] │ │
|
||||
│ └─────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Status: PENDING │
|
||||
│ ┌─────────────────────────────────────────┐ │
|
||||
│ │ [Aprobă] [Respinge] │ │
|
||||
│ └─────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Flow Navigare Dashboard
|
||||
```
|
||||
Dashboard (KPIs)
|
||||
│
|
||||
├── Tap "Analiză Scadențe →"
|
||||
│ └── /reports/maturity-analysis
|
||||
│
|
||||
└── Tap "Facturi Detaliate →"
|
||||
└── /reports/detailed-invoices
|
||||
```
|
||||
|
||||
## 8. Success Metrics
|
||||
|
||||
- **Navigare**: 100% pagini cu footer nav activ
|
||||
- **Performance**: Dashboard load time < 1.5s pe 3G
|
||||
- **UX**: Max 2 tap-uri pentru orice destinație
|
||||
- **Consistency**: 0 pagini fără MobileTopBar pe mobil
|
||||
|
||||
## 9. Open Questions
|
||||
|
||||
- [ ] Settings Hub ar trebui să arate și versiunea aplicației?
|
||||
- [ ] Quick links în Dashboard să aibă și preview cu numere (ex: "5 scadențe azi")?
|
||||
- [ ] MobileDrawerMenu să aibă și opțiune de schimbare temă?
|
||||
|
||||
---
|
||||
|
||||
## Implementare Sugerată (Ordinea User Stories)
|
||||
|
||||
### Faza 1: Componente de Bază
|
||||
1. US-202: MobileDrawerMenu
|
||||
2. US-210: MobileActionBar
|
||||
|
||||
### Faza 2: Router & Pagini Noi
|
||||
3. US-208: Router updates
|
||||
4. US-206: Settings Hub
|
||||
5. US-204: Maturity Analysis View
|
||||
6. US-205: Detailed Invoices View
|
||||
|
||||
### Faza 3: Dashboard & Navigare
|
||||
7. US-201: Dashboard cu MobileBottomNav
|
||||
8. US-203: Dashboard KPIs Only
|
||||
9. US-212: Quick Links
|
||||
10. US-207: Update MobileBottomNav link Setări
|
||||
|
||||
### Faza 4: Hamburger Menu Integration
|
||||
11. US-213: Hamburger menu în toate paginile
|
||||
|
||||
### Faza 5: Editare Bon
|
||||
12. US-209: Butoane context-aware
|
||||
13. US-211: MobileActionBar în ReceiptCreateUnifiedView
|
||||
|
||||
### Faza 6: Documentație
|
||||
14. US-214: Update MOBILE_PATTERNS.md
|
||||
@@ -1,133 +0,0 @@
|
||||
# PRD: Mobile UI Fixes Phase 5
|
||||
|
||||
## 1. Introducere
|
||||
|
||||
Corecții pentru regresii și probleme de UX identificate după implementările din faza anterioară. Include repararea componentelor care nu mai funcționează (FAB, meniu acțiuni), corectarea navigării pe paginile Analize, și optimizarea spațiului vizual.
|
||||
|
||||
## 2. Obiective
|
||||
|
||||
### Obiectiv Principal
|
||||
- Restabilirea funcționalității complete pe Lista Bonuri (FAB + meniu acțiuni per bon)
|
||||
- Corectarea pattern-ului de navigare pe paginile Analize
|
||||
|
||||
### Obiective Secundare
|
||||
- Mărirea spațiului de afișare pentru tabelul de scadențe
|
||||
- Reducerea spațiului gol excesiv din partea de sus a paginilor
|
||||
|
||||
### Metrici de Succes
|
||||
- Toate funcționalitățile interactive funcționează pe mobil și desktop
|
||||
- Build-ul trece fără erori sau warnings relevante
|
||||
- Verificare vizuală cu Playwright confirmă corecturile
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
### US-701: Reparare SpeedDial FAB pe Lista Bonuri
|
||||
**Ca** utilizator pe mobil
|
||||
**Vreau** să văd butonul + în dreapta jos și să pot crea bonuri noi
|
||||
**Pentru că** este metoda principală de adăugare bonuri pe mobil
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] SpeedDial este importat corect din 'primevue/speeddial'
|
||||
- [ ] Butonul + apare în dreapta jos pe mobil (când nu este în selection mode)
|
||||
- [ ] Click pe + deschide opțiunile: Bon Nou Manual, Scanare OCR, Upload în Masă
|
||||
- [ ] npm run build passes fără warnings legate de SpeedDial
|
||||
- [ ] Verify in browser: FAB vizibil și funcțional pe mobil
|
||||
|
||||
### US-702: Verificare Meniu Acțiuni (...) Per Bon
|
||||
**Ca** utilizator
|
||||
**Vreau** să pot accesa meniul de acțiuni pentru fiecare bon
|
||||
**Pentru că** trebuie să pot edita, șterge, valida bonurile individual
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Butonul ... pe fiecare bon deschide meniul cu opțiuni
|
||||
- [ ] Meniul conține opțiunile corecte în funcție de status (Edit, View, Delete, Approve, etc.)
|
||||
- [ ] Meniul se poziționează corect pe mobil și desktop
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-703: Navigare Hamburger pe Paginile Analize
|
||||
**Ca** utilizator pe mobil
|
||||
**Vreau** să văd meniul hamburger pe paginile Analize (nu săgeata înapoi)
|
||||
**Pentru că** trebuie să pot accesa firma, perioada și navigarea din orice pagină
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MaturityAnalysisView (Analize Scadențe) folosește `:show-menu="true"` nu `:show-back="true"`
|
||||
- [ ] DetailedInvoicesView (Facturi Detaliate) folosește `:show-menu="true"` nu `:show-back="true"`
|
||||
- [ ] Click pe hamburger deschide MobileDrawerMenu
|
||||
- [ ] Pattern-ul este consistent cu InvoicesView și CashView/BankView
|
||||
- [ ] Verify in browser: hamburger icon vizibil, drawer se deschide
|
||||
|
||||
### US-704: Mărire Spațiu Tabel Scadențe
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd mai multe rânduri în tabelul de scadențe fără să scrollez
|
||||
**Pentru că** acum încap doar 3-4 rânduri și trebuie să scrollez constant
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] max-height pentru .maturity-list crescut de la 250px la 400px pe desktop
|
||||
- [ ] max-height pentru .maturity-list crescut de la 200px la 350px pe mobil
|
||||
- [ ] min-height pentru .tab-content redus sau eliminat pentru a nu forța scroll
|
||||
- [ ] Verify in browser: cel puțin 8-10 rânduri vizibile fără scroll pe desktop
|
||||
|
||||
### US-705: Reducere Padding/Margin Top Excesiv
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd conținutul imediat fără spațiu gol excesiv în partea de sus
|
||||
**Pentru că** acum partea de sus a paginilor are prea mult spațiu nefolosit
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Reducere margin-bottom pe .page-header de la var(--space-md) la var(--space-sm)
|
||||
- [ ] Verificare padding-top pe .app-container - eliminare dacă e redundant
|
||||
- [ ] Verificare că modificările nu afectează negativ alte pagini
|
||||
- [ ] Verificare în mod desktop și mobil
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
|
||||
1. [REQ-001] SpeedDial trebuie importat și funcțional pe ReceiptsListView
|
||||
2. [REQ-002] Meniul de acțiuni per bon trebuie să se deschidă la click pe ...
|
||||
3. [REQ-003] Paginile Analize trebuie să aibă hamburger menu, nu back button
|
||||
4. [REQ-004] Tabelul de scadențe trebuie să afișeze minimum 8 rânduri fără scroll
|
||||
5. [REQ-005] Spațiul gol din partea de sus a paginilor trebuie redus
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
|
||||
- Nu modificăm logica de business a bonurilor sau scadențelor
|
||||
- Nu schimbăm stilul general Material Design
|
||||
- Nu adăugăm funcționalități noi, doar corectăm cele existente
|
||||
- Nu modificăm paginile admin (CacheStats, ServerLogs) - acele back buttons sunt corecte
|
||||
|
||||
## 6. Considerații Tehnice
|
||||
|
||||
### Stack/Tehnologii
|
||||
- Vue.js 3 cu Composition API
|
||||
- PrimeVue (SpeedDial, Menu components)
|
||||
- CSS Design Tokens
|
||||
|
||||
### Patterns de Urmat
|
||||
- InvoicesView.vue pentru pattern-ul hamburger menu
|
||||
- CSS_PATTERNS.md pentru spacing tokens
|
||||
|
||||
### Fișiere de Modificat
|
||||
| Fișier | Modificări |
|
||||
|--------|------------|
|
||||
| `src/modules/data-entry/views/receipts/ReceiptsListView.vue` | Import SpeedDial, verificare menuItems |
|
||||
| `src/modules/reports/views/MaturityAnalysisView.vue` | show-menu în loc de show-back, reducere padding |
|
||||
| `src/modules/reports/views/DetailedInvoicesView.vue` | show-menu în loc de show-back |
|
||||
| `src/modules/reports/components/dashboard/cards/MaturityAnalysisCard.vue` | Mărire max-height maturity-list |
|
||||
|
||||
### Riscuri Tehnice
|
||||
- SpeedDial mask-ul CSS poate necesita ajustări pentru dark mode
|
||||
- Verificare că nu există conflicte cu MobileBottomNav pe z-index
|
||||
|
||||
## 7. Considerații UI/UX
|
||||
|
||||
- FAB button trebuie să fie vizibil deasupra MobileBottomNav
|
||||
- Meniul de acțiuni trebuie să aibă touch targets de min 44px
|
||||
- Hamburger menu trebuie să fie consistent pe toate paginile de rapoarte
|
||||
|
||||
## 8. Success Metrics
|
||||
- 0 erori de build
|
||||
- Toate cele 5 user stories verificate vizual cu Playwright
|
||||
- Consistență navigare pe toate paginile de rapoarte
|
||||
|
||||
## 9. Open Questions
|
||||
- [x] Cauză FAB nefuncțional: SpeedDial nu este importat (CONFIRMAT)
|
||||
- [ ] Cauză meniu acțiuni nefuncțional: De verificat dacă menuItems e populat corect
|
||||
@@ -1,424 +0,0 @@
|
||||
# PRD: Mobile UX Improvements & Bulk Upload Bug Fixes
|
||||
|
||||
## 1. Introducere
|
||||
|
||||
Acest PRD adresează multiple probleme identificate în modulul de bulk upload bonuri și îmbunătățiri UX pentru interfața mobilă. Problemele includ refresh incorect al listei, pierderea bonurilor cu eroare, lipsa selecției multiple pe mobil, și nevoia unei interfețe mai native pentru Android.
|
||||
|
||||
**Branch de lucru:** `ralph/bulk-receipt-upload` (continuăm în același branch)
|
||||
|
||||
**Context:** PRD-ul anterior (prd-bulk-receipt-upload.md) a implementat funcționalitatea de bază, dar testarea în producție a evidențiat probleme de UX și bugs ce necesită rezolvare.
|
||||
|
||||
## 2. Obiective
|
||||
|
||||
### Obiectiv Principal
|
||||
- Corectarea comportamentului de refresh pentru a păstra bonurile cu eroare în listă și a menține ordinea
|
||||
|
||||
### Obiective Secundare
|
||||
- Implementarea selecției multiple pe mobil cu interfață în stil Android nativ
|
||||
- Afișarea numelui fișierului pentru toate bonurile (nu doar cele în procesare)
|
||||
- Rezolvarea bug-ului de refresh automat la selectarea fișierelor
|
||||
|
||||
### Metrici de Succes
|
||||
- Zero bonuri "pierdute" după procesare bulk
|
||||
- Timp de selecție multiple pe mobil < 3 secunde pentru 10 bonuri
|
||||
- User satisfaction score > 4/5 pentru interfața mobilă
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
### US-034: Fix - Refresh Individual vs Refresh Total
|
||||
**Ca** utilizator
|
||||
**Vreau** ca bonurile să se actualizeze individual fără să se reîncarce toată lista
|
||||
**Pentru că** vreau să văd progresul în timp real fără să pierd poziția în listă
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] SSE handler NU apelează `store.fetchReceipts()` când un receipt nu este în pagina curentă
|
||||
- [ ] În schimb, verifică dacă receipt-ul aparține unui batch activ și îl adaugă local
|
||||
- [ ] Ordinea bonurilor din batch rămâne stabilă (nu se reordonează)
|
||||
- [ ] Bonurile noi din procesare se inserează în poziția corectă
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: uploadează 5 bonuri, nu se reîncarcă pagina între procesări
|
||||
|
||||
**Technical Notes:**
|
||||
- Modificare în `handleSSEStatusChange` din `ReceiptsListView.vue:2397`
|
||||
- Când receipt nu e găsit: verifică dacă batch_id e în batchProgressStore, apoi fetch individual receipt și inserează local
|
||||
|
||||
### US-035: Fix - Bonuri cu Eroare Rămân în Listă
|
||||
**Ca** utilizator
|
||||
**Vreau** ca bonurile cu eroare de procesare să rămână vizibile în listă
|
||||
**Pentru că** vreau să le pot edita manual sau să le șterg
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Bonurile cu `processing_status='failed'` NU sunt eliminate din view după refresh
|
||||
- [ ] Eroarea de extragere dată/sumă afișează bonul cu status "Eroare" și buton "Editează"
|
||||
- [ ] Link rapid "Editează manual" duce la formularul de editare cu datele disponibile pre-populate
|
||||
- [ ] Bonurile failed au highlight vizual (roșu subtil) pentru identificare ușoară
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: bon cu eroare OCR rămâne în listă și poate fi editat
|
||||
|
||||
**Technical Notes:**
|
||||
- Bonurile cu eroare ar trebui să aibă `status='draft'` și `processing_status='failed'`
|
||||
- Nu se șterg la refresh, doar se actualizează in-place
|
||||
|
||||
### US-036: Afișare Nume Fișier pentru Toate Bonurile
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd numele fișierului original pentru bonurile procesate
|
||||
**Pentru că** vreau să identific care bon corespunde cărui fișier uploadat
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Coloana "Fișier" afișează `original_filename` și pentru receipt-uri completate, nu doar pentru job-uri
|
||||
- [ ] Pe mobil, numele fișierului apare sub partenăr (font mic, gri)
|
||||
- [ ] Tooltip pe desktop arată numele complet dacă e trunchiat
|
||||
- [ ] Dacă receipt nu are `original_filename`, afișează "-"
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: bon procesat afișează numele fișierului original
|
||||
|
||||
**Technical Notes:**
|
||||
- Backend trebuie să populeze `original_filename` pe receipt din job-ul OCR
|
||||
- Verifică că auto-save service copiază filename din job la receipt
|
||||
|
||||
### US-037: Fix - Upload Nu Mai Face Refresh Automat
|
||||
**Ca** utilizator
|
||||
**Vreau** ca selectarea fișierelor să nu reîncarce pagina
|
||||
**Pentru că** pierd fișierele selectate înainte să apăs "Procesează"
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Selectarea fișierelor via input NU declanșează refresh/reload pagină
|
||||
- [ ] Fișierele selectate rămân în listă până la submit explicit
|
||||
- [ ] Comportament identic pe desktop și mobil (Chrome, Safari)
|
||||
- [ ] Nu există race condition între clonarea fișierelor și resetarea input-ului
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify on mobile: selectează 5 fișiere, toate rămân în listă
|
||||
|
||||
**Technical Notes:**
|
||||
- Bug probabil în `onBulkFileInputChange` sau în interacțiunea cu store
|
||||
- Verifică că nu există watchers care declanșează refresh la schimbări de state
|
||||
- Test specific pe Chrome Android - vezi gotcha din CLAUDE.md despre File API
|
||||
|
||||
### US-038: Mobile - Selecție Multiplă prin Long-Press
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** să selectez bonuri prin apăsare lungă
|
||||
**Pentru că** vreau să pot șterge sau acționa asupra mai multor bonuri simultan
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Long-press (500ms) pe un card activează modul de selecție
|
||||
- [ ] Card-ul selectat primește checkmark și background diferit
|
||||
- [ ] După activare, tap simplu pe alte carduri le adaugă/elimină din selecție
|
||||
- [ ] Tap în afara cardurilor (pe background) dezactivează modul selecție
|
||||
- [ ] Header contextual arată numărul de elemente selectate
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify on mobile: long-press selectează, tap adaugă la selecție
|
||||
|
||||
**CSS Requirements:**
|
||||
- `.receipt-card.selected { background: var(--blue-50); border-color: var(--blue-500); }`
|
||||
- `.receipt-card .selection-check { position: absolute; top: 8px; right: 8px; }`
|
||||
- Testează dark mode: background selectat vizibil
|
||||
|
||||
### US-039: Mobile - Select All și Buton Ștergere
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** să am butoane "Selectează tot" și "Șterge" în modul selecție
|
||||
**Pentru că** vreau să pot șterge rapid mai multe bonuri
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] În modul selecție, apare top bar contextual cu:
|
||||
- Numărul de selectate: "X selectate"
|
||||
- Buton "Selectează tot"
|
||||
- Buton X pentru a ieși din modul selecție
|
||||
- [ ] Apare bottom bar cu buton "Șterge" (roșu, icon coș)
|
||||
- [ ] "Selectează tot" selectează toate bonurile din pagina curentă
|
||||
- [ ] Buton "Șterge" afișează confirmare înainte de ștergere
|
||||
- [ ] După ștergere, modul selecție se dezactivează
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify on mobile: select all + delete funcționează
|
||||
|
||||
**CSS Requirements:**
|
||||
- Top bar: `position: sticky; top: 0; z-index: 100;`
|
||||
- Bottom bar: `position: fixed; bottom: 0; left: 0; right: 0;`
|
||||
- Animație slide-in pentru bars
|
||||
|
||||
### US-040: Mobile - Layout Android Nativ pentru Lista Bonuri
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** o interfață similară cu aplicațiile Android native
|
||||
**Pentru că** vreau experiență familiară și intuitivă
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] **Top Bar** fixă cu:
|
||||
- Stânga: Hamburger menu / Back arrow
|
||||
- Centru: Titlu "Bonuri Fiscale"
|
||||
- Dreapta: Search icon, Filter icon, More options (3 dots)
|
||||
- [ ] **Filter Chips** sub top bar (orizontal scrollabil):
|
||||
- Toate, Ciorne, În așteptare, Validate, Respinse
|
||||
- Chip activ are background primary color
|
||||
- [ ] **Bottom Navigation** fixă cu 4 tab-uri:
|
||||
- Bonuri (icon receipt, activ)
|
||||
- Upload (icon cloud-upload)
|
||||
- Rapoarte (icon chart)
|
||||
- Setări (icon cog)
|
||||
- [ ] **FAB** (Floating Action Button) în colț dreapta jos:
|
||||
- Icon "+" pentru adăugare bon nou
|
||||
- Se ascunde când se face scroll în jos, apare când scroll în sus
|
||||
- [ ] Lista ocupă spațiul dintre top bar și bottom nav
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify on mobile: layout similar cu Gmail/WhatsApp
|
||||
|
||||
**CSS Requirements:**
|
||||
```css
|
||||
.mobile-top-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 56px;
|
||||
background: var(--surface-card);
|
||||
border-bottom: 1px solid var(--surface-border);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.mobile-bottom-nav {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 56px;
|
||||
background: var(--surface-card);
|
||||
border-top: 1px solid var(--surface-border);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.mobile-fab {
|
||||
position: fixed;
|
||||
bottom: 72px; /* above bottom nav */
|
||||
right: 16px;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 16px;
|
||||
background: var(--primary-500);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
```
|
||||
|
||||
### US-041: Mobile - Layout Android pentru Editare/Creare Bon
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** interfață de editare bon similară cu compose email în Gmail
|
||||
**Pentru că** vreau butoane de acțiune accesibile și layout familiar
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] **Top Bar** cu:
|
||||
- Stânga: X (close) sau Back arrow
|
||||
- Centru: "Bon Nou" / "Editare Bon #123"
|
||||
- Dreapta: Attach icon, Save/Submit icon
|
||||
- [ ] **Content Area** scrollabilă cu form fields
|
||||
- [ ] **Bottom Action Bar** fixă cu butoane:
|
||||
- "Salvează Ciornă" (secondary)
|
||||
- "Trimite pentru Validare" (primary)
|
||||
- [ ] Form fields ocupă 100% width pe mobil
|
||||
- [ ] Keyboard-aware: bottom bar se mută deasupra tastaturii
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify on mobile: layout similar cu Gmail compose
|
||||
|
||||
**CSS Requirements:**
|
||||
```css
|
||||
.mobile-receipt-form {
|
||||
padding-bottom: 80px; /* space for bottom bar */
|
||||
}
|
||||
|
||||
.mobile-form-bottom-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
background: var(--surface-card);
|
||||
border-top: 1px solid var(--surface-border);
|
||||
display: flex;
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
.mobile-form-bottom-bar .p-button {
|
||||
flex: 1;
|
||||
}
|
||||
```
|
||||
|
||||
### US-042: Mobile - Layout Android pentru Vizualizare Bon
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** interfață de vizualizare bon similară cu view email în Gmail
|
||||
**Pentru că** vreau acțiuni rapide și navigare ușoară
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] **Top Bar** cu:
|
||||
- Stânga: Back arrow
|
||||
- Dreapta: Edit icon, Delete icon, More options
|
||||
- [ ] **Content Area** cu detalii bon (read-only)
|
||||
- [ ] **Bottom Action Bar** cu butoane contextuale:
|
||||
- Pentru DRAFT: "Editează", "Trimite"
|
||||
- Pentru PENDING: "Validează", "Respinge" (dacă are permisiuni)
|
||||
- Pentru APPROVED: "Anulează validare" (dacă are permisiuni)
|
||||
- [ ] Swipe left/right pentru navigare între bonuri (optional, nice-to-have)
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify on mobile: acțiuni accesibile din bottom bar
|
||||
|
||||
### US-043: Păstrare Ordine Bonuri la Refresh
|
||||
**Ca** utilizator
|
||||
**Vreau** ca bonurile să rămână în ordinea în care au fost uploadate
|
||||
**Pentru că** vreau să urmăresc progresul fiecărui bon uploadat
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Bonurile din același batch păstrează ordinea de upload (nu se reordonează alfabetic sau by date)
|
||||
- [ ] Un bon finalizat rămâne în aceeași poziție vizuală, nu sare la sfârșit
|
||||
- [ ] SSE updates modifică status-ul in-place, fără a muta rândul
|
||||
- [ ] Refresh manual (pull-to-refresh) poate reordona, dar SSE updates nu
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: bon procesat nu își schimbă poziția în listă
|
||||
|
||||
**Technical Notes:**
|
||||
- Lista trebuie sortată by `created_at DESC` sau by batch order, nu by last_modified
|
||||
- `updateReceiptInPlace` din store NU trebuie să reordoneze array-ul
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
|
||||
1. [REQ-011] Bonurile cu eroare OCR rămân vizibile în listă cu status "Eroare"
|
||||
2. [REQ-012] Refresh via SSE NU reîncarcă toată lista, doar actualizează individual
|
||||
3. [REQ-013] Numele fișierului original e afișat pentru toate bonurile
|
||||
4. [REQ-014] Selecția multiplă pe mobil funcționează via long-press
|
||||
5. [REQ-015] Interfața mobilă urmează design patterns Android Material
|
||||
6. [REQ-016] Bottom navigation are 4 tab-uri: Bonuri, Upload, Rapoarte, Setări
|
||||
7. [REQ-017] FAB pentru "Bon Nou" în colț dreapta jos pe mobil
|
||||
8. [REQ-018] Ordinea bonurilor rămâne stabilă în cadrul unui batch
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
|
||||
- **NU** facem swipe gestures pentru acțiuni (delete/archive) - prea complex
|
||||
- **NU** facem animații complexe de tranziție între pagini
|
||||
- **NU** schimbăm layout-ul desktop - doar mobil
|
||||
- **NU** facem tab-uri funcționale pentru Rapoarte/Setări (placeholder pentru moment)
|
||||
- **NU** facem pull-to-refresh - refresh via SSE e suficient
|
||||
- **NU** facem offline mode sau caching local
|
||||
|
||||
## 6. Considerații Tehnice
|
||||
|
||||
### Stack/Tehnologii
|
||||
- **Frontend:** Vue 3 Composition API, PrimeVue
|
||||
- **Mobile Detection:** `window.innerWidth < 768` sau `navigator.userAgent`
|
||||
- **Touch Events:** Native `touchstart`/`touchend` pentru long-press
|
||||
|
||||
### Patterns de Urmat
|
||||
- Design tokens din `docs/DESIGN_TOKENS.md`
|
||||
- CSS patterns din `docs/CSS_PATTERNS.md`
|
||||
- Mobile-first responsive approach
|
||||
|
||||
### ⚠️ Mobile Long-Press Implementation
|
||||
```javascript
|
||||
// Long-press detection (500ms)
|
||||
let pressTimer = null
|
||||
|
||||
const onTouchStart = (item) => {
|
||||
pressTimer = setTimeout(() => {
|
||||
enterSelectionMode(item)
|
||||
}, 500)
|
||||
}
|
||||
|
||||
const onTouchEnd = () => {
|
||||
clearTimeout(pressTimer)
|
||||
}
|
||||
|
||||
const onTouchMove = () => {
|
||||
clearTimeout(pressTimer) // Cancel if user drags
|
||||
}
|
||||
```
|
||||
|
||||
### Dependențe
|
||||
- Store existent: `receiptsStore.js`
|
||||
- SSE Service: `sseService.js`
|
||||
- Batch Progress Store: `batchProgressStore.js`
|
||||
|
||||
### Riscuri Tehnice
|
||||
- **Touch event conflicts:** Long-press poate conflicta cu scroll pe mobile
|
||||
- Mitigare: Setează threshold mic pentru detectare scroll vs. hold
|
||||
- **Performance:** Lista mare poate încetini selecția
|
||||
- Mitigare: Virtual scrolling dacă > 100 items
|
||||
- **Cross-browser:** Safari iOS poate avea comportament diferit
|
||||
- Mitigare: Test explicit pe Safari iOS
|
||||
|
||||
## 7. Considerații UI/UX
|
||||
|
||||
### Mobile Layout Reference (din imagini)
|
||||
|
||||
**img1.jpg & img2.jpg (WhatsApp style):**
|
||||
- Top bar contextual cu count și acțiuni
|
||||
- Filter chips orizontal scrollabile
|
||||
- Bottom navigation cu 4 tabs
|
||||
- FAB în colț dreapta jos
|
||||
|
||||
**img3.jpg & img4.jpg (Gmail style):**
|
||||
- Top bar minimalist cu back + acțiuni
|
||||
- Bottom action bar cu butoane contextuale
|
||||
- Full-width content area
|
||||
|
||||
### Stări Mobile
|
||||
|
||||
| Stare | Top Bar | Content | Bottom |
|
||||
|-------|---------|---------|--------|
|
||||
| **Normal** | Title + Search + Filter | Lista carduri | Bottom Nav + FAB |
|
||||
| **Selection Mode** | "X selectate" + Select All + Close | Carduri cu checkmarks | Delete button |
|
||||
| **View Receipt** | Back + Edit + Delete | Detalii bon | Acțiuni contextuale |
|
||||
| **Edit Receipt** | Close + Attach + Save | Form fields | Save Draft + Submit |
|
||||
|
||||
### Accesibilitate
|
||||
- Touch targets minim 48x48px
|
||||
- Contrast suficient pentru badges și text secundar
|
||||
- Screen reader support pentru selection mode
|
||||
|
||||
## 8. Success Metrics
|
||||
|
||||
- **Bug Fixes:** 0 bonuri pierdute la procesare bulk
|
||||
- **Upload Success:** 0 refresh-uri neintenționate la selectare fișiere
|
||||
- **Selection Time:** < 2 secunde pentru selectare 5 bonuri
|
||||
- **User Feedback:** Score > 4/5 pentru "Interfața mobilă e intuitivă"
|
||||
|
||||
## 9. Open Questions
|
||||
|
||||
- [ ] FAB-ul trebuie să aibă sub-menu (speed dial) pentru "Bon Nou" + "Upload Bulk"?
|
||||
- [ ] Bottom navigation tab "Upload" deschide file picker direct sau navighează la pagină separată?
|
||||
- [ ] Swipe gestures pentru delete/archive - implementăm în versiunea inițială sau amânăm?
|
||||
- [ ] Animație de highlight când un bon termină procesarea - fade green sau pulse?
|
||||
|
||||
---
|
||||
|
||||
## 10. Dependențe între User Stories
|
||||
|
||||
```
|
||||
US-034 (Fix Refresh) ─┬─→ US-035 (Erori rămân) → US-036 (Filename)
|
||||
│
|
||||
US-037 (Fix Upload) ──┘
|
||||
|
||||
US-038 (Long-press) → US-039 (Select All + Delete)
|
||||
↓
|
||||
US-040 (Mobile List Layout) ←─┘
|
||||
↓
|
||||
US-041 (Mobile Edit Layout) → US-042 (Mobile View Layout)
|
||||
|
||||
US-043 (Ordine) - independent, poate fi făcut oricând
|
||||
```
|
||||
|
||||
**Ordine recomandată de implementare:**
|
||||
|
||||
### Faza 1: Bug Fixes (Critice)
|
||||
1. **US-037**: Fix Upload Nu Mai Face Refresh Automat
|
||||
2. **US-034**: Fix Refresh Individual vs Total
|
||||
3. **US-035**: Bonuri cu Eroare Rămân în Listă
|
||||
4. **US-043**: Păstrare Ordine Bonuri
|
||||
|
||||
### Faza 2: Mobile Enhancements
|
||||
5. **US-036**: Afișare Nume Fișier pentru Toate Bonurile
|
||||
6. **US-038**: Mobile - Selecție Multiplă prin Long-Press
|
||||
7. **US-039**: Mobile - Select All și Buton Ștergere
|
||||
|
||||
### Faza 3: Mobile Native Layout
|
||||
8. **US-040**: Mobile - Layout Android pentru Lista Bonuri
|
||||
9. **US-041**: Mobile - Layout Android pentru Editare/Creare
|
||||
10. **US-042**: Mobile - Layout Android pentru Vizualizare
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2026-01-12
|
||||
**Author:** Claude Code
|
||||
**Status:** Draft - Pending Review
|
||||
@@ -1,252 +0,0 @@
|
||||
# PRD: UI/UX Fixes Phase 6 - Menu Consistency & Mobile Improvements
|
||||
|
||||
## 1. Introducere
|
||||
|
||||
Acest PRD adresează o serie de inconsistențe UI/UX între versiunile desktop și mobile ale aplicației ROA2WEB, probleme cu meniul hamburger pe mobil, și bug-uri funcționale identificate în paginile Analize.
|
||||
|
||||
**Context**: După implementarea fazei anterioare (Unified Mobile Desktop UI), au rămas câteva probleme de consistență și funcționalitate care trebuie rezolvate pentru o experiență utilizator coerentă.
|
||||
|
||||
## 2. Obiective
|
||||
|
||||
### Obiectiv Principal
|
||||
- Asigurarea consistenței între desktop și mobile pentru structura meniului și funcționalitățile disponibile
|
||||
|
||||
### Obiective Secundare
|
||||
- Îmbunătățirea UX pe mobil pentru meniul hamburger (mai compact, mai ușor de navigat)
|
||||
- Corectarea bug-urilor funcționale în paginile Analize
|
||||
- Uniformizarea butoanelor de acțiune (Filtrează/Resetează) pe toate paginile
|
||||
|
||||
### Metrici de Succes
|
||||
- Toate secțiunile de meniu sunt identice pe desktop și mobile
|
||||
- Meniul hamburger mobil permite vizualizarea completă a opțiunilor fără scroll excesiv
|
||||
- Butonul FAB (+) pe lista bonuri funcționează corect și afișează SpeedDial
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
### US-601: Adăugare Secțiune "Analize" în Sidebar Desktop
|
||||
**Ca** utilizator desktop
|
||||
**Vreau** să văd secțiunea "Analize" în sidebar-ul din stânga
|
||||
**Pentru că** în prezent aceasta există doar pe mobil și vreau acces la Scadențe și Facturi Detaliate
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Sidebar-ul desktop (`AppSidebar.vue`) include secțiunea "Analize" cu aceleași link-uri ca pe mobil
|
||||
- [ ] Link-uri: Scadențe (`/reports/maturity-analysis`) și Facturi Detaliate (`/reports/detailed-invoices`)
|
||||
- [ ] Secțiunea apare între "Rapoarte" și "Introduceri Date" (sau după Rapoarte)
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: Desktop sidebar shows "Analize" section with working links
|
||||
|
||||
---
|
||||
|
||||
### US-602: Implementare Tab-uri Clienți/Furnizori în Pagina Scadențe
|
||||
**Ca** utilizator
|
||||
**Vreau** să pot comuta între Clienți și Furnizori folosind tab-uri
|
||||
**Pentru că** în prezent ambele sunt afișate într-o singură listă lungă care este greu de navigat
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Pagina Analiză Scadențe (`MaturityAnalysisView.vue`) are 2 tab-uri: "Clienți" și "Furnizori"
|
||||
- [ ] Tab-ul "Clienți" afișează lista "De încasat" cu totalul
|
||||
- [ ] Tab-ul "Furnizori" afișează lista "De plătit" cu totalul
|
||||
- [ ] Tab-urile funcționează pe desktop și mobil
|
||||
- [ ] Starea tab-ului selectat este păstrată la navigare back
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: Tabs switch between Clienți and Furnizori correctly
|
||||
|
||||
---
|
||||
|
||||
### US-603: Implementare Pagină Facturi Detaliate (Înlocuiește Redirect la Dashboard)
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd facturi detaliate când accesez Analize > Facturi Detaliate
|
||||
**Pentru că** în prezent pagina redirecționează la Dashboard și nu afișează nimic util
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Creează `DetailedInvoicesView.vue` în `src/modules/reports/views/`
|
||||
- [ ] Pagina are 2 tab-uri: "Clienți" și "Furnizori"
|
||||
- [ ] Fiecare tab afișează un tabel cu facturile detaliate (similar cu pagina Facturi, dar filtrate)
|
||||
- [ ] Ruta `/reports/detailed-invoices` funcționează și nu mai redirecționează
|
||||
- [ ] Adaugă ruta în router (`reports.routes.js`)
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: Page shows detailed invoices table with Clienți/Furnizori tabs
|
||||
|
||||
---
|
||||
|
||||
### US-604: Meniu Hamburger Mobil - Toggle Temă cu 3 Stări
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** selectorul de temă să fie un singur buton toggle cu 3 stări
|
||||
**Pentru că** cele 3 butoane separate ocupă prea mult spațiu în meniu
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Înlocuiește cele 3 butoane de temă (Auto/Light/Dark) cu un singur toggle cyclic
|
||||
- [ ] La click, togglează între Auto → Light → Dark → Auto
|
||||
- [ ] Afișează iconița și textul stării curente (ex: "Auto (sistem)")
|
||||
- [ ] Stilul este compact, similar cu toggle-ul din header desktop
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: Mobile menu theme selector cycles through 3 states on tap
|
||||
|
||||
---
|
||||
|
||||
### US-605: Meniu Hamburger Mobil - Companie/Perioadă Colapsabile
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** secțiunile Companie și Perioadă din meniu să fie colapsabile
|
||||
**Pentru că** ocupă mult spațiu și rareori trebuie schimbate
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Secțiunile "Firma" și "Perioada" sunt colapsate by default
|
||||
- [ ] Click pe header-ul secțiunii o expandează/colapsează
|
||||
- [ ] Când sunt colapsate, afișează doar numele firmei/perioadei curente
|
||||
- [ ] Starea colapsată este persistată în localStorage
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: Tap on Firma/Perioada toggles expansion
|
||||
|
||||
---
|
||||
|
||||
### US-606: Meniu Hamburger Mobil - Layout Scrollabil Unificat
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** întregul meniu hamburger să fie într-o singură zonă scrollabilă
|
||||
**Pentru că** acum secțiunea cu link-uri este foarte mică între header și footer fix
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Meniul hamburger mobil (`MobileDrawer.vue` sau echivalent) nu mai are header/footer fixe
|
||||
- [ ] Tot conținutul (logo, firma, perioada, meniuri, utilizator, temă, deconectare) scrollează împreună
|
||||
- [ ] Înălțimea vizibilă pentru meniuri crește semnificativ
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: Entire mobile menu scrolls as one unit
|
||||
|
||||
---
|
||||
|
||||
### US-607: Meniu Hamburger Mobil - Secțiune Utilizator Mai Compactă
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** secțiunea de utilizator (nume, temă, deconectare) să fie mai compactă
|
||||
**Pentru că** ocupă prea mult spațiu vertical
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Numele utilizatorului și butonul Deconectare sunt pe aceeași linie
|
||||
- [ ] Toggle-ul de temă este pe o linie separată, dar compact (vezi US-604)
|
||||
- [ ] Spațiul total redus cu cel puțin 50%
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: User section is visually compact
|
||||
|
||||
---
|
||||
|
||||
### US-608: Buton FAB (+) în Lista Bonuri - Afișare SpeedDial
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** butonul + din lista bonuri să afișeze un meniu SpeedDial
|
||||
**Pentru că** în prezent se schimbă în X dar nu apare niciun meniu
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Click pe FAB (+) afișează opțiuni SpeedDial animate
|
||||
- [ ] Opțiuni: "Bon Nou Manual", "Scanare Bon (OCR)", "Upload în Masă"
|
||||
- [ ] Click pe opțiune navighează la pagina corespunzătoare
|
||||
- [ ] Click în afara meniului sau pe X îl închide
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: FAB shows SpeedDial menu with 3 options on tap
|
||||
|
||||
---
|
||||
|
||||
### US-609: Buton "Resetează" pe Toate Paginile cu Filtre (Mobil)
|
||||
**Ca** utilizator mobil
|
||||
**Vreau** butonul "Resetează" să apară pe toate paginile care au "Filtrează"
|
||||
**Pentru că** în prezent doar Balanța are acest buton, celelalte pagini nu
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Pagina Facturi mobil: header include buton Resetează lângă Filtrează
|
||||
- [ ] Pagina Casă mobil: header include buton Resetează lângă Filtrează
|
||||
- [ ] Pagina Bancă mobil: header include buton Resetează lângă Filtrează
|
||||
- [ ] Pagina Lista Bonuri mobil: header include buton Resetează lângă Filtrează
|
||||
- [ ] Butonul resetează toate filtrele la valorile default
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: All filter pages show Reset button in mobile header
|
||||
|
||||
---
|
||||
|
||||
### US-610: Investigare și Eliminare Spațiu Gol Deasupra Tabelelor
|
||||
**Ca** utilizator
|
||||
**Vreau** să nu existe spațiu gol excesiv între filtre și tabele
|
||||
**Pentru că** este raportat că există spațiu gol mare pe mai multe pagini
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Investighează CSS-ul paginilor: Facturi, Balanță, Casă, Bancă, Lista Bonuri
|
||||
- [ ] Identifică sursa spațiului gol (margin/padding excesiv, container gol, etc.)
|
||||
- [ ] Elimină spațiul gol păstrând designul consistent
|
||||
- [ ] Verifică pe desktop ȘI pe mobil
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: No excessive gap between filters and table on all pages
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
|
||||
1. [REQ-001] Sidebar-ul desktop trebuie să conțină aceleași secțiuni ca meniul mobil
|
||||
2. [REQ-002] Paginile din Analize trebuie să aibă tab-uri pentru separarea Clienți/Furnizori
|
||||
3. [REQ-003] Meniul hamburger mobil trebuie să permită vizualizarea tuturor opțiunilor fără scroll excesiv
|
||||
4. [REQ-004] Toate elementele interactive mobil trebuie să respecte touch target minim 44x44px
|
||||
5. [REQ-005] Toggle-ul de temă trebuie să cicleze între cele 3 stări la un singur tap
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
|
||||
- NU schimbăm structura generală a aplicației sau arhitectura
|
||||
- NU adăugăm funcționalități noi în paginile Analize (doar corectăm cele existente)
|
||||
- NU refactorizăm alte componente care nu sunt menționate
|
||||
- NU modificăm API-ul backend (doar frontend UI)
|
||||
- NU adăugăm noi pagini în afară de Facturi Detaliate
|
||||
|
||||
## 6. Considerații Tehnice
|
||||
|
||||
### Stack/Tehnologii
|
||||
- Vue.js 3 Composition API
|
||||
- PrimeVue components (SpeedDial, TabView, etc.)
|
||||
- CSS cu design tokens din `docs/DESIGN_TOKENS.md`
|
||||
|
||||
### Patterns de Urmat
|
||||
- Componente mobile din `src/shared/components/mobile/`
|
||||
- Mobile detection via `useBreakpoints()` composable
|
||||
- CSS patterns din `docs/CSS_PATTERNS.md`
|
||||
|
||||
### Fișiere Cheie de Modificat
|
||||
- `src/shared/components/AppSidebar.vue` - US-601
|
||||
- `src/modules/reports/views/MaturityAnalysisView.vue` - US-602
|
||||
- `src/modules/reports/views/DetailedInvoicesView.vue` (NOU) - US-603
|
||||
- `src/shared/components/mobile/MobileDrawer.vue` - US-604, US-605, US-606, US-607
|
||||
- `src/modules/data-entry/views/ReceiptsListView.vue` - US-608
|
||||
- Multiple view files - US-609, US-610
|
||||
|
||||
### Dependențe
|
||||
- PrimeVue SpeedDial pentru US-608
|
||||
- PrimeVue TabView pentru US-602, US-603
|
||||
|
||||
### Riscuri Tehnice
|
||||
- Meniul hamburger mobil poate avea layout complex - testare atentă pe multiple dispozitive
|
||||
- SpeedDial PrimeVue poate necesita customizare pentru dark mode
|
||||
|
||||
## 7. Considerații UI/UX
|
||||
|
||||
### Mobile Menu Layout
|
||||
- Tot conținutul într-un singur scroll
|
||||
- Firma/Perioada colapsate by default pentru a economisi spațiu
|
||||
- Secțiune utilizator compactă în partea de jos
|
||||
|
||||
### Tab-uri Analize
|
||||
- Tab-uri clare cu indicatori vizuali pentru starea activă
|
||||
- Counter cu numărul de elemente în fiecare tab
|
||||
- Swipe support pentru navigare între tab-uri (nice-to-have)
|
||||
|
||||
### SpeedDial FAB
|
||||
- Animație smooth la deschidere
|
||||
- Opțiuni cu iconițe și text descriptiv
|
||||
- Overlay semi-transparent pentru focus
|
||||
|
||||
## 8. Success Metrics
|
||||
|
||||
- **Consistență meniu**: 100% același conținut pe desktop și mobil
|
||||
- **Spațiu meniu mobil**: Cel puțin 60% din înălțimea ecranului pentru link-uri
|
||||
- **Funcționalitate FAB**: 100% rate de succes la afișarea SpeedDial
|
||||
- **Timp task**: Utilizatorul poate accesa orice pagină în max 2 tap-uri din meniu
|
||||
|
||||
## 9. Open Questions
|
||||
|
||||
- [ ] Trebuie păstrat și summary-ul cu ambele (Clienți + Furnizori) pe pagina Scadențe, în plus față de tab-uri?
|
||||
- [ ] Facturi Detaliate trebuie să aibă aceleași filtre ca pagina Facturi principală?
|
||||
- [ ] Spațiul gol raportat - este pe toate paginile sau doar pe anumite rezoluții?
|
||||
|
||||
---
|
||||
|
||||
**Autor**: Claude Code (auto-generated)
|
||||
**Data**: 2026-01-13
|
||||
**Versiune**: 1.0
|
||||
@@ -1,451 +0,0 @@
|
||||
# PRD: Unified Mobile & Desktop UI Improvements
|
||||
|
||||
## 1. Introducere
|
||||
|
||||
Acest PRD acoperă îmbunătățirile necesare pentru a unifica experiența UI între mobil și desktop, rezolvând inconsistențe de design, bugs și funcționalități lipsă. Referința de design este pagina `/reports/invoices` care implementează corect pattern-urile Material Design 3.
|
||||
|
||||
**Branch**: `ralph/unified-mobile-md` (continuare)
|
||||
|
||||
## 2. Obiective
|
||||
|
||||
### Obiectiv Principal
|
||||
- Unificarea UI/UX între toate paginile (rapoarte, bonuri, analize) cu un design consistent Material Design 3
|
||||
|
||||
### Obiective Secundare
|
||||
- Fix bugs existente (grupuri neexpandabile, butoane ascunse, export cu erori)
|
||||
- Adăugare funcționalități lipsă pe mobil (selecție companie/perioadă, temă)
|
||||
- Eliminare duplicări și inconsistențe în plasarea butoanelor
|
||||
|
||||
### Metrici de Succes
|
||||
- Toate paginile au aceleași pattern-uri pentru header actions (filtre, reset, export)
|
||||
- Export PDF/XLSX funcțional pe toate paginile
|
||||
- Meniu hamburger identic pe desktop și mobil
|
||||
- Zero bugs vizuale (butoane ascunse, spații blank excesive)
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
---
|
||||
|
||||
### US-501: Header Actions Bar Unificat - Rapoarte
|
||||
**Ca** utilizator
|
||||
**Vreau** să am butoane de Filtre, Reset Filtre și Export (PDF/XLSX dropdown) în header-ul din dreapta pe toate rapoartele
|
||||
**Pentru că** să am acces rapid și consistent la aceste funcții
|
||||
|
||||
**Pagini afectate**:
|
||||
- `/reports/invoices` (referință - deja implementat parțial)
|
||||
- `/reports/trial-balance` (Balanță)
|
||||
- `/reports/cash-bank` (Casă și Bancă)
|
||||
- `/reports/detailed-invoices/clients` (Facturi Detaliate Clienți)
|
||||
- `/reports/detailed-invoices/suppliers` (Facturi Detaliate Furnizori)
|
||||
- `/reports/maturity` (Analize Scadențe)
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Fiecare pagină are în header dreapta: [Filter icon] [Reset icon] [Export dropdown]
|
||||
- [ ] Export dropdown conține: "Export PDF" și "Export XLSX"
|
||||
- [ ] Butonul Filter are indicator vizual (active) când filtrele sunt aplicate
|
||||
- [ ] Butonul Reset resetează toate filtrele la valori implicite
|
||||
- [ ] Pe mobil, acțiunile sunt în MobileTopBar actions
|
||||
- [ ] Pe desktop, acțiunile sunt într-un grup în header dreapta
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: butoanele funcționează pe desktop și mobil
|
||||
|
||||
---
|
||||
|
||||
### US-502: Header Actions Bar Unificat - Lista Bonuri
|
||||
**Ca** utilizator
|
||||
**Vreau** să am butoane de Filtre, Reset Filtre și Export în header-ul listei de bonuri
|
||||
**Pentru că** să fie consistent cu celelalte pagini
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Lista bonuri (`/data-entry`) are în header: [Filter] [Reset] [Export dropdown]
|
||||
- [ ] Stilul butoanelor este identic cu cel din `/reports/invoices`
|
||||
- [ ] Export dropdown: "Export PDF" și "Export XLSX"
|
||||
- [ ] Butoanele vechi "Filtrează" și "Resetează" sunt înlocuite cu noul pattern
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: butoanele au același aspect ca pe pagina Facturi
|
||||
|
||||
---
|
||||
|
||||
### US-503: BottomSheet Filtre pentru Lista Bonuri (Mobil)
|
||||
**Ca** utilizator pe mobil
|
||||
**Vreau** ca filtrele din lista de bonuri să se deschidă într-un BottomSheet
|
||||
**Pentru că** să fie consistent cu Facturi, Balanță, Casă și Bancă
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Click pe butonul Filter deschide BottomSheet (nu inline filters)
|
||||
- [ ] BottomSheet conține toate filtrele existente (status, dată, etc.)
|
||||
- [ ] BottomSheet are butoane "Resetează" și "Aplică" în footer
|
||||
- [ ] Swipe-down sau tap outside închide BottomSheet
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser mobil: filtrele apar în BottomSheet
|
||||
|
||||
---
|
||||
|
||||
### US-504: Fix Export Endpoints Backend
|
||||
**Ca** utilizator
|
||||
**Vreau** ca exportul PDF/XLSX să funcționeze fără erori
|
||||
**Pentru că** să pot descărca rapoartele
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Identificate și fixate erorile din endpoint-urile de export existente
|
||||
- [ ] Export PDF funcțional pentru: Facturi, Balanță, Casă și Bancă, Facturi Detaliate, Scadențe, Bonuri
|
||||
- [ ] Export XLSX funcțional pentru aceleași pagini
|
||||
- [ ] Exportul include DOAR datele filtrate (nu toate)
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: descărcare PDF și XLSX reușită
|
||||
|
||||
---
|
||||
|
||||
### US-505: Meniu Hamburger Desktop = Mobil
|
||||
**Ca** utilizator pe desktop
|
||||
**Vreau** ca meniul hamburger să aibă aceeași structură ca pe mobil
|
||||
**Pentru că** să am acces la toate opțiunile indiferent de dispozitiv
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Meniul desktop are secțiunile: PRINCIPALE, RAPOARTE, ANALIZE, ADMINISTRARE
|
||||
- [ ] Ordinea și itemii sunt identici cu MobileDrawerMenu
|
||||
- [ ] Stilul vizual este consistent (poate fi adaptat pentru desktop dar structura identică)
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser desktop: meniul arată la fel ca pe mobil
|
||||
|
||||
---
|
||||
|
||||
### US-506: Fix MobileDrawerMenu - Deconectare Vizibil
|
||||
**Ca** utilizator pe mobil
|
||||
**Vreau** să văd și să pot accesa butonul de Deconectare
|
||||
**Pentru că** acum este ascuns sub bara de navigare din footer
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Butonul "Deconectare" este complet vizibil în drawer menu
|
||||
- [ ] Adăugat padding-bottom suficient pentru a nu fi acoperit de MobileBottomNav
|
||||
- [ ] Scroll funcționează corect dacă meniul este mai lung decât ecranul
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser mobil: butonul Deconectare este vizibil și clickabil
|
||||
|
||||
---
|
||||
|
||||
### US-507: Selecție Companie/Perioadă pe Mobil
|
||||
**Ca** utilizator pe mobil
|
||||
**Vreau** să pot selecta compania și perioada contabilă
|
||||
**Pentru că** acum această funcționalitate lipsește complet pe mobil
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MobileDrawerMenu sau MobileTopBar include selector companie
|
||||
- [ ] Selector perioadă contabilă disponibil
|
||||
- [ ] Selectarea companiei/perioadei actualizează datele pe toate paginile
|
||||
- [ ] Valorile selectate persistă între sesiuni
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser mobil: pot schimba compania și perioada
|
||||
|
||||
---
|
||||
|
||||
### US-508: Selector Temă pe Mobil (Dark/Light/Auto)
|
||||
**Ca** utilizator pe mobil
|
||||
**Vreau** să pot schimba tema (dark/light/auto)
|
||||
**Pentru că** acum această opțiune lipsește pe mobil
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Opțiune de schimbare temă în MobileDrawerMenu sau Setări
|
||||
- [ ] Trei opțiuni: Light, Dark, Auto (system)
|
||||
- [ ] Schimbarea temei se aplică imediat
|
||||
- [ ] Preferința persistă în localStorage
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser mobil: tema se schimbă corect
|
||||
|
||||
---
|
||||
|
||||
### US-509: Fix Detailed Invoices - Grupuri Expandabile Desktop
|
||||
**Ca** utilizator pe desktop
|
||||
**Vreau** ca grupurile de facturi per client/furnizor să se expandeze la click
|
||||
**Pentru că** acum funcționează doar pe mobil
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Click pe un grup (client/furnizor) expandează/colapsează facturile
|
||||
- [ ] Indicator vizual pentru expand/collapse (chevron icon)
|
||||
- [ ] Animație smooth la expand/collapse
|
||||
- [ ] Comportament identic cu versiunea mobilă
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser desktop: grupurile se extind la click
|
||||
|
||||
---
|
||||
|
||||
### US-510: Detailed Invoices - Eliminare Filtru Clienți/Furnizori
|
||||
**Ca** utilizator
|
||||
**Vreau** ca filtrele din Facturi Detaliate să NU aibă selecția Clienți/Furnizori
|
||||
**Pentru că** sunt deja pagini separate (`/clients` și `/suppliers`)
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Pagina `/reports/detailed-invoices/clients` NU are dropdown Clienți/Furnizori în filtre
|
||||
- [ ] Pagina `/reports/detailed-invoices/suppliers` NU are dropdown Clienți/Furnizori în filtre
|
||||
- [ ] Tipul (clienți/furnizori) este determinat automat din URL
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: filtrul Clienți/Furnizori nu mai apare
|
||||
|
||||
---
|
||||
|
||||
### US-511: Detailed Invoices - Eliminare Buton Filtru Duplicat
|
||||
**Ca** utilizator
|
||||
**Vreau** să am un singur buton de filtre (în header)
|
||||
**Pentru că** acum există și în header și deasupra tabelului
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Butonul de filtre apare DOAR în header (dreapta)
|
||||
- [ ] Eliminat butonul duplicat de deasupra tabelului
|
||||
- [ ] Funcționalitatea rămâne identică
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: un singur buton de filtre
|
||||
|
||||
---
|
||||
|
||||
### US-512: Detailed Invoices - Fix Overlay Butoane Ascunse
|
||||
**Ca** utilizator
|
||||
**Vreau** ca în overlay-ul cu selecții să văd toate butoanele
|
||||
**Pentru că** acum Reset Filtre și Export sunt ascunse sub footer
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Toate butoanele din overlay sunt vizibile
|
||||
- [ ] Butoanele nu sunt acoperite de footer
|
||||
- [ ] Scroll funcționează dacă conținutul e mare
|
||||
- [ ] Z-index corect pentru overlay vs footer
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: toate butoanele sunt vizibile în overlay
|
||||
|
||||
---
|
||||
|
||||
### US-513: Analize Scadențe - Eliminare Secțiune Facturi Detaliate
|
||||
**Ca** utilizator
|
||||
**Vreau** ca pagina Analize Scadențe să NU conțină secțiunea Facturi Detaliate
|
||||
**Pentru că** sunt pagini separate
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Pagina `/reports/maturity` afișează DOAR analiza scadențelor
|
||||
- [ ] Secțiunea "Facturi Detaliate" este eliminată complet
|
||||
- [ ] Link-urile către Facturi Detaliate rămân în meniu
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: pagina conține doar scadențe
|
||||
|
||||
---
|
||||
|
||||
### US-514: Fix Spațiu Blank Excesiv Top (Toate Paginile)
|
||||
**Ca** utilizator
|
||||
**Vreau** ca paginile să NU aibă spațiu gol mare în partea de sus
|
||||
**Pentru că** ocupă ecran inutil
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Identificat cauza spațiului blank (margin/padding excesiv)
|
||||
- [ ] Redus spațiul la maximum 16px între header și conținut
|
||||
- [ ] Toate paginile verificate și corectate
|
||||
- [ ] Layout-ul rămâne corect pe toate device-urile
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: spațiul blank este eliminat
|
||||
|
||||
---
|
||||
|
||||
### US-515: Lista Bonuri - Meniu "Bon Nou/Bulk Upload" Material Design
|
||||
**Ca** utilizator
|
||||
**Vreau** ca meniul pentru Bon Nou și Bulk Upload să arate modern, Material Design
|
||||
**Pentru că** acum arată înghesuit și nu se potrivește cu restul UI-ului
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Meniul redesenat în stil Material Design 3
|
||||
- [ ] Spacing adecvat între opțiuni (min 44px touch targets)
|
||||
- [ ] Iconițe clare pentru fiecare opțiune
|
||||
- [ ] Hover/active states vizibile
|
||||
- [ ] Animații smooth la deschidere/închidere
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: meniul arată modern și consistent
|
||||
|
||||
---
|
||||
|
||||
### US-516: Lista Bonuri - Meniu Acțiuni Per Bon Material Design
|
||||
**Ca** utilizator
|
||||
**Vreau** ca meniul de acțiuni pentru fiecare bon (⋮) să arate modern
|
||||
**Pentru că** acum arată înghesuit și inconsistent
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Meniul acțiuni (Vizualizare, Editare, Ștergere) redesenat MD3
|
||||
- [ ] Opțiuni cu iconițe și text clar
|
||||
- [ ] Touch targets min 44px
|
||||
- [ ] Divider între acțiuni normale și destructive (Ștergere)
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: meniul arată modern
|
||||
|
||||
---
|
||||
|
||||
### US-517: Lista Bonuri Desktop - Dialog Ștergere Material Design
|
||||
**Ca** utilizator pe desktop
|
||||
**Vreau** ca dialogul de confirmare ștergere să arate modern
|
||||
**Pentru că** acum arată înghesuit și vechi
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Dialog redesenat în stil Material Design 3
|
||||
- [ ] Titlu clar: "Șterge bonul?"
|
||||
- [ ] Mesaj descriptiv cu detalii bon
|
||||
- [ ] Butoane: "Anulează" (secondary) și "Șterge" (danger)
|
||||
- [ ] Spacing și padding corespunzătoare
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: dialogul arată modern
|
||||
|
||||
---
|
||||
|
||||
### US-518: Creare/Vizualizare/Editare Bon - Butoane Doar Sus
|
||||
**Ca** utilizator
|
||||
**Vreau** ca în paginile de creare, vizualizare și editare bon, butoanele să fie DOAR în partea de sus
|
||||
**Pentru că** să fie consistent și să nu am butoane duplicate
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Pagina creare bon: butoane (Salvează, Anulează) doar în header
|
||||
- [ ] Pagina vizualizare bon: butoane (Editează, Șterge, Înapoi) doar în header
|
||||
- [ ] Pagina editare bon: butoane (Salvează, Anulează) doar în header
|
||||
- [ ] Eliminate butoanele din footer/body dacă există
|
||||
- [ ] Pe mobil: butoanele sunt în MobileTopBar actions
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser: butoane doar în header pe toate cele 3 pagini
|
||||
|
||||
---
|
||||
|
||||
### US-519: Separare Casă și Bancă în Pagini Distincte
|
||||
**Ca** utilizator
|
||||
**Vreau** ca Casă și Bancă să fie pagini separate (nu combinate)
|
||||
**Pentru că** să pot accesa fiecare raport independent și să am o navigare mai clară
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Pagină separată pentru Casă: `/reports/cash`
|
||||
- [ ] Pagină separată pentru Bancă: `/reports/bank`
|
||||
- [ ] Fiecare pagină are propriul titlu (Casă / Bancă)
|
||||
- [ ] Meniul hamburger (desktop și mobil) are intrări separate pentru Casă și Bancă
|
||||
- [ ] MobileDrawerMenu actualizat cu linkuri separate
|
||||
- [ ] MobileBottomNav sau navigarea include ambele opțiuni (dacă relevant)
|
||||
- [ ] Rutele vechi `/reports/cash-bank` redirect către `/reports/cash` sau sunt eliminate
|
||||
- [ ] Filtrele și exportul funcționează independent pe fiecare pagină
|
||||
- [ ] npm run typecheck passes
|
||||
- [ ] Verify in browser desktop: Casă și Bancă sunt pagini separate accesibile din meniu
|
||||
- [ ] Verify in browser mobil: Casă și Bancă sunt pagini separate în MobileDrawerMenu
|
||||
|
||||
---
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
|
||||
1. [REQ-001] Toate paginile de rapoarte TREBUIE să aibă header actions: Filter, Reset, Export (dropdown PDF/XLSX)
|
||||
2. [REQ-002] Exportul TREBUIE să exporte DOAR datele filtrate curent
|
||||
3. [REQ-003] Meniul hamburger TREBUIE să fie identic între desktop și mobil ca structură
|
||||
4. [REQ-004] Pe mobil, filtrele TREBUIE să fie în BottomSheet, nu inline
|
||||
5. [REQ-005] Touch targets TREBUIE să fie minim 44x44px pe mobil
|
||||
6. [REQ-006] Butoanele de acțiuni (salvare, ștergere, etc.) TREBUIE să fie DOAR în header/top bar
|
||||
7. [REQ-007] Toate dialogurile și meniurile TREBUIE să urmeze stilul Material Design 3
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
|
||||
- ❌ Redesign complet al aplicației - doar unificare și fixes
|
||||
- ❌ Funcționalități noi de business logic - doar UI/UX
|
||||
- ❌ Modificări la structura bazei de date
|
||||
- ❌ Noi endpoint-uri API (doar fix-uri la cele existente)
|
||||
- ❌ Suport pentru alte limbi/i18n
|
||||
- ❌ Implementare PWA sau funcționalități offline
|
||||
|
||||
## 6. Considerații Tehnice
|
||||
|
||||
### Stack/Tehnologii
|
||||
- **Frontend**: Vue 3, PrimeVue, CSS custom cu design tokens
|
||||
- **Backend**: FastAPI (doar pentru fix export endpoints)
|
||||
- **Componente existente**: MobileTopBar, MobileBottomNav, MobileDrawerMenu, BottomSheet, MobileSelectionFooter
|
||||
|
||||
### Patterns de Urmat
|
||||
- **Referință design**: `/reports/invoices` (InvoicesView.vue)
|
||||
- **Mobile actions**: Array în `mobileTopBarActions` computed
|
||||
- **Filtre mobil**: BottomSheet component
|
||||
- **Design tokens**: Folosește DOAR variabile CSS din `DESIGN_TOKENS.md`
|
||||
|
||||
### Fișiere Cheie
|
||||
```
|
||||
src/shared/components/mobile/MobileTopBar.vue
|
||||
src/shared/components/mobile/MobileDrawerMenu.vue
|
||||
src/shared/components/mobile/BottomSheet.vue
|
||||
src/modules/reports/views/InvoicesView.vue (referință)
|
||||
src/modules/reports/views/DetailedInvoicesView.vue
|
||||
src/modules/reports/views/MaturityAnalysisView.vue
|
||||
src/modules/data-entry/views/receipts/ReceiptsListView.vue
|
||||
src/modules/data-entry/views/receipts/ReceiptCreateView.vue
|
||||
src/modules/data-entry/views/receipts/ReceiptEditView.vue
|
||||
src/modules/data-entry/views/receipts/ReceiptDetailView.vue
|
||||
```
|
||||
|
||||
### Dependențe
|
||||
- PrimeVue components (Button, Menu, Dialog, Dropdown)
|
||||
- Design tokens CSS variables
|
||||
- Backend export endpoints existente
|
||||
|
||||
### Riscuri Tehnice
|
||||
- Export endpoints pot avea erori neașteptate - necesită debugging
|
||||
- Unele pagini pot avea logică complexă de filtrare - atenție la regresii
|
||||
|
||||
## 7. Considerații UI/UX
|
||||
|
||||
### Layout Pattern (Header Actions)
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ [☰/←] Titlu Pagină [🔍] [↻] [⬇️▼] │
|
||||
│ (centrat) Filter Reset Export │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Export Dropdown
|
||||
```
|
||||
┌──────────────┐
|
||||
│ 📄 Export PDF │
|
||||
│ 📊 Export XLSX│
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
### Stări UI
|
||||
- **Loading**: Skeleton sau spinner în zona de conținut
|
||||
- **Empty**: Mesaj "Nu există date" cu icon ilustrativ
|
||||
- **Error**: Toast notification + retry button
|
||||
- **Success export**: Toast "Exportul a fost descărcat"
|
||||
|
||||
### Dark Mode
|
||||
- Toate componentele noi TREBUIE testate în dark mode
|
||||
- Folosește design tokens pentru culori (nu hardcoded)
|
||||
|
||||
## 8. Ordine Implementare Recomandată
|
||||
|
||||
### Faza 1: Fixes Critice (bugs)
|
||||
1. US-506: Fix MobileDrawerMenu - Deconectare vizibil
|
||||
2. US-509: Fix Detailed Invoices - Grupuri expandabile desktop
|
||||
3. US-512: Fix overlay butoane ascunse
|
||||
4. US-504: Fix Export endpoints backend
|
||||
|
||||
### Faza 2: Unificare Header Actions
|
||||
5. US-501: Header Actions Bar - Rapoarte
|
||||
6. US-502: Header Actions Bar - Lista Bonuri
|
||||
7. US-503: BottomSheet Filtre pentru Lista Bonuri
|
||||
|
||||
### Faza 3: Cleanup & Eliminări
|
||||
8. US-510: Eliminare filtru Clienți/Furnizori
|
||||
9. US-511: Eliminare buton filtru duplicat
|
||||
10. US-513: Eliminare secțiune Facturi Detaliate din Scadențe
|
||||
11. US-514: Fix spațiu blank top
|
||||
|
||||
### Faza 4: Meniu & Navigare
|
||||
12. US-505: Meniu hamburger desktop = mobil
|
||||
13. US-507: Selecție companie/perioadă mobil
|
||||
14. US-508: Selector temă mobil
|
||||
|
||||
### Faza 5: Material Design Styling
|
||||
15. US-515: Meniu Bon Nou/Bulk Upload MD3
|
||||
16. US-516: Meniu acțiuni per bon MD3
|
||||
17. US-517: Dialog ștergere MD3
|
||||
18. US-518: Butoane doar sus în creare/editare bon
|
||||
|
||||
## 9. Success Metrics
|
||||
|
||||
- **Consistență UI**: 100% pagini cu același pattern header actions
|
||||
- **Zero bugs vizuale**: Toate butoanele vizibile, zero overflow
|
||||
- **Export funcțional**: PDF și XLSX funcționează pe toate paginile
|
||||
- **Mobile parity**: Toate funcțiile disponibile pe mobil (companie, perioadă, temă)
|
||||
|
||||
## 10. Decizii Clarficate
|
||||
|
||||
- ✅ **PDF Export**: Folosește formatarea existentă de la Facturi/Balanță/Casă și Bancă - doar extinde la celelalte pagini
|
||||
- ✅ **Selecție companie/perioadă mobil**: În MobileDrawerMenu, sub secțiunea profil
|
||||
- ✅ **Tema selector mobil**: În MobileDrawerMenu (lângă alte setări)
|
||||
@@ -1,457 +0,0 @@
|
||||
# PRD: Unified Mobile Material Design Interface
|
||||
|
||||
## 1. Introducere
|
||||
|
||||
Aplicația ROA2WEB are deja implementată o interfață Material Design nativă Android pentru modulul de bonuri (ReceiptsListView). Acest PRD definește extinderea aceleiași interfețe unitare la toate paginile aplicației în modul mobil: Dashboard, Facturi, Balanță de Verificare, Trezorerie, Statistici, Loguri etc.
|
||||
|
||||
Scopul este o experiență consistentă cross-module pe dispozitive mobile, cu header/footer unitar și pattern-uri de interacțiune identice.
|
||||
|
||||
## 2. Obiective
|
||||
|
||||
### Obiectiv Principal
|
||||
- **Consistență UI/UX**: Toate paginile mobile să aibă aceeași structură vizuală și pattern-uri de interacțiune ca lista de bonuri
|
||||
|
||||
### Obiective Secundare
|
||||
- Eliminare cod duplicat (buton delete în header când există în footer)
|
||||
- Adăugare navigare back (← Înapoi) în editare bonuri
|
||||
- Dashboard cu carousel swipeable pentru KPI cards
|
||||
- MD3 color tokens pentru theming consistent
|
||||
|
||||
### Metrici de Succes
|
||||
- 100% consistență vizuală între pagini pe mobil
|
||||
- Reducere CSS duplicat cu minim 30%
|
||||
- Zero regresii vizuale în modul desktop
|
||||
- Funcționare pe Android Chrome, iOS Safari, Samsung Internet
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
### US-101: Creare sistem de componente Material Design reutilizabile
|
||||
**Ca** developer
|
||||
**Vreau** componente Vue reutilizabile pentru elementele MD comune
|
||||
**Pentru că** să evit duplicarea codului și să asigur consistența
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Componentă `MobileTopBar.vue` extrasă din ReceiptsListView
|
||||
- [ ] Componentă `MobileBottomNav.vue` extrasă din ReceiptsListView
|
||||
- [ ] Componentă `MobileSelectionFooter.vue` pentru batch actions
|
||||
- [ ] Componentă `MobileFilterChips.vue` pentru filtre orizontale scrollable
|
||||
- [ ] Componentă `BottomSheet.vue` pentru filtre avansate
|
||||
- [ ] Props pentru customizare (title, actions, items)
|
||||
- [ ] npm run build passes
|
||||
|
||||
### US-102: Definire MD3 color tokens în CSS
|
||||
**Ca** developer
|
||||
**Vreau** variabile CSS pentru Material Design 3 color system
|
||||
**Pentru că** să am culori consistente și dark mode automatic
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Fișier `src/assets/css/core/md3-tokens.css` creat
|
||||
- [ ] Tokens pentru: primary, secondary, surface, on-surface, outline
|
||||
- [ ] Dark mode variants cu `[data-theme="dark"]`
|
||||
- [ ] Mapping la tokens existenți unde posibil
|
||||
- [ ] Import în main.css
|
||||
- [ ] npm run build passes
|
||||
|
||||
### US-103: Refactor ReceiptsListView să folosească componente comune
|
||||
**Ca** developer
|
||||
**Vreau** ReceiptsListView să folosească noile componente
|
||||
**Pentru că** să validez API-ul componentelor și să reduc duplicarea
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Import MobileTopBar, MobileBottomNav, MobileSelectionFooter
|
||||
- [ ] Ștergere CSS duplicat din ReceiptsListView
|
||||
- [ ] Funcționalitate identică cu implementarea actuală
|
||||
- [ ] Verify in browser că lista bonuri funcționează identic pe mobil
|
||||
- [ ] npm run build passes
|
||||
|
||||
### US-104: Eliminare buton delete duplicat din header tabel bonuri
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd butonul de ștergere doar în footer când am selecție activă
|
||||
**Pentru că** afișarea în ambele locuri e confuză și ocupă spațiu inutil
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Desktop: bulk-actions-bar NU mai afișează buton Șterge când e pe mobil
|
||||
- [ ] Desktop: bulk-actions-bar afișează doar când `!isMobile`
|
||||
- [ ] Mobile: delete apare DOAR în `mobile-selection-bottom-bar`
|
||||
- [ ] Verify in browser: pe mobil, delete e doar în footer
|
||||
- [ ] Verify in browser: pe desktop, delete e în header table
|
||||
- [ ] npm run build passes
|
||||
|
||||
### US-105: Adăugare buton Înapoi în editare bon (mobile)
|
||||
**Ca** utilizator
|
||||
**Vreau** să pot reveni la lista de bonuri din pagina de editare
|
||||
**Pentru că** navigarea back prin browser nu e intuitivă pe mobil
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MobileTopBar în ReceiptCreateView/ReceiptCreateUnifiedView
|
||||
- [ ] Iconiță ← în stânga header-ului
|
||||
- [ ] Click pe ← navighează la `/data-entry`
|
||||
- [ ] Title: "Editare Bon" sau "Bon nou" în funcție de context
|
||||
- [ ] Verify in browser: butonul funcționează corect
|
||||
- [ ] npm run build passes
|
||||
|
||||
### US-106: Dashboard Mobile cu Swipeable KPI Cards
|
||||
**Ca** utilizator
|
||||
**Vreau** să văd KPI-urile ca un carousel swipeable pe mobil
|
||||
**Pentru că** cardurile stacked ocupă prea mult spațiu vertical
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Componentă `SwipeableCards.vue` creată
|
||||
- [ ] Dots indicator pentru poziție
|
||||
- [ ] Touch swipe left/right funcțional
|
||||
- [ ] DashboardView.vue folosește componenta pe mobil
|
||||
- [ ] Fallback la layout normal pe desktop
|
||||
- [ ] Verify in browser: swipe funcționează pe touch devices
|
||||
- [ ] npm run build passes
|
||||
|
||||
### US-107: InvoicesView Mobile Material Design Header
|
||||
**Ca** utilizator
|
||||
**Vreau** pagina de facturi să aibă același header Material ca lista bonuri
|
||||
**Pentru că** interfața trebuie să fie unitară
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MobileTopBar cu title "Facturi"
|
||||
- [ ] App Bar Actions: refresh, export în header (iconițe dreapta)
|
||||
- [ ] MobileBottomNav identic cu cel din bonuri
|
||||
- [ ] Filtre în Bottom Sheet (nu inline pe mobil)
|
||||
- [ ] Verify in browser: header arată ca la bonuri
|
||||
- [ ] npm run build passes
|
||||
|
||||
### US-108: TrialBalanceView Mobile Material Design Header
|
||||
**Ca** utilizator
|
||||
**Vreau** pagina de balanță să aibă același header Material
|
||||
**Pentru că** interfața trebuie să fie unitară
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MobileTopBar cu title "Balanță de Verificare"
|
||||
- [ ] App Bar Actions: export în header
|
||||
- [ ] MobileBottomNav identic
|
||||
- [ ] Bottom Sheet pentru filtre complexe (perioadă, conturi)
|
||||
- [ ] Verify in browser că arată consistent
|
||||
- [ ] npm run build passes
|
||||
|
||||
### US-109: BankCashRegisterView (Trezorerie) Mobile Material Design
|
||||
**Ca** utilizator
|
||||
**Vreau** pagina de trezorerie să aibă același header Material
|
||||
**Pentru că** interfața trebuie să fie unitară
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MobileTopBar cu title "Trezorerie"
|
||||
- [ ] App Bar Actions: refresh, export
|
||||
- [ ] MobileBottomNav identic
|
||||
- [ ] Bottom Sheet pentru filtre
|
||||
- [ ] Verify in browser
|
||||
- [ ] npm run build passes
|
||||
|
||||
### US-110: ServerLogsView Mobile Material Design
|
||||
**Ca** admin
|
||||
**Vreau** pagina de loguri să aibă interfață Material
|
||||
**Pentru că** și paginile admin trebuie să fie unitare
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MobileTopBar cu title "Loguri Server"
|
||||
- [ ] App Bar Actions: refresh, export
|
||||
- [ ] MobileBottomNav (fără link-ul de setări OCR pentru non-admin)
|
||||
- [ ] Verify in browser
|
||||
- [ ] npm run build passes
|
||||
|
||||
### US-111: CacheStatsView Mobile Material Design
|
||||
**Ca** admin
|
||||
**Vreau** pagina de statistici cache să aibă interfață Material
|
||||
**Pentru că** și paginile admin trebuie să fie unitare
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MobileTopBar cu title "Statistici Cache"
|
||||
- [ ] App Bar Actions: refresh
|
||||
- [ ] MobileBottomNav
|
||||
- [ ] Verify in browser
|
||||
- [ ] npm run build passes
|
||||
|
||||
### US-112: Bottom Sheet Component pentru Filtre
|
||||
**Ca** utilizator
|
||||
**Vreau** să pot accesa filtrele într-un bottom sheet pe mobil
|
||||
**Pentru că** ocupă mai puțin spațiu și e pattern MD familiar
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Componentă `BottomSheet.vue` cu animație slide-up
|
||||
- [ ] Drag handle în partea de sus
|
||||
- [ ] Close pe tap outside sau swipe down
|
||||
- [ ] Slot pentru conținut
|
||||
- [ ] Suport pentru visible v-model
|
||||
- [ ] Verify in browser: animația e smooth
|
||||
- [ ] npm run build passes
|
||||
|
||||
### US-113: Batch Actions per Module (contextuale)
|
||||
**Ca** utilizator
|
||||
**Vreau** acțiuni batch diferite în funcție de modulul curent
|
||||
**Pentru că** bonurile au ștergere, facturile au export+print, balanța doar export
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] MobileSelectionFooter acceptă prop `actions` array
|
||||
- [ ] Bonuri: Delete button (existent) + Export
|
||||
- [ ] Facturi: Export + Print
|
||||
- [ ] Balanță: Export only
|
||||
- [ ] Verify in browser pentru fiecare modul
|
||||
- [ ] npm run build passes
|
||||
|
||||
### US-114: Integrare și testare completă
|
||||
**Ca** QA
|
||||
**Vreau** toate paginile testate pe multiple device-uri
|
||||
**Pentru că** trebuie să fim siguri că nu sunt regresii
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Test pe Chrome Android (real device sau emulator)
|
||||
- [ ] Test pe Safari iOS (simulator sau real)
|
||||
- [ ] Test desktop Chrome/Firefox/Safari
|
||||
- [ ] Verify dark mode funcționează peste tot
|
||||
- [ ] Verify landscape orientation
|
||||
- [ ] npm run build passes
|
||||
- [ ] Zero erori în console
|
||||
|
||||
---
|
||||
|
||||
## User Stories: Documentație și Reguli (Faza 7)
|
||||
|
||||
### US-115: Actualizare CSS_PATTERNS.md cu Mobile Material Design
|
||||
**Ca** developer viitor
|
||||
**Vreau** documentație completă pentru pattern-urile Mobile Material Design
|
||||
**Pentru că** să pot implementa pagini noi consistent fără a citi codul existent
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Secțiune nouă "Mobile Material Design Components" în CSS_PATTERNS.md
|
||||
- [ ] Documentat MobileTopBar: structură HTML, clase CSS, props
|
||||
- [ ] Documentat MobileBottomNav: linkuri, iconițe, structură
|
||||
- [ ] Documentat MobileSelectionFooter: când se afișează, acțiuni
|
||||
- [ ] Documentat BottomSheet: usage, v-model, slots
|
||||
- [ ] Documentat SwipeableCards: props, dots indicator
|
||||
- [ ] Exemple de cod copy-paste ready pentru fiecare componentă
|
||||
- [ ] Screenshots/ASCII diagrams pentru layout-uri
|
||||
|
||||
### US-116: Actualizare DESIGN_TOKENS.md cu MD3 Tokens
|
||||
**Ca** developer viitor
|
||||
**Vreau** documentație pentru noile MD3 color tokens
|
||||
**Pentru că** să știu ce variabile CSS să folosesc pentru Material Design
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Secțiune nouă "Material Design 3 Tokens" în DESIGN_TOKENS.md
|
||||
- [ ] Tabel cu toate variabilele MD3: `--md-sys-color-*`
|
||||
- [ ] Mapping la tokens existenți (ex: `--md-sys-color-primary` → `--primary-color`)
|
||||
- [ ] Exemple dark mode: cum se schimbă valorile
|
||||
- [ ] Reguli când să folosești MD3 tokens vs tokens existenți
|
||||
- [ ] Color swatches vizuale (ASCII sau referință la Figma)
|
||||
|
||||
### US-117: Actualizare CLAUDE.md cu Reguli Mobile Development
|
||||
**Ca** Claude Code (AI)
|
||||
**Vreau** reguli clare în CLAUDE.md pentru dezvoltare mobilă
|
||||
**Pentru că** să respect pattern-urile stabilite la generarea automată de cod
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Secțiune nouă "### Mobile Development Rules" în CLAUDE.md
|
||||
- [ ] Regulă: "Toate paginile mobile TREBUIE să folosească MobileTopBar"
|
||||
- [ ] Regulă: "Filtrele pe mobil se pun în BottomSheet, NU inline"
|
||||
- [ ] Regulă: "Selecția multiplă afișează acțiuni în footer, NU în header"
|
||||
- [ ] Regulă: "Touch targets minim 44x44px"
|
||||
- [ ] Regulă: "Folosește isMobile composable pentru condiționare"
|
||||
- [ ] Checklist rapid pentru code review mobile
|
||||
|
||||
### US-118: Creare MOBILE_PATTERNS.md dedicat
|
||||
**Ca** developer
|
||||
**Vreau** un fișier dedicat pentru documentația mobilă
|
||||
**Pentru că** e prea mult pentru CSS_PATTERNS.md și merită propriul fișier
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Fișier `docs/MOBILE_PATTERNS.md` creat
|
||||
- [ ] Table of Contents cu linkuri rapide
|
||||
- [ ] Secțiuni pentru fiecare componentă
|
||||
- [ ] Secțiune "Quick Start" pentru devs noi
|
||||
- [ ] Secțiune "Do's and Don'ts" cu exemple concrete
|
||||
- [ ] Diagrame ASCII pentru layout mobile
|
||||
- [ ] Linkuri către fișierele sursă componente
|
||||
- [ ] Referință adăugată în CSS_PATTERNS.md și CLAUDE.md
|
||||
|
||||
### US-119: Actualizare claude-learn-frontend.md cu Pattern-uri Noi
|
||||
**Ca** Claude Code (AI)
|
||||
**Vreau** pattern-urile noi salvate în memoria Claude
|
||||
**Pentru că** să le pot aplica automat în sesiuni viitoare
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Pattern nou: "Mobile Material Design Component Architecture"
|
||||
- [ ] Pattern nou: "Bottom Sheet Filter Pattern"
|
||||
- [ ] Pattern nou: "Mobile Selection Mode Flow"
|
||||
- [ ] Gotcha: "Nu duplica delete button în header și footer"
|
||||
- [ ] Gotcha: "Filtrele mobile trebuie în BottomSheet"
|
||||
- [ ] Format corect cu @date și tags
|
||||
|
||||
### US-120: Validare Documentație cu Fresh Developer Test
|
||||
**Ca** lead developer
|
||||
**Vreau** să validez că documentația e suficientă
|
||||
**Pentru că** să mă asigur că un dev nou poate implementa o pagină mobilă fără ajutor
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Un developer (sau AI) poate crea o pagină mobilă nouă doar din docs
|
||||
- [ ] Toate componentele sunt documentate cu exemple
|
||||
- [ ] Nu sunt referințe circulare sau documente lipsă
|
||||
- [ ] Documentația e consistentă între fișiere
|
||||
- [ ] npm run build passes după ce dev-ul urmează docs
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
|
||||
1. [REQ-001] Toate paginile mobile trebuie să aibă MobileTopBar cu structură identică
|
||||
2. [REQ-002] MobileBottomNav trebuie să fie consistent între pagini (aceleași linkuri)
|
||||
3. [REQ-003] Selecția multiplă trebuie să folosească footer fix, nu header tabel
|
||||
4. [REQ-004] Filtrele pe mobil trebuie să fie în Bottom Sheet, nu inline
|
||||
5. [REQ-005] App Bar Actions (iconițe) trebuie să respecte ordinea: refresh, export, print, more
|
||||
6. [REQ-006] Dashboard KPI cards trebuie să fie swipeable cu dots indicator
|
||||
7. [REQ-007] Navigarea înapoi trebuie să fie vizibilă în app bar pentru pagini secundare
|
||||
8. [REQ-008] MD3 tokens trebuie să suporte toate cele 3 theme modes (auto/light/dark)
|
||||
9. [REQ-009] Documentația trebuie actualizată ÎNAINTE de merge în main
|
||||
10. [REQ-010] CLAUDE.md trebuie să conțină reguli explicite pentru mobile development
|
||||
11. [REQ-011] Orice developer nou trebuie să poată implementa o pagină mobilă doar din documentație
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
|
||||
- ❌ Nu modificăm layout-ul desktop (doar mobile)
|
||||
- ❌ Nu schimbăm structura tabelelor existente (sunt deja optimizate)
|
||||
- ❌ Nu implementăm gesture navigation nativă (back swipe) - folosim buton explicit
|
||||
- ❌ Nu adăugăm animații complexe (transform, spring physics)
|
||||
- ❌ Nu diferențiem comportamentul iOS vs Android (identic cross-platform)
|
||||
- ❌ Nu modificăm logica backend sau API calls
|
||||
- ❌ Nu implementăm pull-to-refresh (complexitate excesivă)
|
||||
|
||||
## 6. Considerații Tehnice
|
||||
|
||||
### Stack/Tehnologii
|
||||
- Vue 3 Composition API
|
||||
- PrimeVue components (Button, Dialog, Menu, Sidebar)
|
||||
- CSS custom cu design tokens
|
||||
- Touch events native (touchstart, touchmove, touchend)
|
||||
|
||||
### Patterns de Urmat
|
||||
- Pattern existent din `ReceiptsListView.vue` (US-038, US-039, US-040)
|
||||
- CSS tokens din `src/assets/css/core/tokens.css`
|
||||
- Mobile breakpoint: `max-width: 768px`
|
||||
- Touch target minimum: 44px
|
||||
|
||||
### Dependențe
|
||||
- `useMediaQuery` composable pentru `isMobile`
|
||||
- Router pentru navigare
|
||||
- Design tokens existenți
|
||||
|
||||
### Riscuri Tehnice
|
||||
- **Risc mediu**: Bottom Sheet poate avea probleme cu keyboard pe iOS
|
||||
- Mitigare: Testare extensivă, fallback la modal simplu
|
||||
- **Risc scăzut**: Swipe carousel poate conflicta cu scroll lateral pe tabele
|
||||
- Mitigare: Disable swipe când e în tabel
|
||||
|
||||
## 7. Considerații UI/UX
|
||||
|
||||
### Layout Structure (Mobile)
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ [☰/←] Title [🔍][⚙][⋮]│ ← MobileTopBar
|
||||
├─────────────────────────────────────┤
|
||||
│ [Filter Chips scrollable...] │ ← Optional, per page
|
||||
├─────────────────────────────────────┤
|
||||
│ │
|
||||
│ Page Content │
|
||||
│ (scrollable) │
|
||||
│ │
|
||||
├─────────────────────────────────────┤
|
||||
│ [🏠] [📤] [📊] [⚙] │ ← MobileBottomNav
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
OR (when selection active):
|
||||
|
||||
├─────────────────────────────────────┤
|
||||
│ [🗑️ Șterge selectate] │ ← MobileSelectionFooter
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Stări (States)
|
||||
- **Normal**: Header cu hamburger, content, bottom nav
|
||||
- **Selection Mode**: Header cu X și count, content cu checkmarks, footer cu delete
|
||||
- **Filters Open**: Bottom sheet overlay cu filtre
|
||||
- **Loading**: Skeleton sau spinner în content area
|
||||
- **Empty**: Empty state centrat în content area
|
||||
- **Error**: Toast notification
|
||||
|
||||
### Accesibilitate
|
||||
- Touch targets minim 44x44px
|
||||
- Focus visible pentru keyboard navigation
|
||||
- ARIA labels pe butoanele icon-only
|
||||
- Color contrast minim 4.5:1
|
||||
|
||||
## 8. Success Metrics
|
||||
|
||||
- **Consistență vizuală**: 100% pagini cu header identic
|
||||
- **Code reuse**: Min 70% CSS din componente comune
|
||||
- **Performance**: First Contentful Paint < 1.5s pe 3G
|
||||
- **Bundle size**: Creștere max 10KB gzipped
|
||||
|
||||
## 9. Open Questions
|
||||
|
||||
- [ ] TelegramView are nevoie de interfață Material? (e admin-only)
|
||||
- [ ] Cum gestionăm paginile cu mai mult de 4 acțiuni în app bar?
|
||||
- [ ] OCRMetricsView necesită bottom nav sau e pagină secundară?
|
||||
|
||||
---
|
||||
|
||||
## Implementare Sugerată (Ordinea User Stories)
|
||||
|
||||
### Faza 1: Fundație (US-101, US-102)
|
||||
1. Extract componente comune
|
||||
2. Definire MD3 tokens
|
||||
|
||||
### Faza 2: Refactor Bonuri (US-103, US-104, US-105)
|
||||
3. Validare API componente pe bonuri
|
||||
4. Fix buton delete duplicat
|
||||
5. Adaugă navigare înapoi
|
||||
|
||||
### Faza 3: Dashboard (US-106)
|
||||
6. Implement swipeable cards
|
||||
|
||||
### Faza 4: Reports Module (US-107, US-108, US-109, US-110, US-111)
|
||||
7. Apply pattern la fiecare pagină Reports
|
||||
|
||||
### Faza 5: Shared Components (US-112, US-113)
|
||||
8. Bottom Sheet pentru filtre
|
||||
9. Batch actions contextuale
|
||||
|
||||
### Faza 6: Testing (US-114)
|
||||
10. Cross-device testing
|
||||
|
||||
### Faza 7: Documentație (US-115, US-116, US-117, US-118, US-119, US-120)
|
||||
11. Creare MOBILE_PATTERNS.md dedicat
|
||||
12. Actualizare CSS_PATTERNS.md cu referințe
|
||||
13. Actualizare DESIGN_TOKENS.md cu MD3
|
||||
14. Actualizare CLAUDE.md cu reguli mobile
|
||||
15. Actualizare claude-learn-frontend.md cu patterns
|
||||
16. Validare documentație cu fresh developer test
|
||||
|
||||
---
|
||||
|
||||
## Anexa A: Fișiere de Documentație Afectate
|
||||
|
||||
| Fișier | Tip Modificare | User Story |
|
||||
|--------|---------------|------------|
|
||||
| `docs/MOBILE_PATTERNS.md` | NOU | US-118 |
|
||||
| `docs/CSS_PATTERNS.md` | Update | US-115 |
|
||||
| `docs/DESIGN_TOKENS.md` | Update | US-116 |
|
||||
| `CLAUDE.md` | Update | US-117 |
|
||||
| `.claude/rules/claude-learn-frontend.md` | Update | US-119 |
|
||||
|
||||
## Anexa B: Structura Documentație Finală
|
||||
|
||||
```
|
||||
docs/
|
||||
├── MOBILE_PATTERNS.md # NOU - ghid complet mobile MD
|
||||
├── CSS_PATTERNS.md # + link la MOBILE_PATTERNS.md
|
||||
├── DESIGN_TOKENS.md # + secțiune MD3 tokens
|
||||
├── ONBOARDING_CSS.md # + menționare mobile patterns
|
||||
└── ...
|
||||
|
||||
CLAUDE.md # + secțiune Mobile Development Rules
|
||||
|
||||
.claude/rules/
|
||||
└── claude-learn-frontend.md # + patterns & gotchas noi
|
||||
```
|
||||
Reference in New Issue
Block a user