docs(service-auto): add v2 design doc for learning prototype
CEO review output: rethink of scrapped 2026-04-10 product plan, reframed as learning probe + talent-risk hedge. 24-week timeline, 1 screen + 1 SP + MARIUSM_AUTO test schema. Scope wall absolute: zero touch on 4 existing VFP clients. Document includes 8 review corrections vs first draft: register_server over MarciusLabPool, SP targets dedicated orders table not ACT ledger, explicit connection.commit(), Oracle error code range classification, file handler logging, kill criterion, integration checkpoints at weeks 6+12, template+decision-log as week-24 deliverable. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -540,3 +540,6 @@ scripts/ralph/screenshots/
|
|||||||
scripts/ralph/archive/
|
scripts/ralph/archive/
|
||||||
scripts/ralph/usage.jsonl
|
scripts/ralph/usage.jsonl
|
||||||
.claude/scheduled_tasks.lock
|
.claude/scheduled_tasks.lock
|
||||||
|
|
||||||
|
# Service-auto reference material (local only, not in repo)
|
||||||
|
docs/service-auto/*.pdf
|
||||||
|
|||||||
437
docs/service-auto/claude-main-design-20260411-rethink.md
Normal file
437
docs/service-auto/claude-main-design-20260411-rethink.md
Normal file
@@ -0,0 +1,437 @@
|
|||||||
|
# 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).
|
||||||
Reference in New Issue
Block a user