docs(5.20): PRD medii RAR per cont (Testare/Productie) aprobat + roadmap
Doua medii RAR configurabile per cont, fiecare cu bifa de activare si set propriu de credentiale. medii_disponibile=enabled AND creds deriva tot UX-ul. 13 stories / 6 valuri. Premisa verificata live: test/prod = sisteme separate. 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
478
docs/prd/prd-5.20-target-rar-test-productie.md
Normal file
478
docs/prd/prd-5.20-target-rar-test-productie.md
Normal file
@@ -0,0 +1,478 @@
|
||||
<!-- /autoplan restore point: /home/claude/.gstack/projects/romfast-rar-autopass/main-autoplan-restore-20260629-184940.md -->
|
||||
# PRD 5.20 — Medii RAR per cont (Testare / Productie): activare, credentiale, selectie per trimitere
|
||||
|
||||
**Stare**: aprobat
|
||||
|
||||
> Proces complet: `docs/ROADMAP.md` §5. Contract RAR (sursa de adevar): `docs/api-rar-contract.md`.
|
||||
> Stare: `draft -> aprobat -> in-executie -> verify-pass -> inchis`.
|
||||
|
||||
## 1. Obiectiv
|
||||
|
||||
Trateaza **Testare** si **Productie** ca doua medii RAR configurabile **per cont**. Fiecare mediu are, independent:
|
||||
o **bifa de activare** si un **set propriu de credentiale**. Un mediu e *disponibil* pentru trimitere doar daca e
|
||||
activat SI are credentiale. Din disponibilitate decurge tot UX-ul: cand un singur mediu e disponibil totul merge
|
||||
acolo (fara selector); cand ambele sunt disponibile, apare selector la import + toggle in statusbar + alegere in
|
||||
API. Trimiterile arata mereu un **badge** cu mediul tinta. Scop: clientul declara real pe Productie, iar cine are
|
||||
si cont de test RAR isi poate testa integrarea pe Testare — fara redeploy si fara variabila globala de mediu.
|
||||
|
||||
**Premisa verificata (2026-06-29, doua seturi reale)**: test si prod sunt sisteme RAR **complet separate**; un set
|
||||
de credentiale se autentifica pe **exact unul** (creds dev: test 200 / prod 401; creds client real: test 401 /
|
||||
prod 200). Deci 2 seturi de creds per cont; un cont prod-only NU poate trimite la test fara cont de test emis de RAR.
|
||||
Detaliu memorat: vezi memoria de proiect "rar-test-prod-creds-separate".
|
||||
|
||||
## 2. Non-Goals (anti scope-creep)
|
||||
|
||||
- NU eliminam `AUTOPASS_RAR_ENV` global: ramane **ancora de migrare** + fallback pentru actiuni de sistem fara cont
|
||||
(ex. keepalive login). Per-submission are precedenta cand exista.
|
||||
- NU configuram base_url-uri din UI (raman in `config.py`); NU adaugam un al treilea mediu.
|
||||
- NU gating pe plan/tier pentru Productie (decizie user: liber). „Guard-ul" e: Productie e tinta doar daca e
|
||||
activata + are creds, plus o confirmare unica la activarea Productie (constientizare L.142), NU per trimitere.
|
||||
- NU schimbam masina de stari, backoff-ul, sau payload-ul `postPrezentare`.
|
||||
- NU migram automat credentiale de prod ale clientilor — ei le introduc; migrarea doar muta creds-ul existent in
|
||||
slotul mediului sub care contul opera efectiv.
|
||||
|
||||
## 3. Cerinte transversale (reguli de derivare)
|
||||
|
||||
- **REQ-DISP**: `medii_disponibile(cont)` = mediile din {test, prod} cu `enabled=1` SI creds prezente. Sursa unica
|
||||
de adevar pentru vizibilitatea selector/toggle si pentru validarea unei tinte cerute.
|
||||
- **REQ-VIZ**: selector la import + toggle in statusbar apar DOAR cand `len(medii_disponibile) >= 2`. La 1 mediu,
|
||||
tinta e implicita (acel mediu), fara selector. La 0, trimiterea e blocata cu mesaj „configureaza credentiale RAR".
|
||||
- **REQ-BADGE**: orice trimitere afiseaza badge Test/Productie (chiar si la 1 mediu — claritate ca declari real).
|
||||
- **REQ-DEFAULT**: `rar_env_default(cont)` e mereu unul din mediile disponibile; cont client nou = `prod`. Daca
|
||||
default-ul nu mai e disponibil (mediu dezactivat), cade pe singurul disponibil; daca 0 disponibile -> nicio tinta.
|
||||
- **REQ-CONF**: trimiterea pe Productie nu cere confirmare per-rand; constientizarea vine din badge + o confirmare
|
||||
UNICA la activarea mediului Productie in configurare.
|
||||
|
||||
## 4. Stories atomice
|
||||
|
||||
> Backend + UI pentru acelasi comportament = stories separate. `Fisiere` + `Depinde de` complete.
|
||||
|
||||
### US-001: Schema — medii per cont (activare + creds) + env pe submission
|
||||
**Ca** sistem **vreau** sa stochez per cont activarea si credentialele fiecarui mediu, default-ul, si env-ul tinta
|
||||
pe fiecare submission **pentru ca** test si prod sunt sisteme separate cu credentiale separate.
|
||||
|
||||
- **Depinde de**: —
|
||||
- **Fisiere**: `app/schema.sql`, `app/db.py` (migrare idempotenta), `tests/test_schema_migrate.py`
|
||||
- **Test intai (RED)**: `tests/test_schema_migrate.py` — `test_coloane_medii_pe_cont`,
|
||||
`test_default_client_prod_on_test_off`, `test_migrare_creds_in_slotul_env_global`, `test_submissions_rar_env`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] `accounts`: `rar_test_enabled INTEGER NOT NULL DEFAULT 0`, `rar_prod_enabled INTEGER NOT NULL DEFAULT 1`
|
||||
(ambele CHECK IN (0,1)); `rar_creds_test_enc TEXT`, `rar_creds_prod_enc TEXT`;
|
||||
`rar_env_default TEXT NOT NULL DEFAULT 'prod' CHECK (rar_env_default IN ('test','prod'))`
|
||||
- [ ] `submissions.rar_env TEXT NOT NULL DEFAULT 'test' CHECK (rar_env IN ('test','prod'))`
|
||||
- [ ] **Migrare existenti (NU presupune env-ul)**: `rar_creds_enc` -> slotul `AUTOPASS_RAR_ENV` global de la
|
||||
migrare; seteaza `enabled=1` DOAR pe mediul cu creds; `rar_env_default` = acel mediu. Conturi fara creds:
|
||||
raman pe default-urile coloanei (prod on / test off). Coloana veche RAMANE acum (dropul e in US-013, dupa
|
||||
ce toate citirile trec pe per-env)
|
||||
- [ ] **(AUTO-FIX G — CRITIC, amendament AC) Backfill `submissions.rar_env` EXISTENT din `AUTOPASS_RAR_ENV`
|
||||
global**, NU lasa pe `DEFAULT 'test'`. Un rand prod pre-migrare etichetat 'test' -> US-006 reconciliaza
|
||||
contra endpoint TEST -> no-match -> re-send prod = DUPLICAT REAL IREVERSIBIL. `DEFAULT 'test'` ramane doar
|
||||
plasa pentru randuri net-noi (fiecare INSERT din US-004/005/009 seteaza `rar_env` explicit)
|
||||
- [ ] **(AUTO-FIX E4/3) Recompute `idempotency_key` pentru randurile existente** la forma env-aware
|
||||
(`build_key(account_id, canon, rar_env)` cu `rar_env`-ul backfill-at), ca lookup-urile de dedup (API +
|
||||
import) sa nu rateze randuri legacy -> altfel re-POST = duplicat
|
||||
- [ ] `test_submissions_rar_env` asserteaza ca un rand PRE-migrare ajunge cu env-ul global (NU 'test') si
|
||||
reconciliaza contra endpointului corect
|
||||
- [ ] migrare idempotenta pe DB existent, fara pierdere de date
|
||||
- [ ] `python3 -m pytest tests/test_schema_migrate.py -q` PASS
|
||||
- **Verificare E2E**: DB pre-migrare cu `AUTOPASS_RAR_ENV=test` -> creds aterizeaza in `rar_creds_test_enc`,
|
||||
`rar_test_enabled=1`, `rar_env_default='test'`.
|
||||
|
||||
### US-002: Logica de disponibilitate si default efectiv
|
||||
**Ca** sistem **vreau** un helper unic care intoarce mediile disponibile si default-ul efectiv al unui cont
|
||||
**pentru ca** vizibilitatea UI, API-ul si worker-ul sa decida identic (REQ-DISP/REQ-DEFAULT).
|
||||
|
||||
- **Depinde de**: US-001
|
||||
- **Fisiere**: `app/rar_env.py` (nou) sau `app/mapping.py`, `tests/test_rar_env_disponibil.py`
|
||||
- **Test intai (RED)**: `tests/test_rar_env_disponibil.py` — `test_doar_prod_cu_creds`, `test_ambele`,
|
||||
`test_zero_cand_lipsesc_creds`, `test_default_cade_pe_singurul_disponibil`, `test_enabled_fara_creds_nu_e_disponibil`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] `medii_disponibile(account) -> list[str]` (subset din ['test','prod']) = enabled AND creds prezente
|
||||
- [ ] `rar_env_efectiv(account) -> 'test'|'prod'|None` aplica REQ-DEFAULT
|
||||
- [ ] `python3 -m pytest tests/test_rar_env_disponibil.py -q` PASS
|
||||
- **Verificare E2E**: —
|
||||
|
||||
### US-003: Idempotenta include rar_env
|
||||
**Ca** sistem **vreau** ca `build_key` sa incorporeze `rar_env` **pentru ca** aceeasi prezentare la test si apoi
|
||||
la prod sunt doua trimiteri reale distincte, nu un duplicat.
|
||||
|
||||
- **Depinde de**: —
|
||||
- **Fisiere**: `app/idempotency.py`, `tests/test_idempotency.py`
|
||||
- **Test intai (RED)**: `tests/test_idempotency.py` — `test_key_difera_intre_test_si_prod`, `test_key_stabil_pe_env`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] `build_key(account_id, canon, rar_env)` -> chei diferite test vs prod pe acelasi continut; stabil pe re-apel
|
||||
- [ ] toate apelurile (`router.py`, `import_router.py`) trec env-ul rezolvat
|
||||
- [ ] `python3 -m pytest tests/test_idempotency.py -q` PASS
|
||||
- **Verificare E2E**: —
|
||||
|
||||
### US-004: Rezolvare tinta la ingestie (cerere > default cont) + respinge tinta indisponibila
|
||||
**Ca** sistem **vreau** sa decid env-ul unui submission si sa resping tintele indisponibile **pentru ca** o tinta
|
||||
fara mediu activ/creds nu trebuie sa intre in coada.
|
||||
|
||||
- **Depinde de**: US-002
|
||||
- **Fisiere**: `app/validation.py`, `app/mapping.py`, `tests/test_rar_env_resolve.py`
|
||||
- **Test intai (RED)**: `tests/test_rar_env_resolve.py` — `test_cerere_castiga`, `test_fallback_default_cont`,
|
||||
`test_tinta_indisponibila_respinsa`, `test_valoare_invalida`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] precedenta: valoare ceruta (daca e in `medii_disponibile`) > `rar_env_efectiv(cont)`
|
||||
- [ ] tinta ceruta dar indisponibila -> eroare clara („mediul X nu e activat / fara credentiale"), fara enqueue
|
||||
- [ ] valoare invalida (≠ test/prod) -> eroare de validare, fara fallback silentios
|
||||
- [ ] `python3 -m pytest tests/test_rar_env_resolve.py -q` PASS
|
||||
- **Verificare E2E**: —
|
||||
|
||||
### US-005: API — camp `rar_target` pe POST /v1/prezentari si /valideaza
|
||||
**Ca** integrator ROAAUTO **vreau** sa pot preciza `rar_target`, cu default = default-ul contului meu **pentru ca**
|
||||
sa aleg unde declar fara sa stiu env-ul global.
|
||||
|
||||
- **Depinde de**: US-003, US-004
|
||||
- **Fisiere**: `app/api/v1/router.py`, `app/models.py`, `tests/test_api_rar_target.py`
|
||||
- **Test intai (RED)**: `tests/test_api_rar_target.py` — `test_default_din_cont_cand_lipseste`,
|
||||
`test_target_explicit`, `test_target_indisponibil_respins`, `test_get_ecou_rar_env`, `test_valoare_invalida_422`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] camp optional `rar_target: "test"|"prod"` pe `POST /v1/prezentari` si `/valideaza`
|
||||
- [ ] absent -> `rar_env_efectiv(cont)` (pt client prod-only = `prod`)
|
||||
- [ ] tinta indisponibila -> raspuns clar, fara enqueue; `SubmissionResult` + GET ecou-iesc `rar_env`
|
||||
- [ ] valoare invalida -> 422 fara echo de input (handler global pastrat)
|
||||
- [ ] `python3 -m pytest tests/test_api_rar_target.py -q` PASS
|
||||
- **Verificare E2E**: `POST /v1/prezentari` fara `rar_target` pe un cont prod-only -> submission env=prod.
|
||||
|
||||
### US-006: Worker — sesiuni si trimitere per (cont, env)
|
||||
**Ca** worker **vreau** login/JWT separat per `(account_id, rar_env)`, cu base_url + creds corecte per submission
|
||||
**pentru ca** test si prod sunt sisteme RAR diferite.
|
||||
|
||||
- **Depinde de**: US-001
|
||||
- **Fisiere**: `app/worker/__main__.py` (`AccountSessions`), `app/rar_client.py` (base_url per env),
|
||||
`app/reconcile.py`, `tests/test_worker_rar_env.py`
|
||||
- **Test intai (RED)**: `tests/test_worker_rar_env.py` — `test_sesiune_separata_per_env`,
|
||||
`test_base_url_dupa_submission`, `test_creds_din_slotul_env`, `test_reconcile_pe_env_corect`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] cheia cache sesiune = `(account_id, rar_env)`; JWT/keepalive/last_rar_login_ok per env
|
||||
- [ ] `RarClient` primeste env/base_url explicit (nu doar `settings.rar_base_url`)
|
||||
- [ ] creds alese: submission efemere -> `accounts.rar_creds_{env}_enc`; lipsa -> blocaj clar (nu trimite)
|
||||
- [ ] reconcilierea cauta in `finalizate` pe endpoint-ul `submission.rar_env`
|
||||
- [ ] purjarea atinge DOAR `submissions.rar_creds_enc`, NU `accounts.rar_creds_{env}_enc`
|
||||
- [ ] `python3 -m pytest tests/test_worker_rar_env.py -q` PASS
|
||||
- **Verificare E2E**: doua submission-uri (test + prod, creds prezente) -> doua login-uri distincte in jurnal.
|
||||
|
||||
### US-007: Validare login pe env-ul ales (signup / preview / test integrare)
|
||||
**Ca** sistem **vreau** ca validarea credentialelor sa loveasca mediul caruia ii apartin **pentru ca** o parola
|
||||
prod nu se valideaza contra RAR test si invers (confirmat: 401 incrucisat).
|
||||
|
||||
- **Depinde de**: US-002
|
||||
- **Fisiere**: `app/web/routes.py`, `app/rar_client.py`, `app/web/templates/_integrare.html`,
|
||||
`tests/test_validare_env.py`
|
||||
- **Test intai (RED)**: `tests/test_validare_env.py` — `test_valideaza_pe_env_creds`, `test_mesaj_distinge_env`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] validarea (signup, „testeaza integrarea", preview) foloseste env-ul setului de creds verificat
|
||||
- [ ] mesaj distinct „creds invalide pe TESTARE" vs „pe PRODUCTIE"
|
||||
- [ ] `python3 -m pytest tests/test_validare_env.py -q` PASS
|
||||
- **Verificare E2E**: in UI „testeaza integrarea" cu creds prod -> login pe endpoint prod.
|
||||
|
||||
### US-008: Configurare cont — doua medii (bifa activare + creds), default, confirmare prod
|
||||
**Ca** titular de cont **vreau** sa activez fiecare mediu, sa-i introduc credentialele si sa aleg default-ul
|
||||
**pentru ca** vreau sa controlez unde se poate trimite si unde merge implicit.
|
||||
|
||||
- **Depinde de**: US-001, US-007
|
||||
- **Fisiere**: `app/web/routes.py`, `app/web/templates/_cont.html`, `app/crypto.py` (refolosit),
|
||||
`tests/test_cont_medii.py`
|
||||
- **Test intai (RED)**: `tests/test_cont_medii.py` — `test_activeaza_si_salveaza_creds_per_env`,
|
||||
`test_default_doar_dintre_disponibile`, `test_activare_prod_cere_confirmare`, `test_creds_criptate_fara_echo`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] doua sectiuni „Testare" si „Productie": fiecare cu bifa Activeaza + campuri email/parola; default client =
|
||||
Productie bifat, Testare nebifat
|
||||
- [ ] la salvare, creds-ul fiecarui mediu activat e validat prin login pe acel env (US-007); invalid -> nu se
|
||||
marcheaza disponibil
|
||||
- [ ] selectorul de default ofera DOAR mediile disponibile; nu poti seta default un mediu indisponibil
|
||||
- [ ] activarea mediului Productie cere o confirmare unica „Inteleg ca trimiterile pe Productie sunt declaratii
|
||||
reale (L.142)"
|
||||
- [ ] creds criptate Fernet in `rar_creds_{env}_enc`, niciodata reflectate inapoi in pagina
|
||||
- [ ] `python3 -m pytest tests/test_cont_medii.py -q` PASS
|
||||
- **Verificare E2E**: activez Testare + creds valide si Productie + creds invalide -> doar Testare devine disponibil.
|
||||
|
||||
### US-009: Import web — selector mediu conditionat de disponibilitate
|
||||
**Ca** operator **vreau** sa aleg mediul la import doar cand am ≥2 disponibile, pre-bifat pe default **pentru ca**
|
||||
la un singur mediu alegerea e inutila.
|
||||
|
||||
- **Depinde de**: US-002, US-004
|
||||
- **Fisiere**: `app/import_router.py`, `app/import_parse.py`, `app/web/templates/_upload.html`,
|
||||
`_preview_import.html`, `tests/test_import_rar_env.py`
|
||||
- **Test intai (RED)**: `tests/test_import_rar_env.py` — `test_selector_ascuns_la_un_mediu`,
|
||||
`test_selector_prezent_si_prebifat_la_doua`, `test_commit_seteaza_env_pe_submissions`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] selector Test/Prod apare DOAR daca `len(medii_disponibile) >= 2`; initial = `rar_env_efectiv`
|
||||
- [ ] la 1 mediu: fara selector, toate randurile primesc acel mediu
|
||||
- [ ] la commit, toate submission-urile lotului primesc `rar_env` ales
|
||||
- [ ] `python3 -m pytest tests/test_import_rar_env.py -q` PASS
|
||||
- **Verificare E2E**: cont prod-only -> import fara selector, submissions env=prod; cont cu ambele -> selector pre-bifat.
|
||||
|
||||
### US-010: Badge mediu in liste, preview, jurnal, audit + ecou API
|
||||
**Ca** utilizator **vreau** sa vad pe fiecare trimitere mediul tinta **pentru ca** sa nu confund testul cu realul.
|
||||
|
||||
- **Depinde de**: US-001
|
||||
- **Fisiere**: `app/web/templates/_submissions.html`, `_coada.html`, `_trimitere_detaliu.html`,
|
||||
`_preview_rand.html`, `_jurnal.html`, `app/web/routes.py` (audit export), `app/api/v1/router.py` (GET),
|
||||
`tests/test_badge_rar_env.py`
|
||||
- **Test intai (RED)**: `tests/test_badge_rar_env.py` — `test_badge_in_lista`, `test_audit_contine_rar_env`,
|
||||
`test_get_ecou_rar_env`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] badge vizibil (Test vs Productie, culori distincte) in lista, preview rand, detaliu, jurnal
|
||||
- [ ] `rar_env` in audit export si in `GET /v1/prezentari(/{id})`
|
||||
- [ ] `python3 -m pytest tests/test_badge_rar_env.py -q` PASS
|
||||
- **Verificare E2E**: rand prod -> badge „Productie"; export audit contine coloana.
|
||||
|
||||
### US-011: Statusbar — indicator mediu + toggle conditionat
|
||||
**Ca** operator **vreau** sa vad in statusbar mediul default si sa-l pot schimba cand am ≥2 medii **pentru ca**
|
||||
sa stiu mereu unde trimit si sa comut rapid.
|
||||
|
||||
- **Depinde de**: US-002, US-008
|
||||
- **Fisiere**: `app/web/templates/_status.html`, `base.html`, `app/web/routes.py` (ruta toggle account-scoped),
|
||||
`tests/test_statusbar_env.py`
|
||||
- **Test intai (RED)**: `tests/test_statusbar_env.py` — `test_afiseaza_env_default`,
|
||||
`test_toggle_doar_la_doua_medii`, `test_toggle_schimba_default`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] statusbar afiseaza mediul default al contului logat (Test/Productie), distinct vizual
|
||||
- [ ] toggle apare DOAR la `len(medii_disponibile) >= 2`; comutarea schimba `rar_env_default` (HTMX, fara reload)
|
||||
- [ ] la 1 mediu: doar eticheta statica
|
||||
- [ ] `python3 -m pytest tests/test_statusbar_env.py -q` PASS
|
||||
- **Verificare E2E**: cont cu ambele -> click statusbar schimba default; cont prod-only -> eticheta fixa „Productie".
|
||||
|
||||
### US-012: Audit + e2e pe medii
|
||||
**Ca** lead **vreau** evenimente de audit la activare mediu / schimbare default / blocaj tinta, plus teste e2e
|
||||
**pentru ca** orice atingere a mediului Productie trebuie trasabila.
|
||||
|
||||
- **Depinde de**: US-005, US-006, US-009, US-011
|
||||
- **Fisiere**: `app/audit.py`/`log_event`, `tests/test_e2e_rar_env.py`
|
||||
- **Test intai (RED)**: `tests/test_e2e_rar_env.py` — `test_lant_import_pana_la_queued`, `test_activare_prod_logata`,
|
||||
`test_tinta_indisponibila_blocata_si_logata`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] audit la: activare/dezactivare mediu, schimbare `rar_env_default`, blocaj tinta indisponibila
|
||||
- [ ] e2e (TestClient + SQLite temporar) acopera import->queued cu env corect, ambele cai
|
||||
- [ ] `python3 -m pytest tests/test_e2e_rar_env.py -q` PASS
|
||||
- **Verificare E2E**: jurnal arata „mediu Productie activat" + „default schimbat" cu cont + timestamp.
|
||||
|
||||
### US-013: Retragerea `accounts.rar_creds_enc` (toate citirile -> per-env, apoi DROP)
|
||||
**Ca** sistem **vreau** ca toate cele ~40 de locuri care citesc `accounts.rar_creds_enc` sa treaca pe coloanele
|
||||
per-mediu si apoi sa sterg coloana veche **pentru ca** modelul per-env sa fie sursa unica, fara schema dubla.
|
||||
|
||||
- **Depinde de**: US-005, US-006, US-008 (consumatorii principali deja pe per-env)
|
||||
- **Fisiere**: `app/worker/__main__.py` (fallback + bucla keepalive „toate conturile cu creds"),
|
||||
`app/web/routes.py` (indicatorii `are_creds`), `app/api/v1/integrare_router.py` (`are_creds_rar`),
|
||||
`app/api/v1/router.py` (`POST /v1/conturi/rar-creds` devine env-aware), `app/accounts.py` (purge la stergere cont),
|
||||
`app/db.py` (DROP cu garda), `app/models.py`, `tests/test_retragere_creds_enc.py`
|
||||
- **Test intai (RED)**: `tests/test_retragere_creds_enc.py` — `test_niciun_read_pe_coloana_veche`,
|
||||
`test_conturi_rar_creds_env_aware`, `test_are_creds_pe_per_env`, `test_drop_cu_garda_blocat_daca_lipsa_copiere`
|
||||
- **Acceptance criteria**:
|
||||
- [ ] worker fallback + keepalive citesc `rar_creds_{env}_enc` (per env), nu coloana veche
|
||||
- [ ] `are_creds` (web) + `are_creds_rar` (integrare) devin per-mediu („are creds pe Testare/Productie")
|
||||
- [ ] `POST /v1/conturi/rar-creds` primeste mediul (`rar_target`/`env`) si scrie in slotul corect — **schimbare
|
||||
de contract API**, documentata in `docs/api-rar-contract.md`
|
||||
- [ ] purjarea la stergere cont (`accounts.py`) sterge ambele sloturi per-env
|
||||
- [ ] **DROP cu garda**: migrarea verifica intai ca fiecare `rar_creds_enc` non-null a aterizat intr-un slot
|
||||
per-env (assert), apoi `ALTER TABLE accounts DROP COLUMN rar_creds_enc` (SQLite 3.45 OK); verificare esuata
|
||||
-> NU dropa, ridica eroare (fail-safe)
|
||||
- [ ] **(AUTO-FIX 6a — CRITIC) Elimina ATOMIC blocul `ADD COLUMN rar_creds_enc` din `db.py:77-78`** in aceeasi
|
||||
migrare cu DROP-ul. Altfel urmatorul boot vede coloana absenta si o re-ADD goala -> ping-pong perpetuu,
|
||||
garda se rupe. Garda e one-way: dropeaza doar cand sloturile per-env sunt populate SI coloana inca exista
|
||||
- [ ] **(AUTO-FIX 6b — HIGH) DROP-ul nu crapa boot-ul**: `init_db/_migrate` ruleaza la fiecare pornire a ambelor
|
||||
procese; un `DROP COLUMN` care arunca (SQLite < 3.35 / assert garda esuat) propaga -> API + worker
|
||||
crash-loop. Prinde + degradeaza (log + lasa coloana pe loc), NU arunca. Asserteaza `sqlite_version() >= 3.35`
|
||||
(verifica SQLite din imaginea Docker, nu doar dev box) si sare drop-ul gracios sub acel prag
|
||||
- [ ] **(AUTO-FIX 6c — HIGH) Re-ruleaza backfill old->new IMEDIAT inainte de assert**: creds setate via
|
||||
`POST /v1/conturi/rar-creds` intre deploy-ul US-001 si US-013 aterizeaza doar in coloana veche; copiaza-le
|
||||
in slotul per-env (ancora globala) inainte de garda, altfel garda blocheaza drop-ul la nesfarsit
|
||||
- [ ] **(AUTO-FIX 6d) Verificare prin `PRAGMA table_info(accounts)`** ca `rar_creds_enc` lipseste, NU doar prin
|
||||
grep (ambele coloane — `accounts` si `submissions` — au acelasi nume; purjarea worker-ului ramane pe
|
||||
`submissions.rar_creds_enc`)
|
||||
- [ ] `grep -rn "rar_creds_enc" app/` nu mai gaseste citiri pe `accounts` (doar `submissions.rar_creds_enc` ramane)
|
||||
- [ ] `python3 -m pytest tests/test_retragere_creds_enc.py -q` PASS
|
||||
- **Verificare E2E**: dupa migrare, `PRAGMA table_info(accounts)` nu mai contine `rar_creds_enc`; fluxul de cont
|
||||
(salvare creds, worker trimite) functioneaza pe per-env.
|
||||
|
||||
## 5. Riscuri
|
||||
|
||||
- **Trimitere reala accidentala** (FINALIZATA terminal, L.142): atenuat prin badge omniprezent + Productie disponibil
|
||||
doar dupa activare explicita + creds + confirmare unica la activare. NU exista anulare la RAR.
|
||||
- **Default invalid dupa dezactivare mediu**: REQ-DEFAULT recalculeaza; teste US-002 acopera caderea pe disponibil.
|
||||
- **Migrare ambigua** (CONFIRMAT): `rar_creds_enc` poate fi test SAU prod; migrarea aterizeaza in slotul
|
||||
`AUTOPASS_RAR_ENV` global + activeaza doar acel mediu. De validat pe DB-ul real inainte de deploy.
|
||||
- **Client prod-only nu poate testa**: corect by design; UI explica explicit (nu „creds invalide"), nu ofera Testare
|
||||
fara creds test.
|
||||
- **Idempotenta**: schimbarea cheii (US-003) cere ca TOATE apelurile sa treaca env-ul; grep dupa `build_key` + teste.
|
||||
- **Retragere `rar_creds_enc` (US-013)**: ~40 citiri + endpoint API `POST /v1/conturi/rar-creds` (contract). Blast
|
||||
radius mare, dar single-release e mai curat decat schema dubla. DROP cu garda (assert copiere) = fara pierdere
|
||||
de date; produsul e in TESTE (putine conturi reale). Recuperarea via coloana veche dispare dupa DROP — acceptat.
|
||||
|
||||
## 6. Intrebari deschise — REZOLVATE (user 2026-06-29)
|
||||
|
||||
- [x] **Default API** = default-ul contului (NU „test" hardcodat), fiindca clientii sunt prod-only. CONFIRMAT.
|
||||
- [x] **Activare implicita cont nou** = Productie on / Testare off; contul operator setat manual pe Testare. CONFIRMAT.
|
||||
- [x] **Confirmare Productie** = o data, la activarea mediului in configurare (nu per trimitere). CONFIRMAT.
|
||||
- [x] **`rar_creds_enc` vechi** = se STERGE in acest PRD (US-013), nu in 5.2x. DROP cu garda (assert copiere),
|
||||
toate citirile mutate pe per-env, endpoint `POST /v1/conturi/rar-creds` devine env-aware. CONFIRMAT.
|
||||
|
||||
## 7. Valuri de executie (graful de dependente)
|
||||
|
||||
```
|
||||
Val 1: [US-001] [US-003] ← schema + idempotenta (fisiere distincte) → paralel
|
||||
Val 2: [US-002] ← deblocat de US-001
|
||||
Val 3: [US-004] [US-006] [US-007] ← rezolvare ingestie / worker / validare → paralel
|
||||
Val 4: [US-005] [US-008] [US-009] [US-010] ← API / config cont / import / badge → paralel
|
||||
Val 5: [US-011] ← statusbar (depinde de US-008)
|
||||
Val 6: [US-012] [US-013] ← audit + e2e; retragere rar_creds_enc + DROP (depind de tot)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Raport VERIFY
|
||||
|
||||
> Completat de subagentul verificator (context curat) in faza VERIFY — vezi ROADMAP §5.6.
|
||||
> PASS/FAIL per criteriu, cu dovezi. Lipseste pana la VERIFY.
|
||||
|
||||
---
|
||||
|
||||
<!-- AUTONOMOUS DECISION LOG -->
|
||||
## /autoplan Review (2026-06-29, commit 7371c37)
|
||||
|
||||
Voci: Claude (primar) + Claude subagent (independent). Codex indisponibil (usage limit, revine 18 iul) -> mod `[subagent-only]`. Poarta premisa: user a ales **"Build full per-account multi-env (as planned)"** — premisa de baza (sisteme separate) verificata live; nevoia de dashboard unic justifica per-cont peste 2 deployment-uri pinned.
|
||||
|
||||
### Auto-fixuri (corectitudine/siguranta — incorporate in stories)
|
||||
|
||||
| # | Story | Gap (gasit de) | Fix incorporat | Principiu |
|
||||
|---|-------|----------------|----------------|-----------|
|
||||
| G | US-001 | **CRITIC** (subagent): migrarea backfill-eaza creds dar NU `submissions.rar_env` existent; randuri prod pre-migrare cad pe DEFAULT 'test' -> US-006 reconciliaza contra endpoint TEST -> no-match -> **re-send prod = duplicat real ireversibil** | Migrarea backfill-eaza `submissions.rar_env` din `AUTOPASS_RAR_ENV` global (DEFAULT 'test' doar pentru randuri net-noi). Test: rand prod pre-migrare reconciliaza contra endpoint prod | P1 completeness + siguranta |
|
||||
| L | **US-005/US-013** (NU US-006 — eng finding 5: write-back e in `router.py`, pe care US-006 nu-l atinge) | HIGH (ambele voci, `router.py:250`): write-back creds efemere API -> `accounts.rar_creds_enc` durabil nu e rutat pe slotul `submission.rar_env` | Write-back tinteste `accounts.rar_creds_{submission.rar_env}_enc` + test. **Plus**: nu auto-propaga creds API NEVALIDATE in slotul durabil per-env (ar putea clobber-i un slot login-validat); propaga doar dupa login reusit | P1 |
|
||||
| K | US-013 | HIGH (subagent): `POST /v1/conturi/rar-creds` e contract extern; env-aware in-place = breaking | Endpoint **aditiv**: param `env` optional, default = default cont; apelanti vechi neatinsi. (Independent de decizia DROP) | P5 explicit + back-compat |
|
||||
| M2 | US-013 | MEDIUM (Claude): `_keepalive_target` alege un cont fara notiune de env dupa per-env | Keepalive foloseste ancora globala `AUTOPASS_RAR_ENV` + un cont cu creds in slotul acelui env | P5 |
|
||||
| M3 | US-003 | MEDIUM (Claude): `_already_sent_lookup` (import_router.py:369) are dual-lookup legacy; adaugarea env in cheie cere extinderea lui, nu doar a parametrului | US-003 extinde dual-lookup (cheie noua env-aware + fallback legacy) | P1 |
|
||||
| D | US-001 | HIGH (subagent): corectitudinea migrarii e "de validat manual"; trebuie poarta testata | Script de audit pre-migrare (raporteaza slot-ul atribuit) + assert DROP-cu-garda existent ca poarta, nu nota manuala | P1 |
|
||||
| M | US-012 | MEDIUM (subagent): niciun test live dual-env; riscul dominant (rutare gresita env) e exact ce SQLite nu prinde | Test live opt-in dual-env (extinde `test_live_rar`): 1 rand test + 1 prod -> 2 login-uri, 2 endpoint-uri, badge corecte, reconciliere pe env corect | P1 |
|
||||
| backup | US-013 | MEDIUM (Claude): "recovery via coloana veche dispare dupa DROP — acceptat" | Inainte de DROP, dump coloana veche criptata intr-un backup timestamped (recuperare supravietuieste DROP) | P2 boil-lake |
|
||||
|
||||
### Decizii user la poarta finala (REZOLVATE 2026-06-29) — APROBAT
|
||||
|
||||
- **A (DROP US-013) -> PASTREAZA single-release.** User: "aplicatia e doar in teste, nu folosita de clienti" -> blast radius mic, rollback-ul conteaza mai putin. Decizia §6 ramane. **Garzile 6a/6b/6c sunt obligatorii in AC US-013** (eliminare atomica bloc ADD, catch+degrade fara boot-crash, re-backfill interim) + backup criptat inainte de DROP. NU se amana.
|
||||
- **J/H1 (interlock prod) -> doar butonul de commit colorat (F8), FARA modal.** REQ-CONF ramane. Lantul: bifa activare (o data) + badge "fierbinte" + buton "Declară la PRODUCȚIE (real)". Fara confirmare per-commit (evita oboseala de click; clientii prod-only oricum n-au selector).
|
||||
- **H (fallback default) -> doar toast zgomotos (F5), FARA re-confirmare.** REQ-DEFAULT auto-fallback ramane; toast-ul "Mediul implicit a trecut pe X" face flip-ul vizibil. Fara gate suplimentar.
|
||||
|
||||
### Taste (recomandari acceptate — fara override)
|
||||
- **T1**: token dedicat `--prod` (brick) pentru badge-ul Productie. **T2**: `rar_env` ca nume unic input+output (scoate `rar_target`/`env`).
|
||||
|
||||
### Taste decisions (auto-decise cu recomandare — override la poarta)
|
||||
- **T1 — token culoare Productie**: rosu (`--err`) se ciocneste cu erorile, amber (`--warn`) cu badge-ul legacy. Recomandat: token dedicat `--prod` (brick inchis) SAU `--accent` plin. (design F2)
|
||||
- **T2 — nume camp request**: recomandat `rar_env` peste tot (un singur nume input+output), scoate `rar_target`/`env`. (DX F1)
|
||||
|
||||
### Teme cross-fază (semnal de incredere ridicat — aparut independent in 2+ faze)
|
||||
- **Siguranta declaratiei reale ireversibile** — TOATE 4 fazele (CEO G/H1/J, Design F1/F8/F10, Eng 1b/3/G, DX F2/F3/F4). Semnalul dominant: badge + interlock + discoverability + rutare env corecta converg pe "nu declara real din greseala".
|
||||
- **Flip silentios al mediului default** — CEO-H, Design-F5, DX-F3 (3 faze). Fa flip-ul zgomotos + nu auto-promova prod silentios.
|
||||
- **Risc DROP US-013** — CEO-A, Eng 6a/6b/6c (2 faze). Intareste amanarea DROP-ului.
|
||||
- **Ambiguitate spec/nume care musca implementer-ul** — Design-F14, Eng-4a, DX-F1/F7. Auto-fixurile TREBUIE sa intre in AC + contract inainte de implementare.
|
||||
|
||||
### NOT in scope (confirmat)
|
||||
Eliminarea ancorei globale `AUTOPASS_RAR_ENV`; base_url din UI; al treilea mediu; gating plan/tier pe prod; schimbari masina-stari/backoff/payload; auto-migrare creds prod client. (PRD §2)
|
||||
|
||||
### Ce exista deja (leverage)
|
||||
`crypto.py` Fernet (creds per-env), `AccountSessions` (re-key (cont,env)), `RarClient` (primeste settings; +param env), `config.rar_base_url_test/prod` (deja prezent), `build_key` (+param), `account_scope_clause`. Fara infra noua.
|
||||
|
||||
### Auto-fixuri DESIGN (structurale — incorporate in stories)
|
||||
|
||||
Voci: Claude (primar) + Claude subagent. Scorecard: 1 CRITIC, 7 HIGH, 5 MEDIUM, toate CONFIRMED.
|
||||
|
||||
| # | Story | Gap | Fix incorporat | Sev |
|
||||
|---|-------|-----|----------------|-----|
|
||||
| F1 | US-010 | **CRITIC**: "culori distincte" e singura spec a singurului guard vizual contra riscului dominant | Badge **normativ**: Productie = fill plin, saturat, text alb, iconita + cuvant complet UPPERCASE cu diacritice ("PRODUCȚIE"); Testare = outline/tint linistit (muted/accent), receding. Asimetria de greutate ESTE designul | CRITIC |
|
||||
| F2 | US-010 | HIGH: rosu (`--err`) rezervat erorilor, amber (`--warn`) ocupat de `.badge-env` legacy + needs_* | Token dedicat `--prod` (ex. brick `#B4452F`) SAU `--accent` plin pentru Productie; hex/token scris in AC, nu improvizat per template. (taste: hexul exact -> poarta) | HIGH |
|
||||
| F3/F12 | US-010 | HIGH: "Test/Testare/prod/PRODUCTIE" folosite interschimbabil; bypass `labels.py` | `labels.py` adaugat in Fisiere: `ETICHETE_ENV` + `eticheta_env(env)->(text,css)` (oglindeste `eticheta_scurta`). Productie UPPERCASE+diacritice, Testare title-case; clase `.badge-prod/.badge-test` definite o data in base.html langa `.sugg-sursa` | HIGH |
|
||||
| F11 | US-011 | HIGH: `.badge-env` EXISTENT in header arata `AUTOPASS_RAR_ENV` global -> dupa 5.20 e semantic gresit; doua indicatoare env cu surse diferite in acelasi viewport | US-011 retrage/repurpune header `.badge-env` (preferat: scos pentru user logat, inlocuit de indicatorul account-scoped din statusbar). NU coexista doua surse de adevar | HIGH |
|
||||
| F4 | US-009 | HIGH: starea 0-medii e numita dar nedesignata; blocaj la commit (dupa munca) = calea minima | Blocaj la UPLOAD (nu commit): banner `--warn` (refoloseste pattern "Cont in asteptare", `_status.html:8`) + CTA link `?tab=cont`, inainte de drop-zone | HIGH |
|
||||
| F5 | US-011 | HIGH: schimbarea silentioasa a default-ului (mediu dezactivat) nu are UI -> target real/test comuta fara ca userul sa stie | Toast explicit (componenta `#toast` exista) la schimbarea `rar_env_default` ca efect al disponibilitatii: "Mediul implicit a trecut pe X". Leaga de CEO-H | HIGH |
|
||||
| F8 | US-009 | HIGH: o bifa la activare apoi nimic = sub-avertizare; modalul per-trimitere a fost respins (REQ-CONF) | Butonul de commit POARTA greutatea cand target=Productie: "Declară la PRODUCȚIE (real)" + culoarea Productie (FARA modal, FARA click extra -> nu incalca REQ-CONF). Copy bifa activare: adauga ireversibilitatea ("declarații oficiale, finale și fără anulare") | HIGH |
|
||||
| F6/F7 | US-008/US-011 | MEDIUM: stari loading/error pt toggle HTMX + validare creds la RAR nespecificate; stare per-sectiune (activat-fara-creds-valide) | toggle: `hx-indicator` + disabled in zbor, pe esec NU schimba default + eroare; US-008 validare creds arata `htmx-indicator` ("se verifica la RAR…") + esec in `.banner` cu copy per-env (US-007); fiecare sectiune arata 3 stari: dezactivat / activat-fara-creds / disponibil | MEDIUM |
|
||||
| F9/F10 | US-009 | MEDIUM/HIGH: selectorul absent la 1 mediu = env invizibil la import; default pre-bifat prod la prima trimitere | Mereu randeaza un indicator env la import (eticheta statica la 1 mediu, toggle la >=2, ACEEASI pozitie). Prod pre-bifat e sigur DOAR daca F8+F9 livreaza impreuna — legate explicit in AC | HIGH |
|
||||
| F13 | US-010 | MEDIUM: sa nu forkeze un badge structural nou | Refoloseste idiomul `.sugg-sursa` (10px, weight 700, tint+border) pt Testare; Productie = aceeasi geometrie dar fill plin+alb+icon (spargerea e semnalul) | MEDIUM |
|
||||
|
||||
### Auto-fixuri ENG (corectitudine/deploy — incorporate in stories)
|
||||
|
||||
Voci: Claude (primar) + Claude subagent (verificat contra codului real). **Meta (eng 4a): toate auto-fixurile de mai jos sunt NORMATIVE si trebuie sa intre in AC-ul story-urilor inainte de implementare — un implementer care urmeaza AC-ul literal, fara ele, livreaza bug-urile critice.** G + 6a deja imbinate in AC US-001/US-013.
|
||||
|
||||
| # | Story | Gap (vs cod real) | Fix | Sev |
|
||||
|---|-------|-------------------|-----|-----|
|
||||
| E1/1a | US-006 | `get_token` purjeaza `submissions.rar_creds_enc WHERE account_id=?` -> dupa re-key, login TEST sterge creds efemere ale submission-urilor PROD ale contului -> prod blocat | `WHERE account_id=? AND rar_env=?` + test `test_purge_creds_doar_pe_env` | HIGH |
|
||||
| 1b/E6 | US-006 | `recover_orphans` filtreaza doar pe `account_id`; iterat per sesiune (cont,env) reconciliaza orfanii prod contra endpoint TEST -> no-match -> re-POST prod = DUPLICAT real | +`rar_env` in WHERE; apelat per (cont,env) din `active()`; test orfan env A nereconciliat contra env B | HIGH/CRITIC |
|
||||
| 3/E4 | US-003 | API channel (`router.py:223`) NU are dual-lookup; re-POST al unui rand pre-5.20 cu cheie env-aware rateaza randul legacy -> duplicat. Import dual-lookup ignora env-ul randului matchuit | Recompute-keys la migrare (US-001, vezi acolo) acopera ambele canale uniform; daca pastrezi dual-lookup, exista si in `router.py` SI gate pe `matched_row.rar_env==target_env` | HIGH |
|
||||
| 1c/E8 | US-006 | `claim_one` nu selecteaza `s.rar_env` -> worker nu poate alege cheia sesiune/base_url/slot | AC explicit: claim selecteaza + propaga `rar_env` in dict-ul `claimed` | MEDIUM |
|
||||
| 1d | US-006/US-001 | `worker_heartbeat` e un singur rand global (`WHERE id=1`); US-006 cere `last_rar_login_ok` PER env dar US-001 nu adauga schema per-env -> neimplementabil ca scris | Decizie: pastreaza heartbeat global (JWT/sesiune per env e suficient), scoate "per env" din AC US-006; SAU adauga coloana in US-001. Recomandat: global | MEDIUM |
|
||||
| 1e | US-006 (doc) | `_refresh_nomenclator` upsert intr-un `nomenclator_rar` env-less la fiecare login; login test suprascrie cu coduri test, prod cu prod -> un cod valid pe prod poate fi respins la ingestie daca ultimul refresh a fost test | Documenteaza presupunerea (nomenclator identic intre medii — aceleasi 18 coduri) SAU scope per-env (out of scope acum). Minim: nota explicita | MEDIUM |
|
||||
| 5 | US-005/US-013 | write-back creds API nevalidate -> slot durabil (vezi L de mai sus) | re-asignat la US-005/US-013; propaga doar dupa login reusit | MEDIUM/HIGH |
|
||||
| 6a..6d | US-013 | ping-pong re-ADD / boot-crash / interim-creds / grep ambiguu | imbinate in AC US-013 (vezi acolo) | CRITIC/HIGH |
|
||||
|
||||
### ENG DUAL VOICES — CONSENSUS TABLE
|
||||
```
|
||||
Dimension Claude Subagent Consensus
|
||||
────────────────────────────── ──────── ───────── ────────────────────
|
||||
1. Architecture sound? da/cond da/cond CONFIRMED (cond. fixuri)
|
||||
2. Test coverage sufficient? lacune +API b/c CONFIRMED lacune
|
||||
3. Performance risks? low low CONFIRMED low
|
||||
4. Security (creds routing)? L/5 5+unvalid CONFIRMED
|
||||
5. Error paths (boot)? E1/E9 6a/6b CRIT CONFIRMED (boot-crash)
|
||||
6. Deployment risk (DROP)? migrare CRIT/HIGH CONFIRMED ELEVAT -> intareste challenge A
|
||||
```
|
||||
Codex: indisponibil (N/A). Mesaj-cheie: caile de duplicat ireversibil (1b, 3) si boot-crash/ping-pong (6a, 6b) musca in productie; intaresc recomandarea de a amana DROP-ul (challenge A).
|
||||
|
||||
### Diagrama teste (codepath -> acoperire)
|
||||
| Codepath nou | Story test | Stare |
|
||||
|---|---|---|
|
||||
| `medii_disponibile`/`rar_env_efectiv` | US-002 | acoperit |
|
||||
| resolve target (cerere>default), respinge indisponibil | US-004 | acoperit |
|
||||
| idempotency env-aware + **recompute legacy** | US-003/US-001 | GAP recompute -> adaugat |
|
||||
| **migrare backfill `submissions.rar_env`** | US-001 | GAP (G) -> adaugat in AC |
|
||||
| worker sesiune (cont,env) + base_url per env | US-006 | acoperit |
|
||||
| **purge creds scoped pe env** | US-006 | GAP (E1) -> adaugat |
|
||||
| **recover_orphans per env** | US-006 | GAP (1b) -> adaugat |
|
||||
| **write-back slot routing** | US-005/013 | GAP (L/5) -> adaugat |
|
||||
| reconcile endpoint per env (inline + **orfani**) | US-006 | inline acoperit; orfani GAP -> adaugat |
|
||||
| **keepalive env (ancora globala)** | US-013 | GAP (M2) -> adaugat |
|
||||
| DROP garda: assert + **idempotent re-run** + **fail-loud/no-crash** | US-013 | partial -> intarit (6a/6b/6c) |
|
||||
| **API-channel idempotency back-compat** | US-003 | GAP (3) -> adaugat |
|
||||
| badge/labels env | US-010 | acoperit |
|
||||
| API `rar_target` default/explicit/invalid/indisponibil | US-005 | acoperit |
|
||||
| config 2 sectiuni + confirmare prod | US-008 | acoperit |
|
||||
| statusbar toggle viz + **retragere header `.badge-env`** | US-011 | toggle acoperit; header GAP (F11) -> adaugat |
|
||||
| **live dual-env smoke** | US-012 | GAP (M) -> adaugat opt-in |
|
||||
|
||||
### Auto-fixuri DX (contract API extern — incorporate in stories)
|
||||
|
||||
Voci: Claude (primar) + Claude subagent (perspectiva integrator VFP/ROAAUTO). Riscul ireversibilitatii ridica stacheta pe claritate nume / eroare / discoverability pre-trimitere.
|
||||
|
||||
| # | Story | Gap | Fix | Sev |
|
||||
|---|-------|-----|-----|-----|
|
||||
| F1 | US-005/US-013 | Trei nume pt un concept: input `rar_target`, echo/DB `rar_env`, rar-creds `env` (US-013 AC scrie literal "rar_target/env") | **Un singur cheie: `rar_env`** pe input + output + rar-creds (englez snake, consistent cu coloana si `on_unmapped_error`). Scoate `rar_target`/`env`. (taste usor -> poarta) | HIGH |
|
||||
| F2 | US-004 | Eroarea "mediu indisponibil" e proza, fara `cod`/envelope 6-chei/status; `errors.py` nu e in Fisiere | `RAR_MEDIU_INDISPONIBIL` in `errors.CATALOG` (problema/cauza cu lista disponibile/fix "activeaza in Cont"); adauga `errors.py` la Fisiere US-004; distinge literal-invalid (422 pydantic) de valid-dar-indisponibil (cod dedicat); acopera si cazul 0-medii | HIGH |
|
||||
| F3 | US-004/contract | Flip runtime test->prod prin canal web: operator comuta disponibilitatea -> apelant API fara `rar_env` trece silentios pe prod (real). Migrarea previne flip la DEPLOY, nu la RUNTIME | Mitigat de F4+F5 (probe pre-trimitere); documenteaza reasignarea ca comportament cunoscut; leaga de CEO-H | HIGH |
|
||||
| F4 | US-010 (sau story noua) | Niciun GET nu expune `medii_disponibile`/`rar_env_default` -> integratorul afla env-ul doar din eroare sau dupa o trimitere reala | `GET /v1/conturi/medii` account-scoped: `{medii_disponibile, rar_env_default, test:{enabled,has_creds}, prod:{...}}` (refoloseste helper US-002, <1 fisier) | HIGH |
|
||||
| F5 | US-005 | `ValidareResult` (dry-run) NU ecou-ieste `rar_env`; dry-run e canalul sigur de a confirma unde ar ateriza o trimitere reala | adauga `rar_env: str` la `ValidareResult` + `/valideaza`; `models.py` | MEDIUM |
|
||||
| F6 | US-004/US-005 | Respingere whole-request vs per-rand inconsistenta cu `on_unmapped_error` (per-rand, 200) | Decide + documenteaza; recomandat: corp parsabil imbogatit cu `cod` (prietenos VFP), noteaza asimetria intentionat | MEDIUM |
|
||||
| F7 | US-005/US-010/US-004/US-013 | Contractul (sursa adevar) actualizat doar pt rar-creds; lipsesc field-ul nou, echo-ul, cod-ul nou. **`/v1/conturi/rar-creds` NU e documentat deloc azi** -> US-013 e documentare de la zero, nu amendament | AC explicit "update `api-rar-contract.md`" pe fiecare; US-013 documenteaza endpoint-ul intreg (req/resp, param env, slot default) | HIGH |
|
||||
| F8 | US-013 (doc) | `env` optional default = slot default cont: integrator cu creds TEST pe cont nou (default prod) le scrie silentios in slot prod -> US-007 le respinge "invalide pe PRODUCTIE" desi sunt valide (test) | pastreaza aditiv; documenteaza ca omiterea `env` tinteste slotul default; mesaj validare sugereaza nepotrivire env ("creds valide pentru alt mediu?") | MEDIUM |
|
||||
|
||||
### DX DUAL VOICES — CONSENSUS TABLE
|
||||
```
|
||||
Dimension Claude Subagent Consensus
|
||||
─────────────────────────────── ─────── ───────── ──────────────
|
||||
1. Getting started (aditiv)? low fr low fr CONFIRMED low
|
||||
2. Naming guessable? D1 incon F1 3-nume CONFIRMED -> rar_env
|
||||
3. Error messages actionable? D2 gap F2 gap CONFIRMED gap
|
||||
4. Docs findable & complete? D4 gap F7 gap+ CONFIRMED gap
|
||||
5. Back-compat safe? D3 resid F3 runtime CONFIRMED (1 rezidual)
|
||||
6. Discoverability pre-send? D5 gap F4 gap CONFIRMED gap
|
||||
```
|
||||
Codex: indisponibil (N/A). DX scor initial: ~6/10 (model API solid + aditiv, dar nume inconsistent + eroare neimbogatita + zero discoverability + contract neactualizat). Tinta dupa fixuri: ~9/10.
|
||||
|
||||
### Jurnal integrator (condensat)
|
||||
| Etapa | Azi (plan brut) | Dupa fixuri DX |
|
||||
|---|---|---|
|
||||
| Afla env-urile contului | doar din eroare / dupa trimitere reala | `GET /v1/conturi/medii` |
|
||||
| Trimite | `rar_target` (nume #1) | `rar_env` (un nume) |
|
||||
| Confirma tinta fara trimitere reala | imposibil (valideaza nu ecou-ieste) | `/valideaza` ecou-ieste `rar_env` |
|
||||
| Eroare tinta indisponibila | proza, fara cod | `cod: RAR_MEDIU_INDISPONIBIL` + fix |
|
||||
| Citeste rezultatul | `rar_env` (nume #2) | `rar_env` (acelasi) |
|
||||
| Doc | contract fara field/endpoint | contract complet |
|
||||
Reference in New Issue
Block a user