diff --git a/scripts/ralph/archive/prd-20260112-094257.json b/scripts/ralph/archive/prd-20260112-094257.json new file mode 100644 index 0000000..68ebd18 --- /dev/null +++ b/scripts/ralph/archive/prd-20260112-094257.json @@ -0,0 +1,609 @@ +{ + "projectName": "mobile-ux-improvements", + "branchName": "ralph/bulk-receipt-upload", + "description": "Corectarea comportamentului de refresh pentru bulk upload, implementarea selecției multiple pe mobil cu interfață Android nativă, afișarea numelui fișierului pentru toate bonurile, și rezolvarea bug-urilor de UX raportate.", + "cssRules": { + "documentation": [ + "docs/ONBOARDING_CSS.md", + "docs/DESIGN_TOKENS.md", + "docs/CSS_PATTERNS.md" + ], + "goldenRules": [ + "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)" + ], + "mobileLayoutTokens": { + "topBarHeight": "56px", + "bottomNavHeight": "56px", + "fabSize": "56px", + "fabBottomOffset": "72px", + "touchTargetMin": "48px" + }, + "selectionModeColors": { + "selected": { + "background": "var(--blue-50)", + "border": "var(--blue-500)" + }, + "selectedDark": { + "background": "var(--blue-900)", + "border": "var(--blue-400)" + } + } + }, + "userStories": [ + { + "id": "US-001", + "title": "Backend - Stocare Batch și Processing Status", + "description": "Ca developer, vreau să extind schema Receipt pentru a stoca informații de batch, pentru că am nevoie de persistență pentru tracking.", + "priority": 1, + "acceptanceCriteria": [ + "Câmpuri noi în tabelul receipts: batch_id, processing_status, processing_error, file_hash, processing_started_at, processing_completed_at", + "Index pe batch_id, file_hash, processing_status", + "Migration reversibilă cu Alembic" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-002", + "title": "Backend - Endpoint List cu Batch Info", + "description": "Ca developer, vreau să extind endpoint-ul GET /receipts pentru a include info de batch.", + "priority": 2, + "acceptanceCriteria": [ + "Response include câmpurile de batch și processing pentru fiecare receipt", + "Filtrare pe processing_status și batch_id funcționează", + "Response include processing_stats" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-003", + "title": "Backend - Reject Automat pentru Duplicate (File Hash)", + "description": "Ca sistem, vreau să detectez și să reject fișierele duplicate la upload.", + "priority": 3, + "acceptanceCriteria": [ + "SHA-256 hash pentru duplicate detection", + "Response include existing_receipt_id pentru duplicates" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-004", + "title": "Frontend - Drag Anywhere pentru Upload", + "description": "Ca utilizator, vreau să pot trage fișiere oriunde pe pagina de bonuri.", + "priority": 4, + "acceptanceCriteria": [ + "DragDropOverlay.vue componentă", + "Global listeners cleanup în onUnmounted" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-005", + "title": "Frontend - Row Grouping per Batch în DataTable", + "description": "Ca utilizator, vreau să văd bonurile din același batch grupate vizual.", + "priority": 5, + "acceptanceCriteria": [ + "BatchGroupHeader.vue componentă", + "Grupuri sortate după processing_started_at descending" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-006", + "title": "Frontend - Coloană Status Procesare în Tabel", + "description": "Ca utilizator, vreau să văd statusul fiecărui bon din batch într-o coloană dedicată.", + "priority": 6, + "acceptanceCriteria": [ + "ProcessingStatusCell.vue componentă", + "Status updates în real-time via polling" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-007", + "title": "Frontend - Mesaj Eroare Vizibil în Listă", + "description": "Ca utilizator, vreau să văd mesajul de eroare direct în listă.", + "priority": 7, + "acceptanceCriteria": [ + "Truncated error message cu tooltip pentru full text" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-008", + "title": "Frontend - Quick Filter Chips pentru Statusuri Procesare", + "description": "Ca utilizator, vreau filtre rapide pentru bonurile cu erori sau în procesare.", + "priority": 8, + "acceptanceCriteria": [ + "Chips 'În procesare (N)' și 'Cu erori (N)' în status bar" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-009", + "title": "Frontend - Lock Row în Procesare (Read-Only)", + "description": "Ca utilizator, vreau ca bonurile în procesare să fie read-only.", + "priority": 9, + "acceptanceCriteria": [ + "Butoane și checkbox disabled pentru pending/processing", + "Tooltip pe butoane dezactivate" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-010", + "title": "Frontend - Retry Individual și Retry All Failed", + "description": "Ca utilizator, vreau să pot re-procesa bonurile cu erori.", + "priority": 10, + "acceptanceCriteria": [ + "Buton Reîncercă per rând failed", + "Buton Reîncercă toate erorile în BatchGroupHeader" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-011", + "title": "Frontend - Auto-Resume Polling la Refresh/Revenire", + "description": "Ca utilizator, vreau ca procesarea să continue când revin.", + "priority": 11, + "acceptanceCriteria": [ + "localStorage pentru active batch IDs", + "Auto-resume polling la onMounted" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-012", + "title": "Backend - Auto-Cleanup Erori După 7 Zile", + "description": "Ca sistem, vreau să șterg automat bonurile cu erori după 7 zile.", + "priority": 12, + "acceptanceCriteria": [ + "Background job pentru cleanup", + "Șterge receipts și attachments" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-013", + "title": "Cleanup - Eliminare Pagină Separată Bulk Upload", + "description": "Ca developer, vreau să elimin pagina separată de bulk upload.", + "priority": 13, + "acceptanceCriteria": [ + "Route redirect pentru backwards compatibility", + "Șterge componente nefolosite" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-014", + "title": "Backend - Endpoint Cancel Job Individual", + "description": "Ca sistem, vreau un endpoint API pentru anularea unui job specific de procesare.", + "priority": 14, + "acceptanceCriteria": [ + "POST /api/data-entry/bulk/cancel/{job_id} endpoint creat", + "Job-uri cu status completed/failed returnează 400 Bad Request", + "Job-uri pending/processing sunt marcate cancelled", + "Response include: {success, job_id, cancelled_at, message}" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-015", + "title": "Backend - Endpoint Cancel Batch Complet", + "description": "Ca sistem, vreau un endpoint API pentru anularea tuturor job-urilor dintr-un batch.", + "priority": 15, + "acceptanceCriteria": [ + "POST /api/data-entry/bulk/cancel-batch/{batch_id} endpoint creat", + "Response include: {success, batch_id, cancelled_count, skipped_count, message}" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-016", + "title": "Frontend - Store Actions pentru Cancel", + "description": "Ca dezvoltator, vreau acțiuni în batchProgressStore pentru cancel.", + "priority": 16, + "acceptanceCriteria": [ + "batchProgressStore.cancelJob(jobId) implementat", + "batchProgressStore.cancelBatch(batchId) implementat" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-017", + "title": "Frontend - Afișare Jobs Pending în Tabel", + "description": "Ca utilizator, vreau să văd fișierele încărcate imediat în tabel.", + "priority": 17, + "acceptanceCriteria": [ + "După upload success, rândurile pentru jobs apar instant în tabel", + "Tabelul poate randa atât Receipt-uri cât și BatchJob-uri" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-018", + "title": "Frontend - Tranziție Job → Receipt când OCR Termină", + "description": "Ca sistem, vreau ca rândul de job să se transforme în receipt când OCR termină.", + "priority": 18, + "acceptanceCriteria": [ + "Când polling detectează job completed cu receipt_id, rândul se actualizează", + "Tranziția e smooth - rândul NU dispare și reapare" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-019", + "title": "Frontend - Animație Status Change", + "description": "Ca utilizator, vreau o indicație vizuală când un fișier își schimbă statusul.", + "priority": 19, + "acceptanceCriteria": [ + "Badge-ul de status se schimbă cu CSS transition opacity 300ms", + "Highlight verde/roșu subtil pentru completed/failed" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-020", + "title": "Frontend - Buton Cancel Individual pe Row", + "description": "Ca utilizator, vreau un buton Cancel pe fiecare fișier pending/processing.", + "priority": 20, + "acceptanceCriteria": [ + "Fișierele pending/processing au icon Cancel (×)", + "După cancel success, rândul dispare cu fade-out 300ms" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-021", + "title": "Frontend - Buton Cancel All în BatchGroupHeader", + "description": "Ca utilizator, vreau un buton pentru a anula toate fișierele dintr-un batch.", + "priority": 21, + "acceptanceCriteria": [ + "BatchGroupHeader are buton 'Anulează tot' pentru batch-uri cu pending/processing jobs", + "Job-urile completed/failed rămân vizibile" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-022", + "title": "Frontend - Checkbox Disabled pentru Jobs în Procesare", + "description": "Ca utilizator, vreau ca checkbox-urile să fie disabled pentru fișiere în procesare.", + "priority": 22, + "acceptanceCriteria": [ + "Checkbox-ul este disabled pentru rânduri de tip job", + "Select All NU include job-urile în procesare" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-023", + "title": "Frontend - Restore Jobs la Refresh/Revenire", + "description": "Ca utilizator, vreau să văd job-urile pending când revin pe pagină.", + "priority": 23, + "acceptanceCriteria": [ + "La onMounted, verifică localStorage pentru active batch IDs", + "Job-urile pending/processing apar în tabel" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-024", + "title": "Backend - Endpoint Bulk Delete", + "description": "Ca frontend, vreau să pot trimite o listă de ID-uri pentru ștergere.", + "priority": 24, + "acceptanceCriteria": [ + "DELETE /api/data-entry/receipts/bulk acceptă body: { ids: [...] }", + "Returnează partial success response" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-025", + "title": "Frontend - Buton Șterge în Bulk Actions Bar", + "description": "Ca utilizator, vreau să văd un buton 'Șterge' când am selecții.", + "priority": 25, + "acceptanceCriteria": [ + "Butonul 'Șterge' apare în bulk actions bar când selectedReceipts.length > 0", + "Butonul are icon pi-trash și severity danger" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-026", + "title": "Frontend - Dialog Confirmare Ștergere Bulk", + "description": "Ca utilizator, vreau o confirmare înainte de ștergere.", + "priority": 26, + "acceptanceCriteria": [ + "La click pe 'Șterge', apare dialog cu mesaj confirmare", + "Dialog-ul folosește PrimeVue ConfirmDialog" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-027", + "title": "Frontend - Bulk Delete cu Partial Success Toast", + "description": "Ca utilizator, vreau să văd rezultatul ștergerii.", + "priority": 27, + "acceptanceCriteria": [ + "Toast arată rezultatul: 'X bonuri șterse'", + "Bonurile șterse dispar instant din listă", + "Selecția se golește după ștergere" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-028", + "title": "Frontend - Navigare la Pagina Anterioară când Lista Devine Goală", + "description": "Ca utilizator, vreau să fiu redirecționat când șterg toate bonurile de pe pagină.", + "priority": 28, + "acceptanceCriteria": [ + "După bulk delete, dacă lista devine goală și currentPage > 1, navigare la pagina anterioară", + "Dacă eram pe pagina 1, afișează empty state" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-029", + "title": "Frontend - Metodă updateReceiptInPlace în Store", + "description": "Ca frontend, vreau să actualizez un singur rând fără să re-renderez toată lista.", + "priority": 29, + "acceptanceCriteria": [ + "Metoda updateReceiptInPlace(receiptId, updates) în receiptsStore", + "Object.assign pentru updates, nu înlocuire array" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-030", + "title": "Backend - SSE Endpoint pentru Status Updates", + "description": "Ca frontend, vreau să primesc notificări real-time despre schimbări de status.", + "priority": 30, + "acceptanceCriteria": [ + "GET /api/data-entry/receipts/sse/status returnează SSE stream", + "Format eveniment: {receipt_id, status, processing_status}" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-031", + "title": "Frontend - SSE Client Service", + "description": "Ca frontend, vreau să mă conectez la SSE și să actualizez rândurile individual.", + "priority": 31, + "acceptanceCriteria": [ + "sseService.js cu connect(), disconnect(), onStatusChange()", + "Folosește native EventSource API" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-032", + "title": "Frontend - Înlocuire Polling cu SSE", + "description": "Ca frontend, vreau să folosesc SSE în loc de polling.", + "priority": 32, + "acceptanceCriteria": [ + "SSE în loc de setInterval pentru auto-refresh", + "La primire eveniment SSE, apelează updateReceiptInPlace()" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-033", + "title": "Frontend - Graceful Degradation la SSE Failure", + "description": "Ca utilizator, vreau ca aplicația să funcționeze și fără SSE.", + "priority": 33, + "acceptanceCriteria": [ + "Dacă SSE fail, activează fallback la polling clasic", + "Retry SSE periodic (la 30s)" + ], + "passes": true, + "notes": "Completed previously" + }, + { + "id": "US-034", + "title": "Fix - Refresh Individual vs Refresh Total", + "description": "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.", + "priority": 34, + "acceptanceCriteria": [ + "SSE handler NU apelează store.fetchReceipts() când un receipt nu este în pagina curentă", + "Verifică dacă receipt-ul aparține unui batch activ și îl adaugă local dacă nu există", + "Ordinea bonurilor din batch rămâne stabilă (nu se reordonează)", + "npm run typecheck passes", + "Verify in browser: uploadează 5 bonuri, nu se reîncarcă pagina între procesări" + ], + "technicalNotes": "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 în poziția corectă.", + "passes": true, + "notes": "Completed in iteration 1" + }, + { + "id": "US-035", + "title": "Fix - Bonuri cu Eroare Rămân în Listă", + "description": "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.", + "priority": 35, + "acceptanceCriteria": [ + "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" + ], + "technicalNotes": "Bonurile cu eroare ar trebui să aibă status='draft' și processing_status='failed'. Nu se șterg la refresh, doar se actualizează in-place.", + "passes": true, + "notes": "Completed in iteration 2" + }, + { + "id": "US-036", + "title": "Afișare Nume Fișier pentru Toate Bonurile", + "description": "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.", + "priority": 36, + "acceptanceCriteria": [ + "Coloana 'Fișier' afișează original_filename și pentru receipt-uri completate, nu doar pentru job-uri", + "Pe mobil, numele fișierului apare sub partener (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" + ], + "technicalNotes": "Backend trebuie să populeze original_filename pe receipt din job-ul OCR. Verifică că auto-save service copiază filename din job la receipt.", + "passes": true, + "notes": "Completed in iteration 3" + }, + { + "id": "US-037", + "title": "Fix - Upload Nu Mai Face Refresh Automat", + "description": "Ca utilizator, vreau ca selectarea fișierelor să nu reîncarce pagina, pentru că pierd fișierele selectate înainte să apăs 'Procesează'.", + "priority": 37, + "acceptanceCriteria": [ + "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ă" + ], + "technicalNotes": "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.", + "passes": true, + "notes": "Completed in iteration 4" + }, + { + "id": "US-038", + "title": "Mobile - Selecție Multiplă prin Long-Press", + "description": "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.", + "priority": 38, + "acceptanceCriteria": [ + "Long-press (500ms) pe un card activează modul de selecție", + "Card-ul selectat primește checkmark și background diferit (var(--blue-50))", + "După activare, tap simplu pe alte carduri le adaugă/elimină din selecție", + "Tap în afara cardurilor 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" + ], + "technicalNotes": "Implementare cu setTimeout(500ms) pe touchstart, clear pe touchend/touchmove. CSS: .receipt-card.selected { background: var(--blue-50); border-color: var(--blue-500); }", + "passes": true, + "notes": "Completed in iteration 5" + }, + { + "id": "US-039", + "title": "Mobile - Select All și Buton Ștergere", + "description": "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.", + "priority": 39, + "acceptanceCriteria": [ + "În modul selecție, apare top bar contextual cu: număr selectate, buton 'Selectează tot', buton X pentru ieșire", + "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ă" + ], + "technicalNotes": "Top bar: position: sticky; top: 0. Bottom bar: position: fixed; bottom: 0. Animație slide-in pentru bars.", + "passes": true, + "notes": "Completed in iteration 6" + }, + { + "id": "US-040", + "title": "Mobile - Layout Android Nativ pentru Lista Bonuri", + "description": "Ca utilizator mobil, vreau o interfață similară cu aplicațiile Android native, pentru că vreau experiență familiară și intuitivă.", + "priority": 40, + "acceptanceCriteria": [ + "Top Bar fixă cu: hamburger/back (stânga), titlu centrat, search+filter+more (dreapta)", + "Filter Chips sub top bar (orizontal scrollabil): Toate, Ciorne, În așteptare, Validate, Respinse", + "Bottom Navigation fixă cu 4 tab-uri: Bonuri (activ), Upload, Rapoarte, Setări", + "FAB (56x56px) în colț dreapta jos, 16px de la margine, 72px de la bottom", + "FAB se ascunde când 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" + ], + "technicalNotes": "CSS: .mobile-top-bar { position: fixed; top: 0; height: 56px; z-index: 1000 }. .mobile-bottom-nav { position: fixed; bottom: 0; height: 56px }. .mobile-fab { position: fixed; bottom: 72px; right: 16px; width: 56px; border-radius: 16px }", + "passes": true, + "notes": "Completed in iteration 7" + }, + { + "id": "US-041", + "title": "Mobile - Layout Android pentru Editare/Creare Bon", + "description": "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.", + "priority": 41, + "acceptanceCriteria": [ + "Top Bar cu: X/back (stânga), titlu centrat, attach+save icons (dreapta)", + "Content Area scrollabilă cu form fields 100% width", + "Bottom Action Bar fixă cu: 'Salvează Ciornă' (secondary), 'Trimite pentru Validare' (primary)", + "Keyboard-aware: bottom bar se mută deasupra tastaturii", + "npm run typecheck passes", + "Verify on mobile: layout similar cu Gmail compose" + ], + "technicalNotes": "CSS: .mobile-receipt-form { padding-bottom: 80px }. .mobile-form-bottom-bar { position: fixed; bottom: 0; display: flex; gap: var(--space-sm) }. Butoane cu flex: 1 pentru width egal.", + "passes": true, + "notes": "Completed in iteration 8" + }, + { + "id": "US-042", + "title": "Mobile - Layout Android pentru Vizualizare Bon", + "description": "Ca utilizator mobil, vreau interfață de vizualizare bon similară cu view email în Gmail, pentru că vreau acțiuni rapide și navigare ușoară.", + "priority": 42, + "acceptanceCriteria": [ + "Top Bar cu: back arrow (stânga), edit+delete+more icons (dreapta)", + "Content Area cu detalii bon (read-only)", + "Bottom Action Bar cu butoane contextuale: DRAFT→Editează/Trimite, PENDING→Validează/Respinge, APPROVED→Anulează", + "npm run typecheck passes", + "Verify on mobile: acțiuni accesibile din bottom bar" + ], + "technicalNotes": "Refolosește stilurile din US-041. Butoanele din bottom bar se schimbă dinamic bazat pe receipt.status.", + "passes": true, + "notes": "Completed in iteration 9" + }, + { + "id": "US-043", + "title": "Păstrare Ordine Bonuri la Refresh", + "description": "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.", + "priority": 43, + "acceptanceCriteria": [ + "Bonurile din același batch păstrează ordinea de upload (nu se reordonează)", + "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 poate reordona, dar SSE updates nu", + "npm run typecheck passes", + "Verify in browser: bon procesat nu își schimbă poziția în listă" + ], + "technicalNotes": "Lista trebuie sortată by created_at DESC sau by batch order, nu by last_modified. updateReceiptInPlace din store NU trebuie să reordoneze array-ul.", + "passes": true, + "notes": "Completed in iteration 10" + } + ] +} diff --git a/scripts/ralph/prd.json b/scripts/ralph/prd.json index 68ebd18..11e8b87 100644 --- a/scripts/ralph/prd.json +++ b/scripts/ralph/prd.json @@ -1,19 +1,23 @@ { - "projectName": "mobile-ux-improvements", - "branchName": "ralph/bulk-receipt-upload", - "description": "Corectarea comportamentului de refresh pentru bulk upload, implementarea selecției multiple pe mobil cu interfață Android nativă, afișarea numelui fișierului pentru toate bonurile, și rezolvarea bug-urilor de UX raportate.", + "projectName": "unified-mobile-material-design", + "branchName": "ralph/unified-mobile-md", + "description": "Extinderea interfeței Material Design la toate paginile aplicației în modul mobil pentru consistență UI/UX", "cssRules": { "documentation": [ "docs/ONBOARDING_CSS.md", "docs/DESIGN_TOKENS.md", - "docs/CSS_PATTERNS.md" + "docs/CSS_PATTERNS.md", + "docs/MOBILE_PATTERNS.md" ], "goldenRules": [ "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)" + "NICIODATĂ duplicate CSS (write once, use everywhere)", + "Mobile: toate paginile folosesc MobileTopBar + MobileBottomNav", + "Mobile: filtrele se pun în BottomSheet, NU inline", + "Mobile: selecția afișează acțiuni în footer, NU în header" ], "mobileLayoutTokens": { "topBarHeight": "56px", @@ -21,589 +25,316 @@ "fabSize": "56px", "fabBottomOffset": "72px", "touchTargetMin": "48px" - }, - "selectionModeColors": { - "selected": { - "background": "var(--blue-50)", - "border": "var(--blue-500)" - }, - "selectedDark": { - "background": "var(--blue-900)", - "border": "var(--blue-400)" - } } }, "userStories": [ { - "id": "US-001", - "title": "Backend - Stocare Batch și Processing Status", - "description": "Ca developer, vreau să extind schema Receipt pentru a stoca informații de batch, pentru că am nevoie de persistență pentru tracking.", + "id": "US-101a", + "title": "Creare MobileTopBar.vue component", + "description": "Ca developer vreau componentă MobileTopBar.vue extrasă din ReceiptsListView pentru reutilizare", "priority": 1, "acceptanceCriteria": [ - "Câmpuri noi în tabelul receipts: batch_id, processing_status, processing_error, file_hash, processing_started_at, processing_completed_at", - "Index pe batch_id, file_hash, processing_status", - "Migration reversibilă cu Alembic" + "Componentă src/shared/components/mobile/MobileTopBar.vue creată", + "Props: title (string), showBack (boolean), showMenu (boolean), actions (array)", + "Emit events: menu-click, back-click, action-click", + "Stiluri CSS extrase din ReceiptsListView (.mobile-top-bar)", + "Dark mode support cu [data-theme='dark']", + "npm run build passes" ], "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-002", - "title": "Backend - Endpoint List cu Batch Info", - "description": "Ca developer, vreau să extind endpoint-ul GET /receipts pentru a include info de batch.", - "priority": 2, - "acceptanceCriteria": [ - "Response include câmpurile de batch și processing pentru fiecare receipt", - "Filtrare pe processing_status și batch_id funcționează", - "Response include processing_stats" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-003", - "title": "Backend - Reject Automat pentru Duplicate (File Hash)", - "description": "Ca sistem, vreau să detectez și să reject fișierele duplicate la upload.", - "priority": 3, - "acceptanceCriteria": [ - "SHA-256 hash pentru duplicate detection", - "Response include existing_receipt_id pentru duplicates" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-004", - "title": "Frontend - Drag Anywhere pentru Upload", - "description": "Ca utilizator, vreau să pot trage fișiere oriunde pe pagina de bonuri.", - "priority": 4, - "acceptanceCriteria": [ - "DragDropOverlay.vue componentă", - "Global listeners cleanup în onUnmounted" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-005", - "title": "Frontend - Row Grouping per Batch în DataTable", - "description": "Ca utilizator, vreau să văd bonurile din același batch grupate vizual.", - "priority": 5, - "acceptanceCriteria": [ - "BatchGroupHeader.vue componentă", - "Grupuri sortate după processing_started_at descending" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-006", - "title": "Frontend - Coloană Status Procesare în Tabel", - "description": "Ca utilizator, vreau să văd statusul fiecărui bon din batch într-o coloană dedicată.", - "priority": 6, - "acceptanceCriteria": [ - "ProcessingStatusCell.vue componentă", - "Status updates în real-time via polling" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-007", - "title": "Frontend - Mesaj Eroare Vizibil în Listă", - "description": "Ca utilizator, vreau să văd mesajul de eroare direct în listă.", - "priority": 7, - "acceptanceCriteria": [ - "Truncated error message cu tooltip pentru full text" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-008", - "title": "Frontend - Quick Filter Chips pentru Statusuri Procesare", - "description": "Ca utilizator, vreau filtre rapide pentru bonurile cu erori sau în procesare.", - "priority": 8, - "acceptanceCriteria": [ - "Chips 'În procesare (N)' și 'Cu erori (N)' în status bar" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-009", - "title": "Frontend - Lock Row în Procesare (Read-Only)", - "description": "Ca utilizator, vreau ca bonurile în procesare să fie read-only.", - "priority": 9, - "acceptanceCriteria": [ - "Butoane și checkbox disabled pentru pending/processing", - "Tooltip pe butoane dezactivate" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-010", - "title": "Frontend - Retry Individual și Retry All Failed", - "description": "Ca utilizator, vreau să pot re-procesa bonurile cu erori.", - "priority": 10, - "acceptanceCriteria": [ - "Buton Reîncercă per rând failed", - "Buton Reîncercă toate erorile în BatchGroupHeader" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-011", - "title": "Frontend - Auto-Resume Polling la Refresh/Revenire", - "description": "Ca utilizator, vreau ca procesarea să continue când revin.", - "priority": 11, - "acceptanceCriteria": [ - "localStorage pentru active batch IDs", - "Auto-resume polling la onMounted" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-012", - "title": "Backend - Auto-Cleanup Erori După 7 Zile", - "description": "Ca sistem, vreau să șterg automat bonurile cu erori după 7 zile.", - "priority": 12, - "acceptanceCriteria": [ - "Background job pentru cleanup", - "Șterge receipts și attachments" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-013", - "title": "Cleanup - Eliminare Pagină Separată Bulk Upload", - "description": "Ca developer, vreau să elimin pagina separată de bulk upload.", - "priority": 13, - "acceptanceCriteria": [ - "Route redirect pentru backwards compatibility", - "Șterge componente nefolosite" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-014", - "title": "Backend - Endpoint Cancel Job Individual", - "description": "Ca sistem, vreau un endpoint API pentru anularea unui job specific de procesare.", - "priority": 14, - "acceptanceCriteria": [ - "POST /api/data-entry/bulk/cancel/{job_id} endpoint creat", - "Job-uri cu status completed/failed returnează 400 Bad Request", - "Job-uri pending/processing sunt marcate cancelled", - "Response include: {success, job_id, cancelled_at, message}" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-015", - "title": "Backend - Endpoint Cancel Batch Complet", - "description": "Ca sistem, vreau un endpoint API pentru anularea tuturor job-urilor dintr-un batch.", - "priority": 15, - "acceptanceCriteria": [ - "POST /api/data-entry/bulk/cancel-batch/{batch_id} endpoint creat", - "Response include: {success, batch_id, cancelled_count, skipped_count, message}" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-016", - "title": "Frontend - Store Actions pentru Cancel", - "description": "Ca dezvoltator, vreau acțiuni în batchProgressStore pentru cancel.", - "priority": 16, - "acceptanceCriteria": [ - "batchProgressStore.cancelJob(jobId) implementat", - "batchProgressStore.cancelBatch(batchId) implementat" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-017", - "title": "Frontend - Afișare Jobs Pending în Tabel", - "description": "Ca utilizator, vreau să văd fișierele încărcate imediat în tabel.", - "priority": 17, - "acceptanceCriteria": [ - "După upload success, rândurile pentru jobs apar instant în tabel", - "Tabelul poate randa atât Receipt-uri cât și BatchJob-uri" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-018", - "title": "Frontend - Tranziție Job → Receipt când OCR Termină", - "description": "Ca sistem, vreau ca rândul de job să se transforme în receipt când OCR termină.", - "priority": 18, - "acceptanceCriteria": [ - "Când polling detectează job completed cu receipt_id, rândul se actualizează", - "Tranziția e smooth - rândul NU dispare și reapare" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-019", - "title": "Frontend - Animație Status Change", - "description": "Ca utilizator, vreau o indicație vizuală când un fișier își schimbă statusul.", - "priority": 19, - "acceptanceCriteria": [ - "Badge-ul de status se schimbă cu CSS transition opacity 300ms", - "Highlight verde/roșu subtil pentru completed/failed" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-020", - "title": "Frontend - Buton Cancel Individual pe Row", - "description": "Ca utilizator, vreau un buton Cancel pe fiecare fișier pending/processing.", - "priority": 20, - "acceptanceCriteria": [ - "Fișierele pending/processing au icon Cancel (×)", - "După cancel success, rândul dispare cu fade-out 300ms" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-021", - "title": "Frontend - Buton Cancel All în BatchGroupHeader", - "description": "Ca utilizator, vreau un buton pentru a anula toate fișierele dintr-un batch.", - "priority": 21, - "acceptanceCriteria": [ - "BatchGroupHeader are buton 'Anulează tot' pentru batch-uri cu pending/processing jobs", - "Job-urile completed/failed rămân vizibile" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-022", - "title": "Frontend - Checkbox Disabled pentru Jobs în Procesare", - "description": "Ca utilizator, vreau ca checkbox-urile să fie disabled pentru fișiere în procesare.", - "priority": 22, - "acceptanceCriteria": [ - "Checkbox-ul este disabled pentru rânduri de tip job", - "Select All NU include job-urile în procesare" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-023", - "title": "Frontend - Restore Jobs la Refresh/Revenire", - "description": "Ca utilizator, vreau să văd job-urile pending când revin pe pagină.", - "priority": 23, - "acceptanceCriteria": [ - "La onMounted, verifică localStorage pentru active batch IDs", - "Job-urile pending/processing apar în tabel" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-024", - "title": "Backend - Endpoint Bulk Delete", - "description": "Ca frontend, vreau să pot trimite o listă de ID-uri pentru ștergere.", - "priority": 24, - "acceptanceCriteria": [ - "DELETE /api/data-entry/receipts/bulk acceptă body: { ids: [...] }", - "Returnează partial success response" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-025", - "title": "Frontend - Buton Șterge în Bulk Actions Bar", - "description": "Ca utilizator, vreau să văd un buton 'Șterge' când am selecții.", - "priority": 25, - "acceptanceCriteria": [ - "Butonul 'Șterge' apare în bulk actions bar când selectedReceipts.length > 0", - "Butonul are icon pi-trash și severity danger" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-026", - "title": "Frontend - Dialog Confirmare Ștergere Bulk", - "description": "Ca utilizator, vreau o confirmare înainte de ștergere.", - "priority": 26, - "acceptanceCriteria": [ - "La click pe 'Șterge', apare dialog cu mesaj confirmare", - "Dialog-ul folosește PrimeVue ConfirmDialog" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-027", - "title": "Frontend - Bulk Delete cu Partial Success Toast", - "description": "Ca utilizator, vreau să văd rezultatul ștergerii.", - "priority": 27, - "acceptanceCriteria": [ - "Toast arată rezultatul: 'X bonuri șterse'", - "Bonurile șterse dispar instant din listă", - "Selecția se golește după ștergere" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-028", - "title": "Frontend - Navigare la Pagina Anterioară când Lista Devine Goală", - "description": "Ca utilizator, vreau să fiu redirecționat când șterg toate bonurile de pe pagină.", - "priority": 28, - "acceptanceCriteria": [ - "După bulk delete, dacă lista devine goală și currentPage > 1, navigare la pagina anterioară", - "Dacă eram pe pagina 1, afișează empty state" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-029", - "title": "Frontend - Metodă updateReceiptInPlace în Store", - "description": "Ca frontend, vreau să actualizez un singur rând fără să re-renderez toată lista.", - "priority": 29, - "acceptanceCriteria": [ - "Metoda updateReceiptInPlace(receiptId, updates) în receiptsStore", - "Object.assign pentru updates, nu înlocuire array" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-030", - "title": "Backend - SSE Endpoint pentru Status Updates", - "description": "Ca frontend, vreau să primesc notificări real-time despre schimbări de status.", - "priority": 30, - "acceptanceCriteria": [ - "GET /api/data-entry/receipts/sse/status returnează SSE stream", - "Format eveniment: {receipt_id, status, processing_status}" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-031", - "title": "Frontend - SSE Client Service", - "description": "Ca frontend, vreau să mă conectez la SSE și să actualizez rândurile individual.", - "priority": 31, - "acceptanceCriteria": [ - "sseService.js cu connect(), disconnect(), onStatusChange()", - "Folosește native EventSource API" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-032", - "title": "Frontend - Înlocuire Polling cu SSE", - "description": "Ca frontend, vreau să folosesc SSE în loc de polling.", - "priority": 32, - "acceptanceCriteria": [ - "SSE în loc de setInterval pentru auto-refresh", - "La primire eveniment SSE, apelează updateReceiptInPlace()" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-033", - "title": "Frontend - Graceful Degradation la SSE Failure", - "description": "Ca utilizator, vreau ca aplicația să funcționeze și fără SSE.", - "priority": 33, - "acceptanceCriteria": [ - "Dacă SSE fail, activează fallback la polling clasic", - "Retry SSE periodic (la 30s)" - ], - "passes": true, - "notes": "Completed previously" - }, - { - "id": "US-034", - "title": "Fix - Refresh Individual vs Refresh Total", - "description": "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.", - "priority": 34, - "acceptanceCriteria": [ - "SSE handler NU apelează store.fetchReceipts() când un receipt nu este în pagina curentă", - "Verifică dacă receipt-ul aparține unui batch activ și îl adaugă local dacă nu există", - "Ordinea bonurilor din batch rămâne stabilă (nu se reordonează)", - "npm run typecheck passes", - "Verify in browser: uploadează 5 bonuri, nu se reîncarcă pagina între procesări" - ], - "technicalNotes": "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 în poziția corectă.", - "passes": true, "notes": "Completed in iteration 1" }, { - "id": "US-035", - "title": "Fix - Bonuri cu Eroare Rămân în Listă", - "description": "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.", - "priority": 35, + "id": "US-101b", + "title": "Creare MobileBottomNav.vue component", + "description": "Ca developer vreau componentă MobileBottomNav.vue pentru navigarea de jos pe mobil", + "priority": 2, "acceptanceCriteria": [ - "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" + "Componentă src/shared/components/mobile/MobileBottomNav.vue creată", + "Props: items (array of {to, icon, label, active})", + "4 linkuri: Bonuri, Upload, Rapoarte, Setări", + "Stiluri CSS extrase din ReceiptsListView (.mobile-bottom-nav)", + "router-link pentru navigare", + "npm run build passes" ], - "technicalNotes": "Bonurile cu eroare ar trebui să aibă status='draft' și processing_status='failed'. Nu se șterg la refresh, doar se actualizează in-place.", - "passes": true, - "notes": "Completed in iteration 2" + "passes": false, + "notes": "" }, { - "id": "US-036", - "title": "Afișare Nume Fișier pentru Toate Bonurile", - "description": "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.", - "priority": 36, + "id": "US-101c", + "title": "Creare MobileSelectionFooter.vue component", + "description": "Ca developer vreau componentă pentru acțiuni batch când sunt selectate elemente", + "priority": 3, "acceptanceCriteria": [ - "Coloana 'Fișier' afișează original_filename și pentru receipt-uri completate, nu doar pentru job-uri", - "Pe mobil, numele fișierului apare sub partener (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" + "Componentă src/shared/components/mobile/MobileSelectionFooter.vue creată", + "Props: visible (boolean), actions (array of {label, icon, severity, handler})", + "Animație slide-up cu Transition", + "Stiluri din .mobile-selection-bottom-bar", + "npm run build passes" ], - "technicalNotes": "Backend trebuie să populeze original_filename pe receipt din job-ul OCR. Verifică că auto-save service copiază filename din job la receipt.", - "passes": true, - "notes": "Completed in iteration 3" + "passes": false, + "notes": "" }, { - "id": "US-037", - "title": "Fix - Upload Nu Mai Face Refresh Automat", - "description": "Ca utilizator, vreau ca selectarea fișierelor să nu reîncarce pagina, pentru că pierd fișierele selectate înainte să apăs 'Procesează'.", - "priority": 37, + "id": "US-102", + "title": "Definire MD3 color tokens în CSS", + "description": "Ca developer vreau variabile CSS pentru Material Design 3 color system", + "priority": 4, "acceptanceCriteria": [ - "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ă" + "Fișier src/assets/css/core/md3-tokens.css creat", + "Tokens: --md-sys-color-primary, --md-sys-color-on-primary, --md-sys-color-surface, --md-sys-color-on-surface, --md-sys-color-outline", + "Dark mode variants cu [data-theme='dark']", + "Auto dark mode cu @media (prefers-color-scheme: dark)", + "Import adăugat în main.css", + "npm run build passes" ], - "technicalNotes": "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.", - "passes": true, - "notes": "Completed in iteration 4" + "passes": false, + "notes": "" }, { - "id": "US-038", - "title": "Mobile - Selecție Multiplă prin Long-Press", - "description": "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.", - "priority": 38, + "id": "US-103", + "title": "Refactor ReceiptsListView să folosească componente comune", + "description": "Ca developer vreau ReceiptsListView să folosească noile componente pentru validare API", + "priority": 5, "acceptanceCriteria": [ - "Long-press (500ms) pe un card activează modul de selecție", - "Card-ul selectat primește checkmark și background diferit (var(--blue-50))", - "După activare, tap simplu pe alte carduri le adaugă/elimină din selecție", - "Tap în afara cardurilor 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" + "Import MobileTopBar, MobileBottomNav, MobileSelectionFooter în ReceiptsListView", + "Înlocuire template HTML cu componente", + "Ștergere CSS duplicat din ReceiptsListView (>200 linii)", + "Funcționalitate identică cu implementarea actuală", + "Verify in browser că lista bonuri funcționează identic pe mobil", + "npm run build passes" ], - "technicalNotes": "Implementare cu setTimeout(500ms) pe touchstart, clear pe touchend/touchmove. CSS: .receipt-card.selected { background: var(--blue-50); border-color: var(--blue-500); }", - "passes": true, - "notes": "Completed in iteration 5" + "passes": false, + "notes": "" }, { - "id": "US-039", - "title": "Mobile - Select All și Buton Ștergere", - "description": "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.", - "priority": 39, + "id": "US-104", + "title": "Eliminare buton delete duplicat din header tabel", + "description": "Ca utilizator vreau butonul delete doar în footer, nu și în header când e selecție activă", + "priority": 6, "acceptanceCriteria": [ - "În modul selecție, apare top bar contextual cu: număr selectate, buton 'Selectează tot', buton X pentru ieșire", - "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ă" + "În ReceiptsListView, bulk-actions-bar afișat DOAR când !isMobile", + "Pe mobil, delete apare DOAR în mobile-selection-bottom-bar (footer)", + "Pe desktop, delete rămâne în bulk-actions-bar (header tabel)", + "Verify in browser: pe mobil delete e doar în footer", + "Verify in browser: pe desktop delete e în header", + "npm run build passes" ], - "technicalNotes": "Top bar: position: sticky; top: 0. Bottom bar: position: fixed; bottom: 0. Animație slide-in pentru bars.", - "passes": true, - "notes": "Completed in iteration 6" + "passes": false, + "notes": "" }, { - "id": "US-040", - "title": "Mobile - Layout Android Nativ pentru Lista Bonuri", - "description": "Ca utilizator mobil, vreau o interfață similară cu aplicațiile Android native, pentru că vreau experiență familiară și intuitivă.", - "priority": 40, + "id": "US-105", + "title": "Adăugare buton Înapoi în editare bon", + "description": "Ca utilizator vreau să pot reveni la lista de bonuri din pagina de editare cu buton ←", + "priority": 7, "acceptanceCriteria": [ - "Top Bar fixă cu: hamburger/back (stânga), titlu centrat, search+filter+more (dreapta)", - "Filter Chips sub top bar (orizontal scrollabil): Toate, Ciorne, În așteptare, Validate, Respinse", - "Bottom Navigation fixă cu 4 tab-uri: Bonuri (activ), Upload, Rapoarte, Setări", - "FAB (56x56px) în colț dreapta jos, 16px de la margine, 72px de la bottom", - "FAB se ascunde când 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" + "MobileTopBar adăugat în ReceiptCreateUnifiedView.vue", + "showBack=true pentru a afișa săgeata ←", + "Click pe ← navighează la /data-entry", + "Title dinamic: 'Bon nou' pentru create, 'Editare Bon' pentru edit", + "Verify in browser că butonul funcționează", + "npm run build passes" ], - "technicalNotes": "CSS: .mobile-top-bar { position: fixed; top: 0; height: 56px; z-index: 1000 }. .mobile-bottom-nav { position: fixed; bottom: 0; height: 56px }. .mobile-fab { position: fixed; bottom: 72px; right: 16px; width: 56px; border-radius: 16px }", - "passes": true, - "notes": "Completed in iteration 7" + "passes": false, + "notes": "" }, { - "id": "US-041", - "title": "Mobile - Layout Android pentru Editare/Creare Bon", - "description": "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.", - "priority": 41, + "id": "US-112", + "title": "Creare BottomSheet.vue component pentru filtre", + "description": "Ca utilizator vreau să pot accesa filtrele într-un bottom sheet pe mobil", + "priority": 8, "acceptanceCriteria": [ - "Top Bar cu: X/back (stânga), titlu centrat, attach+save icons (dreapta)", - "Content Area scrollabilă cu form fields 100% width", - "Bottom Action Bar fixă cu: 'Salvează Ciornă' (secondary), 'Trimite pentru Validare' (primary)", - "Keyboard-aware: bottom bar se mută deasupra tastaturii", - "npm run typecheck passes", - "Verify on mobile: layout similar cu Gmail compose" + "Componentă src/shared/components/mobile/BottomSheet.vue creată", + "v-model:visible pentru control", + "Animație slide-up smooth", + "Drag handle în partea de sus", + "Close pe tap outside overlay", + "Slot default pentru conținut", + "npm run build passes" ], - "technicalNotes": "CSS: .mobile-receipt-form { padding-bottom: 80px }. .mobile-form-bottom-bar { position: fixed; bottom: 0; display: flex; gap: var(--space-sm) }. Butoane cu flex: 1 pentru width egal.", - "passes": true, - "notes": "Completed in iteration 8" + "passes": false, + "notes": "" }, { - "id": "US-042", - "title": "Mobile - Layout Android pentru Vizualizare Bon", - "description": "Ca utilizator mobil, vreau interfață de vizualizare bon similară cu view email în Gmail, pentru că vreau acțiuni rapide și navigare ușoară.", - "priority": 42, + "id": "US-106", + "title": "Dashboard Mobile cu Swipeable KPI Cards", + "description": "Ca utilizator vreau KPI-uri ca carousel swipeable pe mobil cu dots indicator", + "priority": 9, "acceptanceCriteria": [ - "Top Bar cu: back arrow (stânga), edit+delete+more icons (dreapta)", - "Content Area cu detalii bon (read-only)", - "Bottom Action Bar cu butoane contextuale: DRAFT→Editează/Trimite, PENDING→Validează/Respinge, APPROVED→Anulează", - "npm run typecheck passes", - "Verify on mobile: acțiuni accesibile din bottom bar" + "Componentă src/shared/components/mobile/SwipeableCards.vue creată", + "Touch swipe left/right funcțional (touchstart, touchmove, touchend)", + "Dots indicator pentru poziție curentă", + "DashboardView.vue folosește componenta când isMobile", + "Fallback la layout grid normal pe desktop", + "npm run build passes" ], - "technicalNotes": "Refolosește stilurile din US-041. Butoanele din bottom bar se schimbă dinamic bazat pe receipt.status.", - "passes": true, - "notes": "Completed in iteration 9" + "passes": false, + "notes": "" }, { - "id": "US-043", - "title": "Păstrare Ordine Bonuri la Refresh", - "description": "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.", - "priority": 43, + "id": "US-107", + "title": "InvoicesView Mobile Material Design", + "description": "Ca utilizator vreau pagina de facturi să aibă același header Material ca lista bonuri", + "priority": 10, "acceptanceCriteria": [ - "Bonurile din același batch păstrează ordinea de upload (nu se reordonează)", - "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 poate reordona, dar SSE updates nu", - "npm run typecheck passes", - "Verify in browser: bon procesat nu își schimbă poziția în listă" + "MobileTopBar adăugat cu title 'Facturi'", + "Actions în header: refresh (pi-refresh), export (pi-download)", + "MobileBottomNav adăugat", + "Filtre existente mutate în BottomSheet pe mobil", + "Verify in browser că arată consistent cu bonuri", + "npm run build passes" ], - "technicalNotes": "Lista trebuie sortată by created_at DESC sau by batch order, nu by last_modified. updateReceiptInPlace din store NU trebuie să reordoneze array-ul.", - "passes": true, - "notes": "Completed in iteration 10" + "passes": false, + "notes": "" + }, + { + "id": "US-108", + "title": "TrialBalanceView Mobile Material Design", + "description": "Ca utilizator vreau pagina de balanță să aibă același header Material", + "priority": 11, + "acceptanceCriteria": [ + "MobileTopBar adăugat cu title 'Balanță de Verificare'", + "Actions în header: export (pi-download)", + "MobileBottomNav adăugat", + "Filtre existente mutate în BottomSheet pe mobil", + "npm run build passes" + ], + "passes": false, + "notes": "" + }, + { + "id": "US-109", + "title": "BankCashRegisterView Mobile Material Design", + "description": "Ca utilizator vreau pagina de trezorerie să aibă același header Material", + "priority": 12, + "acceptanceCriteria": [ + "MobileTopBar adăugat cu title 'Trezorerie'", + "Actions în header: refresh, export", + "MobileBottomNav adăugat", + "Filtre în BottomSheet pe mobil", + "npm run build passes" + ], + "passes": false, + "notes": "" + }, + { + "id": "US-110", + "title": "ServerLogsView Mobile Material Design", + "description": "Ca admin vreau pagina de loguri să aibă interfață Material", + "priority": 13, + "acceptanceCriteria": [ + "MobileTopBar adăugat cu title 'Loguri Server'", + "Actions în header: refresh, export", + "MobileBottomNav adăugat", + "npm run build passes" + ], + "passes": false, + "notes": "" + }, + { + "id": "US-111", + "title": "CacheStatsView Mobile Material Design", + "description": "Ca admin vreau pagina de statistici cache să aibă interfață Material", + "priority": 14, + "acceptanceCriteria": [ + "MobileTopBar adăugat cu title 'Statistici Cache'", + "Actions în header: refresh", + "MobileBottomNav adăugat", + "npm run build passes" + ], + "passes": false, + "notes": "" + }, + { + "id": "US-113", + "title": "Batch Actions per Module contextuale", + "description": "Ca utilizator vreau acțiuni batch diferite în funcție de modulul curent", + "priority": 15, + "acceptanceCriteria": [ + "MobileSelectionFooter acceptă prop actions ca array", + "Bonuri: Delete + Export", + "Facturi (dacă se adaugă selecție): Export + Print", + "Fiecare acțiune are icon, label, severity, handler", + "npm run build passes" + ], + "passes": false, + "notes": "" + }, + { + "id": "US-118", + "title": "Creare MOBILE_PATTERNS.md documentație", + "description": "Ca developer vreau documentație dedicată pentru pattern-urile mobile", + "priority": 16, + "acceptanceCriteria": [ + "Fișier docs/MOBILE_PATTERNS.md creat", + "Table of Contents cu linkuri rapide", + "Secțiuni: MobileTopBar, MobileBottomNav, MobileSelectionFooter, BottomSheet, SwipeableCards", + "Exemple de cod copy-paste pentru fiecare componentă", + "Secțiune Quick Start pentru devs noi", + "Diagrame ASCII pentru layout mobile" + ], + "passes": false, + "notes": "" + }, + { + "id": "US-115", + "title": "Actualizare CSS_PATTERNS.md cu Mobile Material Design", + "description": "Ca developer viitor vreau referință la MOBILE_PATTERNS.md în CSS_PATTERNS.md", + "priority": 17, + "acceptanceCriteria": [ + "Secțiune nouă 'Mobile Material Design' în CSS_PATTERNS.md", + "Link către docs/MOBILE_PATTERNS.md pentru detalii", + "Rezumat scurt al componentelor disponibile", + "Breakpoint-uri mobile documentate" + ], + "passes": false, + "notes": "" + }, + { + "id": "US-116", + "title": "Actualizare DESIGN_TOKENS.md cu MD3 Tokens", + "description": "Ca developer vreau documentație pentru noile MD3 color tokens", + "priority": 18, + "acceptanceCriteria": [ + "Secțiune nouă 'Material Design 3 Tokens' în DESIGN_TOKENS.md", + "Tabel cu toate variabilele --md-sys-color-*", + "Mapping la tokens existenți", + "Exemple pentru dark mode" + ], + "passes": false, + "notes": "" + }, + { + "id": "US-117", + "title": "Actualizare CLAUDE.md cu reguli Mobile Development", + "description": "Ca Claude Code vreau reguli clare pentru dezvoltare mobilă", + "priority": 19, + "acceptanceCriteria": [ + "Secțiune nouă '### Mobile Development Rules' în CLAUDE.md", + "Regulă: Toate paginile mobile folosesc MobileTopBar", + "Regulă: Filtrele pe mobil în BottomSheet", + "Regulă: Selecția afișează acțiuni în footer", + "Regulă: Touch targets minim 44x44px", + "Checklist rapid pentru code review mobile" + ], + "passes": false, + "notes": "" + }, + { + "id": "US-119", + "title": "Actualizare claude-learn-frontend.md cu pattern-uri noi", + "description": "Ca Claude Code vreau pattern-urile salvate în memoria pentru sesiuni viitoare", + "priority": 20, + "acceptanceCriteria": [ + "Pattern: Mobile Material Design Component Architecture", + "Pattern: Bottom Sheet Filter Pattern", + "Pattern: Mobile Selection Mode Flow", + "Gotcha: Nu duplica delete button în header și footer", + "Format corect cu @date și tags #mobile #material-design" + ], + "passes": false, + "notes": "" } ] } diff --git a/scripts/ralph/progress.txt b/scripts/ralph/progress.txt index 7d81886..0918bad 100644 --- a/scripts/ralph/progress.txt +++ b/scripts/ralph/progress.txt @@ -1,516 +1,15 @@ # Ralph Progress Log -Started: Sat Jan 11 02:30:00 PM UTC 2026 -Project: bulk-upload-list-integration (continuation of bulk-receipt-upload) -Branch: ralph/bulk-receipt-upload (existing) -PRD: tasks/prd-bulk-upload-list-integration.md -Note: Continuing on same branch - bulk upload base already implemented +Started: $(date) +Project: unified-mobile-material-design +Branch: ralph/unified-mobile-md +Total Stories: 20 --- -[2026-01-11 14:05:11] Starting Ralph for project: bulk-upload-list-integration -[2026-01-11 14:05:11] Max iterations: 50 -[2026-01-11 14:05:11] === Iteration 1/50 === -[2026-01-11 14:05:11] Working on story: US-011 -[2026-01-11 14:05:11] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_1_US-011.log) -[2026-01-11 15:02:40] SUCCESS: Story US-011 passed! -[2026-01-11 15:02:40] Changes committed -[2026-01-11 15:02:40] Progress: 1/13 stories completed -[2026-01-11 15:02:42] === Iteration 2/50 === -[2026-01-11 15:02:42] Working on story: US-012 -[2026-01-11 15:02:42] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_2_US-012.log) -[2026-01-11 15:08:26] SUCCESS: Story US-012 passed! -[2026-01-11 15:08:26] Changes committed -[2026-01-11 15:08:26] Progress: 2/13 stories completed -[2026-01-11 15:08:28] === Iteration 3/50 === -[2026-01-11 15:08:28] Working on story: US-007 -[2026-01-11 15:08:28] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_3_US-007.log) -[2026-01-11 15:16:09] SUCCESS: Story US-007 passed! -[2026-01-11 15:16:09] Changes committed -[2026-01-11 15:16:09] Progress: 3/13 stories completed -[2026-01-11 15:16:11] === Iteration 4/50 === -[2026-01-11 15:16:11] Working on story: US-001 -[2026-01-11 15:16:11] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_4_US-001.log) -[2026-01-11 15:20:19] SUCCESS: Story US-001 passed! -[2026-01-11 15:20:19] Changes committed -[2026-01-11 15:20:19] Progress: 4/13 stories completed -[2026-01-11 15:20:21] === Iteration 5/50 === -[2026-01-11 15:20:21] Working on story: US-002 -[2026-01-11 15:20:21] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_5_US-002.log) -[2026-01-11 15:25:52] Story US-002 not yet complete, continuing... -[2026-01-11 15:25:52] Progress: 4/13 stories completed -[2026-01-11 15:25:54] === Iteration 6/50 === -[2026-01-11 15:25:54] Working on story: US-002 -[2026-01-11 15:25:54] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_6_US-002.log) -[2026-01-11 15:28:49] SUCCESS: Story US-002 passed! -[2026-01-11 15:28:49] Changes committed -[2026-01-11 15:28:49] Progress: 5/13 stories completed -[2026-01-11 15:28:51] === Iteration 7/50 === -[2026-01-11 15:28:51] Working on story: US-003 -[2026-01-11 15:28:51] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_7_US-003.log) -[2026-01-11 15:31:48] SUCCESS: Story US-003 passed! -[2026-01-11 15:31:48] Changes committed -[2026-01-11 15:31:48] Progress: 6/13 stories completed -[2026-01-11 15:31:50] === Iteration 8/50 === -[2026-01-11 15:31:50] Working on story: US-004 -[2026-01-11 15:31:50] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_8_US-004.log) -[2026-01-11 15:36:36] SUCCESS: Story US-004 passed! -[2026-01-11 15:36:37] Changes committed -[2026-01-11 15:36:37] Progress: 7/13 stories completed -[2026-01-11 15:36:39] === Iteration 9/50 === -[2026-01-11 15:36:39] Working on story: US-005 -[2026-01-11 15:36:39] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_9_US-005.log) -[2026-01-11 15:41:56] SUCCESS: Story US-005 passed! -[2026-01-11 15:41:56] Changes committed -[2026-01-11 15:41:56] Progress: 8/13 stories completed -[2026-01-11 15:41:58] === Iteration 10/50 === -[2026-01-11 15:41:58] Working on story: US-010 -[2026-01-11 15:41:58] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_10_US-010.log) -[2026-01-11 15:48:38] SUCCESS: Story US-010 passed! -[2026-01-11 15:48:38] Changes committed -[2026-01-11 15:48:38] Progress: 9/13 stories completed -[2026-01-11 15:48:40] === Iteration 11/50 === -[2026-01-11 15:48:40] Working on story: US-006 -[2026-01-11 15:48:40] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_11_US-006.log) -[2026-01-11 15:48:44] Story US-006 not yet complete, continuing... -[2026-01-11 15:48:44] Progress: 9/13 stories completed -[2026-01-11 15:48:46] === Iteration 12/50 === -[2026-01-11 15:48:46] Working on story: US-006 -[2026-01-11 15:48:46] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_12_US-006.log) -[2026-01-11 15:57:30] SUCCESS: Story US-006 passed! -[2026-01-11 15:57:30] Changes committed -[2026-01-11 15:57:30] Progress: 10/13 stories completed -[2026-01-11 15:57:32] === Iteration 13/50 === -[2026-01-11 15:57:32] Working on story: US-009 -[2026-01-11 15:57:32] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_13_US-009.log) -[2026-01-11 15:58:11] Story US-009 not yet complete, continuing... -[2026-01-11 15:58:11] Progress: 10/13 stories completed -[2026-01-11 15:58:13] === Iteration 14/50 === -[2026-01-11 15:58:13] Working on story: US-009 -[2026-01-11 15:58:13] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_14_US-009.log) -[2026-01-11 15:58:16] Story US-009 not yet complete, continuing... -[2026-01-11 15:58:16] Progress: 10/13 stories completed -[2026-01-11 15:58:18] === Iteration 15/50 === -[2026-01-11 15:58:18] Working on story: US-009 -[2026-01-11 15:58:18] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_15_US-009.log) -[2026-01-11 15:58:22] Story US-009 not yet complete, continuing... -[2026-01-11 15:58:22] Progress: 10/13 stories completed -[2026-01-11 15:58:24] === Iteration 16/50 === -[2026-01-11 15:58:24] Working on story: US-009 -[2026-01-11 15:58:24] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_16_US-009.log) -[2026-01-11 15:58:27] Story US-009 not yet complete, continuing... -[2026-01-11 15:58:27] Progress: 10/13 stories completed -[2026-01-11 15:58:29] === Iteration 17/50 === -[2026-01-11 15:58:29] Working on story: US-009 -[2026-01-11 15:58:29] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_17_US-009.log) -[2026-01-11 15:58:33] Story US-009 not yet complete, continuing... -[2026-01-11 15:58:33] Progress: 10/13 stories completed -[2026-01-11 15:58:35] === Iteration 18/50 === -[2026-01-11 15:58:35] Working on story: US-009 -[2026-01-11 15:58:35] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_18_US-009.log) -[2026-01-11 15:58:39] Story US-009 not yet complete, continuing... -[2026-01-11 15:58:39] Progress: 10/13 stories completed -[2026-01-11 15:58:41] === Iteration 19/50 === -[2026-01-11 15:58:41] Working on story: US-009 -[2026-01-11 15:58:41] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_19_US-009.log) -[2026-01-11 15:58:44] Story US-009 not yet complete, continuing... -[2026-01-11 15:58:44] Progress: 10/13 stories completed -[2026-01-11 15:58:46] === Iteration 20/50 === -[2026-01-11 15:58:46] Working on story: US-009 -[2026-01-11 15:58:46] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_20_US-009.log) -[2026-01-11 15:58:50] Story US-009 not yet complete, continuing... -[2026-01-11 15:58:50] Progress: 10/13 stories completed -[2026-01-11 15:58:52] === Iteration 21/50 === -[2026-01-11 15:58:52] Working on story: US-009 -[2026-01-11 15:58:52] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_21_US-009.log) -[2026-01-11 15:58:56] Story US-009 not yet complete, continuing... -[2026-01-11 15:58:56] Progress: 10/13 stories completed -[2026-01-11 15:58:58] === Iteration 22/50 === -[2026-01-11 15:58:58] Working on story: US-009 -[2026-01-11 15:58:58] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_22_US-009.log) -[2026-01-11 15:59:01] Story US-009 not yet complete, continuing... -[2026-01-11 15:59:01] Progress: 10/13 stories completed -[2026-01-11 15:59:03] === Iteration 23/50 === -[2026-01-11 15:59:03] Working on story: US-009 -[2026-01-11 15:59:03] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_23_US-009.log) -[2026-01-11 15:59:07] Story US-009 not yet complete, continuing... -[2026-01-11 15:59:07] Progress: 10/13 stories completed -[2026-01-11 15:59:09] === Iteration 24/50 === -[2026-01-11 15:59:09] Working on story: US-009 -[2026-01-11 15:59:09] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_24_US-009.log) -[2026-01-11 15:59:12] Story US-009 not yet complete, continuing... -[2026-01-11 15:59:12] Progress: 10/13 stories completed -[2026-01-11 15:59:14] === Iteration 25/50 === -[2026-01-11 15:59:14] Working on story: US-009 -[2026-01-11 15:59:14] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_25_US-009.log) -[2026-01-11 15:59:18] Story US-009 not yet complete, continuing... -[2026-01-11 15:59:18] Progress: 10/13 stories completed -[2026-01-11 15:59:20] === Iteration 26/50 === -[2026-01-11 15:59:20] Working on story: US-009 -[2026-01-11 15:59:20] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_26_US-009.log) -[2026-01-11 15:59:23] Story US-009 not yet complete, continuing... -[2026-01-11 15:59:23] Progress: 10/13 stories completed -[2026-01-11 15:59:25] === Iteration 27/50 === -[2026-01-11 15:59:25] Working on story: US-009 -[2026-01-11 15:59:25] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_27_US-009.log) -[2026-01-11 15:59:29] Story US-009 not yet complete, continuing... -[2026-01-11 15:59:29] Progress: 10/13 stories completed -[2026-01-11 15:59:31] === Iteration 28/50 === -[2026-01-11 15:59:31] Working on story: US-009 -[2026-01-11 15:59:31] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_28_US-009.log) -[2026-01-11 15:59:35] Story US-009 not yet complete, continuing... -[2026-01-11 15:59:35] Progress: 10/13 stories completed -[2026-01-11 15:59:37] === Iteration 29/50 === -[2026-01-11 15:59:37] Working on story: US-009 -[2026-01-11 15:59:37] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_29_US-009.log) -[2026-01-11 15:59:40] Story US-009 not yet complete, continuing... -[2026-01-11 15:59:40] Progress: 10/13 stories completed -[2026-01-11 15:59:42] === Iteration 30/50 === -[2026-01-11 15:59:42] Working on story: US-009 -[2026-01-11 15:59:42] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_30_US-009.log) -[2026-01-11 15:59:46] Story US-009 not yet complete, continuing... -[2026-01-11 15:59:46] Progress: 10/13 stories completed -[2026-01-11 15:59:48] === Iteration 31/50 === -[2026-01-11 15:59:48] Working on story: US-009 -[2026-01-11 15:59:48] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_31_US-009.log) -[2026-01-11 15:59:52] Story US-009 not yet complete, continuing... -[2026-01-11 15:59:52] Progress: 10/13 stories completed -[2026-01-11 15:59:54] === Iteration 32/50 === -[2026-01-11 15:59:54] Working on story: US-009 -[2026-01-11 15:59:54] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_32_US-009.log) -[2026-01-11 15:59:57] Story US-009 not yet complete, continuing... -[2026-01-11 15:59:57] Progress: 10/13 stories completed -[2026-01-11 15:59:59] === Iteration 33/50 === -[2026-01-11 15:59:59] Working on story: US-009 -[2026-01-11 15:59:59] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_33_US-009.log) -[2026-01-11 16:04:24] SUCCESS: Story US-009 passed! -[2026-01-11 16:04:24] Changes committed -[2026-01-11 16:04:24] Progress: 11/13 stories completed -[2026-01-11 16:04:26] === Iteration 34/50 === -[2026-01-11 16:04:26] Working on story: US-008 -[2026-01-11 16:04:26] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_34_US-008.log) -[2026-01-11 16:08:14] SUCCESS: Story US-008 passed! -[2026-01-11 16:08:14] Changes committed -[2026-01-11 16:08:14] Progress: 12/13 stories completed -[2026-01-11 16:08:16] === Iteration 35/50 === -[2026-01-11 16:08:16] Working on story: US-013 -[2026-01-11 16:08:16] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_35_US-013.log) -[2026-01-11 16:12:10] Story US-013 not yet complete, continuing... -[2026-01-11 16:12:10] Progress: 12/13 stories completed -[2026-01-11 16:12:12] === Iteration 36/50 === -[2026-01-11 16:12:12] Working on story: US-013 -[2026-01-11 16:12:12] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_36_US-013.log) -[2026-01-11 16:14:52] SUCCESS: Story US-013 passed! -[2026-01-11 16:14:52] Changes committed -[2026-01-11 16:14:52] Progress: 13/13 stories completed -[2026-01-11 16:14:54] === Iteration 37/50 === -[2026-01-11 16:14:54] SUCCESS: All stories completed! 🎉 -[2026-01-11 16:14:54] === Ralph Session Complete === -[2026-01-11 16:14:54] Final progress: 13/13 stories completed -[2026-01-11 16:14:54] Branch: ralph/bulk-receipt-upload -[2026-01-11 16:14:54] Logs: /workspace/roa2web/scripts/ralph/logs - ---- -## Phase 2: Real-Time Progress în Listă -Started: 2026-01-11 19:40 -Project: bulk-upload-realtime-progress -Branch: ralph/bulk-receipt-upload (CONTINUĂ - NU crea branch nou!) -PRD: tasks/prd-bulk-upload-realtime-progress.md - -Această fază extinde bulk upload-ul din Phase 1 (US-001→US-013 COMPLETE) cu: -- Afișare fișiere imediat în tabel după upload -- Progres real-time pe măsură ce sunt procesate -- Cancel individual și batch -- Animații pentru status changes - -### Noile User Stories (US-014 → US-023): - -| ID | Title | Priority | Status | -|----|-------|----------|--------| -| US-014 | Backend - Cancel Job Individual | 14 | pending | -| US-015 | Backend - Cancel Batch Complet | 15 | pending | -| US-016 | Frontend - Store Actions Cancel | 16 | pending | -| US-017 | Frontend - Afișare Jobs în Tabel | 17 | pending | -| US-018 | Frontend - Tranziție Job→Receipt | 18 | pending | -| US-019 | Frontend - Animație Status Change | 19 | pending | -| US-020 | Frontend - Cancel Individual Row | 20 | pending | -| US-021 | Frontend - Cancel All în Header | 21 | pending | -| US-022 | Frontend - Checkbox Disabled Jobs | 22 | pending | -| US-023 | Frontend - Restore Jobs Refresh | 23 | pending | - ---- -(Ralph va adăuga aici progresul per iterație) -[2026-01-11 19:42:53] Starting Ralph for project: bulk-upload-realtime-progress -[2026-01-11 19:42:53] Max iterations: 50 -[2026-01-11 19:42:53] === Iteration 1/50 === -[2026-01-11 19:42:53] Working on story: US-014 -[2026-01-11 19:42:53] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_1_US-014.log) -[2026-01-11 19:47:06] SUCCESS: Story US-014 passed! -[2026-01-11 19:47:07] Changes committed -[2026-01-11 19:47:07] Progress: 14/23 stories completed -[2026-01-11 19:47:09] === Iteration 2/50 === -[2026-01-11 19:47:09] Working on story: US-015 -[2026-01-11 19:47:09] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_2_US-015.log) -[2026-01-11 19:53:13] Story US-015 not yet complete, continuing... -[2026-01-11 19:53:13] Progress: 14/23 stories completed -[2026-01-11 19:53:15] === Iteration 3/50 === -[2026-01-11 19:53:15] Working on story: US-015 -[2026-01-11 19:53:15] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_3_US-015.log) -[2026-01-11 19:57:53] Starting Ralph for project: bulk-upload-realtime-progress -[2026-01-11 19:57:53] Max iterations: 50 -[2026-01-11 19:57:53] === Iteration 1/50 === -[2026-01-11 19:57:53] Working on story: US-015 -[2026-01-11 19:57:53] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_1_US-015.log) -[2026-01-11 20:00:23] SUCCESS: Story US-015 passed! -[2026-01-11 20:00:23] Changes committed -[2026-01-11 20:00:23] Progress: 15/23 stories completed -[2026-01-11 20:00:25] === Iteration 2/50 === -[2026-01-11 20:00:25] Working on story: US-016 -[2026-01-11 20:00:25] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_2_US-016.log) -[2026-01-11 20:06:04] SUCCESS: Story US-016 passed! -[2026-01-11 20:06:04] Changes committed -[2026-01-11 20:06:04] Progress: 16/23 stories completed -[2026-01-11 20:06:06] === Iteration 3/50 === -[2026-01-11 20:06:06] Working on story: US-017 -[2026-01-11 20:06:06] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_3_US-017.log) -[2026-01-11 20:12:04] Story US-017 not yet complete, continuing... -[2026-01-11 20:12:04] Progress: 16/23 stories completed -[2026-01-11 20:12:06] === Iteration 4/50 === -[2026-01-11 20:12:06] Working on story: US-017 -[2026-01-11 20:12:06] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_4_US-017.log) -[2026-01-11 20:16:17] SUCCESS: Story US-017 passed! -[2026-01-11 20:16:17] Changes committed -[2026-01-11 20:16:17] Progress: 17/23 stories completed -[2026-01-11 20:16:19] === Iteration 5/50 === -[2026-01-11 20:16:19] Working on story: US-018 -[2026-01-11 20:16:19] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_5_US-018.log) -[2026-01-11 20:22:23] SUCCESS: Story US-018 passed! -[2026-01-11 20:22:23] Changes committed -[2026-01-11 20:22:23] Progress: 18/23 stories completed -[2026-01-11 20:22:25] === Iteration 6/50 === -[2026-01-11 20:22:25] Working on story: US-019 -[2026-01-11 20:22:25] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_6_US-019.log) -[2026-01-11 20:27:28] SUCCESS: Story US-019 passed! -[2026-01-11 20:27:28] Changes committed -[2026-01-11 20:27:28] Progress: 19/23 stories completed -[2026-01-11 20:27:30] === Iteration 7/50 === -[2026-01-11 20:27:30] Working on story: US-020 -[2026-01-11 20:27:30] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_7_US-020.log) -[2026-01-11 20:32:44] SUCCESS: Story US-020 passed! -[2026-01-11 20:32:44] Changes committed -[2026-01-11 20:32:44] Progress: 20/23 stories completed -[2026-01-11 20:32:46] === Iteration 8/50 === -[2026-01-11 20:32:46] Working on story: US-021 -[2026-01-11 20:32:46] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_8_US-021.log) -[2026-01-11 20:35:59] SUCCESS: Story US-021 passed! -[2026-01-11 20:35:59] Changes committed -[2026-01-11 20:35:59] Progress: 21/23 stories completed -[2026-01-11 20:36:01] === Iteration 9/50 === -[2026-01-11 20:36:01] Working on story: US-022 -[2026-01-11 20:36:01] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_9_US-022.log) -[2026-01-11 20:38:17] SUCCESS: Story US-022 passed! -[2026-01-11 20:38:17] Changes committed -[2026-01-11 20:38:17] Progress: 22/23 stories completed -[2026-01-11 20:38:19] === Iteration 10/50 === -[2026-01-11 20:38:19] Working on story: US-023 -[2026-01-11 20:38:19] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_10_US-023.log) -[2026-01-11 20:44:18] Story US-023 not yet complete, continuing... -[2026-01-11 20:44:18] Progress: 22/23 stories completed -[2026-01-11 20:44:20] === Iteration 11/50 === -[2026-01-11 20:44:20] Working on story: US-023 -[2026-01-11 20:44:20] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_11_US-023.log) -[2026-01-11 20:46:15] SUCCESS: Story US-023 passed! -[2026-01-11 20:46:15] Changes committed -[2026-01-11 20:46:15] Progress: 23/23 stories completed -[2026-01-11 20:46:17] === Iteration 12/50 === -[2026-01-11 20:46:17] SUCCESS: All stories completed! 🎉 -[2026-01-11 20:46:17] === Ralph Session Complete === -[2026-01-11 20:46:17] Final progress: 23/23 stories completed -[2026-01-11 20:46:17] Branch: ralph/bulk-receipt-upload -[2026-01-11 20:46:17] Logs: /workspace/roa2web/scripts/ralph/logs - ---- -## Phase 3: Bulk Actions & SSE Real-time Updates -Started: 2026-01-11 21:50 -Project: bulk-actions-sse-refresh -Branch: ralph/bulk-receipt-upload (CONTINUĂ - NU crea branch nou!) -PRD: tasks/prd-bulk-actions-sse-refresh.md - -Această fază adaugă: -- Bulk Delete pentru bonuri selectate -- SSE (Server-Sent Events) pentru actualizări real-time -- Eliminare polling în favoarea SSE -- Graceful degradation cu fallback la polling - -### Noile User Stories (US-024 → US-033): - -| ID | Title | Priority | Status | -|----|-------|----------|--------| -| US-024 | Backend - Endpoint Bulk Delete | 24 | pending | -| US-025 | Frontend - Buton Șterge Bulk Actions | 25 | pending | -| US-026 | Frontend - Dialog Confirmare Ștergere | 26 | pending | -| US-027 | Frontend - Bulk Delete Partial Success | 27 | pending | -| US-028 | Frontend - Navigare Pagină Anterioară | 28 | pending | -| US-029 | Frontend - updateReceiptInPlace Store | 29 | pending | -| US-030 | Backend - SSE Endpoint Status Updates | 30 | pending | -| US-031 | Frontend - SSE Client Service | 31 | pending | -| US-032 | Frontend - Înlocuire Polling cu SSE | 32 | pending | -| US-033 | Frontend - Graceful Degradation SSE | 33 | pending | - ---- -(Ralph va adăuga aici progresul per iterație) -[2026-01-11 22:12:45] Starting Ralph for project: bulk-actions-sse-refresh -[2026-01-11 22:12:45] Max iterations: 50 -[2026-01-11 22:12:45] === Iteration 1/50 === -[2026-01-11 22:12:45] Working on story: US-024 -[2026-01-11 22:12:45] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_1_US-024.log) -[2026-01-11 22:48:00] MANUAL: US-024 marked as passed (code complete, Claude timed out after 30+ minutes) -[2026-01-11 22:48:04] Starting Ralph for project: bulk-actions-sse-refresh -[2026-01-11 22:48:04] Max iterations: 50 -[2026-01-11 22:48:04] === Iteration 1/50 === -[2026-01-11 22:48:04] Working on story: US-025 -[2026-01-11 22:48:04] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_1_US-025.log) -[2026-01-11 22:51:34] SUCCESS: Story US-025 passed! -[2026-01-11 22:51:34] Changes committed -[2026-01-11 22:51:34] Progress: 25/33 stories completed -[2026-01-11 22:51:36] === Iteration 2/50 === -[2026-01-11 22:51:36] Working on story: US-026 -[2026-01-11 22:51:36] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_2_US-026.log) -[2026-01-11 22:55:07] SUCCESS: Story US-026 passed! -[2026-01-11 22:55:07] Changes committed -[2026-01-11 22:55:07] Progress: 26/33 stories completed -[2026-01-11 22:55:09] === Iteration 3/50 === -[2026-01-11 22:55:09] Working on story: US-027 -[2026-01-11 22:55:09] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_3_US-027.log) -[2026-01-11 22:59:03] SUCCESS: Story US-027 passed! -[2026-01-11 22:59:03] Changes committed -[2026-01-11 22:59:03] Progress: 27/33 stories completed -[2026-01-11 22:59:05] === Iteration 4/50 === -[2026-01-11 22:59:05] Working on story: US-028 -[2026-01-11 22:59:05] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_4_US-028.log) -[2026-01-11 23:03:22] SUCCESS: Story US-028 passed! -[2026-01-11 23:03:22] Changes committed -[2026-01-11 23:03:22] Progress: 28/33 stories completed -[2026-01-11 23:03:24] === Iteration 5/50 === -[2026-01-11 23:03:24] Working on story: US-029 -[2026-01-11 23:03:24] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_5_US-029.log) -[2026-01-11 23:04:38] SUCCESS: Story US-029 passed! -[2026-01-11 23:04:38] Changes committed -[2026-01-11 23:04:38] Progress: 29/33 stories completed -[2026-01-11 23:04:40] === Iteration 6/50 === -[2026-01-11 23:04:40] Working on story: US-030 -[2026-01-11 23:04:40] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_6_US-030.log) -[2026-01-11 23:35:52] MANUAL: US-030 marked as passed (SSE endpoint complete, Claude timed out after 30+ minutes) -[2026-01-11 23:35:57] Starting Ralph for project: bulk-actions-sse-refresh -[2026-01-11 23:35:57] Max iterations: 50 -[2026-01-11 23:35:57] === Iteration 1/50 === -[2026-01-11 23:35:57] Working on story: US-031 -[2026-01-11 23:35:57] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_1_US-031.log) -[2026-01-11 23:37:36] SUCCESS: Story US-031 passed! -[2026-01-11 23:37:36] Changes committed -[2026-01-11 23:37:36] Progress: 31/33 stories completed -[2026-01-11 23:37:38] === Iteration 2/50 === -[2026-01-11 23:37:38] Working on story: US-032 -[2026-01-11 23:37:38] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_2_US-032.log) -[2026-01-11 23:41:53] SUCCESS: Story US-032 passed! -[2026-01-11 23:41:53] Changes committed -[2026-01-11 23:41:53] Progress: 32/33 stories completed -[2026-01-11 23:41:55] === Iteration 3/50 === -[2026-01-11 23:41:55] Working on story: US-033 -[2026-01-11 23:41:55] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_3_US-033.log) -[2026-01-11 23:44:52] SUCCESS: Story US-033 passed! -[2026-01-11 23:44:53] Changes committed -[2026-01-11 23:44:53] Progress: 33/33 stories completed -[2026-01-11 23:44:55] === Iteration 4/50 === -[2026-01-11 23:44:55] SUCCESS: All stories completed! 🎉 -[2026-01-11 23:44:55] === Ralph Session Complete === -[2026-01-11 23:44:55] Final progress: 33/33 stories completed -[2026-01-11 23:44:55] Branch: ralph/bulk-receipt-upload -[2026-01-11 23:44:55] Logs: /workspace/roa2web/scripts/ralph/logs - ---- -## Phase 2: Mobile UX Improvements -Started: 2026-01-12 - -### New User Stories Added: -- US-034: Fix - Refresh Individual vs Refresh Total -- US-035: Fix - Bonuri cu Eroare Rămân în Listă -- US-036: Afișare Nume Fișier pentru Toate Bonurile -- US-037: Fix - Upload Nu Mai Face Refresh Automat -- US-038: Mobile - Selecție Multiplă prin Long-Press -- US-039: Mobile - Select All și Buton Ștergere -- US-040: Mobile - Layout Android Nativ pentru Lista Bonuri -- US-041: Mobile - Layout Android pentru Editare/Creare Bon -- US-042: Mobile - Layout Android pentru Vizualizare Bon -- US-043: Păstrare Ordine Bonuri la Refresh - -### Prioritization: -Faza 1 (Bug Fixes): US-034, US-035, US-037, US-043 -Faza 2 (Mobile Enhancements): US-036, US-038, US-039 -Faza 3 (Mobile Native Layout): US-040, US-041, US-042 -[2026-01-12 07:34:34] Starting Ralph for project: mobile-ux-improvements -[2026-01-12 07:34:34] Max iterations: 50 -[2026-01-12 07:34:34] === Iteration 1/50 === -[2026-01-12 07:34:34] Working on story: US-034 -[2026-01-12 07:34:34] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_1_US-034.log) -[2026-01-12 07:38:22] SUCCESS: Story US-034 passed! -[2026-01-12 07:38:22] Changes committed -[2026-01-12 07:38:22] Progress: 34/43 stories completed -[2026-01-12 07:38:24] === Iteration 2/50 === -[2026-01-12 07:38:24] Working on story: US-035 -[2026-01-12 07:38:24] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_2_US-035.log) -[2026-01-12 07:41:39] SUCCESS: Story US-035 passed! -[2026-01-12 07:41:39] Changes committed -[2026-01-12 07:41:39] Progress: 35/43 stories completed -[2026-01-12 07:41:41] === Iteration 3/50 === -[2026-01-12 07:41:41] Working on story: US-036 -[2026-01-12 07:41:41] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_3_US-036.log) -[2026-01-12 07:46:55] SUCCESS: Story US-036 passed! -[2026-01-12 07:46:56] Changes committed -[2026-01-12 07:46:56] Progress: 36/43 stories completed -[2026-01-12 07:46:58] === Iteration 4/50 === -[2026-01-12 07:46:58] Working on story: US-037 -[2026-01-12 07:46:58] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_4_US-037.log) -[2026-01-12 07:51:38] SUCCESS: Story US-037 passed! -[2026-01-12 07:51:38] Changes committed -[2026-01-12 07:51:38] Progress: 37/43 stories completed -[2026-01-12 07:51:40] === Iteration 5/50 === -[2026-01-12 07:51:40] Working on story: US-038 -[2026-01-12 07:51:40] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_5_US-038.log) -[2026-01-12 07:56:08] SUCCESS: Story US-038 passed! -[2026-01-12 07:56:08] Changes committed -[2026-01-12 07:56:08] Progress: 38/43 stories completed -[2026-01-12 07:56:10] === Iteration 6/50 === -[2026-01-12 07:56:10] Working on story: US-039 -[2026-01-12 07:56:10] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_6_US-039.log) -[2026-01-12 08:00:37] SUCCESS: Story US-039 passed! -[2026-01-12 08:00:37] Changes committed -[2026-01-12 08:00:38] Progress: 39/43 stories completed -[2026-01-12 08:00:40] === Iteration 7/50 === -[2026-01-12 08:00:40] Working on story: US-040 -[2026-01-12 08:00:40] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_7_US-040.log) -[2026-01-12 08:06:20] SUCCESS: Story US-040 passed! -[2026-01-12 08:06:20] Changes committed -[2026-01-12 08:06:20] Progress: 40/43 stories completed -[2026-01-12 08:06:22] === Iteration 8/50 === -[2026-01-12 08:06:22] Working on story: US-041 -[2026-01-12 08:06:22] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_8_US-041.log) -[2026-01-12 08:11:12] SUCCESS: Story US-041 passed! -[2026-01-12 08:11:12] Changes committed -[2026-01-12 08:11:12] Progress: 41/43 stories completed -[2026-01-12 08:11:14] === Iteration 9/50 === -[2026-01-12 08:11:14] Working on story: US-042 -[2026-01-12 08:11:14] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_9_US-042.log) -[2026-01-12 08:14:53] SUCCESS: Story US-042 passed! -[2026-01-12 08:14:53] Changes committed -[2026-01-12 08:14:53] Progress: 42/43 stories completed -[2026-01-12 08:14:55] === Iteration 10/50 === -[2026-01-12 08:14:55] Working on story: US-043 -[2026-01-12 08:14:55] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_10_US-043.log) -[2026-01-12 08:20:33] SUCCESS: Story US-043 passed! -[2026-01-12 08:20:33] Changes committed -[2026-01-12 08:20:33] Progress: 43/43 stories completed -[2026-01-12 08:20:35] === Iteration 11/50 === -[2026-01-12 08:20:35] SUCCESS: All stories completed! 🎉 -[2026-01-12 08:20:35] === Ralph Session Complete === -[2026-01-12 08:20:35] Final progress: 43/43 stories completed -[2026-01-12 08:20:35] Branch: ralph/bulk-receipt-upload -[2026-01-12 08:20:35] Logs: /workspace/roa2web/scripts/ralph/logs +Mon Jan 12 09:44:54 AM UTC 2026 +[2026-01-12 09:45:00] Starting Ralph for project: unified-mobile-material-design +[2026-01-12 09:45:00] Max iterations: 100 +[2026-01-12 09:45:00] Creating new branch: ralph/unified-mobile-md +[2026-01-12 09:45:00] === Iteration 1/100 === +[2026-01-12 09:45:00] Working on story: US-101a +[2026-01-12 09:45:00] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_1_US-101a.log) +[2026-01-12 09:46:30] SUCCESS: Story US-101a passed! diff --git a/src/shared/components/mobile/MobileTopBar.vue b/src/shared/components/mobile/MobileTopBar.vue new file mode 100644 index 0000000..bb5b05a --- /dev/null +++ b/src/shared/components/mobile/MobileTopBar.vue @@ -0,0 +1,218 @@ + + + + + diff --git a/tasks/prd-unified-mobile-material-design.md b/tasks/prd-unified-mobile-material-design.md new file mode 100644 index 0000000..c4ac62c --- /dev/null +++ b/tasks/prd-unified-mobile-material-design.md @@ -0,0 +1,457 @@ +# 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 +```