# Design: Service Auto Web — Learning + Talent-Risk Hedge (rethink v2) Generated by /plan-ceo-review on 2026-04-11 (pivot from the scrapped 2026-04-10 doc) Revised by /plan-ceo-review on 2026-04-11 (v2 after HOLD SCOPE review + outside voice) Branch: feat/service-auto Repo: romfast/roa2web Status: ACTIVE Owner: Marius (ERP patron + sole dev) Supersedes: `claude-main-design-20260410-205024.md` — premise invalidated (old doc was a product delivery plan; real intent is learning + capability hedge) ## What this is (and what it is NOT) **This is:** a side-exploration prototype. Part learning project (Vue 3 + FastAPI async + oracledb + PrimeVue), part strategic hedge against the "VFP is dead and I can't find programmers" problem. Target = 1 end-to-end screen with 1 SP write, on the existing test schema MARIUSM_AUTO at the office server `10.0.20.121/ROA`. Budget ≈ 2-4 hrs/week, ≈48-96 hours total over 24 weeks (doubled from the original 12-week plan after sincere budget recalibration — see Review Corrections). **This is NOT:** a product, an MVP, a migration plan, or a commitment to ship anything to any client. The 4 existing clients stay on VFP + Oracle XE local. Zero migration. Zero customer-facing delivery. Zero timeline pressure. **The deliverable is NOT a demo.** The deliverable is **a reusable template for future Oracle-backed modules + a decision log**. See "Final deliverable" below. ## Strategic driver (the one that matters) Visual FoxPro is a dead language. Marius cannot hire programmers willing to learn it. Every year on VFP is another year of compounding talent risk on an ERP that powers 4 long-term clients and generates stable revenue. The only realistic path to "someone else can maintain this eventually" is moving incrementally to web stacks (Python/Vue) where the labor pool exists. **Constraint that makes this hard:** Oracle coupling. The ERP has 25 years of PL/SQL, cross-schema synonyms, tenant-per-schema architecture. Postgres migration is not 1:1 — the PL/SQL and schema mechanics don't translate cleanly. Therefore the migration path is **"stay on Oracle, switch UI + business logic layer to Python/Vue, keep PL/SQL as the durable layer."** Service auto is the lowest-risk place to probe whether this path works. **Honest caveat on the hedge thesis:** PL/SQL + Oracle domain knowledge is itself a scarce skill on the Romanian market. This prototype does NOT solve the hiring pipeline problem for PL/SQL maintainers. What it solves is the Python+Vue+integration layer — the UI/API half of the stack — where the labor pool is genuinely larger. The hedge is "replace the half of the stack where hiring is easier"; it is NOT "fix the hiring problem in one shot." This distinction matters for phase 2 scoping. **Success definition for this prototype:** after 24 weeks (or sooner), Marius has direct evidence (working code, not hand-wavy) that the roa2web monolith can drive Oracle business logic end-to-end via PL/SQL stored procedures, AND a reusable template documenting exactly how. If that evidence is positive, the same pattern applies to the next module. If it's negative, Marius knows this before sinking years into it. ## The prototype — minimum viable experiment One screen, one SP, one test schema, one developer. Absolute scope wall. ### Target feature **Screen:** `ComandaNoua.vue` — formular creare comandă nouă service auto. Minimal fields: tip comandă (select 4 opțiuni), client (dropdown **hardcoded în Vue** — 2-3 clienți test cu 1-2 mașini fiecare), operații solicitate (textarea). Submit → backend → PL/SQL → insert row → return ID → display "Comanda X creată" via **PrimeVue Toast**. **SP:** `SP_CREEAZA_COMANDA(p_tip IN, p_client_id IN, p_masina_id IN, p_operatii IN, p_comanda_id OUT, p_numar OUT)`. **Insert într-un tabel DEDICAT de comenzi** (nume real în MARIUSM_AUTO — de verificat în VFP înainte de a scrie SP-ul, vezi pregătire săpt 3). **NU inserează în ACT** (registrul jurnal) — ACT se hit-uiește doar la facturare, care e NOT IN SCOPE pentru prototype. Validare minimă, return ID + număr. **Schema:** **MARIUSM_AUTO** — schemă dedicată de test, deja existentă pe serverul de la biroul Marius (`10.0.20.121/ROA`), care nu e folosită de altcineva. Zero conexiune la schemele de producție ale celor 4 clienți. Zero copy / impdp necesar — schema există deja. **User Oracle tehnic:** **`ROA_WEB`** — user nou dedicat app-ului FastAPI, cu grants explicite per SP (`GRANT EXECUTE ON MARIUSM_AUTO.SP_CREEAZA_COMANDA TO ROA_WEB`), fără acces direct la tabele. Pattern multi-tenant compatibil — același user va avea grants pe alte scheme în phase 2 dacă probează. ### Things this prototype will probe (the real learning) Fiecare din acestea e o ipoteză pe care prototype-ul trebuie să o confirme sau să o infirme: | # | Ipoteză | Cum o probez | |---|--------|-------------| | 1 | `python-oracledb` async cleanly calls PL/SQL proc cu IN+OUT params | Săpt 1 POC: `poc/hello_async_out.py` cu `oracledb.connect_async()` + `cursor.var(oracledb.NUMBER)` + `await cursor.callproc('test_out', [out])`. **GATE**: dacă merge curat, prototype-ul continuă pe true-async. Dacă NU merge, fallback la pattern-ul sync-facade din `treasury_service.py` (deja proof-ed în prod). Fallback e pre-aprobat, NU blochează săpt 2+. | | 2 | `session_callback` pentru CURRENT_SCHEMA switching nu leak-uiește între requests concurente | Săpt 4: 2 conexiuni paralele pe **aceeași schemă MARIUSM_AUTO**, ambele setează CURRENT_SCHEMA, rulează CALL-uri distincte, verific cu log-uri că nu se încurcă cursor tag reuse. **Limitare acceptată conștient:** testul pe 1 schemă nu dovedește 100% izolarea la multi-schemă — pentru asta ar trebui o a doua schemă test (ex: copie CLEVER), care e în afara budget-ului. Probă de primitive, nu de multi-schemă. | | 3 | GRANTS de tip "EXECUTE ON SP, zero INSERT/UPDATE/DELETE pe tabele" țin în practică | Săpt 3: user `ROA_WEB` încearcă `INSERT INTO MARIUSM_AUTO.ACT` → `ORA-00942` sau `ORA-01031`; `SELECT * FROM MARIUSM_AUTO.ACT` → `ORA-00942`; `EXEC MARIUSM_AUTO.SP_CREEAZA_COMANDA(...)` → success. Un test automat pytest-marcat `integration` care rulează local. | | 4 | `RAISE_APPLICATION_ERROR(-20001, 'mesaj cu diacritice ă î ș ț â')` ajunge în Vue ca eroare user-friendly, encoding corect | Săpt 11-12: SP aruncă eroare (client inexistent, tip invalid, operatii gol), serviciul traduce `oracledb.DatabaseError.code` la HTTP status (20001-20999 → 422 business, 12541/12170 → 503 infra, rest → 500), Vue afișează PrimeVue Toast cu mesajul. Obligatoriu test pe un mesaj cu diacritice pentru a proba `NLS_LANG` / encoding chain end-to-end. | | 5 | FastAPI hot-reload + Vite dev-server + SSH tunnel Oracle e un DX acceptabil pentru side-work de 2-4h/săpt | Săpt 1: măsor timpul de la "save file" la "văd rezultatul" — dacă e > 10s, fix ecosistem înainte de content. **Documentat** în `docs/service-auto/week1-notes.md` cu numere concrete. | Dacă oricare din 1-4 eșuează cu un răspuns clar, **prototype-ul s-a încheiat cu succes** — learning obținut, decision point clar, zero cod irosit care trebuie să supraviețuiască. ## Scope wall — what is explicitly NOT in this prototype Toate aceste subiecte aparțin doc-ului scrapped sau sunt defer-uri la TODO-phase2. Niciunul nu intră aici: - ❌ Cei 4 clienți existenți, vreodată. Ei rămân pe VFP + XE local. Zero atingere. - ❌ Migrare scheme, SSH tunnel VFP→Oracle central, decomisionare XE local - ❌ eFactura / ANAF / SPV upload — irelevant fără producție - ❌ Feature flags per-tenant, `FEATURE_FLAGS` table - ❌ `SP_BON_CONSUM` (cross-schema synonyms), `SP_VALIDEAZA_COMANDA`, `SP_EMITE_FACTURA` — toate deferred - ❌ **Insert în ACT la creare comandă** — ACT e registrul jurnal, se hit-uiește la facturare, care e NOT IN SCOPE - ❌ `reconcile.py`, invariant checking, parallel testing cu VFP - ❌ Runbook rollback, monthly restore drill, uptime monitoring, Telegram alerts - ❌ 5 ecrane MVP (doar 1 — absolute wall) - ❌ Mobile, responsive, iPad, tablet — desktop-only, viewport-whatever-is-convenient - ❌ Playwright e2e, smoke parity pentru SPs - ❌ Endpoint `/clienti` sau `/masini` pentru populare dropdown — hardcoded în Vue - ❌ Onboarding client nou, referral pipeline, assignment cu telefoane - ❌ Phase 2, Phase 3, Phase 4 — menționate doar în decision-log.md la finalul prototype-ului - ❌ SLA, RPO, RTO, warm standby, backup discipline - ❌ `X-Idempotency-Key`, double-submit protection, retry policy - ❌ A doua schemă de test (ex: copie CLEVER) pentru probă multi-schemă — costă prea mult budget Dacă în timpul construcției una dintre aceste tentații începe să pară "doar 30 min în plus", răspunsul e **scriu o notă, nu scriu cod**. Scope wall ține. Note de tipul "probabil o să am nevoie de X pentru phase 2" merg în `docs/service-auto/TODO-phase2.md`, nu în codul prototype-ului. ## Review corrections (from /plan-ceo-review session, 2026-04-11) Această secțiune documentează ce s-a corectat față de prima versiune a planului, pentru a fi transparent despre gândirea care a dus la planul final. ### Correction 1 — Nu se creează `MarciusLabPool` nou **Prima versiune** spunea: "modifică `OracleMultiPool` sau adaugă wrapper" și "creează NEW minimal helper `MarciusLabPool`". **Realitate:** `OracleMultiPool` la `shared/database/oracle_pool.py` are deja suport multi-server prin `_pools: Dict[server_id, ConnectionPool]`. MARIUSM_AUTO se adaugă ca **server nou** prin `register_server('mariusm_test', host='10.0.20.121', port=1521, user='ROA_WEB', password='...', service_name='ROA')` — zero pool nou, zero refactor. ### Correction 2 — Pattern sync-in-async-facade e deja proof-ed în prod **Prima versiune** trata ipoteza #1 ("oracledb async + OUT params") ca unknown. **Realitate:** `backend/modules/reports/services/treasury_service.py` deja apelează SPs cu OUT params de tip `oracledb.CURSOR` și `oracledb.NUMBER` în producție, folosind pattern-ul sync-in-async-facade (`async with oracle_pool.get_connection(...)`, cursor sync, fără `await` pe execute/callproc). **Consecință:** ipoteza #1 e reîncadrată ca probă a pattern-ului `oracledb.connect_async()` **true-async** — nou, neprobeat în codebase. Săpt 1 e **gate** (vezi mai sus): dacă true-async merge → adoptă; dacă nu → fallback la sync-facade care e deja dovedit. ### Correction 3 — SP nu inserează în ACT **Prima versiune** spunea "Insert în ACT, validare minimă". **Realitate:** ACT e registrul jurnal contabil (double-entry bookkeeping, clasa 6/7 — vezi `.claude/rules/financial-indicators.md`). O comandă de service auto la CREARE aterizează într-un **tabel dedicat** (ex: `COMENZI`, `COMD_SA`, nume real de verificat în VFP), NU în ACT. ACT se hit-uiește la **facturare**, care e NOT IN SCOPE. SP-ul corect face INSERT în tabela dedicată de comenzi. **Task în săpt 3 (preparare):** înainte de a scrie SP_CREEAZA_COMANDA, deschide VFP-ul producție (cu grijă, doar read), caută fluxul real de "creează comandă nouă service auto", identifică tabelele atinse, documentează în `docs/service-auto/tabele-service-auto.md`. ### Correction 4 — `connection.commit()` e explicit în pattern **Prima versiune** nu menționa commit. **Realitate:** `oracledb` driver are autocommit OFF default. Fără `connection.commit()` după `cursor.callproc`, SP-ul rulează dar datele NU se salvează — **silent failure clasică**. Pattern-ul corect e: ```python async with oracle_pool.get_connection('mariusm_test') as conn: with conn.cursor() as cursor: out_id = cursor.var(oracledb.NUMBER) out_numar = cursor.var(oracledb.STRING, size=50) cursor.callproc('SP_CREEAZA_COMANDA', [..., out_id, out_numar]) conn.commit() # <-- CRITICAL ``` **Test obligatoriu** în săpt 5-6: după `callproc + commit`, închide conexiunea, deschide alta, `SELECT ... WHERE id = :id` — confirmă că row-ul persistă. Dacă nu, commit-ul e problemă. ### Correction 5 — Error code classification e explicită în plan **Prima versiune** zicea doar "ORA-20001 → toast". **Realitate:** există multe categorii de erori Oracle, iar trducerea la HTTP trebuie să fie range-based: | Cod Oracle | HTTP | Ce vede user-ul | |---|---|---| | 20001 — 20999 (`RAISE_APPLICATION_ERROR`) | 422 | Mesajul din SP, curat de prefix | | 12541, 12170, 12154 (connection / listener errors) | 503 | "Serviciul bazei de date e temporar indisponibil" | | 01017 (invalid credentials) | 500 + critical log | "Eroare de configurare. Contactați administratorul." | | 00942 (table or view not exist — grants leak) | 500 + critical log | "Eroare internă. Contactați administratorul." | | Orice alt cod | 500 + full log | "Eroare internă neașteptată" | Săpt 11-12: scrie service-layer-ul cu `try/except oracledb.DatabaseError` + clasificare pe range. Test cu diacritice în mesaj. ### Correction 6 — Logging persistent per-modul **Prima versiune** nu menționa logging. **Realitate:** `backend/main.py:57` folosește `logging.basicConfig` cu output doar în stdout. Dacă în săpt 5 vrei să recitești log-urile din săpt 2, nu ai unde. Fix local pentru `service_auto`: ```python # backend/modules/service_auto/__init__.py import logging, os os.makedirs('backend/logs', exist_ok=True) logger = logging.getLogger('service_auto') fh = logging.FileHandler('backend/logs/service_auto.log') fh.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(name)s: %(message)s')) logger.addHandler(fh) logger.setLevel(logging.INFO) ``` Log structurat la fiecare call: ```python logger.info("service_auto.create_comanda START", extra={'user': user.username, 'tip': data.tip, 'client_id': data.client_id}) logger.info("service_auto.create_comanda OK", extra={'comanda_id': comanda_id, 'duration_ms': elapsed}) logger.warning("service_auto.create_comanda BUSINESS_ERROR", extra={'ora_code': code}) logger.error("service_auto.create_comanda INFRA_ERROR", extra={'ora_code': code}, exc_info=True) ``` La sfârșit de fiecare săptămână, `grep` în log pentru count-uri și duration p99. ### Correction 7 — Timeline dublat: 12 → 24 săptămâni **Prima versiune** aloca 12 săptămâni × 2-4 h/săpt = 24-48h. **Realitate (outside voice):** 10 tehnologii noi (Vue 3, Pinia, PrimeVue, Axios, FastAPI async, oracledb true-async, `session_callback`, PL/SQL OUT params, JWT reuse cu auth store, error mapping) ÷ 24h = ~2.4h per tehnologie, **zero slack**. Plus 2-3 săpt pierdute realist pe VFP urgențe din 12. **Buget onest: 24 săptămâni × 2-4 h/săpt = 48-96h total.** Scope-ul rămâne același, tempo-ul e mai onest. ### Correction 8 — Week-12-style deliverable schimbă: template reutilizabil, nu demo **Prima versiune** zicea săpt 12 = "cleanup + phase 2 notes". **Realitate:** un demo pe un branch throwaway nu e un hedge — e o demonstrație. Hedge-ul real e un **template reutilizabil**. Noul deliverable pentru săpt 24: - `docs/service-auto/template-modul-oracle.md` — rețetă de 1 pagină pentru "cum adaugi un modul nou peste Oracle în roa2web": register_server pattern, SP signature convention, grants model, error map range, `session_callback` snippet, JWT reuse via AuthenticationMiddleware, logging setup, file layout. - `docs/service-auto/decision-log.md` — go / no-go pentru phase 2: ce a funcționat, ce nu, sub ce condiții se justifică un al doilea modul, când să nu. - `docs/service-auto/learnings.md` — notele săptămânale consolidate în lesson patterns. ## What to reuse from the scrapped doc Nu tot efortul de pe doc-ul vechi e pierdut: - **Manual ROAAUTO PDF** (`docs/service-auto/manual_ROAAUTO.pdf`) — ground truth pentru fluxul real de service auto. Folosit ca input pentru ce câmpuri trebuie să aibă `ComandaNoua.vue` și ca referință pentru verificarea tabelelor atinse la creare comandă. - **Legacy `/workspace/roaauto/frontend/src/views/orders/OrderCreateView.vue`** — starting point pentru `ComandaNoua.vue` la ~125 linii, audit de 30 min în săptămâna 1. - **Convenția de `@cached` + services** din `.claude/rules/backend-patterns.md` — dar NU aplicat la endpoint-ul de INSERT (cache-ul e pentru reads). - **Pattern-ul `treasury_service.py`** ca **golden example** de apel PL/SQL cu OUT params. ## Risks + mitigations ### Risk 1: 2-4 hrs/week + learning curve = prototype drifts into 12+ months Corecția de buget (24 săpt) ajută. **Mitigare principală:** stop-point discipline (milestone self-contained per săptămână) + **kill criterion explicit** (vezi mai jos). Săpt 1 goal e **Hello World Oracle connection** — nu SP, nu schema, nu UI. ### Risk 2: oracledb async + PL/SQL OUT params sunt poorly documented Săpt 1 POC e exact asta, pe o procedură trivială. **Fallback pre-aprobat:** dacă true-async nu merge, prototype-ul continuă cu sync-facade (pattern deja în prod). Zero timp pierdut. ### Risk 3: ~~CURRENT_SCHEMA switching conflictează cu OracleMultiPool~~ **Corectat:** nu conflictează. `OracleMultiPool` izolează per `server_id`. `session_callback` se aplică la `create_pool` call, nu la nivel de instance. Poți adăuga un argument `session_callback=` la pool creation pentru `mariusm_test` fără să atingi pool-urile altor servere. ### Risk 4: Marius abandonează side project-ul după săpt 3 pentru că VFP-ul real cere atenție Realitate acceptată (outside voice): 2-3 săpt pierdute în 12 e probabil. **Mitigare:** timeline dublat la 24, fiecare săptămână e stoppable milestone, plus **kill criterion**. ### Risk 5 (NEW): Integration issues concentrate la final Outside voice observă: fiecare layer e mock-uit până la săpt 11, apoi totul se integrează. Dacă Vue↔FastAPI↔oracledb are un CORS/proxy/JWT header issue, apare fără buffer. **Mitigare:** două **integration checkpoints** intermediare: - Săpt 6 checkpoint: un `curl` hit pe endpoint-ul fără UI, cu JWT real, care cheamă SP-ul și returnează JSON. Confirmă FastAPI↔oracledb chain. - Săpt 9 checkpoint: `ComandaNoua.vue` hit endpoint-ul cu JWT real, confirmă doar un drum happy path fără error handling. Confirmă Vue↔FastAPI chain. ### Risk 6 (NEW): Grants inventory pe MARIUSM_AUTO nedocumentat Outside voice observă: testul negativ săpt 3 presupune clean slate. **Mitigare:** săpt 3, înainte de testul negativ, rulează un `SELECT * FROM DBA_TAB_PRIVS WHERE grantee = 'ROA_WEB'` + `SELECT * FROM DBA_SYS_PRIVS WHERE grantee = 'ROA_WEB'` și documentează starting state în `docs/service-auto/week3-grants-audit.md`. ## Kill criterion (NEW — from outside voice) **Prototype-ul se oprește definitiv** (nu "pauză de o săptămână", ci "end of project, scrie decision-log și gata") dacă ORICARE din: 1. **Săpt 4 checkpoint:** `session_callback` nu funcționează după 2 săpt de încercări (adică nu ai ajuns la o conexiune care schimbă CURRENT_SCHEMA curat, fără race). Decizia: scrie `decision-log.md` cu "session_callback nefezabil în acest oracledb/Python combo, multi-tenant necesită alt approach", apoi stop. 2. **Săpt 8 checkpoint:** nu ai un SP `SP_CREEAZA_COMANDA` funcțional testat din SQL Developer + Python + grants OK. Decizia: `decision-log.md` cu "pattern SP-first prea greu pentru side-project budget", apoi stop. 3. **Săpt 14 checkpoint:** nu ai un curl care apelează endpoint-ul + JWT real + SP + returnează JSON. 4. **Oricând:** 3 săpt consecutive în care nu ai atins nici măcar 1 oră de work pe prototype. Side project-ul e mort, acceptă realitatea, `decision-log.md` cu "abandoned — VFP demands exceeded budget". Stop NU înseamnă eșec. Stop înseamnă "am învățat ce trebuia, continuarea nu mai produce valoare marginală". Fiecare stop produce un `decision-log.md` citibil în 6 luni. ## Timeline (ajustat pentru 2-4 hrs/week × 24 săptămâni) **Fiecare săptămână e self-contained + oprire curată.** Ordering-ul original e păstrat, doar spațiat pe 24 săpt în loc de 12, cu checkpoints de integration intermediare. | Săpt | Target | Cum știu că e gata | |---|---|---| | 1 | Oracle central rulează + `poc/hello_oracle.py` (sync) + `poc/hello_oracle_async.py` (`connect_async`) conectează cu `SELECT 1 FROM DUAL`. **Gate**: decide sync-facade vs true-async. DX check (save → result < 10s?). File handler logging setup. | Log arată rezultat, `docs/service-auto/week1-notes.md` scris | | 2 | `poc/async_out_param_probe.py` — test SP trivial (`CREATE PROCEDURE test_out(p OUT NUMBER) AS BEGIN p := 42; END;`) + Python apel cu `cursor.var(int)` | Script scris, primește `42` | | 3 | **Preparare:** audit grants curenți pe MARIUSM_AUTO (`DBA_TAB_PRIVS`, `DBA_SYS_PRIVS`). **Verifică tabelele** atinse de crearea comenzii în VFP, scrie `tabele-service-auto.md`. Creează user `ROA_WEB` + grants. | `week3-grants-audit.md` + `tabele-service-auto.md` scrise | | 4 | Test negativ ipoteza #3 (INSERT direct → ORA-00942; SELECT direct → ORA-00942; CALL SP → success). Pytest integration marker. | Test automat rulează local, toate cele 3 asserts trec | | 5 | `session_callback` pentru CURRENT_SCHEMA switching, test concurent pe 2 conexiuni paralele pe aceeași schemă | Log-uri clare, niciun cursor tag leak | | 6 | **Checkpoint integration 1**: endpoint FastAPI minimal (fără logic, hardcoded return) + JWT reuse din middleware + curl hit cu JWT real. Doar ca să confirm că chain-ul FastAPI + auth merge. | `curl` cu JWT real returnează 200 | | 7-8 | **Verify tabele** în VFP (din săpt 3), scrie `SP_CREEAZA_COMANDA` în SQL Developer, test manual cu `EXEC` | Row apare în tabela dedicată cu ID returnat prin OUT | | 9-10 | Service-layer Python (`comenzi_service.create_comanda`) care apelează SP-ul prin pattern-ul ales în săpt 1 + `connection.commit()` + test persist după reconnect | Test automat: callproc + commit + new connection + SELECT → row există | | 11 | Endpoint FastAPI `/api/service-auto/comenzi` care primește Pydantic, apelează service, returnează JSON | `curl` hit cu JWT real + body JSON → row inserted | | 12 | **Checkpoint integration 2**: `ComandaNoua.vue` minimal (hardcoded dropdowns) + Pinia store + axios call → endpoint. Doar happy path, zero error handling. | Submit în browser → row inserted → console log "OK" | | 13-16 | Error handling end-to-end: ORA-20001 (diacritice!) → HTTP 422 → PrimeVue Toast în română. ORA-12541 → HTTP 503 → Toast generic. Spinner pe buton cât SP rulează. Reset form la success. | Aruncă intenționat erori în SP, verifică fiecare drum | | 17-20 | Buffer pentru VFP urgențe + lessons refactor (dacă săpt 1-16 au produs cod care trebuie curățat). Dacă nu e nevoie de buffer, rula ipoteza #2 mai adânc (2 conexiuni, concurență mai agresivă). | N/A — buffer | | 21-22 | Scrie `template-modul-oracle.md` — reteta reutilizabilă | Doc scris, citibil de către un alt dev | | 23 | Scrie `decision-log.md` — go/no-go phase 2, learnings consolidate | Doc scris, decizie clară | | 24 | Cleanup: ștergerea `poc/` dacă e cazul, final commit pe branch, `learnings.md` consolidat | Branch clean, commit final | **Timeline-ul e intenționat conservativ.** La 2-4 hrs/week, 24 săpt = 48-96 ore totale. Dacă merge mai repede, perfect — atingi mai devreme la sfârșit. Dacă merge mai încet, fiecare săptămână e încă un milestone self-contained. ## What would make this prototype fail (and it would still be useful) - Ipoteza #1 eșuează pentru **true-async**: fallback la sync-facade, prototype continue. Zero învățare pierdută — sync-facade e deja în producție, știi că merge. - Ipoteza #1 eșuează pentru **ambele** (sync + true-async): dacă nici sync-facade-ul din `treasury_service.py` nu merge la MARIUSM_AUTO, e ceva radical prost cu oracledb instalat la tine. **Stop și investighează**. - Ipoteza #2 eșuează: `session_callback` fragil în practică → Marius știe că pool-per-tenant e necesar, nu pool-single-with-tag. Design major changed, decision-log documentează. - Ipoteza #3 eșuează: GRANTS model nu ține (SP cheamă alte SPs cu privilegii neașteptate) → Marius știe că "Regula de aur via GRANTS" e naivă și trebuie altceva (VPD? row-level security?). Design major changed. - Ipoteza #4 eșuează: error propagation urâtă (encoding, truncation) → Marius știe că trebuie protocol de eroare dedicat, nu `RAISE_APPLICATION_ERROR`. - Ipoteza #5 eșuează: DX pentru 2-4 hrs/week e unusable → Marius știe că side project pe acest stack nu e viabil și trebuie alt approach. Orice din aceste failures e **valoare mai mare** decât "prototype care merge happy path fără să fi întâmpinat nicio problemă reală". Succesul real = învățare, nu cod. ## Next actions (săpt 1, 2026-04-14 → 2026-04-18) Cel mai concret lucru, o singură zi, 2-4 ore: 1. **Verifică SSH tunnel setup** de la containerul de dev (sau workstation-ul de acasă) la `10.0.20.121/ROA`. Există `ssh-tunnel-manager.py` în `backend/shared/` — vezi dacă se refolosește. 2. **`poc/hello_oracle.py`** (sync, la `MARIUSM_AUTO` user sau alt user Oracle existent) — `oracledb.connect(...)` + `SELECT 1 FROM DUAL`. 3. **`poc/hello_oracle_async.py`** (true-async) — `oracledb.connect_async(...)` + același `SELECT 1 FROM DUAL` cu `await cursor.execute(...)`. 4. **Setup logging file handler** pentru modulul `service_auto` (nu exista încă, dar directory-ul `backend/modules/service_auto/` se poate crea în săpt 1 just to house the logging setup). 5. **Raport săpt 1** — `docs/service-auto/week1-notes.md`, max 15 linii: ce a mers, ce a fost greu, DX latency măsurat (save → result în secunde), gate decision (sync vs true-async), buget rămas din săpt 1. Zero SP-uri, zero Vue, zero auth, zero scheme noi. Doar "Python vorbește cu Oracle local" în ambele pattern-uri. ## Non-negotiables 1. **Cei 4 clienți nu sunt atinși niciodată în acest prototype.** MARIUSM_AUTO e dedicat, zero copy, zero conexiune la producție. 2. **Scope wall la 1 ecran + 1 SP.** Tentațiile de scope creep merg la `docs/service-auto/TODO-phase2.md`, nu în cod. 3. **Stop points weekly.** Fiecare săptămână e oprire curată. Nu se acceptă "oh, nu pot să mă opresc aici pentru că e jumătate făcut". 4. **Succesul se măsoară în învățare + template reutilizabil**, nu în ecrane livrate. Un prototype care descoperă o problemă e mai valoros decât unul care evită toate problemele. 5. **Kill criterion trigger-ed → scrie decision-log → stop.** Nu "mai dau 2 săpt să văd". ## Final deliverable (săpt 24) Nu e un ecran. Nu e un demo. E: 1. `docs/service-auto/template-modul-oracle.md` — rețetă de 1 pagină citibilă de către un alt dev în 10 minute: - Cum înregistrezi un server nou în `OracleMultiPool` - Signature convention pentru SPs cu OUT params - Grants model (user tehnic + `EXECUTE ON SP` + `ALTER SESSION SET CURRENT_SCHEMA`) - Error code range classification (20xxx → 422, 12xxx → 503, else → 500) - `session_callback` snippet pentru CURRENT_SCHEMA switching - JWT reuse prin `AuthenticationMiddleware` - Logging file handler per-modul - File layout (`routers/`, `services/`, `models/`) 2. `docs/service-auto/decision-log.md` — go / no-go pentru phase 2: - Ce ipoteze s-au confirmat, care nu - Evidența concretă (log-uri, teste, numere DX) - Condițiile sub care un al doilea modul e justificat - Condițiile sub care NU e justificat (kill criterion retroactiv) 3. `docs/service-auto/learnings.md` — notele săptămânale consolidate, pattern-uri noi, surprize, workarounds descoperite, Oracle edge cases. 4. Cod: tot sub branch `feat/service-auto`, NU merged în main. Branch = arhivă + referință. **Acest deliverable e valoros chiar dacă prototype-ul n-a ajuns la 100% din ipoteze.** --- **END OF RETHINK DESIGN v2. ~9 pages. Budget 2-4 hrs/week × 24 weeks = 48-96 hrs total.** --- ## GSTACK REVIEW REPORT | Review | Trigger | Why | Runs | Status | Findings | |--------|---------|-----|------|--------|----------| | CEO Review | `/plan-ceo-review` | Scope & strategy | 1 | CLEAR (PLAN) | HOLD SCOPE mode, 0 critical gaps post-fix, 10 items deferred to TODO-phase2, plan file rewritten v2 with 8 review corrections | | Codex Review | `/codex review` | Independent 2nd opinion | 0 | — | — | | Eng Review | `/plan-eng-review` | Architecture & tests (required) | 0 | — | — | | Design Review | `/plan-design-review` | UI/UX gaps | 0 | — | — | | DX Review | `/plan-devex-review` | Developer experience gaps | 0 | — | — | **OUTSIDE VOICE:** Claude subagent (Codex unavailable). 15 findings total. 3 load-bearing surfaced as cross-model tension (SP→ACT modeling error, budget ~2x under-scoped, demo vs template deliverable). All 3 accepted by user and integrated into plan v2. **UNRESOLVED:** 0 **VERDICT:** CEO CLEARED — plan rewritten as v2 with 8 corrections, 0 critical gaps, 24-week timeline, template deliverable. Eng review recommended before writing any code (optional for learning prototype but helps catch architectural issues in service_auto module structure).