Files
roa2web-service-auto/docs/service-auto/claude-main-design-20260411-rethink.md
Claude Agent 6aceb85bf1 docs(service-auto): design review + VFP audit (Correction 12)
plan-design-review pass: 6/10 → 9/10. Added interaction-states table
(6-state PrimeVue spec matching ReceiptCreateUnifiedView.vue toast
conventions), design-system inheritance clause (DESIGN.md/TOKENS/
CSS_PATTERNS), a11y one-liner, week-3 subtask for enum+labels
extraction from VFP source.

Cloned gitea.romfast.ro/romfast/vfp_roaauto and wrote a 300+ line
ground-truth audit (docs/service-auto/tabele-service-auto.md)
covering: DEV_ORDL parent/child inheritance with NOM_LUCRARI,
DEV_TIP_DEVIZ enum (1-7, including user-confirmed Productie/
Constatare for 6/7), dev_adauga_lucrare v1 (pack_devize, 12+1
params, body visible in packages.sql) vs v2 (pack_auto, 17+1,
body only in MARIUSM_AUTO), and the pack_sesiune.dev_idLucrare
trigger/session-state pattern (ROA ERP convention from pre-
RETURNING era, not a bug).

Plan Correction 12 added: the prototype needs a ~40-line SP doing
two INSERTs parent→child with RETURNING id_lucrare (bypassing
pack_sesiune), targeting dev_ordl via nom_lucrari. Original
assumption of a 4-param new SP was wrong. Week 3 subtask updated
to reference the audit draft. ACT/RUL untouched at creation time
— Correction 3 still valid.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-05 09:37:09 +00:00

51 KiB
Raw Blame History

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.ACTORA-00942 sau ORA-01031; SELECT * FROM MARIUSM_AUTO.ACTORA-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.
6 Flux-ul de auth multi-server existent (login → email_server_cacheCONTAFIN_ORACLE.UTILIZATORI → JWT cu server_idAuthenticationMiddlewarerequest.state.server_id) suportă un server nou fără modificări la shared code Săpt 3: (a) adaugă MARIUSM_AUTO la ORACLE_SERVERS în backend/.env; (b) INSERT INTO CONTAFIN_ORACLE.UTILIZATORI (username, server_id, ...) pentru Marius; (c) log in prin UI, verifică că server selector arată mariusm_test; (d) după login, inspectează JWT payload în browser devtools — confirmă server_id='mariusm_test'; (e) verifică ce returnează auth_service.get_user_companies('MARIUS M', 'mariusm_test') — dacă MARIUSM_AUTO nu are V_NOM_FIRME, vezi dacă login-ul tolerează companies=[] sau dacă trebuie un fake. Documentat în week3-auth-audit.md. Gate: dacă auth-ul cere modificări la shared code pentru a accepta un server non-CONTAFIN, scope creep → replanning sau kill criterion.

Dacă oricare din 1-6 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 (accesibilitate: PrimeVue defaults gestionează keyboard tab order, ARIA labels, focus ring — zero work custom; nu e "ignorat", e "inherited free")
  • 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 (+ patch minim la oracle_pool.py)

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 clasă nouă.

