# AutoPass — Roadmap & Proces de Dezvoltare > **Sursa unica de progres + procesul de lucru.** O sesiune noua are nevoie doar de promptul: > *"Citeste docs/ROADMAP.md si continua roadmap-ul [optional: livrabila X.Y]."* > Sesiunea isi detecteaza singura faza (§5.7), planifica SAU executa, verifica si inchide — > cu doua porti umane: aprobarea PRD-ului si confirmarea commit-ului. > > Contractul RAR (sursa de adevar de contract) = `docs/api-rar-contract.md`. Acolo unde un plan > difera de contract, **contractul are dreptate**. > > Status fara emoji (preferinta proiect): **TODO** neinceput · **WIP** in lucru · **DONE** gata · > **BLOCAT** blocat de o dependenta · **AMANAT** deferat/taiat cu motiv. --- ## 1. Context Gateway central care declara prestatiile de service-auto la **RAR AUTOPASS** (Legea 142/2023, OM 210/2024), portat din clasa Visual FoxPro `RarAutoPass` (ROAAUTO). Stack: **Python/FastAPI + SQLite (WAL) + httpx + Jinja2/HTMX**. Un container (API) + un proces separat (worker). Doua canale de intrare, ambele **LIVE pe endpoint-ul de test RAR**: - **Treapta 1** — canal API (`POST /v1/prezentari`) pentru ROAAUTO / soft propriu. - **Treapta 2** — import xlsx/csv + mapare coloane + UI web (HTMX) pentru service-uri non-ROA. --- ## 2. Arhitectura (rezumat) ``` Canal API (ROAAUTO) ─┐ Upload web (xlsx/csv) ─┴─▶ Gateway FastAPI ─▶ validare → mapare op→cod → enqueue (PII criptat) │ ▼ WORKER (proces separat): claim atomic → login RAR → postPrezentare → retry │ Dashboard (Jinja2+HTMX) ◀───────┴── monitorizare live RAR + coada + editor mapari + audit CSV ``` Reguli de contract (detalii in `docs/api-rar-contract.md`): `FINALIZATA` e terminal la RAR (fara anulare/corectie prin API); idempotency = hash de continut server-side; JWT TTL = 30h. --- ## 3. Stadiu Implementare (dashboard) > **Singurul loc din document care se modifica pe parcurs.** Detaliile NU intra aici — stau in > PRD-uri (`docs/prd/prd-X.Y-*.md`), linkate in coloana Detalii. La fiecare livrabila terminata: > schimba statusul + data + linkul PRD si actualizeaza "Ultima actualizare". **Ultima actualizare**: 2026-06-23 — 5.7 LIVRAT (raspuns API onest la blocaje + mapare inline din detaliu). Raportat din client VFP: `POST /v1/prezentari` intorcea `submission_id`+`status` FARA motiv pe randuri blocate (`erori` se popula doar pe ramura `on_unmapped_error=True`) → un `needs_data`/`needs_mapping` parea succes ("raspuns fara erori"). Reparat ADITIV: `SubmissionResult` += `nemapate` + `motiv`; `create_prezentari` populeaza `erori` (validare continut, 3 niveluri) / `nemapate` (coduri fara mapare, COD_NEMAPAT) / `motiv` (rezumat uman) pe TOATE caile non-`queued` — enqueue, respins (`on_unmapped_error=True`) si reactivare dedup peste `error`. UI: mapare inline in panoul de detaliu trimitere (`POST /trimitere/{id}/mapeaza`, reuse EXACT `save_mapping`+`reresolve_account`, scoped sesiune + CSRF, re-rezolva pe `batch_id`-ul randului → deblocheaza si randurile-frate; apare doar pe operatii nemapate reale, nu pe auto_send=0) — fara drum prin tab-ul Mapari. `/code-review high`: 2 buguri reale reparate (reactivarea omitea `erori`/`nemapate`/`motiv`; dublu `load_nomenclator` in `_detaliu_ctx`), restul candidatilor infirmati la verify (parse `auto_send` corect via `or ""`; lipsa `conn/account_id` pe ramuri de corectie nereachable cu needs_mapping+unmapped). `pytest -q` **765 passed, 0 failed**. PRD: [prd-5.7](prd/prd-5.7-raspuns-onest-mapare-inline.md). | ISTORIC: FIX out-of-process (raportat din client VFP): `cod_prestatie` necunoscut in nomenclator era trimis raw la RAR → **HTTP 500** (`ORA-12899`, coloana `COD_PRESTATIE` max 5 car.) + record PARTIAL `FINALIZATA` (RAR ne-tranzactional) pe care reconcilierea il marca fals `sent`. Reparat: validare `cod_prestatie` fata de nomenclator la ingestie (cod necunoscut → tratat ca operatie de mapat, nu se mai trimite raw) + optiune boolean `on_unmapped_error` (`false` default → needs_mapping | `true` → respinge) per-cerere cu default per-cont `accounts.on_unmapped_error_default` (migrare aditiva). Confirmat live raspunsul RAR (500 pe cod intern vs 200 pe `OE-1`). Inclus si in `c842e33`: fix lease orfan worker (nepotrivire format data sending_since vs cutoff → orice rand `sending` parea expirat) + guard anti-dublu-POST + fix UI `hx-confirm` mostenit pe randuri (alerta de stergere la click pe rand). Teste: **748 passed** (cele 2 esecuri pre-existente fara legatura). Contract + CLAUDE.md actualizate. | 5.6 IMPLEMENTAT + VERIFY PASS (asteapta commit). Cele 14 stories din PRD 5.6 livrate TDD (RED->GREEN), `pytest -q` **741 passed, 0 failed**. Lifecycle trimiteri blocate (Val A primul, decizie #18): `app/submissions_admin.py` (sterge/repune scoped, 404-before-409); reactivare dedup peste `error` cu CAS + invalidare sesiune worker la creds noi (T1) + propagare `accounts.rar_creds_enc` (#17) + camp aditiv `reactivated:true` (#19); retentie randuri blocate 30z + `purge_after` curatat la reactivare/requeue (T2); API `DELETE`/`/repune` (200+JSON, #20); UI butoane + bulk + banner "Necesita atentia ta" actionabil cu deep-link. Observabilitate: `app/observ.py log_event` (dublu canal `app_events` DB + `RotatingFileHandler` per-proces, redactare creds/PII la scriere via `app/security.redact_pii`/`vin_partial`), `request_id` middleware + `X-Request-ID` pe toate raspunsurile (T8), handler global excepții -> 500 envelope 6-chei + request_id (T7), audit cerere API (`api_prezentari`/`api_auth_esuat`) + audit worker (`rar_login`/tranzitii), tab "Jurnal" filtrabil scoped (non-admin doar contul sau), retentie jurnal 90z. Live RAR `--send` NEPROBAT in sesiune (recomandat la deploy: confirma `rar_login` ok + `submission_sent` in jurnal). PRD actualizat cu raport VERIFY; contract actualizat cu endpointurile noi (T10). | ISTORIC: HOTFIX livrat + 5.6 APROBAT. Hotfix 500 pe `POST /v1/prezentari` (raportat din client Visual FoxPro): `AUTOPASS_CREDS_KEY` din `.env` nu respecta formatul Fernet (32 bytes url-safe base64) → `ValueError` la primul `encrypt_creds` → 500 brut. Reparat: cheie Fernet valida in `.env` + `crypto.validate_creds_key()` apelata in `main.lifespan` (fail-fast la startup, mesaj clar in loc de 500 la primul POST). Confirmat live: POST VFP → 200 `queued`; trimitere reala pe RAR test → `sent idPrezentare=68818` (verificat independent in finalizate). Corectat si mesajul fals din dashboard pentru starea `error` in `labels.py` ("se reincearca automat" → starea e terminala, NU se reincearca). Investigatia a expus 3 goluri structurale (500 brut fara traducere 3 niveluri; lipsa jurnal de aplicatie la nivel de eveniment; lacune de lifecycle — randuri blocate permanente, dedup blocat de un rand `error`, banner "Necesita atentia ta" neactionabil) → **PRD 5.6 APROBAT** (14 stories; decizii §5 rezolvate cu user). PRD: [prd-5.6](prd/prd-5.6-observabilitate-jurnal.md). | ISTORIC: 5.5 LIVRAT (uniformizare/standardizare UI/UX: tabele la grila Trimiteri, meniu hamburger + tab-bar redus Acasa/Mapari, sterge Ajutor de pe Acasa, panou admin cu selectie+bulk pe model nou `accounts.status`. 9 stories in 3 valuri, UI pur cu o singura exceptie backend = stare cont; stergere soft cu purjare PII imediata GDPR. VERIFY 671 teste + E2E browser (2 bug-uri prinse) + `/code-review high` (2 bug-uri reale reparate). Commit `1fbd894`, vezi randul 5.5). | ISTORIC: 5.4 LIVRAT (Erori pe 3 niveluri problema+cauza+fix pe API si UI: catalog central pur `app/errors.py` ca SINGURA sursa de adevar cod→{problema,fix}, consumat de API+UI+worker — face imposibila divergenta intre canale, acelasi invariant ca 5.2. 8 stories in 5 valuri. Tot ADITIV: `field`/`message`/`error` pastrate la octet, adaugam `cod/problema/cauza/fix`; `rar_error` stocat = SUPERSET (chei vechi intacte → `labels.py` nu se rupe intre valuri, zero migrare). Scope = fluxul de declarare; login/signup/CSRF neatinse. UI progresiv: lista compacta, 3 niveluri complete in detaliu/preview, AA light+dark. VERIFY context curat PASS 628 teste (byte-compat+superset verificate direct, E2E API+web; live RAR neprobat — lipsa creds key). `/code-review high`: 2 bug-uri reale reparate in `labels.py` (`motiv_uman` fara ramura 3-niveluri → 401 creds garbled in coloana Motiv; `parse_erori` element gol pe `{}`). 631 teste. Backend trimitere + schema NEATINSE. PRD: [prd-5.4](prd/prd-5.4-erori-3-niveluri.md)). | ISTORIC: 5.3 LIVRAT (Light/Dark mode: tema light ca bloc `[data-theme="light"]` peste variabilele `:root` — dark NESCHIMBAT la octet; comutator soare/luna in header pe toate paginile, default OS-aware cu fallback dark, persistenta `localStorage` doar la comutare explicita, script anti-FOUC in `
` pre-paint; suprafetele de stare hardcodate convertite la `color-mix` in `base.html` + 7 fragmente. Zero backend — pur frontend. VERIFY 2 runde: r1 FAIL a prins literalii dark ramasi in 7 fragmente HTMX (text invizibil in light, test vacuu pe doar base.html) → fix US-003 + test care scaneaza fragmentele; r2 PASS E2E browser (banner light ~13:1 contrast, toggle instant+persista+anti-FOUC, dark identic). `/code-review` high: 1 finding reparat (light `--ok` green sub AA ca text → green-700, ~5.0:1). 584 teste. PRD: [prd-5.3](prd/prd-5.3-light-dark-mode.md)). | ISTORIC: 5.2 LIVRAT (Endpoint dry-run `POST /v1/prezentari/valideaza`: valideaza payload + mapare si intoarce verdictul real — `status_estimat` queued/needs_data/needs_mapping + erori `[{field,message}]` + coduri nemapate + prestatii rezolvate — FARA enqueue, FARA creds, zero scriere DB). 1 story TDD. Cheia de design: helper pur partajat `classify_prezentare` folosit de AMBELE rute, ca dry-run-ul sa nu poata diverge de trimiterea reala (invariant de corectitudine); `create_prezentari` refactorizat pe el cu comportament identic. Scope minim per decizie user: doar validare+mapare (fara idempotency/duplicat, `idempotency.py` neatins), hub `/integrare` amanat ca follow-up (descoperibilitate). VERIFY context curat PASS (577 teste; E2E API cu cele 3 verdicte + COUNT(*)=0 dupa dry-run + fara leak creds in raspuns; regresia de aur verde; live RAR `FINALIZATA` neprobat — lipsa creds key, endpoint read-only nu atinge worker/coada/schema). `/code-review` high: 0 findings (refactor faithful, mutable-default Pydantic-safe, import local necesar anti-circular). PRD: [prd-5.2](prd/prd-5.2-dryrun-valideaza.md). | ISTORIC: 5.1 LIVRAT (Hub de integrare `/integrare`: exemple cod multi-limbaj + retetar VFP cu 2 dialecte + `GET /v1/ping` readiness + export Postman/OpenAPI + "Testeaza conexiunea"). 4 stories in 2 valuri (Val 1 = US-001/US-002/US-004 paralel pe fisiere disjuncte via Agent team; Val 2 = US-003 UI). Atentie operationala: US-003 a rulat intr-un worktree branched din ultimul commit (FARA modificarile necomise ale US-004 din working-tree) si la "copiere manuala" a SUPRASCRIS `routes.py`, stergand ruta `POST /integrare/test-cheie` (8 teste 404) — reparat prin re-aplicarea rutei de catre autorul US-004 pe `routes.py` curent. Lectie: stories care ating acelasi fisier in valuri diferite + worktree = clobber daca worktree-ul nu vede working-tree-ul; foloseste fisiere disjuncte SAU merge atent de catre lead. VERIFY context curat PASS (568 teste) + E2E browser Playwright (deep-link server-side, IA pe 2 niveluri, VFP cu 3 niveluri de tab comuta corect, copy, htmx test-cheie → fragment eroare, 0 erori consola) + enqueue live (`POST /v1/prezentari` → queued); live RAR `FINALIZATA` NEPROBAT in sesiune (lipsa `AUTOPASS_CREDS_KEY`/creds RAR test) — risc minim, backend trimitere NEATINS. `/code-review` high a prins 4 bug-uri reale (toate in suprafata noua, reparate + lock-uite cu teste): snippet C# JSON multi-linie nevalid (CS1010), snippet VFP `json.dumps(indent=0)` inca cu newline-uri → string literal rupt in ambele dialecte, snippet Node `node:buffer` nu exporta FormData → TypeError, script `_integrare.html` ne-scoped acumuland event-listeneri pe tab-bar-ul principal la fiecare swap htmx (scoped pe `#integrare-section`). Notat ca cleanup viitor (nereparat): `_render_integrare` dubleaza SQL `are_creds`/`are_cheie`, `ping` cu 2 conexiuni DB + `account_for_key` de 2 ori, `_campuri_obligatorii` necache-uit, panouri limbaj copy-paste (candidat macro Jinja2). Backend trimitere (worker/masina stari/idempotenta/mapping) si schema NEATINSE. PRD: [prd-5.1](prd/prd-5.1-hub-integrare.md). | ISTORIC: 3.6 INCHIS (editare celule in preview + Acasa unificata). CLOSE: `/code-review` high a prins 1 bug real (decriptare `override_json` neprotejata de try/except in ambele cai de preview — 500 pe tot batch-ul la rotatie cheie Fernet vs. `raw_json` care degrada gratios), reparat in `import_router.preview_import` + `routes._web_compute_preview`; duplicarea `_override_of`/canonicalize notata ca cleanup viitor. 523 teste pass. 7 stories in 3 valuri, executate de 2 echipe in paralel (TeamCreate) pe fisiere disjuncte (core: routes/import/templates; mapari: `_mapari.html`) + US-007 secvential. Livrate: tab "Trimiteri" eliminat→sectiune "Trimiterile tale" sub upload pe Acasa (US-003); upload bara slim accentuata cu hero la first-run (US-004); editare de celule in preview prin `import_rows.override_json` (Approach B, Fernet, patch canonic aplicat ULTIMUL in `_resolve_row_for_preview`+`commit_import` — completeaza inclusiv coloane ABSENTE din fisier), mutatie pura cu status rederivat (US-001); buton Editeaza pe rand cu swap pe ``, empty-state CTA, export `.cardlink`, doar tokens. US-004 `POST /integrare/test-cheie` (`account_for_key` direct, scoped sesiune, no-echo). VERIFY: 568 teste + E2E browser (Playwright: VFP 3 niveluri comuta, htmx test-cheie → fragment eroare, 0 erori consola) + enqueue live; live RAR neprobat (lipsa creds key). `/code-review` high: 4 bug-uri reale reparate (C#/VFP snippet JSON multi-linie nevalid, Node `node:buffer` fara FormData, script ne-scoped acumuland listeneri). Backend trimitere NEATINS. PRD: [prd-5.1](prd/prd-5.1-hub-integrare.md) |
| 5.2 | Endpoint dry-run `POST /v1/prezentari/valideaza` — valideaza payload + mapare, intoarce erorile reale FARA enqueue | DONE | 2026-06-22 | 1 story (US-001), un worker TDD. Helper pur partajat `classify_prezentare` (mapping.py) folosit de AMBELE rute → garanteaza ca dry-run-ul da acelasi verdict ca trimiterea reala (invariant de corectitudine, nu doar DRY); `create_prezentari` refactorizat pe el (comportament identic, test_api.py verde). Ruta read-only: `{results:[{index,valid,status_estimat,erori,nemapate,prestatii_rezolvate}]}`, `rar_credentials` optional+ignorat, zero scriere DB, scope prin `resolve_account_id`. Doar validare+mapare (FARA idempotency/duplicat — decizie user; `idempotency.py` neatins) + hub `/integrare` amanat. VERIFY context curat PASS (577 teste; E2E API: queued/needs_data/needs_mapping + COUNT(*)=0 dupa dry-run, fara leak creds; regresia de aur `POST /v1/prezentari`→queued verde; live RAR neprobat — lipsa `AUTOPASS_CREDS_KEY`/creds test, endpoint read-only nu atinge worker/coada). `/code-review` high: 0 findings. PRD: [prd-5.2](prd/prd-5.2-dryrun-valideaza.md) |
| 5.3 | Light/Dark mode — toggle in header, persistat (localStorage); CSS deja pe variabile `:root` | DONE | 2026-06-22 | 3 stories (US-001 paleta light + US-003 fix suprafete fragmente; US-002 comutator+persistenta+anti-FOUC), un worker TDD secvential (toate ating templates). Tema light = bloc `[data-theme="light"]` care suprascrie variabilele `:root` (dark NESCHIMBAT la octet, default pastrat); fundalurile de stare hardcodate (`#241a1a`/`#201c0f`/`#16241c`) convertite la `color-mix(... 12%, var(--card))` in `base.html` + 7 fragmente `_*.html`. Comutator soare/luna in header (aria-label, >=36px), pe toate paginile (login/signup/dashboard/admin). Default OS-aware (`prefers-color-scheme`, fallback dark); persistenta `localStorage` DOAR la click (init doar sincronizeaza iconita → OS-aware ramane viu pana la comutare explicita); script anti-FOUC in `` inainte de `