docs(prd): PRD 3.4 interfata web ergonomica (tab-uri + wizard + microcopy)

Reorganizare dashboard pe trei principii, doar stratul de prezentare
(Jinja2+HTMX, zero build), fara atingerea worker/mapare/idempotenta:
- tab-uri sus (Acasa/Import/Coada/Mapari/Cont/Nomenclator), un panou activ,
  fragmente lazy, deep-link ?tab= randat server-side, a11y tablist/aria
- import ca stepper 4 pasi (Incarca/Potriveste/Verifica/Confirma)
- ghid de pornire auto-bifat + empty states (US-005)
- microcopy uman intr-un singur loc (labels.py): 'Trimitere automata: activa'
  in loc de 'worker viu'

Intrebari deschise rezolvate (6 tab-uri, ?tab=, pas 2 auto-bifat). Plan-reviews
CEO/Eng/Design aplicate in PRD (a11y, empty states, guard HTMX/CSRF la granita
US-003<->US-004, randare server-side). Stare: aprobat. Rand 3.4 TODO in ROADMAP.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-06-18 19:59:27 +00:00
parent f149b24f96
commit 4e2b6102a4
2 changed files with 274 additions and 0 deletions

View File

@@ -78,6 +78,7 @@ Reguli de contract (detalii in `docs/api-rar-contract.md`): `FINALIZATA` e termi
| 3.2 | Filtrare pe cont a GET-urilor de listare | DONE | 2026-06-17 | scope cheie pe `/v1/prezentari(/{id})`, `/v1/mapari(/pending)`, `/v1/audit/export` (NULL→cont 1); nomenclator global; 404 cross-account identic (B3) + allowlist campuri detaliu (B4) + helper `account_scope_clause` (B2) + index (B5). 14 teste noi, 313 pass. PRD: [prd-3.2](prd/prd-3.2-filtrare-cont-get.md) |
| 3.3a | Self-onboarding web (core) | DONE | 2026-06-17 | `users` (scrypt) + sesiune (`SessionMiddleware`, same_site=strict) + CSRF (enforce prod, inclusiv login/signup) + rate-limit signup/login + signup/login/logout + dashboard & import scoped pe sesiune (NULL→1, anti-leak C6) + gate worker `active=0` (`COALESCE`). 2 runde VERIFY (leak `/_fragments/mapari` prins+reparat) + code-review (csrf erori, scrypt_params, login rate-limit). 361 teste. PRD: [prd-3.3](prd/prd-3.3-self-onboarding-web.md) |
| 3.3b | Self-service cheie/creds + admin web + email | DONE | 2026-06-18 | US-007 (rute web proprii `/cont/roteste-cheie`+`/cont/rar-creds` scoped sesiune, C13), US-010 (rol admin `is_admin` + `require_admin`→403 + CLI `set-admin` + bootstrap primul cont=admin), US-011 (`/admin` activare/dezactivare cu CSRF+PRG, link doar pt admini + logout), US-012 (`app/email.py` notify best-effort degradat fara SMTP + log `SIGNUP`). Fix migrare defensiva `users.is_admin`/`email_verified`. 2 runde VERIFY context curat (r1 a prins migrarea lipsa, reparat; r2 PASS) + `/code-review` high (TOCTOU bootstrap admin mutat in tranzactie + extras `_render_admin` anti-duplicare/N+1). 393 teste. PRD: [prd-3.3](prd/prd-3.3-self-onboarding-web.md) |
| 3.4 | Interfata web ergonomica (tab-uri + wizard + microcopy uman) | TODO | | Reorganizare dashboard: tab-uri sus (Acasa/Import/Mapari/Cont/Nomenclator), import ca stepper 4 pasi, ghid de pornire auto-bifat, etichete umane (`labels.py`) in loc de "worker viu". Doar stratul de prezentare (Jinja2+HTMX), fara backend de trimitere. PRD: [prd-3.4](prd/prd-3.4-ux-dashboard-web.md) |
### Etapa 4 — Viitor (Treapta 3)

View File

@@ -0,0 +1,273 @@
# PRD 3.4 — Interfata web ergonomica (tab-uri + wizard + microcopy uman)
**Stare**: aprobat
> 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**:
- [ ] `labels.py` expune o functie/dict care, pentru fiecare stare din `schema.sql`, da `(text, css_class)`.
- [ ] Nicio stare de submission existenta nu ramane fara eticheta (test parametrizat care iese rosu daca se adauga o stare noua nemapata).
- [ ] 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**:
- [ ] `/_fragments/status` randeaza bara cu etichetele din US-001 (scoped pe cont, ca restul UI).
- [ ] Bara ramane vizibila sus cand se schimba tab-ul (nu e inghitita de panoul activ).
- [ ] 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**:
- [ ] Tab-bar cu cele 6 tab-uri (Acasa · Import · Coada · Mapari · Cont · Nomenclator); "Acasa" implicit la prima incarcare.
- [ ] Un singur panou randat la un moment dat; celelalte fragmente NU se cer pana la activarea tab-ului.
- [ ] Panoul activ (inclusiv din `?tab=`) e randat **server-side** la full load — fara palpaire la refresh, vizibil si fara JS.
- [ ] Accesibilitate: `role=tablist/tab/tabpanel`, `aria-selected` pe tab-ul activ, navigare cu sageti (nu doar focus vizibil).
- [ ] Refresh pe un tab non-implicit revine pe acelasi tab (deep-link prin query string `?tab=`).
- [ ] 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**:
- [ ] Acelasi stepper apare in upload, mapare-coloane si preview, cu pasul corect evidentiat.
- [ ] Pasii deja parcursi sunt marcati ca facuti; cei viitori sunt estompati.
- [ ] Fiecare pas are un titlu-actiune + o fraza scurta de ajutor (microcopy din US-001 unde se aplica).
- [ ] `hx-target` din fragmentele de import se rezolva in panoul de tab; `csrf_token` pastrat in formulare.
- [ ] 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**:
- [ ] Pasul "Conecteaza contul RAR" e nebifat fara creds, bifat cand `are_creds` e adevarat.
- [ ] Pasul "Importa primul fisier" se bifeaza cand contul are cel putin un submission.
- [ ] Cand toti pasii esentiali sunt gata, ghidul e colapsat/discret (nu ocupa tot ecranul).
- [ ] Link-urile din ghid duc la tab-ul corect (Cont / Import).
- [ ] **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
> Completat de subagentul verificator (context curat) in faza VERIFY — vezi ROADMAP §5.6.
> PASS/FAIL per criteriu, cu dovezi (output pytest citat, E2E browser pe `http://localhost:8000/`,
> plus regula de aur: import → worker → FINALIZATA la RAR test). Lipseste pana la VERIFY.