Însă NU e chiar "zero refactor". register_server (linii 55-83) acceptă **kwargs dar le ignoră — nu le stochează în _pool_configs. _get_or_create_pool (linii 108-117) construiește pool_params dintr-un set fix de chei. Pentru a activa session_callback (ipoteza #2), trebuie un patch backward-compatible de ~8 linii la shared/database/oracle_pool.py:

def register_server(self, ..., session_callback=None, **kwargs):
    self._pool_configs[server_id] = {
        ...
        'session_callback': session_callback,
    }

# în _get_or_create_pool, după pool_params:
if config.get('session_callback'):
    pool_params['session_callback'] = config['session_callback']

Zero caller-i existenți folosesc session_callback, deci patch-ul e backward-compatible. Planificat explicit în săpt 5 (vezi timeline) — nu e "scope creep", e un task minim necesar și conștient de scope wall-ul shared code.

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, clonează repo-ul gitea al sursei VFP (gitea.romfast.ro/romfast/vfp_roaauto — importat 2026-04-11 ca ground truth pentru acest prototype), grep după fluxul "creează comandă nouă service auto" în sursele .PRG / .SCX, identifică tabelele atinse și SP-urile / UPDATE-urile existente, documentează în docs/service-auto/tabele-service-auto.md. Nu mai e nevoie să deschizi VFP-ul producție — gitea e strict mai sigur (zero risk de modificare accidentală) și mai rapid (text search vs IDE navigation).

Audit preliminar deja scris 2026-04-11: docs/service-auto/tabele-service-auto.md e un DRAFT generat de Claude pe baza clonei gitea. Conține (a) schema reală comenzi / vcomenzi cu ~28 coloane, (b) SP-ul real de creare pack_auto.dev_adauga_lucrare (17 params IN, 1 OUT — substanțial diferit de ipoteza inițială a planului), (c) enum real tip_comanda (ID-uri 1-7 cu prefixe G/R/P/PR/C), (d) label-urile Romanian pentru câmpuri, (e) lista funcțiilor pack_auto.* și pack_comenzi.* relevante, (f) query-uri SQL de verificat în săpt 3 împotriva schemei reale. Task-ul săpt 3 e să confirme draft-ul împotriva bazei reale, nu să-l scrie de la zero. Vezi Correction 12 pentru implicațiile strategice ale descoperirii SP-ului existent.

Correction 12 — Tabela reală e DEV_ORDL, SP-ul are două versiuni, și există un pack_sesiune coupling

Prima versiune a planului presupunea că:

  • Tabela e comenzi (fizică)
  • SP-ul SP_CREEAZA_COMANDA va fi nou, simplu, cu ~4 IN + 2 OUT
  • Nu există dependențe ascunse

Realitate (2026-04-11 post-audit pe gitea VFP + scripturi instalare):

(a) Inheritance pattern: comandă în nom_lucrari + extensie auto în dev_ordl (confirmat de Marius 2026-04-11). nom_lucrari e tabela parent din ROA ERP generic — conține header-ul "comenzii" (nrord), vizibil în ACT (registrul jurnal) și RUL (rulaje gestiune) doar când comanda e referențiată la facturare. dev_ordl e extensia ROAAUTO (id_lucrare FK → nom_lucrari.id_lucrare) care conține toate detaliile service auto (mașină, km, termen, tip deviz, etc.). Crearea unei comenzi face INSERT în AMBELE tabele, în ordine FK parent → child. Crearea nu touch-uiește ACT/RUL — Correction 3 rămâne validă. Ce vedem ca comenzi / vcomenzi e un VIEW denormalizat care JOIN-uiește cele două tabele

  • lookup-uri (dev_tip_deviz, dev_masiniclienti, parteneri).

(b) Tabela enum pentru tip_comanda este DEV_TIP_DEVIZ — cu schema:

DEV_TIP_DEVIZ (ID_TIP NUMBER(5) PK, DENUMIRE VARCHAR2(50), STERS NUMBER(1))

Seed install (initializari.sql): {1:'POST GARANTIE', 2:'GARANTIE', 3:'REGIE', 4:'PREGATIRE', 5:'REGIE 2'}. IDs 6 și 7 adăugate în producție: {6:'Productie' (prefix PR), 7:'Constatare' (prefix C)} (confirmat de Marius 2026-04-11).

(c) Există DOUĂ versiuni ale dev_adauga_lucrare:

  • v1 INSTALLpack_devize.dev_adauga_lucrare(12 IN + 1 OUT) — body vizibil în Scripturi_instalare/packages.sql:182-212
  • v2 PRODUCȚIEpack_auto.dev_adauga_lucrare(17 IN + 1 OUT) — apelat din VFP (Programe/oproceduri_devize.prg:147-148), body NU e în sursă (pachet adăugat post-install, trăiește doar în DB-ul lui Marius). 5 params noi: nr_dosar, ore_fct, operatii_csv, observatii, defectiuni, id_part_ref.

(d) pack_sesiune.dev_idLucrare NU e un bug, e convenție ROA ERP — pattern-ul e: trigger TRG_NOM_LUCRARI_BEFOINS populează pack_sesiune.dev_idLucrare := :new.id_lucrare după INSERT-ul pe nom_lucrari; apoi INSERT-ul pe dev_ordl citește acel session state. Confirmat prin pattern-ul identic la dev_ordl (triggere.sql:1165-1172: SEQ_DEV_ORDL.NEXTVAL INTO :new.id_ordl + pack_sesiune.dev_idOrdl := :new.id_ordl) și la dev_oper (triggere.sql:928).

Pentru roa2web: bypass trivial — folosim RETURNING id_lucrare INTO v_local după INSERT-ul pe nom_lucrari. Trigger-ul încă rulează și populează session state (irelevant pentru noi), iar noi citim id_lucrare local prin RETURNING. Standard Oracle. Zero dependency.

(e) Flux-ul real — v1 body face 3 operații:

  1. INSERT INTO NOM_LUCRARI (NRORD, ID_MOD) VALUES (nr_com, 1200)parent (header generic) — ESENȚIAL
  2. INSERT INTO DEV_ORDL (..., id_lucrare, ...) RETURNING id_ordlchild (extensia auto, FK la parent) — ESENȚIAL
  3. UPDATE DEV_MASINICLIENTI SET kmint=... WHERE id_masiniclient=... — sync odometru — OPȚIONAL (skip pentru prototype)

Deci nu e "flux cu side effects" — e un pattern de inheritance normal (parent + child), plus o sync colaterală opțională.

Trei opțiuni strategice (decise în săpt 3/4 după extragerea body-ului real)

# Strategie Pro Contra
1 Reuse pack_auto.dev_adauga_lucrare v2 direct Hedge max — dovedește reuse pachet producție cu side-effects Depinde de pack_sesiune; risc sabotaj la primul call
2 Reuse pack_devize.dev_adauga_lucrare v1 Body vizibil în sursă, 5 params mai puțin Același pack_sesiune bug, tot 12 params
3 SP nou minimal SP_CREEAZA_COMANDA_PROTOTIP cu INSERT direct în dev_ordl + id_lucrare=0 + skip side-effects Control total, zero dependențe, ~20 linii PL/SQL, testabil clean, probează ipoteza #1 perfect Bypass-uie business logic (dar asta oricum e phase 2)

Recomandare actualizată: OPȚIUNEA 3 (SP nou minimal cu două INSERT-uri parent+child).

Motivul: deși pack_sesiune s-a dovedit a nu fi bug ci convenție, reuse-ul direct al v1/v2 aduce alte complicații (17 params pentru v2, business logic care ar trebui reimplementată sau bypass-ată, etc.). Opțiunea 3 cu cele două INSERT-uri în ordine (nom_lucrari → dev_ordl, cu RETURNING id_lucrare) e exact pattern-ul corect pentru inheritance, nu un bypass urât. E idiomul Oracle modern (post-9i când RETURNING a devenit standard), iar pack-urile legacy foloseau pack_sesiune doar pentru că n-aveau RETURNING când au fost scrise inițial.

Rezultatul: prototype-ul dovedește ipoteza #1 pe un SP realist care atinge două tabele în ordine FK corectă (nu unul banal test_out), iar template deliverable-ul din săpt 21-22 documentează exact pattern-ul de inheritance parent+child cu RETURNING — direct reutilizabil pentru orice alt modul ROAAUTO sau ROA.

SP minimal propus (Opțiunea 3): vezi §4.3 din docs/service-auto/tabele-service-auto.md pentru corpul complet (~40 linii PL/SQL): două INSERT-uri parent (nom_lucrari) + child (dev_ordl) cu RETURNING id_lucrare între ele, zero dependency pe pack_sesiune.

Impact asupra timeline

  • Săpt 3 — task-ul își schimbă scopul: confirmă existența pack_devize, pack_auto, pack_sesiune în MARIUSM_AUTO + citește body-ul real al pack_auto.dev_adauga_lucrare pentru decizie finală (opțiunea 1 vs 3). Query din §4.2 tabele-service-auto.md.
  • Săpt 7-8 — "scrie SP nou" devine "scrie SP_CREEAZA_COMANDA_PROTOTIP" (opțiunea 3). Simplu: INSERT direct în dev_ordl + RETURNING id_ordl.
  • Ipoteza #1 rămâne la fel de puternică — testezi că Python+oracledb cu OUT params apelează un SP real care face INSERT + RETURNING, nu un test_out(p OUT NUMBER) trivial.
  • Ipoteza #2 (session_callback) devine mai relevantă ca niciodatăpack_sesiune e exact genul de state care ar putea fi inițializat prin session_callback pattern. Săpt 5 task-ul session_callback devine și o investigație preliminară pentru phase 2.

Scope wall ține — tot 1 ecran, tot 1 SP, tot 1 schema test, tot write-only, deliverable = template + decision-log. Ce se schimbă: țintim o tabelă reală (dev_ordl), folosim un enum real (dev_tip_deviz), și documentăm un path clar spre reuse-ul pachet-urilor legacy pentru phase 2. Hedge-ul devine mai credibil, nu mai slab.

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:

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:

# backend/modules/service_auto/__init__.py
import logging
from pathlib import Path

# Absolute path rezolvat relativ la acest file — zero dependență de CWD
_LOG_DIR = Path(__file__).resolve().parents[2] / 'logs'
_LOG_DIR.mkdir(parents=True, exist_ok=True)

logger = logging.getLogger('service_auto')
logger.propagate = False  # fără dublă scriere în stdout via root logger
fh = logging.FileHandler(_LOG_DIR / 'service_auto.log')
fh.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(name)s: %(message)s'))
logger.addHandler(fh)
logger.setLevel(logging.INFO)

Notă: propagate = False evită ca mesajele să apară și în stdout prin root logger-ul din main.py. Dacă vrei ambele (file + stdout), șterge rândul cu propagate.

Log structurat la fiecare call:

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 9 — Week 1 gate reframing pentru ipoteza #1 (true-async)

Prima versiune a planului trata Week 1 gate ca un "flag flip": "dacă true-async merge → adoptă; dacă nu → sync-facade". Realitate: shared/database/oracle_pool.py folosește oracledb.create_pool() — API sync. Pentru adevărat-async există create_pool_async() care e o clasă diferită, cu acquire/close semantics distincte. Integrarea în pool-ul shared e un refactor non-trivial, NU un flag.

Gate reframe:

  • Dacă connect_async() + OUT params merge în POC → decizia e: folosește connect_async ad-hoc în service_auto (zero pooling, acceptă trade-off-ul "1 user, 1 connection per request"), log-ează ca ipoteză phase-2 că integrarea AsyncConnectionPool în OracleMultiPool ar fi worthwhile. Prototype-ul NU atinge shared-code async pool.
  • Dacă POC-ul eșuează → sync-facade prin pool-ul existent (treasury_service pattern). Pre-approved, zero timp pierdut.

Intenția originală se păstrează — învățare reală despre true-async — fără să ascundă în Week 1 gate o săptămână de refactor la shared code.

Correction 10 — Module layout pre-declarat în săpt 1

Prima versiune creează backend/modules/service_auto/__init__.py doar pentru logger, restul structurii apare ad-hoc. Realitate: convenția repo-ului (backend/modules/data_entry/) e routers/ services/ schemas/ models/ db/. Template deliverable-ul săpt 21 e mai puternic dacă documentează o structură deja curată decât dacă retrofitează una.

Action în săpt 1 alongside logger: mkdir -p backend/modules/service_auto/{routers,services,schemas,models}

  • touch câte un __init__.py gol în fiecare. Zero cod, doar scaffold.

Correction 11 — TODO-phase2.md creat în săpt 1

Prima versiune referenția docs/service-auto/TODO-phase2.md ca destinație pentru scope-creep thoughts, dar fișierul nu există. Creează-l în săpt 1 cu un header gol:

# TODO — Phase 2 ideas for service_auto

Temptations captured during the 24-week prototype. NOT commitments. NOT scoped.
This file is a graveyard for "ooh, we could also..." thoughts.

Angajamentul scope-wall devine astfel durabil și citibil.

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.

UX spec — interaction states for ComandaNoua.vue (from /plan-design-review 2026-04-11)

Hypothesis #4 validates error codes end-to-end. Această secțiune fixează comportamentul formularului în fiecare stare — ca să nu se improvizeze în săptămâna 14 la 2h/săpt, în timp ce Marius debug-uiește async Oracle.

Convenția Toast e aliniată cu src/modules/data-entry/views/receipts/ReceiptCreateUnifiedView.vue:666-787 (existing toast.add({severity, summary, detail, life})), zero componente noi.

State Trigger UX behavior PrimeVue primitives
Idle / first load Mount ComandaNoua.vue Focus auto pe Select "tip comandă". Placeholder-uri scurte în română ("Alege tip", "Alege client", "Alege mașina", "Descrie operațiile"). Submit button disabled until toate 4 câmpurile sunt non-empty. Select, Textarea, Button disabled
Loading / in-flight User clicks Submit (a) Submit button → :loading="true" (PrimeVue spinner inline). (b) Toate câmpurile :disabled="true" ca să nu editeze în timpul SP call. (c) Fără overlay / modal. (d) Dacă SP depășește 10s, nimic special (rely on FastAPI default timeout) — tracking ca TODO-phase2 dacă devine problemă. Button :loading, :disabled pe inputs
Success HTTP 200 + {comanda_id, numar} (1) Toast severity: 'success', summary 'Comandă creată', detail 'Nr ${numar}', life: 3000. (2) Reset: client_id=null, masina_id=null, operatii=''. PRESERVE tip_comandă (user creează multiple same-type în succesiune). (3) Re-enable form. (4) Focus revine pe client_id dropdown. toast.add, form ref reset parțial
Business error (20001-20999) HTTP 422 cu detail din SP (1) Toast severity: 'error', summary 'Validare', detail = mesajul din SP (diacritice!), life: 5000. (2) Form PRESERVĂ input-ul (user vrea să corecteze, nu să retype). (3) Re-enable form. (4) Fără field-level highlight pentru prototype — scope wall, SP-ul nu returnează field name. toast.add severity error
Infra error (12xxx, 01017, 00942) HTTP 503 sau 500 (1) Toast severity: 'error', summary 'Eroare conexiune' (503) sau 'Eroare internă' (500), detail = mesaj generic din tabelul Correction 5, life: 5000. (2) Form preservă input. (3) Re-enable Submit — user poate retry. (4) Fără retry-uri automate (keep it simple). toast.add severity error
Client-side validation NONE pentru prototype. SP-ul e sursa de adevăr pentru validare. Rationale: o singură sursă = mai puține layer-e de debug în săpt 13-16. Fewer moving parts = more learning. Un singur control: Submit disabled dacă vreun câmp e empty (trivial, nu contează ca "validare").

Dark mode requirement (din .claude/rules/css-design-system.md): testare OBLIGATORIE în ambele teme (auto / light / dark) via toggle din AppHeader.vue. Fiindcă ComandaNoua.vue folosește PrimeVue + semantic tokens (--surface-card, --text-color, etc.) importate din roa2web, zero CSS custom în prototype → dark mode "free" fără efort. Dacă apare vreo regresie de culoare, e bug în component-ul PrimeVue, nu în ComandaNoua — NU fix în prototype, log în TODO-phase2.md.

Test pass în săpt 13-16: pentru fiecare rând din tabel, un click manual verified, documentat în docs/service-auto/week13-ux-states.md (1 paragraf, 6 rânduri). Zero e2e automation — scope wall.

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 user-level 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ă.
  • Sursa VFP roaauto în gitea (gitea.romfast.ro/romfast/vfp_roaauto, importată 2026-04-11) — ground truth code-level pentru cum se citesc / scriu datele în schemă. Folosită în săpt 3 pentru extragerea: (a) tabelelor atinse la creare comandă, (b) celor 4 valori enum tip comandă, (c) label-urilor Romanian pentru câmpuri, (d) pattern-ului SP-urilor existente (dacă există) ca referință pentru SP_CREEAZA_COMANDA. Înlocuiește nevoia de a deschide VFP-ul producție — zero risk, text searchable, diff-abil.
  • 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 services din .claude/rules/backend-patterns.md — fiecare SP call trăiește într-un service, nu în router. Decoratorul @cached există LOCAL la backend/modules/reports/cache/decorators.py, nu în shared/ — deci NU se importă în service_auto. Oricum e pentru reads, prototype-ul e write-only. Dacă phase 2 aduce reads, decide atunci dacă e worth promovat la shared/.
  • Pattern-ul treasury_service.py ca golden example de apel PL/SQL cu OUT params.
  • Design system roa2webdocs/DESIGN.md, docs/DESIGN_TOKENS.md, docs/CSS_PATTERNS.md, .claude/rules/css-design-system.md. ComandaNoua.vue MUST folosi semantic tokens (--surface-card, --text-color, --color-primary, spacing scale --space-*), zero valori hardcodate, zero CSS scoped custom (doar layout minimal via .form-stack { display: grid; gap: var(--space-md); }). Toast-uri prin useToast() + convenția {severity, summary, detail, life} cu life 3000ms success / 5000ms error. Dark mode testare obligatorie ([data-theme] toggle din AppHeader.vue). Zero componente noi — reuse PrimeVue Select, Textarea, Button, Toast.

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 (reframed — vezi Correction 9): dacă connect_async merge → folosește ad-hoc în service_auto, refactorul de pool rămâne phase-2; dacă nu → sync-facade. DX check (save → result < 10s?). File handler logging setup cu absolute path + propagate=False. Module scaffold: mkdir backend/modules/service_auto/{routers,services,schemas,models}. Creează docs/service-auto/TODO-phase2.md cu header gol. Log arată rezultat, docs/service-auto/week1-notes.md scris, scaffold există, TODO-phase2.md există
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). Clonează gitea.romfast.ro/romfast/vfp_roaauto și grep prin .PRG / .SCX pentru fluxul "creează comandă nouă service auto" — scrie tabele-service-auto.md cu: (a) tabele atinse, (b) cele 4 valori enum tip comandă, (c) label-uri Romanian pentru câmpuri, (d) pattern SP-uri existente (dacă există). Creează user ROA_WEB + grants. Auth path audit (ipoteza #6): adaugă MARIUSM_AUTO la ORACLE_SERVERS în backend/.env, inserează row în CONTAFIN_ORACLE.UTILIZATORI pentru Marius, log in prin UI, confirmă server selector + JWT payload, verifică get_user_companies('MARIUS M', 'mariusm_test') → scrie week3-auth-audit.md. week3-grants-audit.md + tabele-service-auto.md (cu enum + labels + SP-uri din gitea) + week3-auth-audit.md scrise, login funcțional pentru server nou
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ă. Task explicit: patch ~8 linii la shared/database/oracle_pool.py (register_server acceptă session_callback, _get_or_create_pool îl propagă la create_pool). Backward compatible, zero callers existenți afectați. Log-uri clare, niciun cursor tag leak, patch la shared code review-ed și commit-ed
6 Checkpoint integration 1: endpoint GET /api/service-auto/ping care rulează SELECT 1 FROM DUAL pe mariusm_test prin oracle_pool.get_connection('mariusm_test'). Curl cu JWT real (după auth-ul probeat în săpt 3). Probează: auth → middleware → pool → connection → query round-trip pentru serverul nou — întregul chain, fără SP. curl -H "Authorization: Bearer ..." /api/service-auto/ping returnează {"result": 1}
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 1docs/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) 1 CLEAR (PLAN) 8 issues (3 P1/P2 load-bearing + 5 minor committed), 1 critical gap (JWT auth flow) mitigated via new hypothesis #6 + week-3 auth audit, Corrections 9/10/11 added, timeline table updated for weeks 1/3/5/6
Design Review /plan-design-review UI/UX gaps 1 CLEAR (PLAN) score 6/10 → 9/10, 4 decisions added (interaction-states table, design-system inheritance clause, a11y one-liner, week-3 enum+labels capture), 0 unresolved, mockups skip-by-design (learning prototype on existing roa2web theme)
DX Review /plan-devex-review Developer experience gaps 0

