Dashboard-ul incarca htmx din unpkg.com. Gateway-ul ruleaza offline (LXC/VPS
+ Cloudflare Tunnel); cand CDN-ul e blocat/inaccesibil, htmx nu se incarca si
dashboard-ul ramane static: zero polling (banner alerta blocate, coada,
mapari), butoanele de mapare nu trimit. Aceeasi decizie offline-first ca fontul
UI (FINDING-002, fara dependinta CDN).
Fix: vendorizez htmx.org@1.9.12 minificat in app/web/static/, montez StaticFiles
la /static in main.py, base.html refera /static/htmx.min.js. Verificat live:
window.htmx.version=1.9.12, fragment polls 200, zero regresie vizuala.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Link-ul 'tot' era criptic. 'export CSV: trimise' / 'toate' spune ce descarca
fiecare (don't-make-me-think).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tabelul submissions (7 coloane, 591px) iesea din card pe 390px -> toata pagina
scrolla orizontal (docScrollW 636 > 390). Wrap in .tablewrap{overflow-x:auto} +
white-space:nowrap pe celule -> scroll IN card, pagina nu mai deborda. tabular-nums
pe coloanele numerice.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T5 (tools/import_dbf.py): citire prestatii_rar.DBF / mapare_prestatii.DBF cu
dbfread, raport dry-run (randuri valide/duplicate/goale, mapari orfane = cod
necunoscut in nomenclator), --commit cu upsert idempotent in tranzactie.
Dashboard: browser nomenclator, indicator stare RAR (indisponibil? derivat din
ultimul login < 30h, coada arata ultima stare locala), export audit CSV
(/v1/audit/export?status=sent|all&date_from&date_to, b64Image exclus,
coloana purge_after pentru retentia 90z).
Verify: 11 teste noi (test_import_dbf 6, test_dashboard 5), suita 111 pass,
dry-run real pe DBF-urile din repo + smoke live dashboard/CSV.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T6 — worker supravegheat:
- app/worker/healthcheck.py: probe pe heartbeat-ul din DB (beat invechit -> exit 1).
Prinde worker-ul agatat (proces viu, beat inghetat) pe care restart:always nu-l
vede. Cablat ca healthcheck pe serviciul worker in compose.
- sidecar autoheal: restarteaza efectiv containerul unhealthy (compose simplu doar
marcheaza, nu restarteaza la unhealthy).
T7 — deploy:
- tools/backup.py: backup ONLINE via Connection.backup (WAL nu se copiaza sigur cu
cp); --keep N roteste snapshot-urile.
- .env.example documenteaza env-urile; volum persistent numit deja in compose.
Fix critic (split api/worker in 2 containere): AUTOPASS_CREDS_KEY trebuie PARTAJATA
api<->worker, altfel worker nu decripteaza creds-urile criptate de API -> submission
blocate. Acum impusa in compose (${...:?} -> fail explicit daca lipseste).
.gitignore: exceptie !.env.example.
5 teste noi (tests/test_deploy.py). 100 pass total.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Plan sect.5: parola RAR vine per-cerere, stocata CRIPTATA in submission pana la
primul login reusit pe cont, apoi stearsa; JWT 30h acopera restul.
- app/crypto.py: Fernet, cheie din AUTOPASS_creds_key (nesetata -> efemera la
runtime, creds nu supravietuiesc restartului). encrypt/decrypt_creds.
- schema + migrare: submissions.rar_creds_enc (creds criptate).
- ingestie: cripteaza rar_credentials, le lipeste de fiecare submission nou.
Niciodata in clar in DB.
- worker: AccountSessions (login per-cont cu creds decriptate, cache JWT in
memorie, sterge creds-urile contului dupa primul login + refresh nomenclator).
401 creds gresite -> error fara retry; token expirat -> invalidare + requeue;
fara creds (restart) -> requeue "indisponibile" (ROAAUTO re-trimite).
claim_one intoarce account_id + creds_enc; recover_orphans filtrabil pe cont.
- requirements: cryptography==46.0.5.
Nota: refresh nomenclator e acum lazy la primul login per-cont (nu la pornire);
seed-ul fallback acopera editorul offline.
10 teste noi (tests/test_creds_delivery.py). 95 pass total.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Redactare:
- handler RequestValidationError dropeaza input/ctx din 422 (vectorul de
scurgere a rar_credentials.password pe /v1/prezentari); pastreaza type/loc/msg
- app/security.py: scrub/scrub_text + CredentialRedactingFilter pe root+uvicorn
- models.py: password cu repr=False
Auth API-key:
- app/auth.py: hash SHA-256 in api_keys (cheia in clar emisa o singura data),
header X-API-Key / Authorization: Bearer, dependency resolve_account_id
- enforcement pe flag AUTOPASS_require_api_key (prod on->401, dev off->cont
default id=1; cheie prezenta invalida->401 mereu)
- account_id real curge din cheie in ingestie + mapare
- tools/apikey.py: CLI create/rotate/revoke/list (fara endpoint HTTP admin)
16 teste noi (tests/test_security.py). 85 pass total.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T5 reinterpretat: nu import DBF, ci editor web al maparii operatie ROAAUTO ->
cod RAR, cu fuzzy lookup si validare de catre utilizator.
- Contract hibrid: item prestatie accepta cod_prestatie (RAR direct, back-compat)
SAU cod_op_service+denumire (mapat de gateway prin operations_mapping).
- Ingestie: op intern necunoscut -> submission needs_mapping (nu pleaca la RAR);
codul rezolvat se scrie inapoi in payload_json -> payload builder + worker neatinse.
- Editor HTMX (_mapari.html + GET /_fragments/mapari, POST /mapari): listeaza
op-urile nemapate, fuzzy preselecteaza codul RAR, save -> re-rezolvare automata
(queued / needs_data).
- Fuzzy: rapidfuzz.token_sort_ratio pe denumire normalizata (fara diacritice).
- Nomenclator: seed fallback 18 coduri la boot (offline) + refresh live din worker.
- Cont default id=1 cat timp auth API-key (CORE) nu exista (account_id NULL).
- Endpointuri API: GET /v1/mapari/pending, POST /v1/mapari (respinge cod inexistent).
- 15 teste noi (tests/test_mapping.py); 69 pass total.
- Contract actualizat (docs/api-rar-contract.md), rapidfuzz==3.14.5 in requirements.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Verificat contractul RAR AUTOPASS pe endpoint-ul de test si compilat sursa
de adevar `docs/api-rar-contract.md`. Corectii majore fata de planurile vechi:
- JWT TTL = 30h (nu scurt); worker se re-logheaza, retry neplafonat
- b64Image optional; tipPrestatie generat de server (nu se trimite)
- anulare/corectie prin API inexistente pentru FINALIZATA
- needs_data determinist pe R-ODO/I-ODO; reguli validare exacte (VIN/data/nrInm)
Rulat plan-eng-review + plan-design-review, apoi consolidat ambele intr-un
singur plan executabil `docs/plans/plan.md` (design ca anexa). Outside voice
a prins lost-ack double-submit (P1) -> reconciliere inainte de re-send.
Re-push din ROAAUTO scos din v1 (durabilitate = SQLite persistent + restart).
- mutat fisierele spec oficiale RAR in docs/
- adaugat raspunsul oficial al programatorilor RAR (api-rar-documentatie-oficiala.md)
- sterse plan-eng-review.md + plan-design-review.md (consolidate in plan.md)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Arhiva clasei RarAutoPass (VFP) care declara prestatiile la RAR AUTOPASS,
ca baza pentru rescrierea ca gateway central Python/FastAPI.
Include:
- sursa VFP (.prg) + datele necesare migrarii (mapare_prestatii, prestatii_rar)
- spec-ul oficial RAR (txt)
- docs/plans/: plan-design-review + plan-eng-review
- docs/CONTEXT.md: handoff pentru continuarea in alta sesiune
- .gitignore specific Visual FoxPro (ignora artefacte compilate + credentiale)
settings.xml (cu parola de test in clar) EXCLUS; vezi settings.xml.example.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>