Reorganizeaza interfata web pe trei principii, fara a atinge backend-ul de trimitere (worker, mapping, idempotency, masina de stari neatinse): - US-001 app/web/labels.py: modul pur stari tehnice -> text uman + clasa CSS - US-002 bara status /_fragments/status: microcopy uman, defalcare blocate, scoped cont - US-003 shell 6 tab-uri (Acasa/Import/Coada/Mapari/Cont/Nomenclator): deep-link ?tab=, panou activ randat server-side, fragmente inactive lazy, ARIA real - US-004 stepper import 4 pasi (pur vizual; hx-target + csrf pastrate) - US-005 Acasa onboarding checklist auto-bifat + colaps + empty states prietenoase Reparat in cursul VERIFY/CLOSE: izolare teste (reset ratelimit._hits in fixturi), regresie avertisment "cont in asteptare de activare" (re-introdus in bara status), culori hardcodate -> variabile paleta. 434 teste pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
314 lines
23 KiB
Markdown
314 lines
23 KiB
Markdown
# PRD 3.4 — Interfata web ergonomica (tab-uri + wizard + microcopy uman)
|
|
|
|
**Stare**: inchis
|
|
|
|
> Proces complet: `docs/ROADMAP.md` §5. Contractul RAR (sursa de adevar): `docs/api-rar-contract.md`.
|
|
> Starea trece: `draft → aprobat → in-executie → verify-pass → inchis` (actualizata de lead).
|
|
> Aceasta e o livrabila de **UI/UX** — atinge interfata web (Jinja2 + HTMX, zero build), nu logica de
|
|
> trimitere catre RAR. Nu modifica `worker/`, `mapping.py`, `idempotency.py`, masina de stari.
|
|
|
|
## 1. Obiectiv
|
|
|
|
Dashboard-ul curent (`app/web/templates/dashboard.html`) ingramadeste toate sectiunile intr-un
|
|
singur scroll lung: import, status, mapari, cont, coada, nomenclator. Utilizatorul nou nu stie ce
|
|
pas urmeaza, iar etichetele sunt scrise pentru dezvoltator ("Worker viu", "RAR ok"), nu pentru
|
|
operatorul de service.
|
|
|
|
Livrabila reorganizeaza interfata pe **trei principii**, fara a schimba comportamentul backend:
|
|
1. **Tab-uri sus** — un singur panou activ la un moment dat (Acasa, Import, Mapari, Cont, Nomenclator);
|
|
restul incarcate lazy prin HTMX. Bara de status ramane mereu vizibila, indiferent de tab.
|
|
2. **Flux tip wizard** — pasii sunt numerotati si auto-explicativi; utilizatorul nu ghiceste ce
|
|
are de facut. Importul devine un stepper explicit (Incarca → Mapeaza → Verifica → Confirma), iar
|
|
pagina "Acasa" arata un ghid de pornire care bifeaza singur ce e deja configurat.
|
|
3. **Microcopy uman** — etichete scrise pentru oameni, nu pentru cod: "Trimitere automata catre RAR:
|
|
activa" in loc de "Worker viu". Vezi tabelul din §3 (US-001).
|
|
|
|
Decizie de layout confirmata cu utilizatorul (AskUserQuestion): **tab-uri sus**, cu cerinta explicita
|
|
de "pagini ca un wizard, intuitive" si "caption-uri utile, relevante, simple, pentru oameni".
|
|
|
|
## 2. Non-Goals (anti scope-creep)
|
|
|
|
- **Fara schimbari de backend de trimitere**: worker, mapare op→cod, idempotenta, reconciliere,
|
|
masina de stari submissions raman neatinse. Doar stratul de prezentare web.
|
|
- **Fara framework JS / build step**: ramane Jinja2 + HTMX + CSS in `base.html`. Fara React/Vue/Tailwind,
|
|
fara bundler. Eventualul JS e vanilla inline, minim (deja exista pattern: clipboard in `_cont.html`).
|
|
- **Fara endpoint-uri API noi `/v1/*`** si fara schimbari de schema SQL. Tab-urile folosesc fragmentele
|
|
HTMX existente (`/_fragments/*`) plus, la nevoie, fragmente de prezentare noi sub `/_fragments/`.
|
|
- **Fara rescriere a fluxului de import** (parsare, mapare coloane, preview, commit raman ca logica) —
|
|
doar se imbraca intr-un stepper vizual.
|
|
- **Fara redesign al paginilor `login.html` / `signup.html` / `admin.html`** dincolo de aplicarea
|
|
acelorasi etichete/clase daca e trivial. Focusul e dashboard-ul autentificat.
|
|
- **Fara i18n / multi-limba**: textele raman in romana, hardcodate (ca tot proiectul).
|
|
- **Fara tema light / toggle de tema**: pastram paleta dark din `base.html`.
|
|
|
|
## 3. Stories atomice
|
|
|
|
> Fiecare story: cea mai mica unitate care lasa sistemul functional. Backend + UI pentru acelasi
|
|
> comportament = 2 stories. Toate atingerile sunt in `app/web/` (templates + routes + un modul de
|
|
> etichete). Verificare E2E = browser HTMX pe `http://localhost:8000/` (Playwright MCP sau `/browse`).
|
|
> **Regula de aur**: fluxul import → commit → worker → FINALIZATA la RAR test NU are voie sa se strice.
|
|
|
|
### US-001: Microcopy uman pentru status si stari (modul de etichete + teste)
|
|
**Ca** operator de service **vreau** etichete pe care le inteleg fara sa fiu programator
|
|
**pentru ca** sa stiu dintr-o privire ce face sistemul si ce am eu de facut.
|
|
|
|
- **Depinde de**: —
|
|
- **Fisiere**: `app/web/labels.py` (nou), `tests/test_web_labels.py` (nou) (~2 fisiere)
|
|
- **Test intai (RED)**: `tests/test_web_labels.py` — `test_eticheta_worker_viu`, `test_eticheta_worker_mort`,
|
|
`test_eticheta_stare_submission`, `test_toate_starile_au_eticheta` (nicio stare din `schema.sql` fara mapare).
|
|
- **Continut**: un singur loc (`labels.py`) care traduce starile tehnice in text uman + clasa CSS de
|
|
culoare. Tabelul de adevar (caption-uri propuse, de finalizat cu utilizatorul daca difera):
|
|
|
|
| Tehnic (azi) | Eticheta umana propusa | Sub-text / tooltip |
|
|
|---|---|---|
|
|
| Worker `viu` | **Trimitere automata: activa** | Sistemul verifica coada si trimite la RAR la fiecare cateva secunde. |
|
|
| Worker `mort` | **Trimitere automata: oprita** | Nimic nu pleaca spre RAR pana reporneste. Anunta administratorul. |
|
|
| RAR `ok` | **Legatura cu RAR: functionala** | Portalul AUTOPASS raspunde. |
|
|
| RAR `indisponibil` | **Legatura cu RAR: indisponibila** | Portalul RAR nu raspunde acum; coada se reia automat cand revine. |
|
|
| `Ultimul login RAR` | **Ultima autentificare la RAR** | — |
|
|
| `In coada` / `queued` | **In asteptare sa fie trimise** | — |
|
|
| `Trimise` / `sent` | **Declarate la RAR (finalizate)** | Confirmate cu numar de prezentare; nu se mai pot modifica. |
|
|
| `Blocate` | **Necesita atentia ta** | Defalcare pe motiv (lipsa cod / date incomplete / eroare). |
|
|
| `sending` | **Se trimite acum** | — |
|
|
| `needs_mapping` | **Lipseste codul prestatiei** | Alege codul RAR in tab-ul Mapari. |
|
|
| `needs_data` | **Date incomplete (respinse de RAR)** | Corecteaza randul si reimporta. |
|
|
| `error` | **Eroare la trimitere** | Vezi detaliul randului; se reincearca automat sau necesita corectie. |
|
|
|
|
- **Acceptance criteria**:
|
|
- [x] `labels.py` expune o functie/dict care, pentru fiecare stare din `schema.sql`, da `(text, css_class)`.
|
|
- [x] Nicio stare de submission existenta nu ramane fara eticheta (test parametrizat care iese rosu daca se adauga o stare noua nemapata).
|
|
- [x] Functiile sunt pure (fara DB, fara request) — usor de testat unitar.
|
|
- **Verificare E2E**: indirect, prin US-002/US-003 (etichetele apar in UI).
|
|
|
|
### US-002: Bara de status persistenta cu etichete umane (fragment)
|
|
**Ca** operator **vreau** sa vad mereu, sus, starea sistemului in cuvinte clare
|
|
**pentru ca** sa am incredere ca trimiterile chiar pleaca, fara sa stiu ce e un "worker".
|
|
|
|
- **Depinde de**: US-001
|
|
- **Fisiere**: `app/web/templates/_status.html` (nou), `app/web/routes.py` (endpoint `/_fragments/status`),
|
|
`tests/test_web_status_fragment.py` (nou) (~3 fisiere)
|
|
- **Test intai (RED)**: `tests/test_web_status_fragment.py` — `test_status_fragment_text_uman`
|
|
(contine "Trimitere automata", nu "worker viu"), `test_status_blocate_defalcare`,
|
|
`test_status_se_reincarca_htmx` (are `hx-trigger` periodic).
|
|
- **Continut**: extrage blocul de status din `dashboard.html` intr-un fragment dedicat care foloseste
|
|
`labels.py`. Ramane sticky/vizibil sus indiferent de tab-ul activ. Defalca "Necesita atentia ta"
|
|
pe motive. Pastreaza poll-ul HTMX (`every 15s`) deja existent pentru banner.
|
|
- **Acceptance criteria**:
|
|
- [x] `/_fragments/status` randeaza bara cu etichetele din US-001 (scoped pe cont, ca restul UI).
|
|
- [x] Bara ramane vizibila sus cand se schimba tab-ul (nu e inghitita de panoul activ).
|
|
- [x] Cand exista submissions blocate, bara arata defalcarea pe motiv, nu doar un numar.
|
|
- **Verificare E2E**: browser — incarca `/`, bara de status arata text uman; opreste workerul →
|
|
"Trimitere automata: oprita".
|
|
|
|
### US-003: Navigare cu tab-uri (shell dashboard)
|
|
**Ca** operator **vreau** sectiuni separate pe tab-uri, nu un scroll lung
|
|
**pentru ca** sa gasesc rapid ce caut fara sa fiu coplesit.
|
|
|
|
- **Depinde de**: US-002
|
|
- **Fisiere**: `app/web/templates/dashboard.html` (restructurare), `app/web/templates/_tabs.html` (nou,
|
|
optional), `app/web/routes.py` (ruta `/` + suport deep-link tab), `tests/test_web_tabs.py` (nou) (~4 fisiere)
|
|
- **Test intai (RED)**: `tests/test_web_tabs.py` — `test_dashboard_are_tabbar`,
|
|
`test_tab_implicit_acasa`, `test_deeplink_tab_import` (`/?tab=import` randeaza panoul Import
|
|
server-side la full load), `test_tab_activ_randat_server_side` (panoul activ e in HTML-ul initial,
|
|
nu doar cerut prin HTMX dupa load), `test_fragmentele_inactive_lazy` (panourile inactive nu se cer
|
|
la load), `test_tabbar_aria` (atribute `role=tablist`/`tab`/`tabpanel` + `aria-selected` prezente).
|
|
- **Continut**: bara de tab-uri sub header: **Acasa · Import · Coada · Mapari · Cont · Nomenclator**
|
|
(+ "Panou admin" / "Iesi" pastrate in coltul din dreapta sus). Panoul de submissions existent muta
|
|
din scroll in tab-ul **Coada**. Un singur panou activ; tab-ul isi incarca fragmentul prin HTMX la
|
|
activare (lazy), nu toate la load. **Randare server-side a panoului activ** la full load (din `?tab=`):
|
|
fara palpaire la refresh si degradare gratioasa daca JS lipseste — utilizatorul vede macar panoul
|
|
curent. Bara de status (US-002) sta deasupra tab-bar-ului, mereu vizibila. Tab activ marcat vizual.
|
|
**Accesibilitate reala**: `role="tablist"` pe bara, `role="tab"` + `aria-selected` pe fiecare tab,
|
|
`role="tabpanel"` pe panou, navigare cu sageti intre tab-uri (JS vanilla minim). Mobil: tab-bar se
|
|
ruleaza orizontal / se sparge curat (fara meniu hamburger — pastram simplu).
|
|
- **Acceptance criteria**:
|
|
- [x] Tab-bar cu cele 6 tab-uri (Acasa · Import · Coada · Mapari · Cont · Nomenclator); "Acasa" implicit la prima incarcare.
|
|
- [x] Un singur panou randat la un moment dat; celelalte fragmente NU se cer pana la activarea tab-ului.
|
|
- [x] Panoul activ (inclusiv din `?tab=`) e randat **server-side** la full load — fara palpaire la refresh, vizibil si fara JS.
|
|
- [x] Accesibilitate: `role=tablist/tab/tabpanel`, `aria-selected` pe tab-ul activ, navigare cu sageti (nu doar focus vizibil).
|
|
- [x] Refresh pe un tab non-implicit revine pe acelasi tab (deep-link prin query string `?tab=`).
|
|
- [x] Toate functiile existente raman accesibile dintr-un tab (nimic pierdut fata de pagina veche).
|
|
- **Verificare E2E**: browser — click pe fiecare tab incarca panoul corect; refresh pe `?tab=import`
|
|
ramane pe Import; navigare cu sageti intre tab-uri functioneaza (citior de ecran anunta tab-ul activ).
|
|
|
|
### US-004: Importul ca wizard cu pasi numerotati (stepper)
|
|
**Ca** operator care incarca un fisier **vreau** sa vad clar in ce pas sunt si ce urmeaza
|
|
**pentru ca** sa nu ma blochez intrebandu-ma "si acum ce fac?".
|
|
|
|
- **Depinde de**: US-003
|
|
- **Fisiere**: `app/web/templates/_stepper.html` (nou, include partajat),
|
|
`app/web/templates/_upload.html`, `_mapcoloane.html`, `_preview_import.html` (adauga antet stepper),
|
|
`tests/test_web_import_stepper.py` (nou) (~5 fisiere)
|
|
- **Test intai (RED)**: `tests/test_web_import_stepper.py` — `test_stepper_pas1_la_upload`,
|
|
`test_stepper_pas2_la_mapare`, `test_stepper_pas3_la_preview`, `test_stepper_marcheaza_pasii_facuti`,
|
|
`test_import_hx_target_in_tab` (fragmentele de import au `hx-target` care se rezolva in panoul de tab,
|
|
nu pe vechiul container de pagina), `test_import_forms_pastreaza_csrf` (formularele mutate isi pastreaza
|
|
`csrf_token` valid).
|
|
- **Continut**: un antet de stepper reutilizabil cu 4 pasi vizibili in toate fragmentele de import:
|
|
**1. Incarca fisier → 2. Potriveste coloanele → 3. Verifica → 4. Confirma trimiterea**. Pasul curent
|
|
evidentiat, pasii facuti bifati, pasii viitori estompati. Fiecare ecran are un titlu-actiune si o
|
|
fraza de ajutor ("Trage un fisier xlsx/csv aici" / "Spune-ne ce coloana e ce" / "Verifica inainte sa
|
|
trimiti"). Stepper-ul e PUR vizual — nu schimba endpoint-urile sau ordinea logica existenta.
|
|
**Granita cu US-003 (risc tehnic principal)**: cand fragmentele de import se randeaza in tab-ul Import,
|
|
`hx-target`/`hx-swap` din upload→mapare→preview trebuie sa tinteasca un container din interiorul
|
|
panoului de tab (nu vechiul container de la radacina paginii), iar `csrf_token` din formularele de
|
|
import trebuie sa ramana corect. Verificat prin testele de mai sus + regula de aur.
|
|
- **Acceptance criteria**:
|
|
- [x] Acelasi stepper apare in upload, mapare-coloane si preview, cu pasul corect evidentiat.
|
|
- [x] Pasii deja parcursi sunt marcati ca facuti; cei viitori sunt estompati.
|
|
- [x] Fiecare pas are un titlu-actiune + o fraza scurta de ajutor (microcopy din US-001 unde se aplica).
|
|
- [x] `hx-target` din fragmentele de import se rezolva in panoul de tab; `csrf_token` pastrat in formulare.
|
|
- [x] Fluxul de import functioneaza identic (upload → mapare → preview → confirma) — fara regresie.
|
|
- **Verificare E2E**: browser — urca `test_data.csv`, parcurge cei 4 pasi; stepper-ul avanseaza corect;
|
|
commit → randuri in coada → worker → FINALIZATA la RAR test (regula de aur).
|
|
|
|
### US-005: Pagina "Acasa" cu ghid de pornire (checklist auto-bifat)
|
|
**Ca** utilizator nou **vreau** sa mi se spuna exact ce am de configurat ca sa pot trimite
|
|
**pentru ca** sa ajung la prima declaratie reusita fara sa ghicesc pasii.
|
|
|
|
- **Depinde de**: US-003
|
|
- **Fisiere**: `app/web/templates/_acasa.html` (nou), `app/web/routes.py` (context: are_creds, are_cheie_folosita,
|
|
are_trimiteri), `tests/test_web_onboarding.py` (nou) (~3 fisiere)
|
|
- **Test intai (RED)**: `tests/test_web_onboarding.py` — `test_checklist_pas_creds_neconfigurat`,
|
|
`test_checklist_pas_creds_bifat_cand_exista`, `test_checklist_ascuns_cand_totul_gata`,
|
|
`test_linkuri_ghid_duc_la_taburi`, `test_empty_state_coada_gol` (tab Coada fara submissions arata
|
|
indemn catre Import, nu un tabel gol), `test_empty_state_mapari_gol`.
|
|
- **Continut**: tab-ul "Acasa" (implicit) arata un card "Primii pasi" cu o lista bifabila:
|
|
1. **Conecteaza-ti contul RAR** (email + parola portal AUTOPASS) — link la tab Cont.
|
|
2. **(Optional) Ia-ti cheia API** daca trimiti din soft propriu — link la tab Cont.
|
|
3. **Importa primul fisier** — link la tab Import.
|
|
Fiecare pas se bifeaza automat cand e indeplinit (creds configurate → pas 1 bifat; exista cel putin
|
|
o trimitere → pas 3 bifat). Cand toti pasii esentiali sunt gata, ghidul se colapseaza intr-o linie
|
|
discreta ("Totul e configurat — vezi coada"), ca sa nu deranjeze utilizatorul experimentat. Sub ghid,
|
|
pe acelasi tab, un rezumat scurt + scurtaturi (coada recenta / actiuni rapide).
|
|
- **Acceptance criteria**:
|
|
- [x] Pasul "Conecteaza contul RAR" e nebifat fara creds, bifat cand `are_creds` e adevarat.
|
|
- [x] Pasul "Importa primul fisier" se bifeaza cand contul are cel putin un submission.
|
|
- [x] Cand toti pasii esentiali sunt gata, ghidul e colapsat/discret (nu ocupa tot ecranul).
|
|
- [x] Link-urile din ghid duc la tab-ul corect (Cont / Import).
|
|
- [x] **Empty states prietenoase**: tab Coada gol → "Nicio trimitere inca — incepe cu Import" (link la
|
|
tab Import); tab Mapari gol → mesaj scurt + indemn, nu un tabel/lista goala fara context.
|
|
- **Verificare E2E**: browser — cont nou (fara creds): ghid vizibil cu pasi nebifati + tab Coada arata
|
|
empty state cu indemn la Import; dupa setarea credentialelor si un import, pasii se bifeaza si ghidul se restrange.
|
|
|
|
## 4. Riscuri
|
|
|
|
- **Regresie pe fluxul de import** (cel mai mare risc): stepper-ul (US-004) atinge cele 3 fragmente
|
|
de import. Mitigare: stepper PUR vizual, endpoint-urile si ordinea logica raman; regula de aur in
|
|
fiecare VERIFY (import → FINALIZATA la RAR test).
|
|
- **Lazy-load gresit**: daca tab-urile cer toate fragmentele la load, dispare castigul de aglomerare
|
|
si creste load-ul. Mitigare: test explicit `test_fragmentele_inactive_lazy` (US-003).
|
|
- **Scope pe cont pierdut la mutarea in fragmente noi**: fragmentele existente sunt scoped pe sesiune
|
|
(regula NULL→cont 1, anti-leak C6 din 3.3a). Orice fragment nou (status, acasa) trebuie sa pastreze
|
|
acelasi scope. Mitigare: testele de fragment verifica izolarea pe cont; VERIFY reia sweep-ul anti-leak.
|
|
- **CSRF / form-uri**: tab Cont muta form-urile de rotire cheie / creds RAR — trebuie pastrate
|
|
`csrf_token` si `hx-target` corecte. Mitigare: reutilizam `_cont.html` ca atare in tab.
|
|
- **Microcopy "definitiv"**: etichetele din §3 sunt propuneri; daca utilizatorul vrea alt ton, se
|
|
ajusteaza in `labels.py` (un singur loc). Risc mic.
|
|
|
|
## 5. Intrebari deschise — REZOLVATE
|
|
|
|
> Rezolvate cu utilizatorul inainte de executie (poarta de aprobare PRD). Deciziile de mai jos sunt
|
|
> obligatorii pentru EXECUTE.
|
|
|
|
1. **Tab-uri** — DECIS: **6 tab-uri**: **Acasa · Import · Coada · Mapari · Cont · Nomenclator**.
|
|
Fata de propunerea initiala (5), "Coada submissions" devine tab propriu (e ecranul operational
|
|
principal, nu se ascunde sub Acasa). Nomenclatorul ramane tab separat (referinta consultata rar,
|
|
dar cautata explicit). Comasarea Nomenclator-sub-Mapari respinsa: sunt actiuni diferite (editezi
|
|
mapari vs. doar consulti coduri).
|
|
2. **Tab implicit** — DECIS: **Acasa** pentru toti, dar ghidul de pornire (US-005) se **restrange
|
|
automat** cand contul e configurat (creds RAR setate + cel putin o trimitere), lasand un rezumat
|
|
scurt + scurtatura la Coada. Utilizatorul experimentat vede de fapt un mini-rezumat, nu un wizard.
|
|
3. **Etichete (§3 US-001)** — DECIS: se **adopta tabelul din US-001** ca atare. Ton: descriptiv-functional
|
|
("Trimitere automata: activa"), nu colocvial ("Coada se trimite singura"). Toate textele intr-un
|
|
singur loc (`labels.py`) — ajustabile ulterior fara atingerea template-urilor.
|
|
4. **Persistenta tab activ** — DECIS: **query string** (`/?tab=import`). Supravietuieste refresh-ului,
|
|
e testabil server-side (criteriul din US-003), si permite link-uri directe din ghid (US-005). Hash-ul
|
|
respins: nu ajunge la server, deci netestabil in `test_deeplink_tab_import`.
|
|
5. **Stepper import** — DECIS: **4 pasi ficsi** (Incarca · Potriveste coloanele · Verifica · Confirma).
|
|
Cand semnatura de coloane e deja memorata, **pasul 2 apare bifat automat** si fluxul sare vizual la
|
|
pasul 3, dar pasul 2 ramane afisat in stepper (estompat/bifat) pentru orientare — utilizatorul vede
|
|
ca maparea a fost recunoscuta, nu ca a disparut un pas.
|
|
|
|
> Impact asupra stories: US-003 listeaza acum **6 tab-uri** (adaugat "Coada" ca tab propriu — panoul de
|
|
> submissions existent muta din scroll in tab-ul Coada). Restul stories raman neschimbate.
|
|
|
|
## 6. Valuri de executie (graful de dependente)
|
|
|
|
```
|
|
Val 1: [US-001] ← modul pur de etichete, fisiere distincte → poate porni singur
|
|
Val 2: [US-002] ← bara de status, foloseste US-001
|
|
Val 3: [US-003] ← shell-ul de tab-uri, are nevoie de bara de status (US-002)
|
|
Val 4: [US-004] [US-005] ← ambele depind de shell-ul de tab-uri (US-003); fisiere distincte
|
|
(US-004 = fragmentele de import; US-005 = _acasa.html) → paralel
|
|
```
|
|
|
|
> US-004 si US-005 ating fisiere disjuncte (import vs acasa) — pot rula in paralel (max 2 teammates).
|
|
> Atentie: US-003 si US-004 ating amandoua zona de import in `dashboard.html`/include-uri — NU paralel
|
|
> cu US-003; de aceea US-004 e in valul urmator.
|
|
|
|
## 7. Plan-reviews aplicate (CEO / Eng / Design)
|
|
|
|
> Aplicate IN PRD inainte de cod (ROADMAP §5.3). Constatari pliate cu acordul utilizatorului.
|
|
|
|
- **CEO (valoare/scope)**: premisa validata — frecarea de activare pe Treapta 2 (service-uri non-ROAAUTO)
|
|
e wedge-ul real; US-005 (ghid de pornire) are cel mai mare ROI. Scope sanatos (5 stories, doar strat
|
|
de prezentare), fara expansiune. Nota de secventiere: daca timpul scade, US-001/002 + US-005 (microcopy
|
|
+ activare) au prioritate peste estetica de tab-uri (US-003).
|
|
- **Eng (fezabilitate/teste)**: cel mai mare risc tehnic = granita US-003↔US-004 (hx-target/CSRF din
|
|
fragmentele de import mutate in tab) → AC + teste dedicate adaugate in US-004. Adaugat: randare
|
|
server-side a panoului activ (degradare gratioasa fara JS) in US-003. Constrangere de testare:
|
|
TestClient nu executa JS — testele unitare verifica atribute + stare initiala randata server-side;
|
|
interactivitatea (swap, navigare cu sageti) cade pe E2E Playwright.
|
|
- **Design (UI/UX)**: accesibilitate reala a tab-urilor (`role=tablist/tab/tabpanel` + `aria-selected`
|
|
+ navigare cu sageti) in loc de "focus vizibil" — pliat in US-003. Empty states prietenoase (Coada/Mapari
|
|
goale) — pliat in US-005. Tabelul de microcopy validat.
|
|
|
|
---
|
|
|
|
## Raport VERIFY
|
|
|
|
> Verificare condusa de lead (utilizatorul a respins E2E cu browser/server). Acoperire: suita
|
|
> pytest completa + verificare ACs prin FastAPI TestClient + spot-check de integrare. E2E cu browser
|
|
> live si regula de aur LIVE (FINALIZATA la RAR test) NU au fost rulate in aceasta sesiune — vezi nota.
|
|
|
|
**Suita**: `python3 -m pytest -q` → **434 passed** (de la 400 baseline: +34 teste noi 3.4). Fara regresie.
|
|
|
|
### PASS/FAIL per story
|
|
|
|
- **US-001 (labels.py)** — PASS. `tests/test_web_labels.py` (11 teste). `test_toate_starile_au_eticheta`
|
|
parseaza CHECK-ul din `schema.sql` → iese rosu la stare noua nemapata. Functii pure (fara DB/request).
|
|
- **US-002 (bara status)** — PASS. `tests/test_web_status_fragment.py`. `/_fragments/status` randeaza
|
|
"Trimitere automata" (nu "worker viu"), defalcare blocate pe motiv, poll `every 15s`, scoped pe cont.
|
|
- **US-003 (tab-uri)** — PASS. `tests/test_web_tabs.py` (6 teste). TestClient: `role="tablist"` + 6 tab-uri,
|
|
Acasa implicit (`aria-selected="true"`), `/?tab=import` randeaza `#import-section` server-side, panou
|
|
activ in HTML initial, role=tab/tabpanel + aria-selected, navigare cu sageti (JS vanilla). Fragmentele
|
|
inactive NU se cer la load (swap pe click). Deep-link `?tab=` supravietuieste refresh-ului.
|
|
- **US-004 (stepper)** — PASS. `tests/test_web_import_stepper.py` (8 teste). Stepper 4 pasi in
|
|
upload(1)/mapcoloane(2)/preview(3), pasii facuti marcati, `aria-current="step"` pe activ, `hx-target="#import-section"`
|
|
si `csrf_token` pastrate. Fluxul import (upload→mapare→preview→confirma) neatins — endpointuri intacte.
|
|
- **US-005 (Acasa onboarding)** — PASS. `tests/test_web_onboarding.py` (6 teste). Checklist auto-bifat
|
|
(are_creds/are_trimiteri), ghid colapsat cand totul gata, linkuri `?tab=cont`/`?tab=import`, empty states
|
|
prietenoase pe Coada (indemn Import) si Mapari, scoped pe cont.
|
|
|
|
### Regula de aur (regresie)
|
|
Backend de trimitere (worker, mapping, idempotency, import_router, masina de stari) **neatins** — confirmat
|
|
prin diff. Fluxul de import pana la enqueue (`queued`) ramane verde prin `tests/test_import_ui.py` +
|
|
`tests/test_import_e2e.py`. **Trimiterea LIVE la RAR test (FINALIZATA) NU a fost probata in aceasta sesiune**
|
|
(fara browser/creds RAR test) — recomandata o probare manuala `./start.sh test both --send` inainte de prod.
|
|
|
|
### Defecte gasite si reparate in cursul VERIFY/CLOSE
|
|
1. **Izolare teste (429)**: fixturile noi nu reseteau rate-limiterul de login in-proces (`ratelimit._hits`);
|
|
rulate impreuna, login-urile depaseau pragul → 429 → 5 teste rosii la rulare subset. Reparat: `ratelimit._hits.clear()`
|
|
in fixturile celor 4 fisiere noi (pattern din `test_web_login.py`). Suita completa trecea din noroc de ordine.
|
|
2. **Regresie UX** (code-review): avertismentul "Cont in asteptare de activare" (vechiul `_banner.html`) nu
|
|
mai era afisat dupa scoaterea `/_fragments/banner`. Re-introdus in bara de status (`account_active`).
|
|
3. **Consistenta tema**: culori hardcodate in `_acasa.html` → variabile paletei (`--muted`/`--accent`/`--ok`).
|
|
|
|
### Cleanup notat, neremediat (non-blocant)
|
|
- Duplicare intre `_render_panel_{mapari,cont,nomenclator}` si endpointurile fragment existente.
|
|
- `/_fragments/banner` + `_banner.html` raman dead code dupa mutarea avertismentelor in bara de status.
|
|
- Ramura moarta in `_render_panel_for_tab` (fallback acasa fara conn) — inaccesibila (tab pre-validat).
|
|
- Bara de status e lazy (HTMX `load`), nu server-side: fara JS arata "se incarca…". AC formale indeplinite
|
|
(panoul activ e server-side); de reconsiderat la o iteratie viitoare daca conteaza no-JS pe status.
|