# Plan: Consolidare ROA2WEB - Pragmatic Monolith > **Branch**: `feature/unified-app-pragmatic-monolith` > **Status**: APROBAT - Ready for Implementation > **Efort estimat**: ~2.5 zile --- ## Context și Problema ### Situația Curentă - 2 aplicații frontend separate în IIS: `/roa2web/` și `/data-entry/` - Deploy greoi (2 build-uri, 2 configurații IIS separate) - Componentele shared cauzează probleme CSS cross-app (text alb pe fundal alb) - Nu există meniu unificat între aplicații ### Obiectiv - Un singur meniu cu ambele aplicații (Reports + Data Entry) - Deploy simplificat (un build, un site IIS) - Izolare între module (bug în Reports să nu afecteze DataEntry) - URL-uri pe root: `/reports/*`, `/data-entry/*` --- ## Decizie Arhitecturală: Pragmatic Monolith ### De ce NU Micro-frontends? | Criteriu pentru MFE | ROA2WEB | Necesită MFE? | |---------------------|---------|---------------| | 20+ dezvoltatori | 1 dev | ❌ Nu | | Deploy de multe ori/zi | Săptămânal | ❌ Nu | | Milioane de utilizatori | 1-5 concurenți | ❌ Nu | | Framework-uri diferite | Vue only | ❌ Nu | **Verdict**: Module Federation / Single-SPA = OVERKILL ### Abordare Aleasă: Monolith cu Mecanisme de Izolare - **Error Boundaries** per modul (bug în Reports nu strică DataEntry) - **Lazy Loading** (bundle-uri separate, încărcate la nevoie) - **Stores izolate** per modul - **Feature flags** pentru control **Blast radius cu protecții: 50-70%** (aproape ca 2 apps separate!) --- ## Arhitectura Finală ``` ┌─────────────────────────────────────────────────────────────┐ │ ROA2WEB Unified SPA │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐ │ │ │ Reports Module │ │ DataEntry Module │ │ Shared │ │ │ │ /reports/* │ │ /data-entry/* │ │ - Auth │ │ │ │ (lazy loaded) │ │ (lazy loaded) │ │ - Company │ │ │ │ │ │ │ │ - Period │ │ │ │ ErrorBoundary │ │ ErrorBoundary │ │ - Header │ │ │ └────────┬────────┘ └────────┬─────────┘ └──────────────┘ │ │ │ │ │ │ ┌────────┴────────────────────┴─────────┐ │ │ │ Vue Router + Global Error Handler │ │ │ └────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ┌─────────┴─────────┐ │ IIS Proxy │ └─────────┬─────────┘ ┌───────────────┴───────────────┐ │ │ ┌────────▼────────┐ ┌──────────▼────────┐ │ Reports Backend │ │ DataEntry Backend │ │ port 8001 │ │ port 8003 │ │ (Oracle RO) │ │ (SQLite + Oracle) │ └─────────────────┘ └───────────────────┘ ``` --- ## Structura Proiect Unified ``` roa2web/ ├── src/ │ ├── main.js │ ├── App.vue # Meniu unificat │ ├── router/index.js # Rute unificate cu lazy loading │ │ │ ├── modules/ │ │ ├── reports/ # MODUL IZOLAT │ │ │ ├── ReportsLayout.vue # Error boundary pentru modul │ │ │ ├── views/ │ │ │ │ ├── DashboardView.vue │ │ │ │ ├── InvoicesView.vue │ │ │ │ ├── BankCashRegisterView.vue │ │ │ │ ├── TrialBalanceView.vue │ │ │ │ ├── TelegramView.vue │ │ │ │ └── CacheStatsView.vue │ │ │ ├── stores/ │ │ │ └── services/ │ │ │ │ │ └── data-entry/ # MODUL IZOLAT │ │ ├── DataEntryLayout.vue │ │ ├── views/ │ │ │ ├── ReceiptsListView.vue │ │ │ └── ReceiptCreateView.vue │ │ ├── stores/ │ │ └── services/ │ │ │ ├── shared/ # Shared între module │ │ ├── components/ # AppHeader, SlideMenu, CompanySelector, etc. │ │ ├── stores/ # Auth, Company, Period │ │ └── styles/ │ │ │ └── config/ │ ├── menu.js # Configurație meniu unificat │ └── features.js # Feature flags │ ├── vite.config.js └── package.json ``` --- ## Pași Implementare ### Faza 1: Setup Proiect (0.5 zile) 1. Creează directorul `roa2web/` 2. Setup `package.json` cu dependencies combinate din ambele apps 3. Setup `vite.config.js` cu: - Dual proxy: `/api/reports/*` → `:8001`, `/api/data-entry/*` → `:8003` - Lazy loading chunks configuration - Base path `/` 4. Setup `main.js` cu Pinia, PrimeVue, Router ### Faza 2: Migrare Module (1 zi) 1. Copiază views din `reports-app/frontend/src/views/` → `modules/reports/views/` 2. Copiază views din `data-entry-app/frontend/src/views/` → `modules/data-entry/views/` 3. Copiază stores specifice fiecărui modul 4. Creează `ReportsLayout.vue` și `DataEntryLayout.vue` cu error boundaries 5. Setup router unificat: ```javascript const routes = [ { path: '/login', component: LoginView }, { path: '/reports', component: () => import('./modules/reports/ReportsLayout.vue'), children: [ { path: 'dashboard', component: () => import('./modules/reports/views/DashboardView.vue') }, { path: 'invoices', component: () => import('./modules/reports/views/InvoicesView.vue') }, // ... ] }, { path: '/data-entry', component: () => import('./modules/data-entry/DataEntryLayout.vue'), children: [ { path: '', component: () => import('./modules/data-entry/views/ReceiptsListView.vue') }, { path: 'create', component: () => import('./modules/data-entry/views/ReceiptCreateView.vue') }, ] }, { path: '/', redirect: '/reports/dashboard' } ] ``` ### Faza 3: Izolare și Resilience (0.5 zile) 1. Implementează `ErrorBoundary.vue`: ```vue ``` 2. Separă stores per modul (nu global) 3. Adaugă feature flags în `config/features.js` 4. Testează izolarea: introduce bug în Reports, verifică că DataEntry funcționează ### Faza 4: Build & Deploy (0.5 zile) 1. Verifică bundle splitting cu `npm run build`: ``` dist/assets/ ├── index-[hash].js # Shell + shared (~150KB) ├── reports-[hash].js # Reports module (~200KB) └── data-entry-[hash].js # DataEntry module (~100KB) ``` 2. Update IIS web.config pentru SPA routing (toate rutele → index.html) 3. Update deployment scripts pentru single app 4. Test end-to-end pe server 5. Deploy în producție --- ## Meniu Unificat ```javascript // config/menu.js export const menuSections = [ { title: 'Rapoarte', items: [ { to: '/reports/dashboard', icon: 'pi pi-home', label: 'Dashboard' }, { to: '/reports/invoices', icon: 'pi pi-file', label: 'Facturi' }, { to: '/reports/bank-cash', icon: 'pi pi-money-bill', label: 'Casa și Banca' }, { to: '/reports/trial-balance', icon: 'pi pi-calculator', label: 'Balanță' }, ] }, { title: 'Introduceri Date', items: [ { to: '/data-entry', icon: 'pi pi-list', label: 'Lista Bonuri' }, { to: '/data-entry/create', icon: 'pi pi-plus', label: 'Bon Nou' }, ] }, { title: 'Sistem', items: [ { to: '/reports/telegram', icon: 'pi pi-telegram', label: 'Telegram' }, { to: '/reports/cache-stats', icon: 'pi pi-chart-bar', label: 'Cache Stats' }, ] } ]; ``` --- ## Fișiere de Referință ### Fișiere Existente (sursă pentru copiere) - `reports-app/frontend/src/views/*.vue` - Views Reports - `reports-app/frontend/src/stores/*.js` - Stores Reports - `reports-app/frontend/src/services/api.js` - API service Reports - `data-entry-app/frontend/src/views/*.vue` - Views DataEntry - `data-entry-app/frontend/src/stores/*.js` - Stores DataEntry - `data-entry-app/frontend/src/services/api.js` - API service DataEntry - `shared/frontend/components/` - Componente shared (AppHeader, SlideMenu, etc.) - `shared/frontend/stores/` - Stores shared (auth, companies, accountingPeriod) ### Configurații de Referință - `reports-app/frontend/vite.config.js` - Pentru proxy și build config - `reports-app/frontend/package.json` - Pentru dependencies - `data-entry-app/frontend/vite.config.js` - Pentru proxy config - `data-entry-app/frontend/package.json` - Pentru dependencies --- ## URL-uri Finale | Path | Descriere | |------|-----------| | `/` | Redirect la `/reports/dashboard` | | `/login` | Pagină login | | `/reports/dashboard` | Dashboard principal | | `/reports/invoices` | Facturi | | `/reports/bank-cash` | Casa și Banca | | `/reports/trial-balance` | Balanță de Verificare | | `/reports/telegram` | Telegram Bot | | `/reports/cache-stats` | Statistici Cache | | `/data-entry` | Lista Bonuri | | `/data-entry/create` | Bon Nou | | `/data-entry/:id` | Detalii Bon | | `/data-entry/:id/edit` | Editare Bon | --- ## Note Importante 1. **Backend-urile rămân separate** - port 8001 (Reports) și port 8003 (DataEntry) 2. **IIS proxy routing** - trebuie configurat pentru a ruta API calls corect 3. **Error Boundaries** - critice pentru izolarea modulelor 4. **Lazy Loading** - asigură bundle splitting corect 5. **Feature flags** - permit dezactivarea unui modul fără redeploy --- ## Handover Notes Această implementare va înlocui cele 2 aplicații separate cu o aplicație unificată. După implementare, directoarele `reports-app/frontend/` și `data-entry-app/frontend/` pot fi arhivate/șterse, păstrând doar `unified-app/`. Backend-urile rămân neschimbate în `reports-app/backend/` și `data-entry-app/backend/`.