Files
roa2web-service-auto/IMPLEMENTATION_PLAN_UNIFIED_APP.md
2025-12-22 01:01:58 +02:00

11 KiB

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:
    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:
    <template>
      <div v-if="error" class="module-error">
        <h3>⚠️ {{ moduleName }} a întâmpinat o eroare</h3>
        <p>{{ error.message }}</p>
        <button @click="retry">Reîncearcă</button>
      </div>
      <slot v-else />
    </template>
    
  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

// 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/.