feat(5.12): modal editare + cont obligatoriu la import; design.md + PRD 5.13 revizuit (/autoplan)
5.12 (livrat): editare in modal a randurilor de preview, cont obligatoriu inainte de import, formular editare extras (_form_editare, _editare_preview_modal), plus suita de teste aferenta (preview edit/compact, mapare op, form editare, signup, admin panel). Design + planificare: - docs/design.md: sistem de design (tokeni, breakpoints, scara control, componente, a11y). - docs/prd/prd-5.12-* si prd-5.13-* (5.13 cu raport /autoplan: CEO+Design+Eng, audit trail). Curatare: sterse PNG-urile de test/mockup temporare din radacina. Nota: implementarea CSS 5.13 (responsive compact + sistem butoane) NU e inca facuta — planul revizuit cere refactorul testelor fragile din test_web_responsive.py INAINTE de CSS. 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
232
docs/design.md
Normal file
232
docs/design.md
Normal file
@@ -0,0 +1,232 @@
|
||||
# design.md — Sistemul de design Gateway RAR AUTOPASS
|
||||
|
||||
Sursa de adevar pentru deciziile vizuale ale aplicatiei web. **Orice plan de design
|
||||
(`/plan-design-review`, `/design-consultation`, `/design-review`) si orice modificare
|
||||
de UI trebuie sa porneasca de aici.** Unde un mockup sau o propunere difera de acest
|
||||
document, documentul are dreptate (sau se actualizeaza explicit, intr-un commit separat).
|
||||
|
||||
Limba UI: romana, fara diacritice in cod/atribute tehnice, cu diacritice acceptate in
|
||||
textul vizibil (fontul are `latin-ext`). Fara emoji.
|
||||
|
||||
CSS-ul traieste inline in `app/web/templates/base.html` (un singur `<style>`). Nu exista
|
||||
build step. Tokenii de mai jos sunt variabile CSS reale definite acolo.
|
||||
|
||||
---
|
||||
|
||||
## 1. Principii
|
||||
|
||||
1. **Compact, nu inghesuit.** Densitate mare de informatie utila, dar cu ritm si spatiu.
|
||||
Pe ecrane mici aratam ESENTIALUL, nu tot ce incape pe desktop. Restul intra in detaliu
|
||||
(modal) sau in linii secundare mici.
|
||||
2. **Compactarea e si pentru desktop.** Cand o componenta e mai lizibila compacta (ex.
|
||||
wizard-ul de import), forma compacta se aplica pe toate latimile, nu doar pe mobil.
|
||||
3. **Mobile-first ca verificare, nu ca scuza.** Orice ecran trebuie sa fie complet
|
||||
utilizabil la 360px latime, fara scroll orizontal de pagina si fara text rupt vertical.
|
||||
4. **Starea prin text + culoare, niciodata doar culoare** (accesibilitate; pill-uri cu
|
||||
eticheta umana, glife ✓/✗ cu text).
|
||||
5. **O singura zona de actiune dominanta pe ecran.** Un singur buton primar vizibil per
|
||||
context (ex. „Trimite la RAR"). Restul sunt secundare/ghost.
|
||||
6. **Tinte de atins generoase pe touch, sobre pe desktop.** Vezi scara de control.
|
||||
|
||||
---
|
||||
|
||||
## 2. Tokeni
|
||||
|
||||
### 2.1 Culoare (variabile CSS, 4 teme)
|
||||
|
||||
Paleta e definita pe `:root` (dark, default) si suprascrisa pe `[data-theme="light|petrol"]`.
|
||||
`auto` se rezolva la light/dark dupa `prefers-color-scheme`. **Nu folosi culori hardcodate;
|
||||
foloseste mereu variabilele.** Pentru tente, `color-mix(in srgb, var(--x) N%, transparent|var(--card))`.
|
||||
|
||||
| Token | Rol | dark | light | petrol |
|
||||
|-------|-----|------|-------|--------|
|
||||
| `--bg` | fundal pagina | `#0f1218` | `#f5f7fa` | `#0e1416` |
|
||||
| `--card` | suprafata card/meniu | `#181c24` | `#ffffff` | `#161e20` |
|
||||
| `--ink` | text principal | `#e6e9ef` | `#1a1d24` | `#e6e9ef` |
|
||||
| `--muted` | text secundar | `#8b93a7` | `#5c6473` | `#8b93a7` |
|
||||
| `--line` | borduri/separatoare | `#262b36` | `#e2e5ea` | `#232c2e` |
|
||||
| `--accent` | actiune primara / link | `#2E74D6` | `#1F66C9` | `#0E7C7B` |
|
||||
| `--ok` | succes / trimis | `#2FBF8F` | `#15803d` | `#2FBF8F` |
|
||||
| `--warn` | atentie / de verificat | `#E0A93B` | `#b45309` | `#E0A93B` |
|
||||
| `--err` | eroare / distructiv | `#E05D5D` | `#dc2626` | `#E05D5D` |
|
||||
|
||||
Accentul light (`#1F66C9`) e ales pentru contrast AA pe alb (5.51:1). Orice text colorat
|
||||
pe `--card` trebuie sa ramana >= 4.5:1 in toate cele 3 palete.
|
||||
|
||||
### 2.2 Tipografie
|
||||
|
||||
Font: **IBM Plex Sans** (UI), **IBM Plex Mono** (VIN, coduri, ID-uri). Self-hosted, `latin-ext`
|
||||
pentru diacritice, `font-display:swap`. Greutati disponibile: 400, 500, 700.
|
||||
|
||||
Scara (px / weight) — folosita consecvent, nu inventa marimi noi:
|
||||
|
||||
| Rol | size | weight | note |
|
||||
|-----|------|--------|------|
|
||||
| Titlu pagina (header) | 20 (desktop) / 17 (mobil) | 700 | letter-spacing -.01em |
|
||||
| Titlu sectiune / card | 15 | 600 | `h2.sec` |
|
||||
| Subtitlu / `h3` | 14 | 600 | |
|
||||
| Corp / controale | 14 | 400/500 | inputuri, butoane |
|
||||
| Eticheta camp, link card | 13 | 400/500 | `.cardlink`, label form |
|
||||
| Secundar / meta | 12 | 400 | text muted, sub-linii |
|
||||
| Micro (coduri, badge) | 11 | 500/700 | mono pentru coduri |
|
||||
|
||||
Numerele tabulare: `font-variant-numeric: tabular-nums` pe tabele (aliniere coloane).
|
||||
Coduri/VIN/ID: `font-family: "IBM Plex Mono"`.
|
||||
|
||||
### 2.3 Spatiere
|
||||
|
||||
Scara 4px: **4, 6, 8, 10, 12, 14, 16, 20, 24**. Padding card desktop `16px 20px`, mobil `16px`.
|
||||
Gap intre carduri `14–16px`. Gap intre controale pe o linie `8–12px`.
|
||||
|
||||
### 2.4 Radius
|
||||
|
||||
| Valoare | Uz |
|
||||
|---------|-----|
|
||||
| `6px` | controale: butoane, input, select |
|
||||
| `7–8px` | carduri-rand, meniuri, butoane icon |
|
||||
| `10px` | carduri de sectiune |
|
||||
| `12px` | modal (desktop) |
|
||||
| `99px` | pill-uri, badge-uri, bara de progres |
|
||||
|
||||
### 2.5 Elevatie
|
||||
|
||||
Plat implicit (border `1px solid var(--line)`). Umbra DOAR pentru elemente plutitoare:
|
||||
meniuri/kebab `0 8px 24px rgba(0,0,0,.18)`, modal `0 16px 48px rgba(0,0,0,.35)`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Breakpoints
|
||||
|
||||
Un singur prag conceptual mobil la **768px**; un prag de densitate la **1024px**.
|
||||
|
||||
| Interval | Numit | Regula |
|
||||
|----------|-------|--------|
|
||||
| `>= 1024px` | desktop | layout complet; aplica si compactarile globale (wizard) |
|
||||
| `768–1024px` | tableta | **card-uri** pentru tabelele actionabile (preview, mapari), 2 pe rand; tabelele dense read-only raman cu scroll contained |
|
||||
| `< 768px` | mobil | un card pe rand, o coloana, tinte touch 44px |
|
||||
|
||||
CSS custom properties NU functioneaza in `@media`; pragul se scrie literal
|
||||
(`@media (max-width:767px)`, `@media (max-width:1024px)`). Reutilizeaza aceste praguri,
|
||||
nu introduce altele noi.
|
||||
|
||||
---
|
||||
|
||||
## 4. Scara de control (tinte de atins)
|
||||
|
||||
| Context | min-height | Uz |
|
||||
|---------|-----------|-----|
|
||||
| Touch (`< 768px`) | **44px** | orice buton/link/select interactiv |
|
||||
| Desktop standard | **36px** | butoane, icon-btn, cardlink, intrari meniu |
|
||||
| Compact (desktop) | **32px** | kebab summary, butoane pager, pill-cat |
|
||||
|
||||
Pe desktop nu fortam 44px peste tot (devine greoi); pe mobil da. Latimea butoanelor:
|
||||
**auto, nu full-width**, cu exceptia butonului primar de actiune dintr-o bara dedicata
|
||||
(ex. „Trimite la RAR" in bara sticky, „Salveaza si continua").
|
||||
|
||||
---
|
||||
|
||||
## 5. Componente
|
||||
|
||||
### 5.1 Butoane — sistem unificat
|
||||
|
||||
Patru variante. Toate: `font:inherit` (IBM Plex Sans), `font-weight:500`, `border-radius:6px`,
|
||||
`padding:8px 14px` (desktop), tinta conform scarii de control. Tranzitie `filter/background .15s`.
|
||||
|
||||
| Varianta | Clasa | Fundal | Text | Bordura | Uz |
|
||||
|----------|-------|--------|------|---------|-----|
|
||||
| Primar | `.btn` (default `<button>`) | `--accent` | `#fff` | `--accent` | actiunea dominanta |
|
||||
| Secundar | `.btn-secondary` | transparent | `--ink` | `--line` | actiuni neutre (Editeaza, Filtreaza) |
|
||||
| Ghost | `.btn-ghost` | transparent | `--accent` | transparent | actiuni tertiare/linkuri-actiune |
|
||||
| Distructiv | `.btn-danger` | transparent | `--err` | `--err` | Sterge; hover → fundal `--err`, text `#fff` |
|
||||
|
||||
**Iconite in butoane:** label text + iconita optionala la stanga (16px, `fill:currentColor`,
|
||||
`aria-hidden`). **Butoanele icon-only sunt interzise pentru actiuni cu text echivalent**
|
||||
(ex. Salveaza/Sterge in tabele) — au cauzat „bloc colorat cu iconita invizibila" pe mobil.
|
||||
Cand spatiul e strans, foloseste un grup compact `[ Salveaza ] [ Sterge ]` cu text scurt,
|
||||
nu doua blocuri full-width unul sub altul. Icon-only ramane permis DOAR pentru: comutator
|
||||
tema, hamburger cont, kebab, inchidere modal — toate cu `aria-label`.
|
||||
|
||||
Stari: `:hover` → `filter:brightness(1.08)` (primar) sau `background:var(--line)` (secundar/ghost);
|
||||
`:focus-visible` → `outline:2px solid var(--accent); outline-offset:2px`; `:disabled` →
|
||||
`opacity:.45; cursor:default`. Stare „dirty" (modificari nesalvate) pe butonul de salvare:
|
||||
fundal `--accent`.
|
||||
|
||||
### 5.2 Card
|
||||
|
||||
`background:var(--card); border:1px solid var(--line); border-radius:10px`. Carduri de
|
||||
sectiune cu titlu `h2.sec` (15/600). Carduri-rand (lista pe mobil/tableta) cu radius 8–10px,
|
||||
stivuite vertical, gap intern 7–8px.
|
||||
|
||||
### 5.3 Tabel → card-uri (responsive)
|
||||
|
||||
Tabelele **actionabile** (Trimiteri, Preview import, Mapari) devin card-uri sub 1024px.
|
||||
Regula de card (vezi §3): NU folosi pattern-ul „eticheta cu `min-width` fix + valoare in
|
||||
flex" — sparge valorile pe verticala. In schimb:
|
||||
|
||||
- **Stivuieste**: eticheta mica deasupra valorii (`display:block`), SAU
|
||||
- **Card semantic**: linie titlu (identificator + stare), linii secundare mici. Preferat
|
||||
pentru liste lungi (Trimiteri, Preview).
|
||||
|
||||
Sub 768px: un card pe rand. 768–1024px: grid 2 carduri pe rand
|
||||
(`grid-template-columns:repeat(2,1fr); gap:12px`).
|
||||
|
||||
Tabelele **dense read-only** (Jurnal, Nomenclator, Admin) raman tabel cu scroll orizontal
|
||||
**contained in card** (`.tablewrap { overflow-x:auto }`), nu se cardifica.
|
||||
|
||||
### 5.4 Stepper / wizard import — COMPACT pe toate latimile
|
||||
|
||||
Patru pasi: Incarca fisier · Potriveste coloanele · Verifica · Confirma trimiterea.
|
||||
|
||||
- **Desktop**: o bara slim orizontala — pastila numar (sau ✓) + titlu scurt pe O linie,
|
||||
pasul activ evidentiat. **Fara paragraf de ajutor inalt** in bara (ajutorul, daca e
|
||||
nevoie, e text mic sub bara, o singura linie). Inaltime tinta ~44px, nu blocuri inalte.
|
||||
- **Tableta/mobil**: colapsat la o singura linie — `Pasul N din 4 · <Titlu>` + bara de
|
||||
progres (`height:5px; border-radius:99px`, umplere `--accent` la `N/4`). Ajutorul pasului
|
||||
activ sub bara, text 12px muted.
|
||||
|
||||
Niciodata 4 coloane egale cu text — se taie/se rupe pe ecrane inguste.
|
||||
|
||||
### 5.5 Pill-uri si badge-uri
|
||||
|
||||
Stare: `.pill` 12px, radius 99px, cu clasa de culoare (`.s-ok/.s-warn/...`). Filtre de
|
||||
stare: `.pill-cat` (contur inactiv, umplere activa pe culoarea categoriei). Badge contor:
|
||||
cerc 18px, `--err`, text alb 11/700.
|
||||
|
||||
### 5.6 Formulare
|
||||
|
||||
Label 12–13px muted deasupra controlului. Input/select: `--bg`, bordura `--line`, radius 6px,
|
||||
padding `7px 10px`. Pe mobil controalele de formular din sectiunile de continut sunt
|
||||
full-width (tinta 44px). Pe desktop pastreaza latimi rezonabile (`select` max ~340px).
|
||||
|
||||
### 5.7 Modal
|
||||
|
||||
Desktop: dialog centrat `max-width:680px`, radius 12px, backdrop `rgba(0,0,0,.55)`,
|
||||
scroll intern. Mobil (`< 768px`): full-screen (fara colturi/umbra), buton inchidere 44px,
|
||||
focus-trap + scroll-lock + `inert` pe `<main>`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Accesibilitate (obligatoriu)
|
||||
|
||||
- Contrast text >= 4.5:1 (normal), >= 3:1 (>=18px bold) in toate cele 3 palete.
|
||||
- Stare comunicata prin text, nu doar culoare.
|
||||
- `:focus-visible` vizibil pe tot ce e interactiv (outline `--accent`).
|
||||
- Tinte touch >= 44px pe mobil.
|
||||
- Icon-only obligatoriu cu `aria-label`; SVG decorativ `aria-hidden="true"`.
|
||||
- Modale: `role="dialog"`, `aria-modal`, focus-trap, focus return pe trigger.
|
||||
- `prefers-reduced-motion`: scurteaza/elimina tranzitiile non-esentiale.
|
||||
|
||||
---
|
||||
|
||||
## 7. Pentru planurile de design (cum se foloseste acest fisier)
|
||||
|
||||
Inainte de orice propunere vizuala:
|
||||
1. Citeste acest fisier integral. Foloseste DOAR tokenii de aici (culoare, type, radius, spatiu).
|
||||
2. Verifica fiecare ecran la 360 / 768 / 1024 / 1280px.
|
||||
3. Aplica compactarile globale (wizard, butoane) si pe desktop, nu doar pe mobil.
|
||||
4. Respecta „un singur primar per context" si scara de control.
|
||||
5. Daca o propunere cere un token nou (culoare/marime/radius), justifica si adauga-l AICI
|
||||
in acelasi PR — nu introduce valori ad-hoc in template.
|
||||
|
||||
Stadiul de implementare a regulilor responsive se urmareste in PRD-ul activ
|
||||
(`docs/prd/prd-5.13-responsive-compact.md`) si in `docs/ROADMAP.md`.
|
||||
598
docs/prd/prd-5.12-editare-modal-cont-obligatoriu-import.md
Normal file
598
docs/prd/prd-5.12-editare-modal-cont-obligatoriu-import.md
Normal file
@@ -0,0 +1,598 @@
|
||||
<!-- /autoplan restore point: /home/claude/.gstack/projects/romfast-rar-autopass/main-autoplan-restore-20260626-201417.md -->
|
||||
# PRD 5.12 — Editare unificata in modal + cont cu companie/email/CUI obligatorii + rafinari import (calendar data, mapare cu antet+prima inregistrare, un singur Salveaza, preview compact) + responsive tableta/mobil
|
||||
|
||||
**Stare**: inchis (verify-pass 2026-06-26; 8 stories TDD prin agent team, VERIFY context curat PASS + 1 FAIL remediat, /code-review high 3 buguri reparate; regresie 987 passed/1 skipped/0 failed; asteapta confirmare commit — poarta umana)
|
||||
|
||||
> Proces complet: `docs/ROADMAP.md` §5. Contractul RAR (sursa de adevar de contract):
|
||||
> `docs/api-rar-contract.md`. Starea trece: `draft → aprobat → in-executie → verify-pass → inchis`
|
||||
> (actualizata de lead). Acest PRD nu repeta strategia/contractul — le linkeaza.
|
||||
>
|
||||
> Continua 5.11 ([prd-5.11](prd-5.11-ux-import-compact-preview-navigatie.md)). **Backendul de
|
||||
> trimitere (worker, masina de stari de trimitere, idempotenta, contract RAR) ramane NEATINS.**
|
||||
> Atingeri de schema permise (ambele coloane noi, migrare defensiva `_migrate`, ca la 3.3b/3.5/3.6):
|
||||
> `accounts.email` (US-001) si `import_rows.reviewed` (US-007, marcaj „verificat" per rand de preview).
|
||||
> Vezi Non-Goals.
|
||||
|
||||
## 1. Obiectiv
|
||||
|
||||
Continuam dogfooding-ul de first-run inceput in 5.11. Sase frictiuni confirmate E2E in browser
|
||||
(Playwright pe `exemple/prezentari_test.csv`, 2026-06-26) — toate UI/UX, plus o regula de date pe
|
||||
conturi:
|
||||
|
||||
1. **Editarea unui rand din preview e rupta vizual si arunca o eroare JS.** Modul de editare inline
|
||||
(`tr.preview-edit` cu `display:block` intr-un tabel `table-layout:fixed`) colapseaza coloanele —
|
||||
antetul si formularul se randeaza pe verticala, caracter cu caracter (reprodus identic cu
|
||||
`image copy.png`). La click pe **Anuleaza** se arunca in consola
|
||||
`TypeError: Cannot read properties of null (reading 'htmx-internal-data')` (reprodus live).
|
||||
Decizie utilizator: **editarea trebuie sa fie un MODAL, ca la Trimiteri, refolosind ACELASI
|
||||
formular** (fara cod duplicat).
|
||||
2. **Data prestatiei se scrie doar manual** (input text cu hint `YYYY-MM-DD`). Trebuie sa se poata
|
||||
alege si din **calendar** (`<input type="date">` nativ, decizie utilizator — zero dependinte JS).
|
||||
3. **Conturile nu au reguli minime de identitate.** Confirmat in baza: toate conturile au `cui=NULL`,
|
||||
iar conturile create din CLI/teste nu au niciun utilizator → fara email. Decizie utilizator:
|
||||
un cont inregistrat trebuie sa aiba **obligatoriu companie, email si CUI**.
|
||||
4. **Maparea coloanelor nu arata datele.** Pasul 2 listeaza nume de coloana + 2 exemple stivuite, dar
|
||||
nu se vede clar **capul de tabel (numele coloanelor) + valorile primei inregistrari**, ca operatorul
|
||||
sa stie ce mapeaza.
|
||||
5. **Panoul „Operatii de mapat la cod RAR" cere un Salveaza per rand.** La un fisier cu N operatii
|
||||
nemapate sunt N butoane „Salveaza" si N submit-uri. Trebuie **un singur buton Salveaza** care
|
||||
salveaza toate maparile odata.
|
||||
6. **Tabelul de preview (pasul 3) nu e compact si are o coloana neclara.** Randurile sunt foarte inalte
|
||||
(VIN-ul se sparge pe verticala), iar coloana **„Verificat?"** nu are sens evident in acest pas
|
||||
(operatorul nu intelege bifa). Trebuie lista mai compacta si coloana clarificata/eliminata.
|
||||
7. **Pe tableta si mobil interfata arata prost si articolele din header se suprapun.** Header-ul are grila
|
||||
desktop `1fr auto 1fr` (`min-height:92px`, logo 60px) si un singur prag mobil `@media (max-width:767px)`,
|
||||
dar **nimic pentru tableta (768–1024px)** — acolo logo + titlu + badge mediu + comutator tema + versiune
|
||||
+ hamburger se inghesuie si se suprapun. Tot fluxul (header, import, preview, modal, Trimiteri, Mapari,
|
||||
Cont) trebuie **compact, functional si ergonomic** pe tableta si telefon, cu tinte touch si fara suprapuneri.
|
||||
|
||||
Toate sunt **UI/UX**, cu o singura exceptie de date controlata: identitatea contului (companie/email/CUI
|
||||
obligatorii, US-001/002).
|
||||
|
||||
## 2. Non-Goals (anti scope-creep)
|
||||
|
||||
- **Nu** atingem worker-ul, reconcilierea, idempotenta, `build_key`, masina de stari de trimitere sau
|
||||
contractul RAR.
|
||||
- **Nu** schimbam canalul API (`POST /v1/prezentari` / `/valideaza`) si nici logica de mapare
|
||||
(`mapping.py` `resolve_prestatii`). Maparea operatie→cod ramane neschimbata; doar UI-ul de mapare din
|
||||
pasul de import se reorganizeaza (US-005) si reuseaza `save_mapping`/`reresolve_account` existente.
|
||||
- **Nu** stergem coloanele DB `auto_send` (deja neutralizate in 5.11) si nu reintroducem conceptul.
|
||||
- **Nu** schimbam stocarea editarii de preview: ramane `import_rows.override_json` (Approach B din 3.6),
|
||||
ruta `POST /_import/{id}/rand/{i}/editeaza` ramane sursa de adevar; doar **suprafata** de editare trece
|
||||
din rand-inline in modal.
|
||||
- **Nu** facem editare in bloc / multi-rand si nici editare a operatiei/codului RAR din modalul de rand
|
||||
(codul se mapeaza din panoul „Operatii de mapat", ca azi).
|
||||
- **Nu** schimbam fluxul de login/parola; un cont poate avea in continuare mai multe loginuri (`users`),
|
||||
dar primeste un email canonic de contact pe `accounts` (US-001).
|
||||
- **Nu** rescriem validarea de continut (`validation.py`); `<input type="date">` produce tot `YYYY-MM-DD`,
|
||||
acceptat azi.
|
||||
|
||||
## 3. Stories atomice
|
||||
|
||||
> Fiecare story: cea mai mica unitate care lasa sistemul functional. Backend + UI pentru acelasi
|
||||
> comportament = 2 stories. Toate rutele web noi sub `require_login`, scoped pe contul din sesiune
|
||||
> (404 cross-account), CSRF pe toate POST-urile.
|
||||
>
|
||||
> **Cerinta transversala (toate story-urile cu UI): responsive obligatoriu.** Fiecare suprafata noua/atinsa
|
||||
> (US-002..007) se verifica E2E pe **3 viewport-uri: desktop (≥1280px), tableta (768–1024px) si mobil
|
||||
> (≤767px / ~390px)** — fara overflow orizontal (`scrollWidth <= clientWidth`), fara suprapuneri, tinte
|
||||
> touch ≥44px, modal full-screen pe mobil. US-008 acopera header-ul + cadrul global; fiecare story isi
|
||||
> verifica propria suprafata pe cele 3 viewport-uri.
|
||||
|
||||
### US-001: Backend — companie/email/CUI obligatorii pe cont (`accounts.email` + validari)
|
||||
**Ca** administrator al gateway-ului **vreau** ca orice cont sa aiba companie, email si CUI **pentru ca**
|
||||
azi conturile pot exista fara email (CLI/teste) si fara CUI, deci nu pot fi identificate fiscal/contactate.
|
||||
|
||||
- **Depinde de**: —
|
||||
- **Fisiere**: `app/schema.sql` (coloana `accounts.email` + `_migrate` defensiv), `app/accounts.py`
|
||||
(`create_account` accepta+valideaza `email`; helper `account_is_complete`), `app/web/auth_routes.py`
|
||||
(signup: CUI devine obligatoriu; scrie `accounts.email`), `tools/account.py` (CLI create cere
|
||||
`--email` + `--cui`), `tests/test_accounts.py`, `tests/test_signup.py` (~6 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_accounts.py` —
|
||||
`test_create_account_fara_email_ridica`, `test_create_account_fara_cui_ridica`,
|
||||
`test_email_normalizat_lowercase_trim`, `test_migrare_adauga_coloana_email_idempotent`,
|
||||
`test_account_is_complete_false_pe_legacy_incomplet`;
|
||||
`tests/test_signup.py` — `test_signup_fara_cui_422`, `test_signup_scrie_email_pe_account`,
|
||||
`test_signup_cui_existent_mesaj_prietenos` (NU mesajul tehnic cu `activate --account`).
|
||||
- **Acceptance criteria**:
|
||||
- [x] Migrare: `accounts.email TEXT` (nullable la nivel de schema pentru conturile legacy), `_migrate`
|
||||
defensiv idempotent (ca `users.is_admin` la 3.3b). Contul de sistem id=1 ramane fara email (exceptat).
|
||||
- [x] `create_account(conn, name, cui, email, active)` — `name`/`cui`/`email` goale → `ValueError`
|
||||
cu cauza+fix (catalog `errors.py` daca exista cod potrivit); `email` normalizat (trim+lower);
|
||||
`cui` normalizat (trim+upper, ca azi). CUI duplicat → mesajul existent.
|
||||
- [x] Signup web: `cui` devine **obligatoriu** (azi optional); la succes scrie `accounts.email = email`-ul
|
||||
utilizatorului. Lipsa CUI → re-randare formular cu eroare (422), pastrand campurile.
|
||||
- [x] **CUI duplicat la signup = mesaj prietenos, NU cel tehnic** (decizie user 2026-06-26, optiunea 1):
|
||||
„Aceasta firma (CUI …) e deja inregistrata. Cere accesul de la administratorul contului." — fara
|
||||
referinta la CLI `activate --account`. **Model: 1 firma = 1 cont = 1 login**; fluxul de
|
||||
invitatie/alaturare a unui al doilea email pe aceeasi firma e deferit la TODOS (optiunea 2).
|
||||
- [x] **Canal de contact concret in mesaj** (T3 gate /autoplan, aprobat 2026-06-26): mesajul include un
|
||||
email/canal de suport configurabil din settings (ex. `support_email`); daca setarea lipseste,
|
||||
fallback la formularea de mai sus. Operatorul primeste un pas urmator real, nu doar „cere accesul".
|
||||
Nu mai lasam mesajul tehnic ridicat de `create_account` sa ajunga verbatim in signup — detectam
|
||||
CUI duplicat in handler-ul de signup si compunem mesajul prietenos acolo (NU `error=str(exc)`).
|
||||
- [x] CLI `tools/account.py create` cere `--email` + `--cui` (refuza fara ele); `--with-key` neschimbat.
|
||||
- [x] `account_is_complete(row)` (companie + email + CUI ne-goale) — helper pur, fara efecte.
|
||||
- [x] **NU** atinge `users`, `submissions`, worker-ul sau idempotenta.
|
||||
- **Verificare E2E**: TestClient — signup fara CUI → 422; signup complet → `accounts.email` populat;
|
||||
`create_account` fara email/cui → ValueError.
|
||||
|
||||
### US-002: UI — gate de activare + pagina Cont editeaza companie/email/CUI + banner legacy
|
||||
**Ca** operator/administrator **vreau** sa vad si sa completez companie/email/CUI **pentru ca**
|
||||
conturile incomplete (legacy) trebuie aduse la regula fara re-inregistrare.
|
||||
|
||||
- **Depinde de**: US-001
|
||||
- **Fisiere**: `app/web/templates/_cont.html` (sectiune noua „Date firma"), `app/web/routes.py`
|
||||
(ruta `POST /cont/date-firma` scoped sesiune + CSRF; context `account_meta`+`cont_incomplet`),
|
||||
`app/web/templates/admin.html` + `app/web/routes.py` (gate activare pe `account_is_complete`),
|
||||
`app/web/templates/_banner.html` sau `_acasa.html` (banner „Completeaza datele firmei"),
|
||||
`tests/test_web_cont.py`, `tests/test_admin.py` (~6 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_cont.py` —
|
||||
`test_cont_afiseaza_companie_email_cui`, `test_post_date_firma_actualizeaza`,
|
||||
`test_post_date_firma_cui_duplicat_eroare`, `test_banner_cont_incomplet_pe_legacy`;
|
||||
`tests/test_admin.py` — `test_activare_cont_incomplet_refuzata`.
|
||||
- **Acceptance criteria**:
|
||||
- [x] `_cont.html` are o sectiune „Date firma" (deasupra cheii API) cu companie + email + CUI editabile,
|
||||
prefilled din `accounts`; `POST /cont/date-firma` valideaza (reuse `create_account`-style) + CSRF +
|
||||
scoped sesiune; eroare pe CUI duplicat / camp gol, mesaj 3-niveluri.
|
||||
- [x] Banner ne-blocant „Completeaza datele firmei (email/CUI)" pe Acasa cand `account_is_complete` e fals;
|
||||
dispare dupa completare. NU blocheaza importul/uploadul.
|
||||
- [x] In panoul admin, butonul **Activeaza** e dezactivat (cu tooltip) pe conturi incomplete —
|
||||
nu activam la RAR un cont fara identitate completa.
|
||||
- [x] Fara regresie pe rutele existente din `_cont.html` (cheie API, creds RAR).
|
||||
- **Verificare E2E**: browser pe `/?tab=cont` — completez email+CUI → banner dispare; admin nu poate
|
||||
activa un cont incomplet.
|
||||
|
||||
### US-003: UI — pasul „Potriveste coloanele" arata antet + prima inregistrare
|
||||
**Ca** operator **vreau** sa vad numele coloanelor din fisier si valorile primului rand **pentru ca**
|
||||
sa stiu exact ce date mapez la fiecare camp RAR.
|
||||
|
||||
- **Depinde de**: —
|
||||
- **Fisiere**: `app/web/templates/_mapcoloane.html`, `app/web/routes.py` (`web_upload_import` /
|
||||
`web_save_mapare_coloane` paseaza deja `sample_rows`; expune `prima_inregistrare`),
|
||||
`tests/test_web_mapcoloane.py` (~3 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_mapcoloane.py` —
|
||||
`test_mapcoloane_arata_cap_tabel_coloane`, `test_mapcoloane_arata_valori_prima_inregistrare`,
|
||||
`test_mapcoloane_fara_randuri_degradeaza` (fisier cu antet, fara randuri de date → fara crash).
|
||||
- **Acceptance criteria**:
|
||||
- [x] Deasupra (sau langa) randurile de mapare, un mic tabel orizontal cu **un cap de tabel = numele
|
||||
coloanelor din fisier** si **un rand = valorile primei inregistrari** (truncate la o lungime
|
||||
rezonabila, `title` pe valoare integrala). Foloseste `.tablewrap` pentru scroll orizontal pe mobil.
|
||||
- [x] Fiecare coloana din capul de tabel ramane vizual asociata cu select-ul ei de mapare (ex. aceeasi
|
||||
ordine, sau evidentiere la hover) — operatorul vede „coloana X (valoare „...") → campul canonic Y".
|
||||
- [x] Fisier fara randuri de date → se arata doar capul de tabel, fara „prima inregistrare" (fara crash).
|
||||
- [x] Nicio schimbare de backend de parsare/mapare; doar randare (datele exista deja in `sample_rows`).
|
||||
- **Verificare E2E**: browser pasul 2 — upload `prezentari_test.csv` → vad antetul real + valorile randului 1.
|
||||
|
||||
### US-004: UI+backend — un singur „Salveaza" pe „Operatii de mapat la cod RAR"
|
||||
**Ca** operator **vreau** sa salvez toate maparile de operatii dintr-un singur click **pentru ca**
|
||||
azi e cate un buton per operatie si trebuie apasat pe fiecare.
|
||||
|
||||
- **Depinde de**: —
|
||||
- **Fisiere**: `app/web/templates/_preview_import.html` (panoul de mapare → un singur `<form>`),
|
||||
`app/web/routes.py` (ruta noua `POST /_import/{id}/mapare-operatii` plural; pastreaza
|
||||
`mapare-operatie` singular pentru compat sau o inlocuieste — vezi AC), `tests/test_web_mapare_op.py`
|
||||
(~3 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_mapare_op.py` —
|
||||
`test_mapare_operatii_salveaza_multiple_intr_un_post`,
|
||||
`test_mapare_operatii_ignora_randuri_neselectate` (op fara cod ales → nesalvata, nu eroare),
|
||||
`test_mapare_operatii_re_rezolva_blocatele` (randurile cu cod ales trec din `needs_mapping`).
|
||||
- **Acceptance criteria**:
|
||||
- [x] Panoul „Operatii de mapat la cod RAR" devine UN singur `<form>` cu un select per operatie +
|
||||
**un singur buton „Salveaza maparile"** la final.
|
||||
- [x] `POST /_import/{id}/mapare-operatii` primeste perechi `(cod_op_service, cod_prestatie)` (liste
|
||||
paralele), apeleaza `save_mapping` pentru fiecare operatie cu cod ales (reuse exact, fara logica
|
||||
noua de mapare), apoi **o singura** recompute `_web_compute_preview` + re-randare `#import-section`.
|
||||
- [x] Operatiile fara cod ales (`— alege cod RAR —`) sunt ignorate (nu produc eroare, nu se salveaza).
|
||||
- [x] Toggle-ul auto_send NU reapare (eliminat in 5.11).
|
||||
- [x] CSRF + scoped sesiune + guard batch committed (409) pastrate.
|
||||
- **Verificare E2E**: browser pasul 3 — aleg coduri pentru toate operatiile, un click pe „Salveaza
|
||||
maparile" → toate randurile trec din „Cod RAR lipsa", o singura re-randare.
|
||||
|
||||
### US-005: Refactor — formular de editare partajat (DRY) intre Trimiteri si preview
|
||||
**Ca** dezvoltator **vreau** un singur formular de editare de continut **pentru ca** sa nu existe cod
|
||||
duplicat intre modalul Trimiteri si editarea de preview (sursa bug-urilor inline din 3.6/5.11).
|
||||
|
||||
- **Depinde de**: —
|
||||
- **Fisiere**: `app/web/templates/_form_editare.html` (NOU — partial cu campurile vehicul/data/odo),
|
||||
`app/web/templates/_trimitere_detaliu.html` (consuma partial-ul), `app/web/templates/_macros.html`
|
||||
(macro `camp` extins cu `tip='date'`), `tests/test_web_form_editare.py` (~4 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_form_editare.py` —
|
||||
`test_form_editare_are_input_date_pe_data_prestatie`,
|
||||
`test_trimitere_detaliu_foloseste_form_partajat`,
|
||||
`test_camp_macro_randeaza_type_date`.
|
||||
- **Acceptance criteria**:
|
||||
- [x] Partial `_form_editare.html` randeaza grila responsiva existenta
|
||||
(`repeat(auto-fit, minmax(200px,1fr))`) cu campurile: `nr_inmatriculare`, `vin`, `data_prestatie`,
|
||||
`odometru_final`, `odometru_initial`, plus map de erori per-camp (tipar `corectie_errors`).
|
||||
Parametrizat prin: URL de POST, valorile curente, harta de erori, eticheta butonului primar.
|
||||
- [x] **`data_prestatie` = `<input type="date">`** (calendar nativ); valoarea ramane `YYYY-MM-DD`.
|
||||
Daca valoarea curenta nu e `YYYY-MM-DD` valid, inputul degradeaza grijuliu (gol + hint), fara crash.
|
||||
- [x] `_trimitere_detaliu.html` randeaza acelasi partial in ramura `editabil` — comportamentul modalului
|
||||
Trimiteri (post `/corecteaza`, select cod RAR pe needs_data/needs_mapping) ramane identic.
|
||||
- [x] Macro `camp` suporta `tip='date'` fara sa strice apelurile `type='text'` existente.
|
||||
- **Verificare E2E**: browser — modalul Trimiteri (rand `needs_data`) arata un calendar la Data prestatie;
|
||||
salvarea+revalidarea functioneaza ca azi.
|
||||
|
||||
### US-006: UI — „Editeaza" din preview deschide MODALUL (acelasi formular), nu rand inline
|
||||
**Ca** operator **vreau** sa editez un rand de preview intr-un modal curat **pentru ca** editarea inline
|
||||
e rupta vizual si arunca eroare la Anuleaza.
|
||||
|
||||
- **Depinde de**: US-005
|
||||
- **Fisiere**: `app/web/templates/_preview_rand.html` (scoate ramura `editing`/`tr.preview-edit` +
|
||||
scriptul de mutual-exclusion; butonul „Editeaza" tinteste modalul global), `app/web/routes.py`
|
||||
(ruta GET fragment editare preview → randeaza `_form_editare.html` in `#detaliu-modal-body`;
|
||||
POST `/_import/{id}/rand/{i}/editeaza` ramane, dar raspunde cu inchidere modal + OOB pe rand+contoare),
|
||||
`app/web/templates/_preview_import.html` (foloseste modalul global `#detaliu-modal`),
|
||||
`tests/test_web_preview_edit.py` (~5 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_preview_edit.py` —
|
||||
`test_editeaza_preview_serveste_fragment_modal` (NU `tr.preview-edit`),
|
||||
`test_salvare_preview_inchide_modal_si_oob_rand`,
|
||||
`test_anuleaza_nu_lasa_rand_orfan` (regresie pe eroarea htmx null),
|
||||
`test_editare_preview_scoped_404_alt_cont`, `test_editare_batch_committed_409`.
|
||||
- **Acceptance criteria**:
|
||||
- [x] Butonul „Editeaza" pe rand face `hx-get` catre fragmentul de editare cu `hx-target="#detaliu-modal-body"`
|
||||
(acelasi mecanism de modal ca la Trimiteri, deschis prin clasa/markup existent in `base.html`).
|
||||
- [x] Fragmentul randeaza `_form_editare.html` cu POST la `/_import/{id}/rand/{i}/editeaza`,
|
||||
`hx-target="#detaliu-modal-body"`. La succes: **modalul se inchide** (`HX-Trigger: inchideModal`,
|
||||
ca la `/corecteaza`) si randul + contoarele se actualizeaza prin **OOB swap** (reuse `include_oob`).
|
||||
- [x] **Ramura `editing` / `tr.preview-edit` + scriptul inline de mutual-exclusion sunt ELIMINATE** din
|
||||
`_preview_rand.html` (sursa colapsarii pe verticala + a erorii `htmx-internal-data` la Anuleaza).
|
||||
- [x] „Anuleaza" = inchiderea modalului (mecanismul global), fara cerere catre `/_import/.../rand/{i}`,
|
||||
deci fara eroarea JS reprodusa. Test de regresie pe consola curata.
|
||||
- [x] Mutatie pura pe `override_json` pastrata (ruta neschimbata logic); scoping JOIN→404,
|
||||
guard committed→409 raman.
|
||||
- [x] Pe eroare de validare, modalul ramane deschis cu valorile + erorile per-camp (tipar Trimiteri).
|
||||
- **Verificare E2E**: browser pasul 3 — Editeaza → modal cu calendar + campuri; completez data → Salveaza →
|
||||
modal se inchide, randul trece pe „Gata de trimis", contoarele cresc; Anuleaza → modal se inchide,
|
||||
**0 erori in consola**.
|
||||
|
||||
### US-007: UI — preview compact + scoaterea coloanei „Verificat?"
|
||||
**Ca** operator **vreau** o lista de preview compacta si fara coloane neclare **pentru ca** randurile
|
||||
sunt prea inalte (VIN pe verticala) si nu inteleg bifa „Verificat?".
|
||||
|
||||
- **Depinde de**: US-006
|
||||
- **Fisiere**: `app/schema.sql` (coloana `import_rows.reviewed` + `_migrate` defensiv),
|
||||
`app/web/templates/_preview_rand.html`, `app/web/templates/_preview_import.html`
|
||||
(scoate coloana `col-verificat` + logica inline `reviewed_rows` din tabel),
|
||||
`app/web/templates/_form_editare.html` / fragmentul modal (buton „Confirma valorile" pe `needs_review`),
|
||||
`app/web/templates/base.html` (latimi `col-*` recalibrate, anti-overflow),
|
||||
`app/api/v1/import_router.py` + `app/web/routes.py` (citesc `reviewed` in `_resolve_row_for_preview` /
|
||||
`_web_compute_preview` ca `needs_review`-confirmat → `ok`; gate `n_confirmat` la commit foloseste
|
||||
`reviewed`, nu bife inline; ruta care seteaza `reviewed=1`), `tests/test_web_preview_compact.py`,
|
||||
`tests/test_import_review.py` (~7 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_preview_compact.py` —
|
||||
`test_preview_fara_coloana_verificat`,
|
||||
`test_preview_vin_nu_se_sparge_pe_verticala` (VIN intr-o singura linie / wrap controlat);
|
||||
`tests/test_import_review.py` —
|
||||
`test_needs_review_exclus_din_gata_pana_la_confirmare`,
|
||||
`test_confirmare_in_modal_seteaza_reviewed_si_devine_ok`,
|
||||
`test_reviewed_nu_intra_in_payload_sau_idempotency` (marcaj separat, NU camp de continut),
|
||||
`test_migrare_adauga_coloana_reviewed_idempotent`,
|
||||
`test_editare_valoare_pe_needs_review_reseteaza_reviewed` (daca schimbi valoarea, re-cere confirmare).
|
||||
- **Acceptance criteria**:
|
||||
- [x] Coloana **„Verificat?" eliminata** din tabelul de preview; antetul si celulele scad la 8 coloane.
|
||||
- [x] Randuri compacte: VIN nu se mai sparge pe verticala (latime minima pe coloana Vehicul / `white-space`
|
||||
controlat); fara overflow orizontal la 1280px (`scrollWidth <= clientWidth`); cardurile <768px raman.
|
||||
- [x] **Decizie inchisa (Q1): confirmare in modal, rand exclus pana confirmi.** Un rand `needs_review`:
|
||||
- apare cu pill „Verifica valori" + motivul concret in „Note" (data ambigua / formule Excel / coercion);
|
||||
- este **exclus din „gata de trimis"** (nu intra in `n_confirmat`) pana cand operatorul il deschide in
|
||||
modal (US-006) si apasa **„Confirma valorile"** (sau il corecteaza), ceea ce seteaza
|
||||
`import_rows.reviewed=1`; abia atunci randul devine `ok` la recalculul `_resolve_row_for_preview`.
|
||||
- [x] **Banner discoverability deasupra tabelului** (T1 gate /autoplan, aprobat 2026-06-26): cand exista randuri
|
||||
`needs_review`, un banner ne-blocant deasupra tabelului explica: „Randurile cu <pill>Verifica valori</pill>
|
||||
nu pleaca la RAR pana le deschizi si confirmi in modal." Fara el, gate-ul mutat din coloana vizibila in
|
||||
modal devine usor de ratat (operatorul crede ca pill-ul e informativ). Bannerul dispare cand
|
||||
`summary.needs_review == 0`.
|
||||
- [x] **Buton explicit „Confirma valorile"** (T2 gate /autoplan, aprobat 2026-06-26): in modal (US-006), randurile
|
||||
`needs_review` au un buton SEPARAT „Confirma valorile" care seteaza `reviewed=1` — atestare explicita,
|
||||
distincta de salvarea unei corectii de continut. NU se seteaza `reviewed=1` implicit la orice save
|
||||
(altfel operatorul ar atesta o valoare ambigua fara intentie). Salvarea unei CORECTII pe un rand deja
|
||||
confirmat reseteaza `reviewed` (vezi AC urmator).
|
||||
- [x] **Marcaj separat, nu camp de continut**: `import_rows.reviewed` (nullable/int, migrare defensiva) NU
|
||||
intra in payload, in `override_json` sau in cheia de idempotenta. Daca utilizatorul **schimba** o
|
||||
valoare a unui rand deja confirmat, `reviewed` se reseteaza (re-cere confirmare).
|
||||
- [x] Comitul ramane gate HARD pe `n_confirmat` (niciun rand ambiguu nu pleaca la RAR fara confirmare
|
||||
umana explicita) — acum derivat din `reviewed`, nu din bife inline `reviewed_rows`.
|
||||
- [x] Bara de confirmare („Trimite la RAR") si contoarele raman corecte dupa editari/confirmari (OOB),
|
||||
fara coloana Verificat?.
|
||||
- [x] Guard committed→409 si scoping JOIN→404 pe ruta de confirmare (acelasi tipar ca `/editeaza`).
|
||||
- **Verificare E2E**: browser pasul 3 (cu un xlsx cu data ambigua / VIN numeric) — lista compacta, fara
|
||||
coloana Verificat?, VIN pe o linie; randul `needs_review` ramane exclus din „gata de trimis" pana il
|
||||
confirm in modal („Confirma valorile") → devine „Gata de trimis", contorul creste.
|
||||
|
||||
### US-008: UI — responsive tableta + mobil (header fara suprapuneri + cadru compact/ergonomic)
|
||||
**Ca** operator pe telefon/tableta **vreau** o interfata compacta, fara articole de header suprapuse
|
||||
**pentru ca** azi pe mobil arata prost si elementele din header se calca unele pe altele.
|
||||
|
||||
- **Depinde de**: — (header/cadru global); coordonat cu US-006/007 pentru modal+preview pe mobil
|
||||
- **Fisiere**: `app/web/templates/base.html` (header grid + media queries tableta 768–1024 + mobil ≤767,
|
||||
modal full-screen, `.cont-menu`, tinte touch), eventual `app/web/templates/_status.html` /
|
||||
`_acasa.html` (contoare + nav pe randuri inguste), `tests/test_web_responsive.py` (~3 fisiere)
|
||||
- **Test intai (RED)**: `tests/test_web_responsive.py` —
|
||||
`test_header_are_breakpoint_tableta` (exista reguli `@media` intre 768 si 1024 pentru header),
|
||||
`test_header_elemente_nu_au_min_height_fix_pe_mobil`,
|
||||
`test_modal_full_screen_pe_mobil` (clasa/regula prezenta). (Testele de markup/CSS; pixel-level la E2E.)
|
||||
- **Acceptance criteria**:
|
||||
- [x] **Header fara suprapuneri pe tableta (768–1024px)**: logo + titlu + badge mediu + comutator tema +
|
||||
versiune + hamburger se aseaza fara sa se calce (grid/flex care wrap-uieste sau ascunde versiunea/
|
||||
titlul lung); `min-height:92px` nu forteaza inghesuirea. Pe mobil (≤767px) raman regulile existente,
|
||||
verificate ca nu se suprapun la ~390px latime.
|
||||
- [x] **Compact + ergonomic**: spatieri reduse pe mobil, tinte interactive ≥44px (butoane, pill-uri,
|
||||
linkuri nav, intrari hamburger), fara dublu-scroll; modalul de editare (US-006) e **full-screen**
|
||||
pe mobil (nu o casuta minuscula).
|
||||
- [x] **Fara overflow orizontal** pe niciuna din paginile principale (Acasa/import, preview pas 3, Mapari,
|
||||
Cont, login/signup) la 768px si la ~390px (`scrollWidth <= clientWidth`).
|
||||
- [x] Contoarele de status + nav-ul „Trimiteri/Mapari" se aseaza pe randuri lizibile pe mobil (fara taiere).
|
||||
- [x] Light/Dark/Petrol/Auto raman corecte pe toate viewport-urile (fara regresie de tema).
|
||||
- **Verificare E2E**: browser Playwright cu `browser_resize` la **390×844 (mobil)**, **820×1180 (tableta)**
|
||||
si **1280×800 (desktop)** — screenshot pe Acasa/import, preview pas 3 (cu modal deschis) si Cont; header
|
||||
fara suprapuneri pe toate trei; 0 overflow orizontal; tinte touch ok.
|
||||
|
||||
## 4. Riscuri
|
||||
|
||||
- **R1 — Gate `needs_review` la scoaterea coloanei.** Coloana „Verificat?" era gate-ul HARD prin care
|
||||
randurile cu valori ambigue (data ambigua, formula Excel) intrau in trimitere doar dupa bifa umana.
|
||||
Scoaterea ei naiva ar auto-include randuri ambigue (declaratie ireversibila la RAR). Mitigare:
|
||||
confirmarea se muta in modalul de editare (US-007 AC); `n_confirmat` ramane gate HARD. Vezi Q1.
|
||||
- **R2 — Refactor formular partajat (US-005) atinge modalul Trimiteri (cale LIVE).** `_trimitere_detaliu.html`
|
||||
e folosit pentru corectii reale care re-trimit la RAR. Mitigare: US-005 = refactor fara schimbare de
|
||||
comportament; teste byte-compat pe post `/corecteaza` + regresia existenta verde inainte de US-006/007.
|
||||
- **R3 — `<input type="date">` si valori ne-`YYYY-MM-DD`.** Fisiere cu data in alt format ajung in editare
|
||||
ca text ne-valid pentru inputul date (s-ar goli). Mitigare: AC US-005 — degradare grijulie (gol + hint),
|
||||
fara pierdere tacuta; data ramane editabila si re-validata la salvare.
|
||||
- **R4 — Migrare `accounts.email`.** Conturi legacy raman cu `email=NULL`. Mitigare: coloana nullable +
|
||||
`account_is_complete` (banner + gate activare), nu hard-block; contul de sistem id=1 exceptat.
|
||||
- **R5 — Eroarea htmx `htmx-internal-data`.** Reprodusa la Anuleaza pe editarea inline. Mitigare: US-006
|
||||
elimina complet ramura inline + scriptul; test de regresie pe consola curata.
|
||||
- **R6 — Responsive = fisier fierbinte `base.html`.** US-008 atinge header + media queries, fisier partajat
|
||||
cu alte story-uri (US-007 latimi `col-*`). Mitigare: serializare la lead (NU paralel pe `base.html`);
|
||||
verificare pixel pe 3 viewport-uri ca breakpoint-ul de tableta nu strica desktop-ul/mobilul existent.
|
||||
|
||||
## 5. Intrebari deschise
|
||||
|
||||
> Se rezolva cu utilizatorul ÎNAINTE de executie (poarta de aprobare PRD).
|
||||
|
||||
- **Q1 (gate `needs_review`) — INCHIS (user, 2026-06-26): confirmare in modal, rand exclus pana confirmi.**
|
||||
Context — `needs_review` apare cand validarea TRECE dar parsarea fisierului a fost incerta, in 3 cazuri
|
||||
(sursa: `import_parse.py` + `import_router.py:201-230`), aproape exclusiv la **xlsx** (la CSV nu se
|
||||
declanseaza — de-aceea coloana e goala in cazul comun):
|
||||
1. **Data ambigua** — zi ≤12 si format neclar (`05.06` = 5 iun. sau 6 mai?).
|
||||
2. **Coloana cu formule Excel** fara valori calculate (rata mare de celule goale).
|
||||
3. **Coercion suspect** la citire xlsx — VIN numeric (pierde zerourile din fata) / odometru ca float.
|
||||
Decizie: scoatem coloana mereu-prezenta „Verificat?"; randul `needs_review` ramane **exclus din „gata de
|
||||
trimis"** pana e deschis in modal si **confirmat** („Confirma valorile") sau corectat, persistand
|
||||
`import_rows.reviewed=1` (marcaj separat, NU camp de continut → nu intra in payload/idempotenta).
|
||||
Implementat in US-007.
|
||||
- **Q2 (model cont-email) — INCHIS (user, 2026-06-26): model A** (email canonic pe `accounts`), cu
|
||||
**1 firma = 1 cont = 1 login**. CUI ramane unic; al doilea email pe acelasi CUI e respins la signup cu
|
||||
mesaj prietenos (US-001). Fluxul de invitatie/alaturare (mai multi utilizatori per firma) → TODOS.
|
||||
- **Q3 (CLI legacy `tools/account.py`)**: facem `--email`/`--cui` obligatorii rupe scripturile vechi de
|
||||
test? Daca da, pastram un flag `--allow-incomplete` doar pentru teste, sau actualizam fixture-urile.
|
||||
|
||||
## 6. Valuri de executie (graful de dependente)
|
||||
|
||||
```
|
||||
Val 1 (paralel, fisiere disjuncte):
|
||||
[US-001] accounts.email + validari companie/email/CUI (schema/accounts/auth_routes/cli)
|
||||
[US-003] mapcoloane: antet + prima inregistrare (_mapcoloane.html/routes)
|
||||
[US-004] un singur Salveaza pe operatii (_preview_import.html/routes)
|
||||
[US-005] formular de editare partajat (DRY) + input date (_form_editare/_trimitere_detaliu/_macros)
|
||||
|
||||
Val 2 (deblocate de Val 1):
|
||||
[US-002] Cont editeaza date firma + gate activare + banner (dep US-001; _cont/admin/routes)
|
||||
[US-006] Editeaza preview → modal (acelasi formular) (dep US-005; _preview_rand/_preview_import/routes)
|
||||
|
||||
Val 3 (deblocat de US-006; ating base.html → serializate):
|
||||
[US-007] preview compact + scoate „Verificat?" + gate review (dep US-006; _preview_*/base.css/import_router)
|
||||
[US-008] responsive tableta+mobil + header fara suprapuneri (base.html media queries; coordonat cu US-006/007)
|
||||
```
|
||||
|
||||
Fisiere fierbinti partajate (serializate de lead, NU paralel pe acelasi fisier): `routes.py`
|
||||
(US-001/002/003/004/006), `_preview_import.html` (US-004/006/007), `_preview_rand.html` (US-006/007),
|
||||
`base.html` (US-007 latimi `col-*` + US-008 header/media queries — serializate strict intre ele). Vezi ROADMAP §5.5.
|
||||
|
||||
---
|
||||
|
||||
## Raport VERIFY
|
||||
|
||||
> Faza VERIFY rulata de subagent verificator independent (context curat, PRD-only, ROADMAP §5.6),
|
||||
> 2026-06-26. Lead orchestrare prin agent team (8 teammates Sonnet TDD pe valuri cu fisiere disjuncte;
|
||||
> `routes.py` si `base.html` serializate ca fisiere fierbinti). Backend trimitere (worker, masina de
|
||||
> stari de trimitere, idempotenta `build_key`, contract RAR, canal API) NEATINS — confirmat
|
||||
> `git diff --stat` (app/worker/, app/idempotency.py, app/mapping.py, app/validation.py = 0 modificari).
|
||||
|
||||
### Rezultat: PASS (toate 8 stories)
|
||||
|
||||
- **Suita**: `python3 -m pytest -q` -> **987 passed, 1 skipped, 0 failed** (baseline 934 -> +53 teste noi).
|
||||
Live RAR `FINALIZATA` = opt-in indisponibil in mediu (normal, ca la livrabilele anterioare).
|
||||
- **PASS/FAIL per story** (dovezi cod + teste, verificator independent):
|
||||
- US-001 accounts email/CUI — PASS (migrare defensiva, create_account valideaza, account_is_complete
|
||||
id=1 exceptat, signup CUI obligatoriu + mesaj prietenos T3, CLI --email/--cui).
|
||||
- US-002 Cont date firma + gate activare + banner — PASS.
|
||||
- US-003 mapcoloane antet + prima inregistrare — PASS (confirmat E2E browser).
|
||||
- US-004 un singur Salveaza pe operatii — PASS (ruta plurala, D#12 skip invalid).
|
||||
- US-005 formular editare partajat + input date — PASS (D#5/D#6/D#10).
|
||||
- US-006 Editeaza preview -> MODAL — PASS (ramura inline eliminata, Anuleaza fara eroare htmx, E2E 0 erori consola).
|
||||
- US-007 preview compact + gate review in modal — PASS (reviewed marcaj separat, NU in payload/idempotenta;
|
||||
gate HARD pe ambele canale; T1 banner; T2 buton Confirma; D#9 reset).
|
||||
- US-008 responsive tableta + mobil — PASS (E2E pe 390/820/1280, header fara suprapuneri, D#13 verificat).
|
||||
- **Invariante critice**: R2 (submissions neatins dupa editare preview) PASS; reviewed in afara
|
||||
payload/override/idempotency PASS; migrari idempotente PASS; ramura inline `tr.preview-edit` eliminata PASS.
|
||||
|
||||
### VERIFY a gasit 1 FAIL -> remediat TDD, re-confirmat
|
||||
- FAIL: `signup.html` eticheta CUI „(optional)" + input fara `required` (contrazicea AC US-001 „CUI obligatoriu";
|
||||
serverul respingea corect 422 dar UI comunica gresit). Reparat TDD (eticheta `*` + `required`),
|
||||
test de lock `test_signup_html_cui_obligatoriu_ui`.
|
||||
|
||||
### Faza CLOSE — `/code-review high` (8 unghiuri prin subagenti, verificare cod first-hand)
|
||||
3 buguri reale reparate TDD (regresie finala 987 passed):
|
||||
1. **HIGH** — `confirma-review` folosea `hx-swap="none"` -> scriptul `updateN()` din continutul principal nu
|
||||
se executa -> `n_confirmat` ramanea stale -> „Trimite la RAR" pica pe gate HARD 422 (fluxul confirma->commit
|
||||
US-007 rupt la prima incercare). Fix: formularul Confirma valorile aliniat la `hx-target="#detaliu-modal-body"`
|
||||
`hx-swap="innerHTML"` (ca /editeaza).
|
||||
2. **MEDIUM** — email duplicat la signup arata mesajul gresit „firma e deja inregistrata" (`"deja folosit"`
|
||||
prindea si `ValueError("email deja folosit")` din `create_user`). Fix: detectie email-dup inaintea CUI-dup,
|
||||
mesaj specific emailului.
|
||||
3. **MEDIUM (a11y)** — butonul Editeaza din preview deschidea modalul ocolind `open()` (fara inert/focus-trap/
|
||||
focus-return). Fix: handler-ul global `htmx:beforeRequest` trateaza si `.btn-editeaza` -> `open()`; JS inline eliminat.
|
||||
Notat ca debt (neblocant): API preview re-deriva needs_review peste DB `resolved_status` cross-channel (web commit
|
||||
numara oricum `reviewed=1`); mesaje prietenoase „camp gol" dead-code in cont_date_firma/signup (edge mascat de HTML
|
||||
required); `zip()` truncheaza la liste POST inegale; `id` cont in mesajul CUI-duplicat; duplicari de cleanup
|
||||
(context modal, markup banner, N query nomenclator).
|
||||
|
||||
### Nedovedit in sesiune
|
||||
- Live RAR `FINALIZATA` prin `--send` (opt-in, lipsa creds/mediu) — risc minim, backend trimitere NEATINS.
|
||||
|
||||
---
|
||||
|
||||
## GSTACK REVIEW REPORT (/autoplan, 2026-06-26)
|
||||
|
||||
Branch: main · Commit: 283299f · Voci: Claude subagents (CEO/Design/Eng/DX) + verificare cod first-hand.
|
||||
**Codex = INDISPONIBIL** (usage limit, reset 2026-07-18) -> mod `[subagent-only]` pe toate fazele.
|
||||
Restore point: vezi comentariul HTML din capul fisierului. Test plan: `~/.gstack/projects/romfast-rar-autopass/main-prd5.12-test-plan-20260626.md`.
|
||||
|
||||
### Rezumat
|
||||
PRD matur: Q1/Q2 inchise de user, Non-Goals clare, graf de valuri, R1-R6. Rutele si fisierele citate exista
|
||||
toate in cod. Review-ul a confirmat fezabilitatea si a gasit **4 lacune de specificatie reale** (nu blocante,
|
||||
dar de inchis inainte de executie) + cateva rafinari. Niciun User Challenge (un singur model activ -> nu se
|
||||
poate forma consens cross-model; recomandarile de mai jos sunt sugestii, nu provocari).
|
||||
|
||||
### Decision Audit Trail
|
||||
|
||||
| # | Faza | Decizie | Clasificare | Principiu | Rationament | Respins |
|
||||
|---|------|---------|-------------|-----------|-------------|---------|
|
||||
| 1 | CEO | NU splitam in 5.12a/5.12b | Taste | P3/P6 | Valurile izoleaza deja US-001/002 (Val1/Val2) pe fisiere disjuncte; split adauga overhead de release fara castig tehnic pt. echipa mica | Split in 2 release-uri (CEO subagent) |
|
||||
| 2 | CEO | Respins „testeaza worker-ul intai" (F1/F3/F8) | Mechanical | P3 | Non-Goals ingheata explicit worker/contract/idempotenta; conflateaza acest PRD UI cu munca de backend separata | CEO subagent F1/F3/F8 |
|
||||
| 3 | CEO | First-run E2E smoke -> ramane in TODOS (deja listat) | Mechanical | P3 | Deja deferat din 5.11; recomandat, neblocant | A bloca 5.12 pe el |
|
||||
| 4 | CEO | needs_review: pastram gate-ul, nu cerem date de utilizare | Mechanical | P1 | Gate-ul e safety-critical (declaratie ireversibila RAR); US-007 muta UI-ul, nu sterge gate-ul | CEO F5 (gather usage data first) |
|
||||
| 5 | Eng | Partial partajat = DOAR campuri vehicul+data+err/fix; cod_prestatie select + nemapate_inline RAMAN in `_trimitere_detaliu` | Mechanical | P5/P4 | `_trimitere_detaliu` are 2 surse de cod (select + sectiune mapare inline) imposibil de absorbit fara branching fragil | Partial „atotcuprinzator" |
|
||||
| 6 | Eng | US-005 parametrizeaza si `fix_map` (+ aria-label cu VIN) | Mechanical | P1 | Forma preview are fix-hints + aria-label cu context VIN; lista PRD le omitea -> ar pierde info la extractie | A lasa lista PRD ca atare |
|
||||
| 7 | Eng | `import_rows.reviewed INTEGER DEFAULT 0` (nu NULL) | Mechanical | P5 | Gate-ul devine `reviewed=0` clar, fara ambiguitate NULL vs 0 | DEFAULT NULL |
|
||||
| 8 | Eng | Gate commit derivat din DB `reviewed` pe AMBELE canale; API `reviewed_rows` pastrat dar seteaza `reviewed=1` (contract stabil) | Mechanical | P1/P5 | Evita divergenta web/API si pastreaza contractul `/v1/import/.../commit` | A schimba doar web-ul (divergenta tacuta) |
|
||||
| 9 | Eng | reset `reviewed` la schimbare valoare se implementeaza in calea editeaza/override | Mechanical | P1 | E un AC US-007 fara loc de implementare numit; `apply_row_override` e locul | A-l lasa nespecificat |
|
||||
| 10 | Design | `<input type=date>` ne-ISO: gol + hint + valoare bruta in hidden, fara pierdere | Taste->auto | P1 | Previne pierderea tacuta de date pe formate Excel; backend deja marcheaza needs_review | A goli pur si simplu inputul |
|
||||
| 11 | Design | US-003 fisier fara randuri: mesaj explicit „antet fara randuri de date" + blocheaza Continua | Mechanical | P1 | Edge case altfel = esec tacut | Doar „fara crash" |
|
||||
| 12 | US-004 | Bulk mapping: validare per-item, skip invalid + sumar, restul salvate, 1 re-render | Mechanical | P1 | PRD acopera „fara cod = ignorat" dar nu „cod invalid pe 1 din N" | All-or-nothing |
|
||||
| 13 | US-008 | Modal full-screen mobil: VERIFICA, nu re-adauga (exista base.html:407) | Mechanical | P4 | Regula deja prezenta la `@media max-width:767px` | A re-implementa |
|
||||
| 14 | DX | Q3: actualizam fixture-urile via factory in `conftest.py`, FARA `--allow-incomplete` in prod | Taste | P5/P4 | Escape-hatch lasa o veruca in codul de productie; factory centralizat e curat si mai bun pe termen lung | `--allow-incomplete` flag |
|
||||
| T1 | Design | needs_review: banner persistent deasupra tabelului | Taste -> APROBAT user 2026-06-26 | P1/P5 | Gate-ul mutat in modal devine usor de ratat; bannerul il face explicit | Doar pill+tooltip |
|
||||
| T2 | Design/Eng | „Confirma valorile" = buton explicit separat (nu implicit pe save) | Taste -> APROBAT user 2026-06-26 | P5 | Atestare explicita pe valori ambigue; evita confirmarea accidentala | Implicit pe orice save |
|
||||
| T3 | DX | Mesaj CUI duplicat include canal de contact configurabil (fallback la actual) | Taste -> APROBAT user 2026-06-26 | P1 | Operatorul primeste un pas urmator real; detectie in handler signup, nu `str(exc)` | Pastreaza mesajul ca in PRD |
|
||||
|
||||
### NOT in scope (confirmat)
|
||||
- Worker, reconciliere, idempotenta, `build_key`, masina de stari de trimitere, contract RAR (Non-Goals).
|
||||
- Canal API `POST /v1/prezentari` / `/valideaza` si `mapping.resolve_prestatii` — neschimbate.
|
||||
- Multi-utilizatori per firma (flux invitatie/alaturare) -> TODOS.
|
||||
- First-run E2E smoke ca poarta de release -> TODOS (deja deferat din 5.11).
|
||||
- Split 5.12a/5.12b -> respins (vezi D#1).
|
||||
|
||||
### What already exists (de refolosit, nu reconstruit)
|
||||
- Modal global `#detaliu-modal` + `inchideModal` (`HX-Trigger-After-Settle`, routes.py:1235/1394) — US-006 il refoloseste.
|
||||
- `include_oob` pentru OOB swap rand+contoare — US-006/007 il refolosesc.
|
||||
- `save_mapping` / `reresolve_account` — US-004 le refoloseste (fara logica noua de mapare).
|
||||
- Macro `camp` exista INLINE in ambele forme (`_preview_rand.html:51`, `_trimitere_detaliu.html:98`) — US-005 il EXTRAGE (nu „extinde in `_macros.html`" cum spune lista de fisiere; `_macros.html` are azi doar `autosend_toggle` gol).
|
||||
- Modal full-screen mobil + tinte touch 44px — deja in base.html (`@media max-width:767px`, liniile 407-427). US-008 = tableta + verificare, nu rescriere.
|
||||
- `_migrate` defensiv idempotent (tipar `users.is_admin` 3.3b) — US-001/007 il urmeaza.
|
||||
|
||||
---
|
||||
|
||||
## Faza 1 — CEO (strategie & scope)
|
||||
|
||||
CEO DUAL VOICES — CONSENSUS:
|
||||
```
|
||||
Dimensiune Claude Codex Consens
|
||||
------------------------------------- -------- ------- ---------
|
||||
1. Premise valide? DA* N/A n/a (1 voce)
|
||||
2. Problema corecta? DA N/A n/a
|
||||
3. Calibrare scope? DISAGREE N/A -> taste (split?)
|
||||
4. Alternative explorate suficient? PARTIAL N/A n/a
|
||||
5. Riscuri competitive acoperite? DA N/A n/a
|
||||
6. Traiectorie 6 luni sanatoasa? DA N/A n/a
|
||||
* premise = decizii user deja luate (Q1/Q2 inchise, modal/calendar = „decizie utilizator")
|
||||
```
|
||||
**Examinat, nimic blocant pe strategie.** PRD-ul rezolva first-run friction confirmat E2E; scope-ul e calibrat
|
||||
prin valuri. CEO subagent a recomandat split-ul in 2 release-uri (D#1, respins) si a ridicat findings de „testeaza
|
||||
worker-ul" care cad in afara Non-Goals (D#2, respinse). Single-critical pastrat: Q3 (backward-compat CLI) — real,
|
||||
mutat la faza DX/Eng. Dream-state delta: 5.12 inchide first-run UX; ramane (separat) poarta E2E smoke + flux
|
||||
multi-user firma.
|
||||
|
||||
## Faza 2 — Design (UI/UX)
|
||||
|
||||
Litmus (Claude design; Codex n/a):
|
||||
```
|
||||
Dimensiune Scor Nota
|
||||
-------------------------------- ----- -------------------------------------------
|
||||
Ierarhie informatie (mapcoloane) 7/10 US-003 ok; recomandat cap-tabel sticky pe fisiere cu 15+ coloane
|
||||
Stari (load/empty/error/partial) 6/10 empty-file (US-003) si date ne-ISO (US-005) sub-specificate
|
||||
Gate needs_review in modal 6/10 LANDMINE: gate HARD mutat dintr-o coloana vizibila intr-un modal
|
||||
Responsive tableta (US-008) 7/10 breakpoint lipseste azi; spec sa fie pixel-exact, nu aspirational
|
||||
Interactiune modal (US-006/007) 6/10 „Confirma valorile" = buton separat vs implicit-pe-save (ambiguu)
|
||||
```
|
||||
**Issue-uri auto-decise:** D#10 (date ne-ISO), D#11 (empty-file mesaj). **Taste surfaced la gata:** banner
|
||||
discoverability pe needs_review (T1) + buton „Confirma valorile" explicit (T2).
|
||||
|
||||
## Faza 3 — Eng (arhitectura & teste)
|
||||
|
||||
ENG DUAL VOICES — CONSENSUS:
|
||||
```
|
||||
Dimensiune Claude Codex Consens
|
||||
--------------------------- -------- ------- ---------
|
||||
1. Arhitectura sanatoasa? DA(cond) N/A n/a — cond. pe partial corect parametrizat
|
||||
2. Acoperire teste? PARTIAL N/A n/a — vezi test plan, 4 gap-uri
|
||||
3. Riscuri performanta? DA N/A n/a — irelevant (UI/CRUD mic)
|
||||
4. Securitate? DA N/A n/a — CSRF+scoped pastrate pe rute noi
|
||||
5. Cai de eroare? PARTIAL N/A n/a — bulk mapping partial, date ne-ISO
|
||||
6. Risc deployment? DA N/A n/a — 2 migrari nullable defensive
|
||||
```
|
||||
|
||||
Diagrama arhitectura (componente noi vs existente):
|
||||
```
|
||||
US-001 create_account(+email) -> auth_routes.signup ──┐
|
||||
accounts.email (migrare) -> tools/account.py CLI ┤ (3 call-sites de actualizat)
|
||||
account_is_complete ┘
|
||||
US-005 _form_editare.html (NOU) <── _trimitere_detaliu.html (cod_prestatie select + nemapate_inline RAMAN aici)
|
||||
└──< _preview_rand.html (US-006: ramura inline ELIMINATA)
|
||||
US-006 preview „Editeaza" -> #detaliu-modal-body (GET fragment) -> POST /editeaza -> inchideModal + OOB
|
||||
US-007 import_rows.reviewed (migrare) -> _resolve_row_for_preview -> gate n_confirmat
|
||||
├── web routes.py /confirma (citeste DB reviewed)
|
||||
└── API import_router commit_import (reviewed_rows -> seteaza reviewed=1; contract stabil)
|
||||
US-008 base.html @media (768-1024) NOU + verificare 767 existent
|
||||
```
|
||||
|
||||
**Findings auto-decise:** D#5 (partial scope), D#6 (fix_map), D#7 (reviewed DEFAULT 0), D#8 (gate pe 2 canale),
|
||||
D#9 (reset reviewed in apply_row_override), D#12 (bulk partial). Test plan scris pe disc (44 codepath-uri,
|
||||
4 gap-uri marcate). **Invariant critic confirmat (R2):** editarea preview ramane override-only, NU re-queue —
|
||||
test obligatoriu (#24/#25 in test plan): dupa editare preview, `submissions` neatins.
|
||||
|
||||
## Faza 3.5 — DX (CLI + erori + contract API)
|
||||
|
||||
DX CONSENSUS (Claude; Codex n/a):
|
||||
```
|
||||
Dimensiune Nota
|
||||
--------------------------------- -------------------------------------------
|
||||
CLI create --email/--cui Q3 nerezolvat: a face flag-uri obligatorii rupe fixture-urile
|
||||
Mesaj eroare CUI duplicat prietenos da, dar „cere accesul de la admin" nu spune CUM
|
||||
Contract API commit reviewed_rows risc de divergenta tacuta -> rezolvat de D#8 + test #39
|
||||
Migrare fixture-uri recomandat factory in conftest.py (DX gap real)
|
||||
```
|
||||
**Auto-decis:** D#14 (Q3 -> factory, fara `--allow-incomplete`). **Taste surfaced:** mesaj CUI duplicat sa includa
|
||||
un canal de contact concret (T3).
|
||||
|
||||
### Cross-Phase Themes
|
||||
- **Tema A — Gate-ul needs_review (Design + Eng).** Design: mutarea in modal ascunde gate-ul (discoverability).
|
||||
Eng: gate-ul trebuie sa fie DB-backed pe ambele canale + reset la editare. Semnal high-confidence: tratati
|
||||
needs_review ca feature de sine statator in US-007, nu ca „stergere de coloana". -> T1 + D#8/D#9.
|
||||
- **Tema B — Sub-specificarea „Confirma valorile" (Design + Eng).** Ambii: cand se seteaza `reviewed=1`?
|
||||
Buton separat vs implicit pe save. -> T2.
|
||||
- **Tema C — Q3 backward-compat (CEO + DX + Eng).** Toate trei: a face email/CUI obligatorii rupe fixture-uri.
|
||||
-> D#14 (factory).
|
||||
|
||||
### Implementation Tasks (aggregate)
|
||||
_Niciun fisier `tasks-*.jsonl` per faza (autoplan ruleaza review-urile inline, nu skill-urile standalone)._
|
||||
Task-urile concrete = AC-urile din US-001..008 + cele 14 decizii din audit trail + 4 gap-urile din test plan.
|
||||
|
||||
### Status: DONE_WITH_CONCERNS
|
||||
Concerns (de inchis inainte de executie, niciunul blocant): cele 3 taste decisions de la gate (T1 banner,
|
||||
T2 buton confirma, T3 contact CUI) + integrarea celor 14 decizii in AC-urile US. Codex indisponibil -> review
|
||||
single-voice; re-ruleaza dupa 2026-07-18 daca vrei al doilea unghi adversarial.
|
||||
334
docs/prd/prd-5.13-responsive-compact.md
Normal file
334
docs/prd/prd-5.13-responsive-compact.md
Normal file
@@ -0,0 +1,334 @@
|
||||
<!-- /autoplan restore point: /home/claude/.gstack/projects/romfast-rar-autopass/feat-5.12-5.13-responsive-autoplan-restore-20260627-182914.md -->
|
||||
# PRD 5.13 — Responsive compact (mobil/tableta) + sistem de butoane + design.md
|
||||
|
||||
**Stare**: DRAFT — pentru /autoplan (implementarea NU e facuta inca)
|
||||
**Data**: 2026-06-27
|
||||
**Sursa de design**: [docs/design.md](../design.md) (sursa de adevar pentru planurile de design)
|
||||
|
||||
> Nota: o sesiune anterioara a explorat o implementare + mockup-uri si a fost REVENITA
|
||||
> (working tree readus la 5.12). Acest PRD ramane ca specificatie de planificat prin
|
||||
> `/autoplan`. Sectiunile „Livrabile" / „Raport VERIFY" de mai jos descriu directia
|
||||
> propusa si dovezile din explorare, NU stare livrata — re-validati prin autoplan.
|
||||
|
||||
## Context / problema
|
||||
|
||||
PRD 5.12 a marcat „responsive tableta/mobil" ca livrat, dar dogfooding-ul real
|
||||
(screenshot-uri `localhost_8010_.png`, `step3-preview.png`, `tablet-820.png`,
|
||||
`mobile-*.png`) a aratat ca paginile arata execrabil pe ecrane mici:
|
||||
|
||||
- **P0 break vertical**: in cardurile de Trimiteri pe mobil, eticheta lua `min-width:120px`
|
||||
fix iar valoarea (nod text intr-un flex) se strangea la ~0 si `word-break:break-word`
|
||||
o spargea **caracter cu caracter pe verticala** („B 0 7 5 8" pe coloana). Ilizibil.
|
||||
- **P0 stepper import**: 4 coloane egale cu text + `overflow:hidden` → pe tableta „Confirma
|
||||
trimiterea" era taiat; pe mobil 4 benzi minuscule cu text pe 3 randuri.
|
||||
- **P0 tabel preview pe tableta** (768–1024px): 8 coloane `table-layout:fixed` cu latimi
|
||||
fixe storceau vehicul+operatie → text rupt.
|
||||
- **P1 „afiseaza tot ca pe desktop"**: cardurile aratau toate cele 6–8 campuri, nu esentialul.
|
||||
- **P1 butoane exagerate**: `.tabel-card td button { width:100%; min-height:44px }` facea
|
||||
Salveaza + Sterge **doua blocuri full-width** unul sub altul; butoanele icon-only din
|
||||
„Mapari salvate" aveau **iconite invizibile** (SVG mic intr-un bloc colorat mare).
|
||||
- **P2**: mapare coloane cu scroll orizontal pe mobil; versiunea `vX.Y.Z` ocupa spatiu in
|
||||
header pe mobil; bara sticky de confirmare se rupea necontrolat.
|
||||
|
||||
Feedback user pe mockup-uri (2026-06-27):
|
||||
- Compactarea sa fie **si pe desktop** (ex. wizard-ul mai compact peste tot).
|
||||
- Pe **desktop** butoanele Salveaza/Sterge = **doar text** (fara iconita).
|
||||
- Pe **mobil** = iconite, dar un set modern, **recognoscibil** (Lucide stroke), nu cele vechi.
|
||||
- Nevoie de un **design.md** pe care planurile de design sa-l foloseasca.
|
||||
|
||||
## Decizii (confirmate cu user prin AskUserQuestion + mockup-uri)
|
||||
|
||||
1. **Directie**: carduri compacte, esential vizibil, butoane mici. (D: „da, dar ajustez")
|
||||
2. **Tableta (768–1024px)**: tabelele actionabile devin **carduri, 2 pe rand** (grid).
|
||||
3. **Scope**: pachet complet P0+P1+P2 + teste + acest PRD + ROADMAP + design.md.
|
||||
4. **Butoane**: desktop = text; mobil = iconita patrata 44px, set **Lucide stroke** (contur).
|
||||
5. **Wizard**: compact **peste tot** (inclusiv desktop): bara slim pe o linie; pe mobil
|
||||
„Pasul N din 4 · Titlu" + bara de progres.
|
||||
|
||||
## Livrabile
|
||||
|
||||
### design.md (nou)
|
||||
Sistemul de design: principii, tokeni (culoare 4 teme, tipografie IBM Plex, spatiere, radius,
|
||||
elevatie), breakpoints (768/1024), scara de control (44/36/32), componente (butoane, card,
|
||||
tabel→card, stepper, pill, formulare, modal), accesibilitate, si o sectiune „Pentru planurile
|
||||
de design". Sursa de adevar; planurile pornesc de aici.
|
||||
|
||||
### Cod (doar CSS + markup template; backend NEATINS)
|
||||
- **`_macros.html`**: macro `icon(name)` (Lucide save/trash/edit/plus, stroke) + `act_btn(label, ic, kind, attrs)`
|
||||
(buton de actiune responsiv: desktop text / mobil iconita).
|
||||
- **`base.html`** (CSS, inline):
|
||||
- Sistem de butoane `.btn-secondary/.btn-ghost/.btn-danger/.btn-sm` + default primar imbunatatit
|
||||
(font-weight 500, focus-visible).
|
||||
- Sistem `.act` / `.act-save` / `.act-del` / `.act-group`: desktop = text, mobil = iconita 44px.
|
||||
- Stepper compact `.stepper*` (track slim desktop/tableta; rezumat + bara progres mobil).
|
||||
- Card mobil Trimiteri/Preview **rescris**: stivuit compact, vehicul = titlu, stare = pill,
|
||||
`#`/checkbox ascunse, **fara gap fix de 120px** (fix break vertical).
|
||||
- **Tableta 768–1024px**: `.tabel-trimiteri` + `.tabel-card` → grid 2 carduri/rand.
|
||||
- Versiune ascunsa pe mobil; bara sticky confirmare compacta; mapare coloane stivuita full-width.
|
||||
- Coloana actiuni preview 92→104px + `.btn-editeaza { white-space:nowrap }`.
|
||||
- **`_stepper.html`**: rescris pe clasele compacte (fara stiluri inline inalte).
|
||||
- **`_mapari.html`**: butoanele icon-only inlocuite cu `act_btn` (salvate + reguli-text + formate-coloane).
|
||||
|
||||
### Teste
|
||||
- `test_web_responsive.py`: aserturile existente pastrate (toate trec).
|
||||
- `test_web_mapari_actiuni.py`: actualizat de la `.icon-btn` la sistemul `.act` (act-save/act-del,
|
||||
aria-label pe fiecare, `.act-ic` prezent), docstring marcat „superseda 5.10".
|
||||
|
||||
## Invariante respectate
|
||||
- Breakpoint unic 768px + densitate 1024px; un singur bloc `@media (max-width:767px) {` principal
|
||||
pe care se bazeaza testele (regulile noi adaugate inauntru, nu in blocuri noi inaintea lui).
|
||||
- Tabelele dense read-only (Jurnal/Nomenclator/Admin) raman scroll-contained, NU se cardifica.
|
||||
- Backend trimitere (worker, masina stari, idempotenta, contract RAR, canal API, mapping,
|
||||
validation) NEATINS. Zero schema. Pur CSS + markup.
|
||||
|
||||
## Raport VERIFY (live, app pornit cu DB seedata, Playwright 390/820/1280)
|
||||
- **Trimiteri mobil 390**: carduri compacte, pill stare + vehicul bold + operatie+cod, fara
|
||||
break vertical. Header compact, versiune ascunsa. PASS.
|
||||
- **Trimiteri tableta 820**: grid 2 carduri/rand, fara scroll orizontal. PASS.
|
||||
- **Trimiteri desktop 1280**: tabel complet neschimbat (fara regresie). PASS.
|
||||
- **Mapari mobil 390**: Salveaza = iconita discheta albastra, Sterge = iconita cos rosu (Lucide,
|
||||
patrate 44px, recognoscibile), NU blocuri full-width. PASS.
|
||||
- **Wizard import**: compact pe o linie pe desktop (✓ Incarca · ✓ Coloane · 3 Verifica · 4 Confirma)
|
||||
+ ajutor sub; pe mobil „Pasul 3 din 4 · Verifica" + bara progres. PASS.
|
||||
- **Preview import mobil 390**: carduri compacte per rand + bara confirmare compacta. PASS.
|
||||
- Regresie pytest: vezi ROADMAP (suita verde).
|
||||
|
||||
## Debt notat (neblocant)
|
||||
- Duplicarea pill stare + `eticheta_problema` pe error/needs_* arata redundant in carduri
|
||||
(„Eroare / Eroare") — logica de continut in `routes.py`/`labels.py`, nu responsive.
|
||||
- Filtrele de data (Azi/7zile/30zile/Custom) stivuiesc full-width pe mobil (4 randuri); ar putea
|
||||
fi grid 2x2 — imbunatatire viitoare.
|
||||
|
||||
---
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- GSTACK REVIEW REPORT — /autoplan (subagent-only; codex usage-limited) -->
|
||||
<!-- ============================================================ -->
|
||||
|
||||
# GSTACK REVIEW REPORT
|
||||
|
||||
> Pipeline: CEO -> Design -> Eng -> Final Gate (DX skipped: produs end-user, nu unealta de developer).
|
||||
> Voci: Claude subagent independent pe fiecare faza. **Codex INDISPONIBIL** (usage limit
|
||||
> OpenAI pana la 2026-07-18) -> toate fazele ruleaza `[subagent-only]`. Consensul nu poate
|
||||
> fi "CONFIRMED de ambele modele"; o singura voce.
|
||||
|
||||
## Faza 1 — CEO (strategie & scope)
|
||||
|
||||
### CEO dual voices
|
||||
- **Codex (CEO):** `[codex-unavailable: usage limit]`.
|
||||
- **Claude subagent (CEO):** rulat foreground, independent. Findings:
|
||||
- **F1 (high):** premisa "utilizarea pe mobil e reala" e asumata, nedovedita. Submiterea RAR
|
||||
e data-entry din xlsx/csv la receptia service-ului = task desktop/tastatura. Wizardul
|
||||
(upload -> mapare -> preview -> commit) e greu utilizabil pe telefon indiferent de CSS.
|
||||
Niciun semnal real (analytics/cerere user) citat; doar screenshot-uri ale propriului render urat.
|
||||
- **F2 (high):** reframe — durerea reala sunt bug-urile de layout de pe DESKTOP (break vertical,
|
||||
stepper taiat, butoane full-width, iconite invizibile), nu "responsive". Tier 1 = bug-uri +
|
||||
sistem butoane + design.md (valoare clara, zilnica). Tier 2 = cardificare mobil/tableta (speculativ).
|
||||
- **F3 (medium):** "CSS inline intr-un singur <style>, no build" e enuntat ca axioma, fara a fi
|
||||
cantarit vs alternative (Tailwind CDN, Pico.css). Pentru HTMX e o alegere aparabila, dar
|
||||
netestata/nelintata -> un blob `<style>` in crestere unde o editare de media-query strica tacit alte ecrane.
|
||||
- **F4 (critical, REZOLVAT partial):** risc de churn — re-implementare din proza. CEO recomanda
|
||||
recuperarea commit-ului revertit. **Verificat in git reflog: nu exista commit 5.13** (a fost
|
||||
explorare in working tree, revertita, niciodata commis). Deci nu e nimic de recuperat din git ->
|
||||
singura cale e re-implementarea din PRD -> PRD-ul TREBUIE facut mai specific (vezi Eng §2/§5).
|
||||
- **F5 (medium):** scenariul de regret la 6 luni — rewrite CSS multi-template pentru audienta cu
|
||||
mobil ~zero; `<style>` se dubleaza; un viitor content-change reintroduce clasa de bug "break vertical"
|
||||
pentru ca nimic structural nu o previne; modul "card pe tableta" nevazut de un user real. Ce NU va
|
||||
parea prost: design.md + sistemul de butoane.
|
||||
- **F6 (pozitiv):** design.md e bun (tokeni, ratii de contrast AA, gotcha CSS-var-in-@media). De
|
||||
pastrat/commis independent de soarta lui 5.13.
|
||||
|
||||
### CEO consensus table
|
||||
```
|
||||
CEO DUAL VOICES — CONSENSUS TABLE (codex N/A: usage limit)
|
||||
═══════════════════════════════════════════════════════════════
|
||||
Dimension Claude Codex Consensus
|
||||
──────────────────────────────────── ─────── ───── ─────────
|
||||
1. Premises valid? NO (F1) N/A 1-voce: NU (mobil nedovedit)
|
||||
2. Right problem to solve? PARTIAL N/A 1-voce: reframe la bug+butoane (F2)
|
||||
3. Scope calibration correct? NO N/A 1-voce: full P0+P1+P2 supradimensionat
|
||||
4. Alternatives explored? NO (F3) N/A 1-voce: framework nediscutat
|
||||
5. Competitive/market risks? N/A N/A irelevant (tool intern B2B)
|
||||
6. 6-month trajectory sound? PARTIAL N/A 1-voce: design.md+butoane da; cardificare risc
|
||||
═══════════════════════════════════════════════════════════════
|
||||
O singura voce -> nimic "CONFIRMED de ambele". Findings critice tratate ca atare oricum.
|
||||
```
|
||||
|
||||
### NOT in scope (confirmat / deferat)
|
||||
- Backend (worker, masina stari, idempotenta, contract RAR, canal API, mapping, validation): NEATINS. [PRD]
|
||||
- Tabele dense read-only (Jurnal/Nomenclator/Admin): raman scroll-contained, NU se cardifica. [PRD]
|
||||
- Refactor `routes.py`/`labels.py` pentru "Eroare/Eroare": deferat (debt). Dar vezi Design §2 — un guard
|
||||
de template (pill-only cand eticheta == stare) e ieftin si in-scope.
|
||||
- Adoptarea unui framework CSS: respins (P4 DRY + no-build potrivit stack-ului HTMX), dar de notat explicit ca decizie.
|
||||
|
||||
### What already exists (grounding pe cod real, nu pe "Raport VERIFY")
|
||||
- `docs/design.md` (232 linii): **FACUT**, calitate buna. Deliverabilul "design.md" e in esenta livrat.
|
||||
- Sistem butoane (`.act`/`.act-save`/`.btn-secondary`/`.btn-ghost`/`.btn-danger`/`.btn-sm`): **NEFACUT** (absent in base.html).
|
||||
- Macro `icon()` / `act_btn()` + Lucide: **NEFACUT** (absent in `_macros.html`; doar `camp`+`autosend_toggle`).
|
||||
- Stepper compact: **NEFACUT** (`_stepper.html` inca flex 4-coloane inline = exact anti-patternul P0).
|
||||
- Grid 2 carduri/rand tableta 768-1024px: **NEFACUT** (blocul @media 1024 doar ascunde `.col-actualizat`).
|
||||
- Card mobil Trimiteri (fara gap fix 120px): **NEFACUT** (`base.html:410-412` inca `td{display:flex}`+`::before{min-width:120px}`).
|
||||
- "Raport VERIFY ... PASS" din PRD = din explorarea revertita, NU stare curenta. De NU tratat ca acceptanta.
|
||||
|
||||
### Dream-state delta
|
||||
- CURRENT: 5.12 livrat (modal cont obligatoriu) + fundatie responsive 5.9/5.11; bug-uri P0 inca prezente in tree.
|
||||
- THIS PLAN: compactare + butoane + cardificare mobil/tableta + design.md (deja partial).
|
||||
- 12-MONTH IDEAL: un sistem de design tokenizat (design.md) aplicat consecvent, cu teste pe COMPORTAMENT
|
||||
la breakpoint (nu doar string-match pe clase), astfel incat editarile CSS sa nu mai poata reverti tacit.
|
||||
Delta: planul nu instituie teste pe comportament; ramane string-match fragil (vezi Eng §2).
|
||||
|
||||
### CEO completion summary
|
||||
Plan corect ca directie de design, dar (a) supra-incadrat ca "responsive" cand miezul de valoare e
|
||||
fix-bug-desktop + butoane + design.md; (b) premisa "mobil real" nedovedita; (c) re-implementare din
|
||||
proza fara specificul CSS/test -> risc mare de a reverti din nou. design.md e cel mai durabil activ.
|
||||
|
||||
---
|
||||
|
||||
## DECIZIE PREMISA (gate user, 2026-06-27)
|
||||
**Scope: pachet complet FARA grid 2-carduri/rand pe tableta.** Actionable lists (Trimiteri,
|
||||
Preview, Mapari) raman **o coloana pana la 1024px**. Reverseaza Decizie #2 din PRD.
|
||||
-> `design.md` §3 si §5.3 trebuie editate la "o coloana pana la 1024px" in acelasi PR.
|
||||
-> Deliverabilul "grid 2/rand" si testul lui aferent SCOT din scope; se adauga guard ca raman 1 coloana.
|
||||
|
||||
## Faza 2 — Design (subagent-only; codex usage-limited)
|
||||
|
||||
### Design dual voices
|
||||
- **Codex (design):** `[codex-unavailable: usage limit]`.
|
||||
- **Claude subagent (design):** independent. Findings:
|
||||
- **Meta-hazard (high):** sectiunea "Raport VERIFY ... PASS" se citeste ca raport de finalizare
|
||||
desi munca e nelivrata -> relabel "Criterii de acceptanta (de dovedit)" sau sterge.
|
||||
- **Ierarhie card mobil 7/10:** `vehicul=titlu, stare=pill, operatie+cod` corect. RISC pe ce se
|
||||
ascunde: (a) `actualizat` (timestamp) = singurul semnal "se misca / e blocat?" pe mobil ->
|
||||
pastreaza o linie meta 12px muted SAU garanteaza in modal si spune-o; (b) `checkbox` ascuns ->
|
||||
omoara multi-select pe mobil; daca bulk "Trimite la RAR" e workflow real = regresie functionala
|
||||
tacuta (high). PRD trebuie sa declare explicit daca bulk e desktop-only by design.
|
||||
- **Stari lipsa (high):** empty/loading/error/partial ale listelor cardificate nespecificate
|
||||
(fragmente HTMX-swapped). "Eroare/Eroare" (pill+eticheta) e cel mai vizibil exact in cardul nou
|
||||
-> guard de TEMPLATE ieftin (pill-only cand `eticheta_problema == stare_text`), nu refactor routes.py.
|
||||
- **Sistem iconite 8/10 (sound):** desktop-text/mobil-icon corect, rezolva "SVG invizibil in bloc".
|
||||
Gap: (a) `act_btn` TREBUIE sa emita `aria-label={{label}}` in ramura icon-only (invariant de macro);
|
||||
(b) Sterge fara confirmare pe 44px touch = risc data-loss la mis-tap -> confirm/undo pe `act-del`.
|
||||
- **Stepper 7/10:** "Pasul N din 4" + bara progres clar. CONTRADICTIE tableta: design.md §3 = tableta
|
||||
distincta, §5.4 baga "Tableta/mobil" impreuna in forma colapsata, iar PRD linia 5 zice "compact peste
|
||||
tot". La 820px = track slim sau "Pasul N din 4"? De ales explicit.
|
||||
- **Specificitate 9/10:** cel mai puternic punct; PRD referentiaza tokenii design.md. Contradictie minora:
|
||||
stepper inline foloseste `rgba(91,141,239,.10)` hardcodat vs design.md §2.1 (color-mix obligatoriu).
|
||||
|
||||
### Design litmus scorecard
|
||||
```
|
||||
DESIGN LITMUS (codex N/A: usage limit)
|
||||
═══════════════════════════════════════════════════════════════
|
||||
Dimensiune Claude Codex Nota
|
||||
────────────────────────────────── ────── ───── ──────────────
|
||||
1. Ierarhie informatie 7/10 N/A risc pe campuri ascunse (timestamp/checkbox)
|
||||
2. Stari (empty/loading/error) 3/10 N/A nespecificate (high)
|
||||
3. Sistem iconite/butoane 8/10 N/A aria-label macro + confirm delete
|
||||
4. Stepper / wizard 7/10 N/A contradictie tableta de rezolvat
|
||||
5. Specificitate + aliniere md 9/10 N/A 1 culoare hardcodata de scos
|
||||
6. Tabel->card responsive (2-up scos) N/A o coloana pana la 1024px (decizie user)
|
||||
7. Accesibilitate (design.md §6) 8/10 N/A solid; lipseste pattern confirm distructiv
|
||||
═══════════════════════════════════════════════════════════════
|
||||
```
|
||||
|
||||
### Auto-decizii Design (6 principii)
|
||||
- Guard template "Eroare/Eroare" (pill-only): **INCLUS** (P2 boil-lakes, <1 fisier, in cardul rescris). [TASTE -> gate]
|
||||
- `act_btn` invariant aria-label in ramura icon-only: **INCLUS** (P1 completeness + a11y obligatoriu). [mecanic]
|
||||
- Confirm/undo pe `act-del` mobil: **INCLUS** ca cerinta (P1; data-loss). Implementare = confirm nativ simplu, nu modal nou (P5). [TASTE -> gate]
|
||||
- Linie meta `actualizat` pe card mobil (12px muted, timp relativ): **INCLUS** (P1; semnal "blocat"). [TASTE -> gate]
|
||||
- Bulk-select pe mobil: **DECLARAT desktop-only by design** (P3 pragmatic; checkbox ascuns pe mobil ramane), de notat in PRD. [TASTE -> gate]
|
||||
- Relabel "Raport VERIFY" -> "Criterii de acceptanta": **INCLUS** (mecanic, evita falsa finalizare).
|
||||
- Rezolvare contradictie stepper tableta: **la 768-1024px = forma colapsata "Pasul N din 4"** (P5 explicit, consecvent cu mobil; track slim doar >=1024px). [mecanic]
|
||||
- Scoatere culoare hardcodata stepper -> `color-mix(var(--accent))`: **INCLUS** (DRY/tokeni design.md §2.1). [mecanic]
|
||||
|
||||
## Faza 3 — Eng (subagent-only; codex usage-limited)
|
||||
|
||||
### Eng dual voices
|
||||
- **Codex (eng):** `[codex-unavailable: usage limit]`.
|
||||
- **Claude subagent (eng):** independent, grounded pe cod real. Findings:
|
||||
- **§2 Fragilitate teste (CRITICAL):** vezi artefact test-plan. Invariantul PRD ("un singur bloc
|
||||
@media principal") e FACTUAL GRESIT — exista DOUA blocuri (377, 404); testele feliaza ferestre
|
||||
fixe `[idx:idx+5000]` de la PRIMA aparitie; rescrierea cardului impinge `min-height:0`/`100vw`
|
||||
peste fereastra -> `test_header...` + `test_modal...` PIC. Cauza probabila a revert-ului.
|
||||
FIX OBLIGATORIU INAINTE de CSS: refactor cele 2 teste sa ancoreze pe sentinel + slice pana la EOF.
|
||||
- **§1 Arhitectura (medium):** `act_btn` randeaza si textul si SVG-ul inline, ascunzand unul per
|
||||
breakpoint -> fiecare rand de tabel duce `<path>` Lucide chiar pe desktop (bloat DOM/octeti pe
|
||||
toate viewporturile). Acceptabil (P5 simplu) sau `<use href="#sprite">` definit o data.
|
||||
- **§3 Edge cases (medium):** VIN 17 car. (`_preview_rand.html:33` nowrap) — verifica sa nu produca
|
||||
scroll orizontal la 360px dupa scoaterea gap-ului 120px.
|
||||
- **§4 Teste (high):** `test_web_mapari_actiuni.py` are 3 aserturi pe `.icon-btn` (toate se rup);
|
||||
lipsesc teste pentru: card mobil fara 120px (P0 fara guard!), `act_btn` aria-label, stepper compact.
|
||||
Plus (post-decizie): guard ca actionable lists raman 1 coloana pana la 1024px (nu 2-up).
|
||||
- **§5 Risc re-implementare (high):** PRD da intentie, nu CSS exact/offset-uri; fara fix-ul de teste
|
||||
re-implementarea reverteaza din nou. `git reflog`: NU exista commit 5.13 de recuperat (explorare necommisa).
|
||||
- **§6 Complexitate ascunsa:** `_stepper.html` e ~70 linii inline -> mutarea in base.html = CRESTERE
|
||||
base.html; plaseaz-o DEPARTE de blocul mobil 404 ca sa nu strangi bugetul de octeti al ferestrei.
|
||||
|
||||
### Eng consensus table
|
||||
```
|
||||
ENG DUAL VOICES — CONSENSUS (codex N/A: usage limit)
|
||||
═══════════════════════════════════════════════════════════════
|
||||
Dimensiune Claude Codex Nota
|
||||
────────────────────────────────── ────── ───── ─────────────────
|
||||
1. Arhitectura sound? DA* N/A inline-CSS ok; SVG bloat minor
|
||||
2. Test coverage suficient? NU N/A fragil + lipsuri (high)
|
||||
3. Riscuri performanta? minor N/A SVG inline pe randuri
|
||||
4. Securitate? N/A N/A pur CSS/markup, fara suprafata noua
|
||||
5. Error paths? NU N/A stari card nespecificate (cu Design)
|
||||
6. Risc deploy/regresie? RIDICAT N/A revert auto daca testele nu se repara intai
|
||||
═══════════════════════════════════════════════════════════════
|
||||
```
|
||||
|
||||
### Arhitectura (diagrama)
|
||||
```
|
||||
base.html (un singur <style>, no build)
|
||||
├─ :root tokeni (design.md §2) [exista]
|
||||
├─ .btn / .btn-secondary/.btn-ghost/.btn-danger/.btn-sm [DE ADAUGAT]
|
||||
├─ .act / .act-save / .act-del / .act-group [DE ADAUGAT]
|
||||
├─ .stepper* (track slim >=1024; colapsat <1024) [DE ADAUGAT, departe de blocul 404]
|
||||
├─ @media (min-width:768px)and(max-width:1024px) { ... } [exista; FARA grid 2-up]
|
||||
├─ @media (max-width:767px) { #377 mic } [exista — sursa fragilitatii]
|
||||
└─ @media (max-width:767px) { #404 PRINCIPAL } [card rescris AICI, dupa header/modal]
|
||||
_macros.html : icon(name) + act_btn(label,ic,kind,attrs) [DE ADAUGAT; aria-label invariant]
|
||||
_stepper.html: rescris pe .stepper* (fara inline inalt) [DE RESCRIS]
|
||||
_mapari.html : .icon-btn -> act_btn [DE MIGRAT]
|
||||
TESTE : refactor ferestre fixe INAINTE de CSS [BLOCANT]
|
||||
```
|
||||
|
||||
### Auto-decizii Eng (6 principii)
|
||||
- Refactor cele 2 teste fragile INAINTE de CSS: **OBLIGATORIU, BLOCANT** (P1+P5; altfel revert garantat). [mecanic]
|
||||
- Corectare invariant PRD "un singur bloc @media": **CORECTAT** (sunt doua; regula reala = adauga dupa header/modal + slice EOF). [mecanic]
|
||||
- SVG inline vs `<use>` sprite: **inline acum** (P5 explicit/simplu); sprite notat ca optimizare. [TASTE -> gate]
|
||||
- Teste noi (#2 card fara 120px, #3 act_btn aria, #4 stepper, #5 window-guard, +1-coloana guard): **INCLUSE** (P1). [mecanic]
|
||||
- "Aserturile existente pastrate (toate trec)" din PRD: **CORECTAT** la "refactor + pastreaza intentia" (imposibil ca atare). [mecanic]
|
||||
|
||||
## Decision Audit Trail
|
||||
|
||||
| # | Faza | Decizie | Clasif. | Principiu | Rationament |
|
||||
|---|------|---------|---------|-----------|-------------|
|
||||
| 1 | CEO | Scope: complet FARA grid 2/rand tableta | GATE user | - | user a ales la premise gate; ambele voci design contestau 2-up |
|
||||
| 2 | CEO | Backend NEATINS, pur CSS/markup | mecanic | P4 | confirmat de PRD; zero schema |
|
||||
| 3 | CEO | Fara framework CSS (inline ramane) | mecanic | P4/P5 | no-build potrivit HTMX; notat ca decizie |
|
||||
| 4 | CEO | Commit revertit de recuperat? NU exista | mecanic | - | git reflog: explorare necommisa; re-impl din PRD |
|
||||
| 5 | Design | Guard template "Eroare/Eroare" pill-only | taste | P2 | in cardul rescris, <1 fisier |
|
||||
| 6 | Design | act_btn aria-label invariant icon-only | mecanic | P1 | a11y obligatoriu design.md §6 |
|
||||
| 7 | Design | Confirm/undo pe act-del mobil | taste | P1 | data-loss la mis-tap 44px |
|
||||
| 8 | Design | Linie meta `actualizat` pe card mobil | taste | P1 | singurul semnal "blocat" pe mobil |
|
||||
| 9 | Design | Bulk-select = desktop-only by design | taste | P3 | checkbox ascuns pe mobil; de declarat |
|
||||
| 10 | Design | Relabel "Raport VERIFY" -> "acceptanta" | mecanic | - | evita falsa finalizare |
|
||||
| 11 | Design | Stepper 768-1024 = forma colapsata | mecanic | P5 | consecvent cu mobil; track slim >=1024 |
|
||||
| 12 | Design | Stepper color-mix in loc de hardcodat | mecanic | P4 | design.md §2.1 tokeni |
|
||||
| 13 | Eng | Refactor teste fragile INAINTE de CSS | mecanic | P1/P5 | BLOCANT; cauza probabila revert |
|
||||
| 14 | Eng | SVG inline acum (sprite deferat) | taste | P5 | simplu > optimizare prematura |
|
||||
| 15 | Eng | 5 teste noi + migrare mapari | mecanic | P1 | acopera P0 + a11y + scope guard |
|
||||
| 16 | Eng | design.md §3/§5.3 -> "1 coloana <=1024" | mecanic | - | consecventa cu decizia de scope |
|
||||
|
||||
## Cross-Phase Themes
|
||||
- **"Raport VERIFY se citeste ca facut, dar nu e"** — semnalat de Design (meta-hazard) SI implicit de
|
||||
Eng (§5 re-impl). Semnal high-confidence: relabel + grounding pe cod real, nu pe raport.
|
||||
- **Stari/erori nespecificate** — Design §2 (stari card) + Eng §4 (error paths). De adaugat o matrice de stari.
|
||||
- **Fragilitate -> revert** — Eng §2 (teste) + CEO F5 (nimic structural nu previne re-bug). Repara testele intai.
|
||||
|
||||
## Eng completion summary
|
||||
Directia de design e fina; planul livreaza DOAR daca fragilitatea testelor (§2) e rezolvata INTAI
|
||||
(refactor cele 2 teste pe ancora+EOF), altfel rescrierea cardului mobil reverteaza singura din nou.
|
||||
Invariantul PRD despre "un singur bloc @media" e gresit si trebuie corectat. design.md ramane activul durabil.
|
||||
Reference in New Issue
Block a user