feat(web): uniformizare/standardizare UI/UX + lifecycle conturi (PRD 5.5)
Aduce toate suprafetele dashboard-ului la grila tabelului Trimiteri, muta
navigarea intr-un meniu de cont (hamburger) si da panoului admin actiuni
reale de ciclu de viata. 9 stories, 3 valuri. UI pur (reskin + reasezare)
cu O SINGURA exceptie backend: modelul de stare a contului.
- US-001 sectiunea "Ajutor" eliminata din Acasa (wayfinding redundant).
- US-002 Nomenclator la grila standard (_submissions.html ca referinta).
- US-003 macro autosend compact (Manual<->Auto). Semantica de PREZENTA
`auto_send` (bifat->true, absent->false) NEALTERATA — compatibil cu ambele
parsere (Form(bool) la /mapari, bool(form.get()) la import). Zero backend.
- US-004 accounts.status (pending/active/blocked/archived/deleted), migrare
defensiva idempotenta derivata din `active`, gate worker claim_one pe
status='active' (echivalenta active=1 <=> status='active' pastrata).
- US-005 tabel Mapari compact + panou Ajutor (<details>, proza o singura data),
coloana "In coada".
- US-006 meniu hamburger dropdown (Cont/Integrare/Nomenclator/Admin/logout) +
context is_authenticated/is_admin/csrf_token defensiv in base.html.
- US-007 tab-bar redus la Acasa+Mapari; rutele /_fragments/{cont,integrare,
nomenclator} + deep-link ?tab= raman valide.
- US-008 rute admin block/archive/delete + bulk pe lista account_id,
require_admin + CSRF + PRG, dev id=1 sarit in bulk.
- US-009 admin UI: selectie bife + master + bara bulk + kebab per-rand,
grupare pe stare (bloc nou blocate/arhivate), nota "cont dev implicit" scoasa.
Stergere = SOFT: tombstone (status='deleted'), dar PII purjata IMEDIAT
(rar_creds_enc + chei API revocate + CUI eliberat pentru re-inregistrare),
GDPR/L.142.
VERIFY: 671 teste pass (+40). E2E browser (Playwright) a prins 2 bug-uri
invizibile la TestClient: bara bulk cu display:flex inline invingea [hidden]
(mutat in CSS .bulk-bar[hidden]); conturi arhivate cadeau sub "in asteptare"
(grupare pe status). /code-review high a prins 2 bug-uri reale: soft delete
pastra creds RAR + CUI la nesfarsit fara purjare accounts (GDPR neonorat);
apostrof in numele firmei rupea confirm() inline din kebab — ambele reparate,
plus cleanup boilerplate rute (_lifecycle_route).
Backend trimitere (worker masina stari/idempotenta/mapping) neatins, cu
exceptia gate-ului de cont. Design: docs/design/5.5-uniformizare-ui.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
277
docs/design/5.5-uniformizare-ui.md
Normal file
277
docs/design/5.5-uniformizare-ui.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# Design 5.5 — Uniformizare & standardizare UI/UX
|
||||
|
||||
**Stare**: aprobat (decizii utilizator 2026-06-23, vezi §10)
|
||||
**Context**: dashboard web HTMX (`app/web/templates/`), paleta dark/light deja livrata (5.3),
|
||||
erori 3-niveluri (5.4). Acest document = sursa de adevar **vizuala** pentru PRD 5.5. Unde PRD-ul
|
||||
descrie *ce* livram pe stories, aici descriem *cum arata* si *de ce*.
|
||||
|
||||
> Nu reinventam estetica. Paleta, tipografia si tokenii din `base.html` (5.3) raman **NESCHIMBATI
|
||||
> la octet**. Standardizarea = aducem toate tabelele si paginile la acelasi vocabular de componente
|
||||
> care exista deja in tabelul Trimiteri (`_submissions.html`), tabelul considerat corect de referinta.
|
||||
|
||||
---
|
||||
|
||||
## 1. Problema (audit pe codul real)
|
||||
|
||||
Inventar al neuniformitatii curente:
|
||||
|
||||
| Suprafata | Simptom | Referinta corecta |
|
||||
|-----------|---------|-------------------|
|
||||
| Tabel **Mapari** (`_mapari.html`) | Labartat: coloana "Punere in coada" injecteaza prin macro `autosend_toggle` 3 randuri de text explicativ pe **fiecare** linie → randuri inalte, butoanele **Salveaza/Sterge** ies din viewport, trebuie scroll orizontal | grila Trimiteri |
|
||||
| Tabel **Nomenclator** (`_nomenclator.html`) | Functional dar minim; nu imparte exact acelasi aspect/hover/aliniere cu Trimiteri | grila Trimiteri |
|
||||
| **Acasa** (`_acasa.html`) | Sectiune "Ajutor: Mapari / Coduri RAR" redundanta (wayfinding repetat) | — (se elimina) |
|
||||
| **Navigare** | Cont, Integrare, Nomenclator stau ca tab-uri amestecate cu lucrul zilnic; logout + link admin sunt agatate ad-hoc in coltul dreapta-sus al dashboard-ului, absente pe alte pagini | meniu de cont dedicat |
|
||||
| **Panou admin** (`admin.html`) | Conturile in asteptare au doar "Activeaza" per-rand; lipsesc selectie multipla si actiunile blocare/arhivare/stergere. Nota "Cont dev implicit" e jargon intern nederivabil | tabel cu selectie + bara bulk |
|
||||
|
||||
Principiu de standardizare: **un singur tabel, o singura componenta de antet de sectiune, un singur
|
||||
loc pentru ajutor** (link/disclosure, nu text inline repetat pe randuri).
|
||||
|
||||
---
|
||||
|
||||
## 2. Design tokens (existenti — se reutilizeaza, nu se modifica)
|
||||
|
||||
Din `base.html` (`:root` dark + `[data-theme="light"]`). Citat aici doar ca referinta; **nicio
|
||||
valoare noua de culoare**. Orice suprafata noua foloseste `color-mix(... var(--card))` pentru stari
|
||||
(lectia 5.3: zero literali hardcodati, altfel se sparge light mode).
|
||||
|
||||
```
|
||||
--bg --card --ink --muted --line
|
||||
--ok (verde) --warn (chihlimbar) --err (rosu) --accent (albastru)
|
||||
```
|
||||
|
||||
Spacing: cardurile 16-20px padding; celule tabel `8px 10px`; gap-uri 6/8/12/16px (scara existenta).
|
||||
Radius: 6px controale, 10px carduri, 99px pill-uri. Tipografie: tabel 14px `tabular-nums`,
|
||||
antet `th` 12px uppercase `--muted`. **Nu introducem fonturi sau marimi noi.**
|
||||
|
||||
---
|
||||
|
||||
## 3. Componenta canonica: Tabelul standard
|
||||
|
||||
Tabelul Trimiteri defineste contractul. Orice tabel din aplicatie il respecta:
|
||||
|
||||
```
|
||||
.tablewrap > table
|
||||
thead th -> 12px uppercase, color --muted, font-weight 500, white-space nowrap
|
||||
tbody td -> 14px, padding 8px 10px, border-bottom 1px var(--line), nowrap implicit
|
||||
stare -> <span class="pill {s-*}">{text uman}</span> (glifa+text, nu doar culoare)
|
||||
coloana lunga (motiv) -> white-space:normal; max-width:280px (singura exceptie de la nowrap)
|
||||
empty state -> .empty (centrat, --muted, cu CTA contextual)
|
||||
```
|
||||
|
||||
Reguli care fac diferenta vizibila fata de "labartat":
|
||||
1. **Coloanele de control sunt inguste si nowrap.** Niciun text explicativ in celule. Explicatiile
|
||||
traiesc o singura data, in antetul cardului (link "Ajutor") sau intr-un `<details>`.
|
||||
2. **Actiunile incap fara scroll orizontal.** Coloana "Actiuni" la dreapta, `white-space:nowrap`,
|
||||
butoane scurte. Pe ecrane inguste scroll-ul ramane IN card (`.tablewrap`), nu in pagina.
|
||||
3. **Densitate constanta.** Inaltimea randului = o linie de text + padding. Sub-text (ex. "2 blocate",
|
||||
"acum: COD") merge in `<div class="muted" style="font-size:12px">` sub valoarea principala, nu
|
||||
pe coloana separata.
|
||||
|
||||
### 3.1 Antet de sectiune standard (cu Ajutor)
|
||||
|
||||
```
|
||||
+--------------------------------------------------------------+
|
||||
| De rezolvat [ Ajutor ] | <- h2 15px la stanga, link la dreapta
|
||||
+--------------------------------------------------------------+
|
||||
```
|
||||
|
||||
`Ajutor` = link discret `.cardlink` care comuta un `<details>`/panou de text (vezi §5). Mutam acolo
|
||||
toata proza care azi se repeta pe randuri. Un singur loc, citit la nevoie.
|
||||
|
||||
---
|
||||
|
||||
## 4. Tabelul Mapari — inainte / dupa
|
||||
|
||||
### Inainte (labartat)
|
||||
Fiecare rand din "De rezolvat" si "Mapari salvate" poarta `autosend_toggle`, care randeaza:
|
||||
- "La fisierele viitoare cu aceasta operatie:" (12px)
|
||||
- checkbox + **"Pune automat in coada"**
|
||||
- "Nebifat = «Tine pentru verificare». Doar pentru aceasta operatie; nimic nu pleaca la RAR..." (11px)
|
||||
|
||||
x N randuri. Coloana e mai lata decat selectul de cod; Salveaza/Sterge sunt impinse afara.
|
||||
|
||||
### Dupa (compact, ca Trimiteri)
|
||||
|
||||
```
|
||||
De rezolvat [ Ajutor ]
|
||||
-----------------------------------------------------------------
|
||||
OPERATIE SUGESTII COD RAR IN COADA ACTIUNI
|
||||
RevTehBP A012 (88%) [ A012 v ] (o) Auto [Salveaza]
|
||||
2 blocate ( ) Manual
|
||||
-----------------------------------------------------------------
|
||||
```
|
||||
|
||||
- Coloana **IN COADA** = comutator scurt cu doua stari etichetate **Auto** / **Manual** (radio sau
|
||||
switch), fara nicio propozitie. Tooltip pe control: "Auto = pune automat in coada la fisierele
|
||||
viitoare cu aceasta operatie; Manual = tine pentru verificare."
|
||||
- Explicatia completa (de ce exista maparile, ce inseamna Auto vs Manual, ce e blocat) → in panoul
|
||||
**Ajutor** din antet, scris o singura data.
|
||||
- **Invariant backend pastrat**: controlul emite tot `name="auto_send" value="true"` cu semantica de
|
||||
prezenta (bifat→true, absent→false), exact ca azi. Zero atingere backend (lectia 5.3/3.6:
|
||||
reskin la nivel de macro, parserele `/mapari` si `/_import/.../mapare-operatie` raman valide).
|
||||
- "Mapari salvate" si "Formate de coloane" → aceeasi grila; sub-textul ("acum: COD — nume",
|
||||
"N coloane", maparea coloana→camp) ramane `muted` 12px sub valoare, nu pe coloane separate verbose.
|
||||
|
||||
Macro-ul `autosend_toggle` se rescrie compact (acelasi `name`/`form`/`checked`), deci se schimba
|
||||
intr-un singur loc si se propaga si in fluxul de import (mapcoloane) unde e refolosit.
|
||||
|
||||
---
|
||||
|
||||
## 5. Panoul Ajutor (mapari)
|
||||
|
||||
Un `<details>` nativ in antetul cardului "De rezolvat" (sau link care expandeaza acelasi `<details>`),
|
||||
inchis implicit, fara JS:
|
||||
|
||||
```
|
||||
Ajutor (v)
|
||||
Maparile leaga o operatie din softul tau (cod intern ROAAUTO) de un cod RAR oficial.
|
||||
- Operatii necunoscute raman blocate in needs_mapping si NU pleaca la RAR pana le mapezi.
|
||||
- Sugestiile (%) vin din potrivire fuzzy pe denumire — verifica-le inainte sa salvezi.
|
||||
- In coada: Auto = la urmatoarele fisiere cu aceasta operatie, randurile intra automat in coada.
|
||||
Manual = raman pentru verificare; nimic nu pleaca la RAR pana confirmi tu.
|
||||
- La schimbarea unui cod, submission-urile blocate pe acea operatie se re-rezolva automat.
|
||||
```
|
||||
|
||||
Avantaj: text scris o data, accesibil, fara cost de inaltime pe fiecare rand. `<details>` =
|
||||
accesibil din tastatura nativ, fara dependente.
|
||||
|
||||
---
|
||||
|
||||
## 6. Navigare: meniu hamburger (decizie: dropdown ancorat dreapta-sus)
|
||||
|
||||
### 6.1 Header
|
||||
|
||||
```
|
||||
[Gateway RAR AUTOPASS] [test] [☀] v1.0 [☰]
|
||||
|
|
||||
+------------------+
|
||||
| Cont |
|
||||
| Integrare |
|
||||
| Nomenclator |
|
||||
| Panou admin | <- doar admin
|
||||
|------------------|
|
||||
| Iesi din cont | <- form POST /logout
|
||||
+------------------+
|
||||
```
|
||||
|
||||
- Iconita `☰` (`min 36x36`, `aria-label="Meniu cont"`, `aria-expanded`, `aria-controls`) langa toggle-ul
|
||||
de tema. Dropdown ancorat sub iconita, aliniat la dreapta. **Fara overlay** pe pagina.
|
||||
- Inchidere: click in afara, `Esc`, sau selectarea unui element. Focus trap minimal: `Esc` readuce
|
||||
focusul pe `☰`. Navigare cu sageti optionala (consistent cu pattern-ul tab existent), dar `Tab`
|
||||
natural e suficient.
|
||||
- Continut **dependent de autentificare** (vezi §6.3).
|
||||
|
||||
### 6.2 Tab-bar dupa mutare (decizie: doar Acasa · Mapari)
|
||||
|
||||
```
|
||||
[ Acasa ] [ Mapari ]
|
||||
```
|
||||
|
||||
Cont, Integrare, Nomenclator parasesc tab-bar-ul → meniul `☰`. Raman doar cele doua suprafete de
|
||||
**lucru zilnic**. Badge-urile de contoare (Mapari) raman pe tab. Deep-link `?tab=` si rutele
|
||||
`/_fragments/{cont,integrare,nomenclator}` raman valide (accesate acum din meniu, nu din tab-bar) —
|
||||
deci zero rute moarte, doar punctul de intrare se muta.
|
||||
|
||||
### 6.3 Stare de autentificare in header
|
||||
|
||||
`base.html` e partajat de `login.html`, `signup.html`, `dashboard.html`, `admin.html`. Meniul trebuie
|
||||
sa stie daca esti logat:
|
||||
|
||||
- **Autentificat**: arata Cont, Integrare, Nomenclator, (Panou admin daca `is_admin`), separator,
|
||||
"Iesi din cont" (form `POST /logout` cu `csrf_token`).
|
||||
- **Neautentificat** (login/signup): meniul arata doar "Autentificare" / "Inregistrare" (sau iconita
|
||||
`☰` ascunsa pe aceste pagini — vezi PRD US). Niciun link de cont, niciun logout.
|
||||
|
||||
Necesita ca `base.html` sa primeasca `is_authenticated`, `is_admin`, `csrf_token` in context. Se
|
||||
adauga ca un helper de context partajat (un singur loc), nu duplicat in fiecare render. Acesta e
|
||||
singurul "backend touch" din zona de navigare si trebuie sa fie aditiv si defensiv (lipsa cheilor →
|
||||
meniu in stare neautentificata, nu eroare).
|
||||
|
||||
---
|
||||
|
||||
## 7. Panou admin: selectie + actiuni bulk
|
||||
|
||||
### 7.1 Tabel conturi in asteptare (si analog conturi active)
|
||||
|
||||
```
|
||||
[v] Selecteaza tot 2 selectate:
|
||||
[Activeaza] [Blocheaza] [Arhiveaza] [Sterge] <- bara bulk, apare la selectie
|
||||
-----------------------------------------------------------------------
|
||||
[v] ID COMPANIE CUI EMAIL INREGISTRAT ACTIUNI
|
||||
[v] 7 Auto SRL RO123 a@b.ro 12.06.2026 [ ... ]
|
||||
[ ] 8 Moto SA RO456 c@d.ro 13.06.2026 [ ... ]
|
||||
-----------------------------------------------------------------------
|
||||
```
|
||||
|
||||
- Coloana de **checkbox** la stanga + un master "selecteaza tot" in antet.
|
||||
- **Bara de actiuni bulk** ascunsa pana exista o selectie; afiseaza numarul selectat si butoanele
|
||||
contextuale. Actioneaza pe toate randurile bifate (POST cu lista de `account_id`).
|
||||
- **Actiuni per-rand** in meniul `[ ... ]` (kebab): aceleasi verbe, pentru o singura tinta.
|
||||
- Verbele, ca stari de cont distincte (vezi §7.2): **Activeaza, Blocheaza, Arhiveaza, Sterge**.
|
||||
- `Sterge` = actiune distructiva → `hx-confirm` / dialog de confirmare obligatoriu.
|
||||
- `Blocheaza`/`Arhiveaza` reversibile → confirmare doar pe bulk (cantitate).
|
||||
- Stari vizuale ale verbelor: distructiv (`Sterge`) cu `color:var(--err)`; restul neutre `.cardlink`.
|
||||
|
||||
### 7.2 Model de stare cont (impact backend — vezi PRD riscuri)
|
||||
|
||||
Azi: `accounts.active` (0/1); "pending" = inregistrat dar `active=0`. Cele 4 verbe cer stari
|
||||
distincte care nu incap intr-un bool. Propunere (PRD o ratifica): coloana `accounts.status`
|
||||
TEXT, migrare defensiva, derivata din `active` la prima rulare:
|
||||
|
||||
```
|
||||
pending -> inregistrat, neactivat inca (active=0, status nesetat istoric)
|
||||
active -> operational (active=1)
|
||||
blocked -> suspendat reversibil (nu logheaza, worker nu trimite)
|
||||
archived -> ascuns din liste, date pastrate (read-only)
|
||||
deleted -> stergere (GDPR/L.142) (hard delete SAU soft cu purge)
|
||||
```
|
||||
|
||||
- Worker `claim_one` gate-uieste pe **status='active'** (azi pe `COALESCE(active,1)=1`) — schimbare
|
||||
semantica de pastrat compatibila: `active=1 ⇔ status='active'`.
|
||||
- **Contul dev id=1 e protejat** de Blocheaza/Arhiveaza/Sterge (cont de sistem), exact ca azi la
|
||||
activate/deactivate. Daca e selectat in bulk, e sarit, nu eroare.
|
||||
- Nota "Cont dev implicit (id=1)" din pagina **se elimina** (jargon intern, nederivabil de operator).
|
||||
Protectia ramane in cod, nu o explicam in UI.
|
||||
|
||||
> Aceasta e singura zona cu schema/backend real. Restul livrabilei e UI pur (reskin + reasezare).
|
||||
|
||||
---
|
||||
|
||||
## 8. Accesibilitate & paritate tema
|
||||
|
||||
- **AA pe light+dark** pentru orice text nou (lectia 5.3: verzi/rosii hardcodate cad sub AA). Stari
|
||||
doar prin `color-mix(... var(--card))`, niciun literal.
|
||||
- Stare = **glifa + text**, nu doar culoare (pill-urile existente respecta deja).
|
||||
- Meniul `☰`: `aria-expanded`, `aria-controls`, inchidere pe `Esc`, focus readus pe trigger.
|
||||
- `<details>` Ajutor: accesibil nativ din tastatura.
|
||||
- Checkbox-uri admin: `aria-label` per rand ("Selecteaza contul {companie}"); master = "Selecteaza tot".
|
||||
- Toate controalele >=36px zona de atins (consistent cu toggle tema / `.cardlink`).
|
||||
|
||||
## 9. Motiune
|
||||
|
||||
Minima, consistenta cu existentul: dropdown `☰` fade/translate scurt (~120ms, ca `.tab-link`
|
||||
transition). `<details>` = comportament nativ. Fara animatii noi de amploare. Respecta
|
||||
`prefers-reduced-motion` daca adaugam tranzitii (omitere la cerere).
|
||||
|
||||
## 10. Decizii utilizator (2026-06-23)
|
||||
|
||||
1. Meniu hamburger = **dropdown ancorat dreapta-sus** (nu drawer).
|
||||
2. Tab-bar = **Acasa · Mapari**; Nomenclator + Cont + Integrare + Panou admin → meniul `☰`.
|
||||
3. Mapari = **grila compacta ca Trimiteri**, toggle scurt **Auto/Manual**, link **Ajutor** in antet;
|
||||
textul repetat de pe randuri se elimina.
|
||||
4. Admin = **selectie cu bife + bara de actiuni bulk** (Activeaza/Blocheaza/Arhiveaza/Sterge) +
|
||||
actiuni per-rand; nota "cont dev implicit" **eliminata**.
|
||||
5. Sectiunea "Ajutor" de pe Acasa se **elimina**.
|
||||
6. Nomenclator capata exact aspectul tabelului Trimiteri.
|
||||
|
||||
## 11. Componente atinse (harta pentru PRD)
|
||||
|
||||
| Componenta | Fisier | Tip schimbare |
|
||||
|------------|--------|---------------|
|
||||
| Header + meniu `☰` + context auth | `base.html` (+ context render rute) | reasezare + mic backend context |
|
||||
| Tab-bar redus | `dashboard.html` | reasezare |
|
||||
| Acasa fara Ajutor | `_acasa.html` | stergere |
|
||||
| Mapari standard + toggle compact + Ajutor | `_mapari.html`, `_macros.html` | reskin UI (zero backend) |
|
||||
| Nomenclator ca Trimiteri | `_nomenclator.html` | reskin UI |
|
||||
| Admin selectie + bulk + verbe noi | `admin.html` + rute `/admin/*` | UI + **backend (status)** |
|
||||
| Model stare cont | `schema.sql`, `users.py`, worker gate | **backend + migrare** |
|
||||
229
docs/prd/prd-5.5-uniformizare-ui.md
Normal file
229
docs/prd/prd-5.5-uniformizare-ui.md
Normal file
@@ -0,0 +1,229 @@
|
||||
# PRD 5.5 — Uniformizare & standardizare UI/UX
|
||||
|
||||
**Stare**: aprobat (2026-06-23)
|
||||
|
||||
> Proces: `docs/ROADMAP.md` §5. Contract RAR (sursa de adevar): `docs/api-rar-contract.md`.
|
||||
> **Design vizual (sursa de adevar pentru *cum arata*)**: `docs/design/5.5-uniformizare-ui.md`.
|
||||
> Stare: `draft → aprobat → in-executie → verify-pass → inchis`.
|
||||
|
||||
## 1. Obiectiv
|
||||
|
||||
Aducem toate suprafetele dashboard-ului la acelasi vocabular de componente ca tabelul **Trimiteri**
|
||||
(referinta corecta), reasezam navigarea intr-un **meniu de cont** (hamburger) si dam panoului admin
|
||||
actiuni reale de ciclu de viata pe conturi. Tinta: aplicatia arata si se comporta uniform, fara
|
||||
tabele labartate, fara wayfinding redundant, fara scroll orizontal pentru actiuni. Detaliile vizuale
|
||||
si deciziile utilizatorului: `docs/design/5.5-uniformizare-ui.md` (§10).
|
||||
|
||||
## 2. Non-Goals (anti scope-creep)
|
||||
|
||||
- **Fara redesign de estetica**: paleta/tipografia/tokenii din `base.html` (5.3) raman NESCHIMBATI la octet.
|
||||
- **Fara atingere a fluxului de trimitere**: worker (masina stari submissions, idempotenta, mapping-rezolvare)
|
||||
NEATINS, cu o singura exceptie controlata — gate-ul `claim_one` pe noua stare de cont (US-004), pastrand
|
||||
echivalenta `active=1 ⇔ status='active'`.
|
||||
- **Fara schimbare a semanticii `auto_send`**: comutatorul Auto/Manual ramane reskin la nivel de macro
|
||||
(`name="auto_send"`, semantica de prezenta). Zero atingere a parserelor `/mapari` si `/_import/...`.
|
||||
- **Fara rute noi de date / fara HTTP nou pe chei API**: lifecycle-ul conturilor e admin-only, sub
|
||||
`require_admin` + CSRF, exact ca rutele admin existente.
|
||||
- **Fara responsive/mobile nou** dincolo de ce ofera deja `.tablewrap` (scroll in card).
|
||||
- **Tabelul Trimiteri ramane neatins** — e referinta, nu tinta.
|
||||
|
||||
## 3. Stories atomice
|
||||
|
||||
### US-001: Elimina sectiunea "Ajutor" din Acasa
|
||||
**Ca** operator **vreau** o pagina Acasa fara wayfinding redundant **pentru ca** linkurile Mapari/Coduri RAR
|
||||
sunt deja in navigare.
|
||||
|
||||
- **Depinde de**: —
|
||||
- **Fisiere**: `app/web/templates/_acasa.html`, `tests/test_web_acasa.py` (~2 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_acasa.py` — `test_acasa_fara_sectiune_ajutor` (randul "Ajutor:" + linkurile
|
||||
inline lipsesc din HTML-ul Acasa)
|
||||
- **Acceptance criteria**:
|
||||
- [ ] Blocul `Ajutor: <a>Mapari</a> <a>Coduri RAR</a>` (liniile ~47-55) eliminat din `_acasa.html`.
|
||||
- [ ] Restul Acasa (upload, "Primii pasi", sectiunea Trimiteri) neschimbat.
|
||||
- [ ] `python3 -m pytest tests/test_web_acasa.py -q` verde.
|
||||
- **Verificare E2E**: browser HTMX pe `/` — Acasa nu mai afiseaza randul Ajutor; upload + Trimiteri intacte.
|
||||
|
||||
### US-002: Tabel Nomenclator cu aspectul tabelului Trimiteri
|
||||
**Ca** operator **vreau** ca nomenclatorul sa arate identic cu Trimiteri **pentru ca** consistenta reduce
|
||||
sarcina cognitiva.
|
||||
|
||||
- **Depinde de**: —
|
||||
- **Fisiere**: `app/web/templates/_nomenclator.html`, `tests/test_web_nomenclator.py` (~2 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_nomenclator.py` — `test_nomenclator_grila_standard` (`.tablewrap` + `table`
|
||||
+ antet `th` standard + `.pill` pe cod; empty-state `.empty`)
|
||||
- **Acceptance criteria**:
|
||||
- [ ] Foloseste aceeasi structura `.tablewrap > table` cu antet `th` standard ca `_submissions.html`.
|
||||
- [ ] Codul prestatie ramane in `.pill`; coloanele aliniate, hover/aspect identice cu Trimiteri.
|
||||
- [ ] Empty-state pastrat (`Nomenclator gol...`), in `.empty`.
|
||||
- [ ] `python3 -m pytest tests/test_web_nomenclator.py -q` verde; AA light+dark (zero literali de culoare).
|
||||
- **Verificare E2E**: browser — Nomenclator si Trimiteri arata din aceeasi familie vizuala in dark si light.
|
||||
|
||||
### US-003: Macro `autosend_toggle` compact (Auto / Manual)
|
||||
**Ca** operator **vreau** un comutator scurt In coada, fara text repetat pe randuri **pentru ca** proza
|
||||
inline ingrasa randurile si impinge actiunile afara din ecran.
|
||||
|
||||
- **Depinde de**: —
|
||||
- **Fisiere**: `app/web/templates/_macros.html`, `tests/test_web_macros.py` (~2 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_macros.py` — `test_autosend_compact` (macro-ul randeaza control Auto/Manual,
|
||||
pastreaza `name="auto_send" value="true"` + `form=` + starea `checked`, si NU mai contine propozitiile
|
||||
explicative "La fisierele viitoare..."/"Nebifat = ...")
|
||||
- **Acceptance criteria**:
|
||||
- [ ] `autosend_toggle(form_id, checked)` randeaza un comutator compact etichetat **Auto** / **Manual**
|
||||
(radio sau switch), nowrap, fara propozitii inline.
|
||||
- [ ] Pastreaza EXACT `name="auto_send"`, `value="true"`, semantica de prezenta (bifat→true / absent→false),
|
||||
`form="{{form_id}}"`, `checked` reflecta `checked`.
|
||||
- [ ] Explicatia detaliata NU mai e in macro (se muta in panoul Ajutor, US-005). Tooltip scurt admis pe control.
|
||||
- [ ] `python3 -m pytest tests/test_web_macros.py tests/test_import_e2e.py -q` verde (parserele backend nealterate).
|
||||
- **Verificare E2E**: in fluxul import (mapcoloane) si in Mapari, comutatorul produce acelasi `auto_send`
|
||||
bool ca azi (queued vs needs_review neschimbat).
|
||||
|
||||
### US-004: Model de stare a contului (`accounts.status`) + gate worker
|
||||
**Ca** sistem **vreau** stari de cont distincte (pending/active/blocked/archived/deleted) **pentru ca**
|
||||
adminul are nevoie de blocare/arhivare/stergere, nu doar activ/inactiv.
|
||||
|
||||
- **Depinde de**: —
|
||||
- **Fisiere**: `app/schema.sql`, `app/db.py` (migrare defensiva), `app/users.py`, `app/worker/...` (gate `claim_one`),
|
||||
`tests/test_account_status.py`, `tests/test_worker_*.py` (~5 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_account_status.py` — `test_migrare_deriva_status_din_active`,
|
||||
`test_blocked_nu_e_claimuit`, `test_archived_nu_e_claimuit`, `test_dev_id1_protejat`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] Coloana `accounts.status` TEXT cu CHECK pe `{pending,active,blocked,archived,deleted}` (stergere = soft,
|
||||
`status='deleted'` + purjare de catre jobul de retentie T16); migrare **defensiva si idempotenta** (pattern
|
||||
`_migrate` ca la `is_admin`), derivata din `active` la prima rulare: `active=1→active`, altfel `pending`.
|
||||
- [ ] Helperi puri in `users.py`: `set_account_status(id, status)`, `delete_account(id)`, cu protectia
|
||||
contului dev `id=1` (ridica/ignora, nu corupe).
|
||||
- [ ] Worker `claim_one` gate-uieste pe `status='active'`, pastrand echivalenta cu `COALESCE(active,1)=1`
|
||||
de azi (conturile blocked/archived NU sunt claimuite).
|
||||
- [ ] `active` ramane consistent (`active=1 ⇔ status='active'`) cat timp coexista, fara regresie pe testele worker.
|
||||
- [ ] `python3 -m pytest -q` verde (suita completa).
|
||||
- **Verificare E2E**: marcheaza un cont `blocked` → submission-urile lui nu pleaca la RAR; `active` → pleaca.
|
||||
|
||||
### US-005: Tabel Mapari standardizat + panou Ajutor
|
||||
**Ca** operator **vreau** tabelele Mapari compacte ca Trimiteri, cu actiunile vizibile fara scroll si ajutor
|
||||
intr-un singur loc **pentru ca** acum sunt labartate si butoanele Salveaza/Sterge ies din ecran.
|
||||
|
||||
- **Depinde de**: US-003
|
||||
- **Fisiere**: `app/web/templates/_mapari.html`, `tests/test_web_mapari.py` (~2 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_mapari.py` — `test_mapari_grila_compacta` (coloane inguste nowrap, actiuni
|
||||
la dreapta), `test_mapari_ajutor_disclosure` (un singur `<details>`/link Ajutor in antet, fara proza pe randuri)
|
||||
- **Acceptance criteria**:
|
||||
- [ ] Cele 3 sectiuni (De rezolvat / Mapari salvate / Formate coloane) folosesc grila standard ca Trimiteri;
|
||||
coloana "In coada" foloseste macro-ul compact din US-003.
|
||||
- [ ] Butoanele **Salveaza**/**Sterge** vizibile fara scroll orizontal pe latime de dashboard normala
|
||||
(coloana Actiuni la dreapta, nowrap); sub-text (`N blocate`, `acum: COD`) ca `muted` 12px sub valoare.
|
||||
- [ ] Antetul "De rezolvat" contine un link/`<details>` **Ajutor** cu explicatia maparilor + Auto/Manual,
|
||||
scrisa O SINGURA DATA; proza inline de pe randuri eliminata.
|
||||
- [ ] CSRF, `hx-post`, `hx-target="#mapari-section"`, formularele si re-rezolvarea la edit cod — neschimbate.
|
||||
- [ ] `python3 -m pytest tests/test_web_mapari.py -q` verde; AA light+dark.
|
||||
- **Verificare E2E**: browser — mapezi o operatie (Salveaza vizibil fara scroll), comuti Auto/Manual, deschizi Ajutor;
|
||||
submission blocat se deblocheaza la salvarea codului (comportament neschimbat).
|
||||
|
||||
### US-006: Meniu hamburger in header + context de autentificare
|
||||
**Ca** utilizator **vreau** un meniu de cont in dreapta-sus cu Cont/Integrare/Nomenclator/Panou admin/logout
|
||||
**pentru ca** acestea nu sunt lucru zilnic si aglomereaza tab-bar-ul.
|
||||
|
||||
- **Depinde de**: —
|
||||
- **Fisiere**: `app/web/templates/base.html`, `app/web/routes.py` (helper context partajat),
|
||||
`tests/test_web_header_menu.py` (~3 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_header_menu.py` — `test_meniu_autentificat_are_linkuri_cont`,
|
||||
`test_meniu_admin_doar_pentru_admin`, `test_meniu_neautentificat_fara_logout` (login/signup → fara linkuri de cont)
|
||||
- **Acceptance criteria**:
|
||||
- [ ] Iconita `☰` in header (langa toggle tema), `aria-label`, `aria-expanded`, `aria-controls`; dropdown ancorat
|
||||
dreapta-sus; inchidere la click-afara + `Esc` (focus readus pe `☰`). Fara overlay.
|
||||
- [ ] Continut autentificat: Cont, Integrare, Nomenclator, **Panou admin** (doar `is_admin`), separator,
|
||||
**Iesi din cont** (form `POST /logout` cu `csrf_token`).
|
||||
- [ ] `base.html` primeste `is_authenticated`/`is_admin`/`csrf_token` printr-un helper de context partajat (un
|
||||
singur loc); **defensiv**: lipsa cheilor → meniu in stare neautentificata, nu eroare.
|
||||
- [ ] Pe login/signup meniul nu arata linkuri de cont/logout.
|
||||
- [ ] `python3 -m pytest tests/test_web_header_menu.py -q` verde.
|
||||
- **Verificare E2E**: browser — `☰` deschide/inchide (Esc + click-afara), linkurile navigheaza corect, logout iese;
|
||||
pe login meniul nu expune cont.
|
||||
|
||||
### US-007: Tab-bar redus la Acasa · Mapari
|
||||
**Ca** operator **vreau** un tab-bar doar cu suprafetele de lucru zilnic **pentru ca** Cont/Integrare/Nomenclator
|
||||
traiesc acum in meniul de cont.
|
||||
|
||||
- **Depinde de**: US-006
|
||||
- **Fisiere**: `app/web/templates/dashboard.html`, `tests/test_web_dashboard_tabs.py` (~2 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_dashboard_tabs.py` — `test_tabbar_doar_acasa_mapari`,
|
||||
`test_fragmente_mutate_inca_accesibile` (`/_fragments/{cont,integrare,nomenclator}` raman 200 + deep-link `?tab=`)
|
||||
- **Acceptance criteria**:
|
||||
- [ ] `tabs` in `dashboard.html` = doar `acasa`, `mapari`; badge-urile de contoare raman pe Mapari.
|
||||
- [ ] Logout + link admin ad-hoc din coltul dreapta-sus al dashboard-ului eliminate (mutate in meniul US-006).
|
||||
- [ ] Rutele `/_fragments/cont|integrare|nomenclator` + `?tab=` raman valide (accesate din meniu); zero rute moarte,
|
||||
zero 404 pe deep-link existent.
|
||||
- [ ] Navigarea ARIA cu sageti pe tab-bar ramane corecta cu 2 tab-uri.
|
||||
- [ ] `python3 -m pytest tests/test_web_dashboard_tabs.py -q` verde.
|
||||
- **Verificare E2E**: browser — tab-bar arata doar Acasa/Mapari; deschizi Nomenclator/Cont/Integrare din `☰`,
|
||||
deep-link `/?tab=integrare` inca functioneaza.
|
||||
|
||||
### US-008: Rute admin pentru ciclul de viata al conturilor (block/archive/delete + bulk)
|
||||
**Ca** admin **vreau** endpointuri care blocheaza/arhiveaza/sterg conturi, individual si in bulk **pentru ca**
|
||||
panoul are nevoie sa actioneze pe selectie.
|
||||
|
||||
- **Depinde de**: US-004
|
||||
- **Fisiere**: `app/web/routes.py` (rute `/admin/*`), `tests/test_admin_lifecycle.py` (~2 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_admin_lifecycle.py` — `test_block_archive_delete_single`,
|
||||
`test_bulk_pe_lista_account_id`, `test_bulk_sare_contul_dev`, `test_non_admin_403`, `test_csrf_obligatoriu`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] Rute `POST /admin/block`, `/admin/archive`, `/admin/delete` (+ pastreaza `activate`) sub `require_admin` + CSRF,
|
||||
cu PRG (redirect inapoi la `/admin`), folosind helperii din US-004.
|
||||
- [ ] Accepta o LISTA de `account_id` (bulk) si o singura tinta (per-rand) prin acelasi handler.
|
||||
- [ ] Contul dev `id=1` e sarit in bulk (nu eroare) si refuzat individual; `delete` cere confirmare la nivel UI
|
||||
(US-009) si purjeaza datele conform retentiei (GDPR/L.142).
|
||||
- [ ] Non-admin → 403; lipsa CSRF → respins.
|
||||
- [ ] `python3 -m pytest tests/test_admin_lifecycle.py -q` verde.
|
||||
- **Verificare E2E**: POST autentificat ca admin pe fiecare verb (single + bulk) muta starea corect; contul dev neatins.
|
||||
|
||||
### US-009: Panou admin — selectie cu bife + bara bulk + actiuni per-rand
|
||||
**Ca** admin **vreau** sa selectez conturi si sa aplic actiuni pe selectie **pentru ca** activarea/blocarea una
|
||||
cate una e lenta.
|
||||
|
||||
- **Depinde de**: US-008
|
||||
- **Fisiere**: `app/web/templates/admin.html`, `tests/test_web_admin.py` (~2 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_admin.py` — `test_admin_coloana_selectie_si_master`,
|
||||
`test_bara_bulk_cu_cele_4_verbe`, `test_actiuni_per_rand`, `test_fara_nota_cont_dev`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] Tabel conturi in asteptare (si analog active): coloana checkbox + master "Selecteaza tot"
|
||||
(`aria-label` per rand + master).
|
||||
- [ ] Bara de actiuni bulk (ascunsa pana la selectie) cu **Activeaza / Blocheaza / Arhiveaza / Sterge**;
|
||||
`Sterge` cu `hx-confirm`/dialog; trimite lista de `account_id` la rutele US-008.
|
||||
- [ ] Actiuni per-rand (kebab `...`) cu aceleasi verbe; `Sterge` cu `color:var(--err)` + confirmare.
|
||||
- [ ] Nota "Cont dev implicit (id=1)" **eliminata** din pagina (protectia ramane in cod, US-004/US-008).
|
||||
- [ ] `python3 -m pytest tests/test_web_admin.py -q` verde; AA light+dark; tabel in grila standard.
|
||||
- **Verificare E2E**: browser ca admin — bifezi 2 conturi, bara bulk apare cu numarul selectat, Arhiveaza muta randurile;
|
||||
Sterge cere confirmare; contul dev nu poate fi selectat-distrus.
|
||||
|
||||
## 4. Riscuri
|
||||
|
||||
- **Schema `accounts.status` (US-004)** = singura schimbare de date. Mitigare: migrare defensiva idempotenta (pattern
|
||||
`_migrate` deja folosit la `accounts.active`/`users.is_admin`), derivata din `active`, cu echivalenta `active=1 ⇔
|
||||
status='active'` pana cand `active` poate fi retras intr-o livrabila viitoare. Testele worker existente sunt plasa.
|
||||
- **`base.html` partajat (US-006)**: e folosit de login/signup/admin/dashboard. Risc de context lipsa → meniu rupt.
|
||||
Mitigare: helper de context partajat + defaulturi defensive (lipsa → neautentificat), test pe toate cele 4 pagini.
|
||||
- **Coliziune pe fisiere intre stories** (lectia 5.1 clobber): US-006 si US-007 ating ambele zona de navigare
|
||||
(`base.html` vs `dashboard.html`, plus scoaterea logout-ului ad-hoc din `dashboard.html`). Mitigare: US-007 depinde
|
||||
de US-006 si ruleaza secvential (acelasi teammate recomandat), nu in worktree-uri paralele.
|
||||
- **`delete` cont (US-008)**: actiune distructiva ireversibila. Mitigare: confirmare UI obligatorie, contul dev protejat,
|
||||
purjare aliniata la retentia existenta (T16), nu stergere ad-hoc de date conexe fara plan.
|
||||
- **Macro autosend (US-003)**: orice schimbare de `name`/semantica ar rupe tacit clasificarea queued/needs_review.
|
||||
Mitigare: test care asereaza `name="auto_send"` + prezenta, plus `test_import_e2e` ramane verde.
|
||||
|
||||
## 5. Intrebari deschise — REZOLVATE (aprobare utilizator 2026-06-23)
|
||||
|
||||
- **Stergere cont** → **soft delete**: `status='deleted'`, scos imediat din toate listele, date purjate de jobul
|
||||
de retentie existent (T16, GDPR/L.142). NU hard DELETE imediat (auditabil + fereastra de revenire).
|
||||
- **Blocheaza vs Arhiveaza** → `blocked` = suspendare **reversibila**, contul ramane in liste, marcat vizibil,
|
||||
worker nu trimite; `archived` = **scos din listele active**, date pastrate read-only. Etichete confirmate.
|
||||
- **Comutatorul In coada** → **radio etichetat Auto / Manual** (explicit), nu switch on/off.
|
||||
|
||||
## 6. Valuri de executie (graful de dependente)
|
||||
|
||||
```
|
||||
Val 1: [US-001] [US-002] [US-003] [US-004] ← fara dependente, fisiere disjuncte → paralel
|
||||
Val 2: [US-005] ← dep US-003 (macro)
|
||||
[US-006] ← fara dep (navigare/header)
|
||||
[US-008] ← dep US-004 (rute admin pe model stare)
|
||||
Val 3: [US-007] ← dep US-006 (acelasi fisier de navigare → secvential, NU worktree paralel)
|
||||
[US-009] ← dep US-008 (UI admin pe rutele de lifecycle)
|
||||
```
|
||||
Reference in New Issue
Block a user