OUTSIDE VOICE (CEO round): 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.

OUTSIDE VOICE (ENG round): Skipped. Rationale: design already absorbed one full outside-voice round in CEO review; advisor consulted during orientation as independent second perspective; prototype scope has diminishing returns on third adversarial pass; Codex CLI unavailable in this environment.

OUTSIDE VOICE (DESIGN round): Skipped by design. Advisor consulted once during orientation to sanity-check the "skip mockups" judgment (confirmed: generating fictional mockups for a learning prototype that must inherit existing roa2web PrimeVue theme would be actively misleading). No second adversarial pass — design surface is ~15 lines of plan text, not a visual system.

DESIGN REVIEW SUMMARY:

  • Passes 1, 3 (Info Arch, User Journey): no findings — single form, 1-user prototype.
  • Pass 4 (AI Slop): N/A — no custom design surface, every pixel inherited from existing roa2web theme.
  • Pass 2 (Interaction States) 3/10 → 9/10: 6-state table added (idle/loading/success/business-error/infra-error/client-validation) with concrete PrimeVue behavior, toast lifecycle aligned to ReceiptCreateUnifiedView.vue convention (life 3000/5000ms), tip comandă preserved on success reset, dark-mode inheritance documented, client-side validation intentionally omitted for prototype (fewer layers to debug).
  • Pass 5 (Design System) 2/10 → 9/10: inheritance clause added referencing DESIGN.md, DESIGN_TOKENS.md, CSS_PATTERNS.md, .claude/rules/css-design-system.md. Semantic tokens mandatory, zero hardcoded values, zero custom components.
  • Pass 6 (A11y) 5/10 → 9/10: one-liner clarifying PrimeVue defaults handle keyboard/ARIA/focus so it isn't mistaken for scope creep.
  • Pass 7 (Unresolved Decisions): 2 items (4 tip comandă enum values + Romanian field labels) folded into week-3 VFP audit subtask — sourced from ground truth, not invented.

