263 lines
13 KiB
Markdown
263 lines
13 KiB
Markdown
# Decision Log — Service Auto Prototype
|
|
|
|
**Prototype**: ROA2WEB `feat/service-auto`
|
|
**Owner**: Marius (ERP patron + sole dev)
|
|
**Timeline**: 24 săptămâni @ 2-4h/săpt
|
|
**Last updated**: 2026-04-11
|
|
|
|
Acest fișier urmărește verdictele pe cele 6 ipoteze din
|
|
`docs/service-auto/claude-main-design-20260411-rethink.md §"Things this prototype will probe"`.
|
|
Fiecare verdict e actualizat pe măsură ce testele rulează.
|
|
**Recomandarea finală** (merge/no-go pentru phase 2) se completează după săpt 24.
|
|
|
|
---
|
|
|
|
## Kill Criterion Status
|
|
|
|
Niciun kill criterion nu a fost declanșat până la data de mai sus.
|
|
|
|
Reminder: dacă orice ipoteză eșuează cu un răspuns clar → prototype încheiat cu succes
|
|
(learning obținut, decision point clar, zero cod irosit). Kill ≠ eșec.
|
|
|
|
---
|
|
|
|
## Ipoteza #1 — `python-oracledb` + OUT params
|
|
|
|
**Ipoteză**: `python-oracledb` apelează curat PL/SQL proc cu IN + OUT params (NUMBER + VARCHAR2).
|
|
|
|
**Status**: `CONFIRMED` ✅
|
|
|
|
**Dovezi**:
|
|
- Săpt 2 (`poc/async_out_param_probe.py`): `cursor.var(oracledb.NUMBER)` + `cursor.callproc`
|
|
→ `out_var.getvalue()` returnează `42.0` corect. Assert PASSED.
|
|
Latență callproc: ~1ms după connect. Note: `.getvalue()` returnează `float`, necesită `int()` cast.
|
|
- Săpt 3 (test #1 + #2 `SP_CREEAZA_COMANDA_PROTOTIP`): SP cu 4 IN + 2 OUT (NUMBER + VARCHAR2)
|
|
apelat via sync-facade în `oracle_pool.get_connection('mariusm_test')`.
|
|
Test #1: 5.9ms, OUT p_id_ordl=412, p_nrord='P01-2'. Post-rollback: 0 rows ✅
|
|
- Pattern implementat în `backend/modules/service_auto/services/comanda_service.py`
|
|
|
|
**Decizie adoptată**: sync-facade (consistent cu `oracle_pool.py`), nu true-async
|
|
(`connect_async`). Motivat în `week1-notes.md §Gate Correction 9`.
|
|
|
|
**Implicație pentru template**: pattern `cursor.var(oracledb.NUMBER/STRING)` + `callproc`
|
|
+ `int(out.getvalue())` e reutilizabil direct pentru orice SP cu OUT params.
|
|
|
|
---
|
|
|
|
## Ipoteza #2 — `session_callback` nu leak-uiește între requests
|
|
|
|
**Ipoteză**: `session_callback` pentru `CURRENT_SCHEMA` switching nu produce state leak
|
|
între requests concurente pe același pool.
|
|
|
|
**Status**: `CONFIRMED` ✅
|
|
|
|
**Dovezi** (2026-04-12, `test_pool_concurrency.py` — 3/3 passed):
|
|
- `test_two_concurrent_connections_return_correct_results`: 2 asyncio tasks simultane pe
|
|
același pool, bind values distincte (111, 222) → rezultate corecte fără cross-bleed.
|
|
- `test_session_callback_runs_per_connection`: `session_callback` înregistrat pe server config
|
|
→ confirmat că se apelează la prima conexiune din pool; nu leaked state inter-connection.
|
|
- `test_ten_concurrent_queries_no_errors`: 10 tasks concurente pe pool cu `max=5` →
|
|
`POOL_GETMODE_WAIT` queue-uiește corect excesul; toate 10 completate fără erori.
|
|
|
|
**Nota bene**: pool `mariusm_test` nu folosește `session_callback` (ROA_WEB apelează SP cu
|
|
schemă explicită `MARIUSM_AUTO.SP_...`). Patch-ul `session_callback` în `oracle_pool.py`
|
|
e disponibil pentru modulele viitoare care au nevoie de `CURRENT_SCHEMA` switching.
|
|
|
|
---
|
|
|
|
## Ipoteza #3 — GRANTS model: EXECUTE ON SP, zero DML direct
|
|
|
|
**Ipoteză**: user `ROA_WEB` cu `GRANT EXECUTE ON SP` + zero `INSERT/UPDATE/DELETE` pe
|
|
tabele → INSERT direct returnează `ORA-00942`, SP call returnează succes.
|
|
|
|
**Status**: `CONFIRMED` ✅
|
|
|
|
**Dovezi** (2026-04-12):
|
|
- `ROA_WEB` creat de DBA cu `GRANT CREATE SESSION` + `GRANT EXECUTE ON SP` +
|
|
`GRANT SELECT ON AUTO_VMASINICLIENTI` + `GRANT SELECT ON DEV_TIP_DEVIZ`.
|
|
- `test_grants_integration.py` — 3/3 passed (anterior 3 skipped — fișier lipsă parola):
|
|
- `test_insert_direct_fails` → `ORA-00942` ✅ (INSERT blocat)
|
|
- `test_select_direct_fails` → `ORA-00942` ✅ (SELECT pe tabel neautorizat blocat)
|
|
- `test_exec_sp_succeeds` → SP apelat cu succes ✅
|
|
- Verificare live: `AUTO_VMASINICLIENTI` (266 rows) + `DEV_TIP_DEVIZ` (7 rows) accesibile;
|
|
`NOM_LUCRARI` direct → `ORA-00942` (Oracle ascunde complet obiectul, nu returnează 0 rows).
|
|
- Pool `mariusm_test` switchat la `ROA_WEB` în `.env` / `.env.prod` / `.env.test`.
|
|
|
|
**Arhitectura multi-tenant documentată** (`grants-audit.md §4`):
|
|
- Oracle 21c: schema-level grants (23ai) nu există. Proxy auth respins — anulează boundary SP-only.
|
|
- Soluție: grants per-obiect incluse în deployment scripts. Firmă nouă = 1 script onboarding.
|
|
Obiect nou în toate schemele = 1 script companion care loopează `V_NOM_FIRME`.
|
|
|
|
---
|
|
|
|
## Ipoteza #4 — Diacritice encoding end-to-end
|
|
|
|
**Ipoteză**: `RAISE_APPLICATION_ERROR(-20001, 'mesaj cu ă î ș ț â')` ajunge în Vue ca
|
|
eroare user-friendly, encoding corect prin tot stack-ul (Oracle → oracledb → FastAPI → Vue).
|
|
|
|
**Status**: `CONFIRMED` ✅ (Oracle→oracledb→FastAPI; Vue pending manual browser test)
|
|
|
|
**Dovezi** (2026-04-12, `test_diacritice_encoding.py` — 2/2 passed):
|
|
- L1 — Oracle→oracledb: `RAISE_APPLICATION_ERROR(-20001, 'Client invalid: ă î ș ț â Ă Î Ș Ț Â')`
|
|
trimis via bind variable → `DatabaseError.args[0].message` conține toate diacriticele intact.
|
|
Set complet testat: `ă î ș ț â Ă Î Ș Ț Â`. NLS chain funcționează fără configurare explicită.
|
|
- L2 — oracledb→FastAPI: `_handle_oracle_error(e)` → `HTTPException(422, detail)` conține
|
|
diacriticele, prefix `ORA-20001:` stripped corect.
|
|
- Vue (manual pending): necesită browser + backend pornit; Toast PrimeVue afișează `detail`
|
|
din 422 response. Probabilitate eșec mică (Vue nu modifică string-uri JSON).
|
|
|
|
---
|
|
|
|
## Ipoteza #5 — DX acceptabil (save→result < 10s)
|
|
|
|
**Ipoteză**: FastAPI hot-reload + Vite dev-server + SSH tunnel Oracle e un DX acceptabil
|
|
pentru side-work de 2-4h/săpt.
|
|
|
|
**Status**: `CONFIRMED` ✅
|
|
|
|
**Dovezi** (`week1-notes.md §Conectivitate`):
|
|
|
|
| Operație | Timp |
|
|
|----------|------|
|
|
| Sync connect | 33ms |
|
|
| Async connect | 22ms |
|
|
| Query | 0.2-3.3ms |
|
|
| SP callproc (săpt 3) | 5.9ms |
|
|
|
|
- Server Oracle e direct (10.0.20.121:1521) — fără SSH tunnel pe acest server.
|
|
- uvicorn `--reload` detectează schimbările și reîncarcă în < 1s.
|
|
- Total "save fișier → văd rezultatul" ≪ 10s. Gate trecut.
|
|
|
|
**Implicație**: ecosistemul nu necesită optimizare înainte de content. DX confirmat.
|
|
|
|
---
|
|
|
|
## Ipoteza #6 — Auth multi-server fără modificări shared code
|
|
|
|
**Ipoteză**: flux-ul de auth existent (login → JWT cu `server_id` → `AuthenticationMiddleware`)
|
|
suportă un server nou fără modificări la `shared/` code.
|
|
|
|
**Status**: `CONFIRMED` ✅
|
|
|
|
**Dovezi Oracle** (`week3-auth-audit.md`, 2026-04-11):
|
|
- `pack_drepturi.verificautilizator('MARIUS M', '123')` → `803` ✅
|
|
- `V_NOM_FIRME`: 3 firme cu `schema='MARIUSM_AUTO'` (id 110/167/169) ✅
|
|
|
|
**Dovezi HTTP** (2026-04-12):
|
|
```
|
|
POST /api/auth/login {"username":"VIZUALIZARE","password":"123","server_id":"mariusm_test"}
|
|
→ JWT companies: ["110","167","169"] ✅
|
|
→ JWT server_id: "mariusm_test" ✅
|
|
→ zero modificări în shared/auth/ ✅
|
|
|
|
GET /api/service-auto/ping (Bearer JWT)
|
|
→ {"result":1,"server":"mariusm_test","latency_ms":0.43} ✅
|
|
```
|
|
|
|
Nota: MARIUS M are 2FA activat (email configurat) → testat cu VIZUALIZARE (no email,
|
|
aceleași 3 firme MARIUSM_AUTO). Același cod auth, același JWT structure.
|
|
|
|
---
|
|
|
|
## Decizii arhitecturale documentate
|
|
|
|
### D1 — Sync-facade în loc de true-async (Săpt 1)
|
|
**Decizie**: `oracle_pool.get_connection()` + `pool.acquire()` (sync) în `async def`.
|
|
**Motivare**: consistent cu pattern-ul deja proof-ed în `treasury_service.py` prod.
|
|
True-async (`connect_async`) nu aduce beneficii la latențele măsurate (22-33ms connect).
|
|
|
|
### D2 — SP_CREEAZA_COMANDA_PROTOTIP nou în loc de reuse pack_auto (Săpt 3)
|
|
**Decizie**: Opțiunea 3 din design doc — SP minimal cu 2 INSERT-uri (nom_lucrari → dev_ordl)
|
|
și `RETURNING id_lucrare`, zero dependency pe `pack_sesiune`.
|
|
**Motivare**: `pack_auto.dev_adauga_lucrare` v2 are 17 params + `pack_sesiune` coupling;
|
|
SP nou cu RETURNING e idiomul Oracle modern și mai ușor de testat.
|
|
|
|
### D3 — CONTAFIN_ORACLE în faza A, ROA_WEB în faza B (Săpt 3)
|
|
**Decizie**: Faza A (săpt 3+) folosește CONTAFIN_ORACLE (DBA role, zero grant work).
|
|
ROA_WEB creat în faza B când ipoteza #3 e pusă la test.
|
|
**Motivare**: faza A validează H1+H2+H5+H6 independent de H3.
|
|
|
|
### D4 — Pool `mariusm_test` separat de `central` (Săpt 3)
|
|
**Decizie**: ID distinct `mariusm_test` în ORACLE_SERVERS deși e același host/user ca `central`.
|
|
**Motivare**: pool sizing independent pentru module service_auto + swap atomic la ROA_WEB
|
|
în faza B (schimbă doar `.env`, zero modificări cod).
|
|
|
|
---
|
|
|
|
## Recomandare finală
|
|
|
|
**Decizie: MERGE** ✅ — prototype confirmă că arhitectura e viabilă pentru phase 2.
|
|
|
|
**Data**: 2026-04-12
|
|
**Toate 6 ipoteze**: CONFIRMED (H1, H2, H3, H4, H5, H6)
|
|
|
|
### Verdict pe ipoteze
|
|
|
|
| # | Ipoteză | Verdict | Implicație phase 2 |
|
|
|---|---|---|---|
|
|
| H1 | oracledb + OUT params | ✅ CONFIRMED | Pattern `cursor.var()` reutilizabil direct |
|
|
| H2 | session_callback concurență | ✅ CONFIRMED | Disponibil pentru module multi-schemă viitoare |
|
|
| H3 | ROA_WEB grants SP-only | ✅ CONFIRMED | Arhitectura grants documentată + automatizată |
|
|
| H4 | Diacritice encoding | ✅ CONFIRMED | NLS chain OK fără configurare explicită |
|
|
| H5 | DX < 10s | ✅ CONFIRMED | Ecosistem nu necesită optimizare |
|
|
| H6 | Auth multi-server zero shared code | ✅ CONFIRMED | Pattern reutilizabil pentru orice server Oracle nou |
|
|
|
|
### Ce a funcționat mai bine decât așteptat
|
|
|
|
- **Viteza SP**: 5.9ms callproc (față de estimat 50ms) — server local, zero latency Oracle
|
|
- **Diacritice**: zero configurare NLS necesară — oracledb + Oracle 21c funcționează out-of-box
|
|
- **Auth reuse**: zero linii modificate în `shared/` — `.env` + `register_server()` suficiente
|
|
- **ROA_WEB grants**: soluția cu `V_NOM_FIRME` loop e mai curată decât anticipat
|
|
|
|
### Precauții pentru phase 2
|
|
|
|
- **session_callback multi-schemă**: testul de concurență a confirmat pool-ul, dar izolarea
|
|
CURRENT_SCHEMA între două scheme diferite pe același pool nu e testată — tagged connections
|
|
necesare dacă apare cazul (vezi TODO-phase2.md)
|
|
- **SP production-grade**: `SP_CREEAZA_COMANDA_PROTOTIP` e minimal — nu setează `id_sucursala`,
|
|
`id_inspector`, `proc_tvav`, `observatii`. Phase 2 decide: extinde SP-ul sau migrează la
|
|
`pack_auto.dev_adauga_lucrare` (17 params, coupling cu pack_sesiune)
|
|
- **Vue manual browser test**: ComandaNoua.vue nu a fost testată în browser (H4 Vue layer)
|
|
|
|
### Deliverables prototype livrate
|
|
|
|
| Fișier | Ce conține |
|
|
|---|---|
|
|
| `docs/service-auto/template-modul-oracle.md` | Rețetă reutilizabilă: 11 secțiuni, de la `.env` la tests |
|
|
| `docs/service-auto/learnings.md` | 7 patterns consolidate din notele săptămânale |
|
|
| `docs/service-auto/grants-audit.md` | Arhitectura grants multi-tenant + scripts onboarding |
|
|
| `backend/modules/service_auto/` | Modul complet: router, service, schemas, tests (22/22) |
|
|
| `src/modules/service-auto/views/ComandaNoua.vue` | Formular cu date reale din Oracle |
|
|
| `poc/hello_oracle.py`, `poc/async_out_param_probe.py` | POC-urile de referință |
|
|
|
|
---
|
|
|
|
## 2026-04-13 — Skip 3 integration tests obsolete (post bc481da refactor)
|
|
|
|
### Context
|
|
După commit `bc481da` (multi-tenant refactor) + `9cd7f35` (phase 3 PACK_AUTO)
|
|
+ migrația `ff_2026_04_13_01_AUTO.sql` (grants Tier 3), 3 integration tests
|
|
vechi din hypothesis-probing phase 1 au rămas pe un contract depășit.
|
|
|
|
### Teste marcate cu `@pytest.mark.skip`
|
|
|
|
| Test | Cauză | Acțiune viitoare |
|
|
|---|---|---|
|
|
| `test_grants_integration::test_select_direct_fails` | `ff_2026_04_13_01_AUTO.sql` acordă SELECT pe NOM_LUCRARI lui ROA_WEB (necesar pentru `/operatii`). Asserția ORA-00942 e inversă realității actuale. | Șterge sau rescrie cu altă tabelă la care ROA_WEB n-are acces (dacă mai există un astfel de caz). |
|
|
| `test_grants_integration::test_exec_sp_succeeds` | `SP_CREEAZA_COMANDA_PROTOTIP` nu mai e folosit în producție — `comanda_service.crea_comanda` invocă `PACK_SERII_NUMERE.NUMAR_AUTO_INI` + `PACK_AUTO.DEV_ADAUGA_LUCRARE`. Apelul cu 4 IN params cauzează PLS-00306. | Rescrie ca smoke live pe `PACK_AUTO.DEV_ADAUGA_LUCRARE` (17 params) SAU șterge — acoperit de `test_router_authorization` + live smoke tests. |
|
|
| `test_comanda_persist::test_comanda_persist_and_reconnect` | Același SP obsolete + durabilitate acum validată prin live smoke `POST /api/service-auto/comenzi` (vezi HANDOFF.md, 2026-04-13). | Rescrie ca e2e peste endpoint-ul HTTP dacă e nevoie, altfel șterge. |
|
|
|
|
### Impact suite
|
|
|
|
| Înainte | După |
|
|
|---|---|
|
|
| 62 passed, 3 failed (PLS-00306 + ORA-00942 inversat) | 62 passed, 3 skipped (0 failed) |
|
|
|
|
### Ce NU s-a atins
|
|
|
|
- Nu s-a modificat cod production (`services/`, `routers/`, `schemas/`) — nu
|
|
există regresie reală, doar teste care testau contractul vechi.
|
|
- `test_insert_direct_fails` rămâne activ și trece — ROA_WEB încă NU are INSERT pe NOM_LUCRARI, asertiunea e corectă.
|
|
- `test_pool_concurrency` (3/3 passed) și `test_diacritice_encoding` (2/2 passed) au ieșit din lista de "failing" — trec pe setup-ul curent; HANDOFF.md era puțin în urmă.
|
|
|