ENG REVIEW SUMMARY:

  • Architecture (3 issues): (#1, P1) JWT auth flow for MARIUSM_AUTO undesigned → added hypothesis #6 + week-3 auth audit subtask. (#2, P2) oracle_pool.py needs ~8-line backward-compatible patch to thread session_callback; "zero refactor" claim corrected in Correction 1 and scheduled explicitly in week 5. (#3, P2) Week 1 gate reworded: true-async success means ad-hoc connect_async inside service_auto, NOT pool refactor — AsyncConnectionPool integration becomes phase-2 hypothesis (Correction 9).
  • Code Quality (3 committed fixes): Correction 6 logging snippet fixed (absolute path + propagate=False), @cached wording clarified (reports-local, not shared), Correction 10 added (module scaffold in week 1), Correction 11 added (TODO-phase2.md stub in week 1).
  • Test plan: 7/12 hypothesis-branches planned, JWT flow test added (manual smoke in week 3), diacritics byte-level assertion flagged as week-17-20 buffer refinement. Test plan artifact written to ~/.gstack/projects/romfast-roa2web/claude-feat-service-auto-eng-review-test-plan-20260411-140656.md.
  • Performance: N/A for 1-user prototype. Optional: register mariusm_test with min=1, max=2.
  • Parallelization: N/A — single dev, inherently sequential.

UNRESOLVED: 0

VERDICT: CEO + ENG + DESIGN CLEARED — plan v2 + eng-review corrections + design-review UX spec (1 interaction-states table, 1 design-system inheritance clause, 1 a11y note, 1 week-3 enum/labels audit task). 24-week learning prototype is ready to execute. Next action: week 1 per timeline (hello_oracle POC + DX check + module scaffold + TODO-phase2.md stub + logging setup).