Modified all specification files to reference the project root directory (.) instead of creating a new unified-app/ subdirectory: - spec.md: Updated project structure and all file paths - SUMMARY.md: Updated critical files paths and documentation references - critical-files.md: Updated all source/destination paths for migration - MIGRATION_CHECKLIST.md: Updated directory creation and file paths All implementation files will now be created directly in /mnt/e/proiecte/roa2web/ instead of /mnt/e/proiecte/roa2web/unified-app/ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1115 lines
35 KiB
Markdown
1115 lines
35 KiB
Markdown
# Feature: Unified App - Pragmatic Monolith Consolidation
|
|
|
|
## Overview
|
|
|
|
Consolidate the two separate frontend applications (Reports App and Data Entry App) into a single unified SPA with both modules accessible from one menu. This pragmatic monolith approach maintains module isolation while simplifying deployment and providing a unified user experience with a single build and single IIS site.
|
|
|
|
**Status**: Implementation-Ready
|
|
**Complexity**: Medium
|
|
**Estimated Effort**: 2.5 days
|
|
|
|
---
|
|
|
|
## Problem Statement
|
|
|
|
### Current Issues
|
|
- Two separate frontend deployments in IIS (`/roa2web/` and `/data-entry/`)
|
|
- Complex deployment process (2 builds, 2 IIS configurations)
|
|
- CSS conflicts when using shared components (white text on white background)
|
|
- No unified navigation between modules
|
|
- Duplicate setup and configuration code
|
|
|
|
### Benefits of Unification
|
|
- Simplified deployment (single build, single IIS site)
|
|
- Unified user experience with single menu
|
|
- Shared component consistency
|
|
- Module isolation preserved through error boundaries
|
|
- Optimized bundle loading via lazy loading
|
|
|
|
---
|
|
|
|
## User Stories
|
|
|
|
### Primary Users
|
|
- As a **user**, I want to access both Reports and Data Entry modules from a single menu so that I can navigate seamlessly between functionalities.
|
|
- As a **developer**, I want simplified deployment with a single build process so that I can reduce deployment complexity and maintenance overhead.
|
|
- As a **user**, I want the app to remain functional even if one module encounters an error so that my work is not interrupted.
|
|
- As an **administrator**, I want a single IIS site configuration so that I can manage deployment more easily.
|
|
|
|
---
|
|
|
|
## Functional Requirements
|
|
|
|
### Core Requirements
|
|
|
|
#### 1. Unified Navigation
|
|
- Single top-level menu with sections for Reports and Data Entry modules
|
|
- Menu structure:
|
|
- **Rapoarte** (Reports) section with Dashboard, Invoices, Bank/Cash, Trial Balance
|
|
- **Introduceri Date** (Data Entry) section with Receipts List, New Receipt
|
|
- **Sistem** section with Telegram Bot, Cache Stats
|
|
- Active route highlighting
|
|
- Responsive slide menu (mobile + desktop)
|
|
|
|
#### 2. Module Isolation
|
|
- Error boundary per module (Reports, Data Entry)
|
|
- Bug in one module does not crash the other
|
|
- Independent lazy loading per module
|
|
- Separate stores per module (no cross-contamination)
|
|
|
|
#### 3. URL Structure
|
|
```
|
|
/login → Login page
|
|
/ → Redirect to /reports/dashboard
|
|
|
|
/reports/dashboard → Dashboard (Reports module)
|
|
/reports/invoices → Invoices view
|
|
/reports/bank-cash → Bank/Cash register view
|
|
/reports/trial-balance → Trial Balance view
|
|
/reports/telegram → Telegram Bot management
|
|
/reports/cache-stats → Cache statistics
|
|
|
|
/data-entry → Receipts list (Data Entry module)
|
|
/data-entry/create → Create new receipt
|
|
/data-entry/:id → View receipt details
|
|
/data-entry/:id/edit → Edit receipt
|
|
```
|
|
|
|
#### 4. Shared Components Integration
|
|
- Use existing shared components from `shared/frontend/`:
|
|
- `LoginView.vue` - Login page
|
|
- `AppHeader.vue` - Top navigation bar
|
|
- `SlideMenu.vue` - Sidebar menu
|
|
- `CompanySelector.vue` - Company dropdown
|
|
- `PeriodSelector.vue` - Accounting period selector
|
|
- Maintain consistent styling and behavior across modules
|
|
|
|
#### 5. Authentication & Authorization
|
|
- Unified JWT authentication
|
|
- Single login flow for both modules
|
|
- Preserve existing auth store factory pattern
|
|
- Session persistence across module navigation
|
|
|
|
### Secondary Requirements
|
|
|
|
#### 1. Feature Flags
|
|
- Ability to enable/disable modules via configuration
|
|
- Feature flag configuration in `src/config/features.js`
|
|
- UI hides disabled module menu items
|
|
|
|
#### 2. Loading States
|
|
- Module-level loading spinners
|
|
- Skeleton screens for lazy-loaded routes
|
|
- Progress indication during module switching
|
|
|
|
#### 3. Analytics & Monitoring
|
|
- Track module switching events
|
|
- Error boundary triggers logged
|
|
- Performance metrics per module
|
|
|
|
---
|
|
|
|
## Technical Requirements
|
|
|
|
### Project Structure
|
|
|
|
```
|
|
.
|
|
├── public/
|
|
│ └── favicon.ico
|
|
├── src/
|
|
│ ├── main.js # App entry point
|
|
│ ├── App.vue # Root component with unified menu
|
|
│ │
|
|
│ ├── router/
|
|
│ │ └── index.js # Unified router with lazy loading
|
|
│ │
|
|
│ ├── modules/
|
|
│ │ ├── reports/ # ISOLATED REPORTS MODULE
|
|
│ │ │ ├── ReportsLayout.vue # Error boundary wrapper
|
|
│ │ │ ├── views/ # Reports views (migrated)
|
|
│ │ │ │ ├── DashboardView.vue
|
|
│ │ │ │ ├── InvoicesView.vue
|
|
│ │ │ │ ├── BankCashRegisterView.vue
|
|
│ │ │ │ ├── TrialBalanceView.vue
|
|
│ │ │ │ ├── TelegramView.vue
|
|
│ │ │ │ └── CacheStatsView.vue
|
|
│ │ │ ├── stores/ # Module-specific stores
|
|
│ │ │ │ ├── dashboard.js
|
|
│ │ │ │ ├── invoices.js
|
|
│ │ │ │ ├── treasury.js
|
|
│ │ │ │ ├── trialBalance.js
|
|
│ │ │ │ └── cacheStore.js
|
|
│ │ │ └── services/ # Module API services
|
|
│ │ │ └── api.js # Reports API client
|
|
│ │ │
|
|
│ │ └── data-entry/ # ISOLATED DATA ENTRY MODULE
|
|
│ │ ├── DataEntryLayout.vue # Error boundary wrapper
|
|
│ │ ├── views/ # Data Entry views (migrated)
|
|
│ │ │ └── receipts/
|
|
│ │ │ ├── ReceiptsListView.vue
|
|
│ │ │ └── ReceiptCreateView.vue
|
|
│ │ ├── components/ # Module-specific components
|
|
│ │ │ └── ocr/
|
|
│ │ │ ├── OCRUploadZone.vue
|
|
│ │ │ ├── OCRPreview.vue
|
|
│ │ │ └── OCRConfidenceIndicator.vue
|
|
│ │ ├── stores/ # Module-specific stores
|
|
│ │ │ └── receiptsStore.js
|
|
│ │ └── services/ # Module API services
|
|
│ │ └── api.js # Data Entry API client
|
|
│ │
|
|
│ ├── shared/ # SHARED COMPONENTS & LOGIC
|
|
│ │ ├── components/ # Shared UI components
|
|
│ │ │ ├── layout/
|
|
│ │ │ │ ├── AppHeader.vue
|
|
│ │ │ │ └── SlideMenu.vue
|
|
│ │ │ ├── LoginView.vue
|
|
│ │ │ ├── CompanySelector.vue
|
|
│ │ │ ├── PeriodSelector.vue
|
|
│ │ │ └── ErrorBoundary.vue # NEW: Error boundary component
|
|
│ │ ├── stores/ # Shared stores (factories)
|
|
│ │ │ ├── auth.js # Auth store factory
|
|
│ │ │ ├── companies.js # Companies store factory
|
|
│ │ │ └── accountingPeriod.js # Period store factory
|
|
│ │ └── styles/ # Shared CSS
|
|
│ │ ├── login.css
|
|
│ │ ├── layout/
|
|
│ │ │ ├── header.css
|
|
│ │ │ └── navigation.css
|
|
│ │ └── shared.css
|
|
│ │
|
|
│ ├── config/
|
|
│ │ ├── menu.js # Unified menu configuration
|
|
│ │ └── features.js # Feature flags
|
|
│ │
|
|
│ └── assets/
|
|
│ └── css/ # Global CSS (from reports-app)
|
|
│ ├── core/ # Design tokens
|
|
│ ├── components/ # Reusable UI patterns
|
|
│ ├── patterns/ # Interactive patterns
|
|
│ ├── layout/ # Page structure
|
|
│ ├── utilities/ # Utility classes
|
|
│ └── vendor/ # PrimeVue overrides
|
|
│
|
|
├── vite.config.js # Unified Vite config (root)
|
|
├── package.json # Merged dependencies (root)
|
|
├── .env.example # Environment template (root)
|
|
└── README.md # Unified app documentation (root)
|
|
```
|
|
|
|
### Files to Create
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `package.json` | Merged dependencies from both apps |
|
|
| `vite.config.js` | Dual proxy config, lazy loading, base path `/` |
|
|
| `src/main.js` | App initialization, PrimeVue setup, global components |
|
|
| `src/App.vue` | Root component with unified menu |
|
|
| `src/router/index.js` | Unified router with lazy loading |
|
|
| `src/config/menu.js` | Menu configuration |
|
|
| `src/config/features.js` | Feature flags |
|
|
| `src/shared/components/ErrorBoundary.vue` | Error boundary component |
|
|
| `src/modules/reports/ReportsLayout.vue` | Reports error boundary wrapper |
|
|
| `src/modules/data-entry/DataEntryLayout.vue` | Data Entry error boundary wrapper |
|
|
| `.env.example` | Environment variables template |
|
|
| `README.md` | Documentation |
|
|
|
|
### Files to Migrate
|
|
|
|
#### From `reports-app/frontend/`
|
|
|
|
**Views** (→ `modules/reports/views/`):
|
|
- DashboardView.vue
|
|
- InvoicesView.vue
|
|
- BankCashRegisterView.vue
|
|
- TrialBalanceView.vue
|
|
- TelegramView.vue
|
|
- CacheStatsView.vue
|
|
- ~~LoginView.vue~~ (use shared)
|
|
|
|
**Stores** (→ `modules/reports/stores/`):
|
|
- dashboard.js
|
|
- invoices.js
|
|
- treasury.js
|
|
- trialBalance.js
|
|
- cacheStore.js
|
|
- ~~auth.js~~ (use shared)
|
|
- ~~companies.js~~ (use shared)
|
|
- ~~accountingPeriod.js~~ (use shared)
|
|
|
|
**Services** (→ `modules/reports/services/`):
|
|
- api.js (adapt for `/api/reports/` prefix)
|
|
|
|
**CSS** (→ `assets/css/`):
|
|
- Copy entire `src/assets/css/` directory structure
|
|
- All design tokens, components, patterns, utilities
|
|
|
|
#### From `data-entry-app/frontend/`
|
|
|
|
**Views** (→ `modules/data-entry/views/receipts/`):
|
|
- ReceiptsListView.vue
|
|
- ReceiptCreateView.vue
|
|
- ~~LoginView.vue~~ (use shared)
|
|
|
|
**Components** (→ `modules/data-entry/components/`):
|
|
- ocr/OCRUploadZone.vue
|
|
- ocr/OCRPreview.vue
|
|
- ocr/OCRConfidenceIndicator.vue
|
|
|
|
**Stores** (→ `modules/data-entry/stores/`):
|
|
- receiptsStore.js
|
|
- ~~auth.js~~ (use shared)
|
|
- ~~companies.js~~ (use shared)
|
|
- ~~accountingPeriod.js~~ (use shared)
|
|
|
|
**Services** (→ `modules/data-entry/services/`):
|
|
- api.js (adapt for `/api/data-entry/` prefix)
|
|
|
|
**CSS** (→ merge with `assets/css/`):
|
|
- main.css (merge with reports-app main.css)
|
|
- Any component-specific styles
|
|
|
|
#### From `shared/frontend/`
|
|
|
|
**Components** (→ `shared/components/`):
|
|
- LoginView.vue
|
|
- layout/AppHeader.vue
|
|
- layout/SlideMenu.vue
|
|
- CompanySelector.vue
|
|
- PeriodSelector.vue
|
|
|
|
**Stores** (→ `shared/stores/`):
|
|
- auth.js (factory)
|
|
- companies.js (factory)
|
|
- accountingPeriod.js (factory)
|
|
|
|
**Styles** (→ `shared/styles/`):
|
|
- login.css
|
|
- layout/header.css
|
|
- layout/navigation.css
|
|
|
|
### Dependencies
|
|
|
|
#### Unified package.json (root directory)
|
|
|
|
Merge all dependencies from both apps:
|
|
|
|
**From reports-app**:
|
|
- axios: ^1.6.2
|
|
- chart.js: ^4.5.0
|
|
- date-fns: ^2.30.0
|
|
- jspdf: ^3.0.1
|
|
- jspdf-autotable: ^5.0.2
|
|
- pinia: ^2.1.7
|
|
- primeicons: ^6.0.1
|
|
- primevue: ^3.46.0
|
|
- qrcode.vue: ^3.6.0
|
|
- vue: ^3.4.0
|
|
- vue-chartjs: ^5.3.2
|
|
- vue-router: ^4.2.5
|
|
- xlsx: ^0.18.5
|
|
|
|
**From data-entry-app**:
|
|
- All duplicates already covered
|
|
- Additional: @primevue/themes: ^4.0.0 (optional, may remove)
|
|
|
|
**DevDependencies**:
|
|
- @playwright/test: ^1.54.2
|
|
- @vitejs/plugin-vue: ^5.0.0
|
|
- eslint: ^8.56.0
|
|
- eslint-plugin-vue: ^9.20.0
|
|
- prettier: ^3.1.1
|
|
- vite: ^5.0.10
|
|
|
|
### API Routing
|
|
|
|
#### Vite Dev Server Proxy
|
|
|
|
```javascript
|
|
// vite.config.js
|
|
server: {
|
|
port: 3000,
|
|
proxy: {
|
|
'/api/reports': {
|
|
target: 'http://localhost:8001',
|
|
changeOrigin: true,
|
|
rewrite: (path) => path.replace(/^\/api\/reports/, '/api')
|
|
},
|
|
'/api/data-entry': {
|
|
target: 'http://localhost:8003',
|
|
changeOrigin: true,
|
|
rewrite: (path) => path.replace(/^\/api\/data-entry/, '/api')
|
|
},
|
|
'/uploads': {
|
|
target: 'http://localhost:8003',
|
|
changeOrigin: true
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### IIS Production Proxy
|
|
|
|
```xml
|
|
<!-- web.config URL rewrite rules -->
|
|
<rule name="Proxy Reports API">
|
|
<match url="^api/reports/(.*)" />
|
|
<action type="Rewrite" url="http://localhost:8001/api/{R:1}" />
|
|
</rule>
|
|
|
|
<rule name="Proxy Data Entry API">
|
|
<match url="^api/data-entry/(.*)" />
|
|
<action type="Rewrite" url="http://localhost:8003/api/{R:1}" />
|
|
</rule>
|
|
|
|
<rule name="Proxy Uploads">
|
|
<match url="^uploads/(.*)" />
|
|
<action type="Rewrite" url="http://localhost:8003/uploads/{R:1}" />
|
|
</rule>
|
|
```
|
|
|
|
### Build Configuration
|
|
|
|
#### Vite Config - Lazy Loading & Bundle Splitting
|
|
|
|
```javascript
|
|
// vite.config.js
|
|
export default defineConfig({
|
|
plugins: [vue(), htmlTimestampPlugin()],
|
|
base: process.env.NODE_ENV === 'production' ? '/' : '/',
|
|
resolve: {
|
|
alias: {
|
|
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
|
'@shared': fileURLToPath(new URL('./src/shared', import.meta.url)),
|
|
'@reports': fileURLToPath(new URL('./src/modules/reports', import.meta.url)),
|
|
'@data-entry': fileURLToPath(new URL('./src/modules/data-entry', import.meta.url))
|
|
},
|
|
dedupe: ['vue', 'vue-router', 'pinia', 'primevue']
|
|
},
|
|
build: {
|
|
outDir: 'dist',
|
|
sourcemap: true,
|
|
rollupOptions: {
|
|
output: {
|
|
manualChunks: {
|
|
// Core vendors
|
|
'vendor-core': ['vue', 'vue-router', 'pinia'],
|
|
'vendor-primevue': ['primevue/config', 'primevue/button', 'primevue/datatable'],
|
|
'vendor-utils': ['axios', 'date-fns'],
|
|
|
|
// Charts (reports only)
|
|
'vendor-charts': ['chart.js', 'vue-chartjs'],
|
|
|
|
// Excel/PDF exports
|
|
'vendor-export': ['xlsx', 'jspdf', 'jspdf-autotable'],
|
|
|
|
// Module-specific chunks (lazy loaded)
|
|
// Reports module loaded via dynamic import
|
|
// Data Entry module loaded via dynamic import
|
|
},
|
|
entryFileNames: `assets/[name].[hash].js`,
|
|
chunkFileNames: `assets/[name].[hash].js`,
|
|
assetFileNames: `assets/[name].[hash].[ext]`
|
|
}
|
|
}
|
|
}
|
|
})
|
|
```
|
|
|
|
**Expected Build Output**:
|
|
```
|
|
dist/
|
|
├── index.html
|
|
├── assets/
|
|
│ ├── vendor-core.[hash].js (~150KB) - Vue, Router, Pinia
|
|
│ ├── vendor-primevue.[hash].js (~200KB) - PrimeVue components
|
|
│ ├── vendor-utils.[hash].js (~80KB) - Axios, date-fns
|
|
│ ├── vendor-charts.[hash].js (~150KB) - Chart.js (lazy)
|
|
│ ├── vendor-export.[hash].js (~200KB) - XLSX, jsPDF (lazy)
|
|
│ ├── reports.[hash].js (~150KB) - Reports module (lazy)
|
|
│ ├── data-entry.[hash].js (~100KB) - Data Entry module (lazy)
|
|
│ ├── main.[hash].js (~50KB) - App shell
|
|
│ └── main.[hash].css (~80KB) - Global CSS
|
|
```
|
|
|
|
---
|
|
|
|
## Design Decisions
|
|
|
|
### Approach: Pragmatic Monolith
|
|
|
|
**Why NOT Micro-frontends (Module Federation / Single-SPA)?**
|
|
|
|
| Micro-Frontend Criterion | ROA2WEB Reality | Justification |
|
|
|-------------------------|-----------------|---------------|
|
|
| 20+ developers on separate teams | 1 developer | Overkill - no team coordination needed |
|
|
| Deploy multiple times per day | Weekly deploys | No benefit from independent deployments |
|
|
| Millions of users, high scale | 1-5 concurrent users | No scaling justification |
|
|
| Different frameworks per team | Vue 3 only | No technical diversity |
|
|
| Independent release cycles | Single release cycle | Adds unnecessary complexity |
|
|
|
|
**Pragmatic Monolith Benefits**:
|
|
- Simple build process (single `npm run build`)
|
|
- Shared dependencies (smaller bundle size)
|
|
- Error boundaries provide 50-70% isolation (close to separate apps)
|
|
- Lazy loading prevents loading unused modules
|
|
- Feature flags allow disabling modules without redeploy
|
|
|
|
### Error Boundary Implementation
|
|
|
|
**ErrorBoundary.vue Component**:
|
|
```vue
|
|
<template>
|
|
<div v-if="error" class="module-error">
|
|
<div class="error-icon">⚠️</div>
|
|
<h3>{{ moduleName }} a întâmpinat o eroare</h3>
|
|
<p class="error-message">{{ error.message }}</p>
|
|
<div class="error-actions">
|
|
<button @click="retry" class="btn btn-primary">Reîncearcă</button>
|
|
<button @click="goHome" class="btn btn-secondary">Mergi la Dashboard</button>
|
|
</div>
|
|
</div>
|
|
<slot v-else />
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onErrorCaptured } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
|
|
const props = defineProps({
|
|
moduleName: { type: String, required: true }
|
|
})
|
|
|
|
const router = useRouter()
|
|
const error = ref(null)
|
|
|
|
onErrorCaptured((err, instance, info) => {
|
|
error.value = err
|
|
console.error(`[${props.moduleName}] Error caught:`, err, info)
|
|
return false // Prevent error from propagating
|
|
})
|
|
|
|
const retry = () => {
|
|
error.value = null
|
|
window.location.reload()
|
|
}
|
|
|
|
const goHome = () => {
|
|
error.value = null
|
|
router.push('/reports/dashboard')
|
|
}
|
|
</script>
|
|
```
|
|
|
|
**Usage in Module Layouts**:
|
|
```vue
|
|
<!-- ReportsLayout.vue -->
|
|
<template>
|
|
<ErrorBoundary module-name="Reports">
|
|
<router-view />
|
|
</ErrorBoundary>
|
|
</template>
|
|
|
|
<!-- DataEntryLayout.vue -->
|
|
<template>
|
|
<ErrorBoundary module-name="Data Entry">
|
|
<router-view />
|
|
</ErrorBoundary>
|
|
</template>
|
|
```
|
|
|
|
### Lazy Loading Strategy
|
|
|
|
**Router Configuration**:
|
|
```javascript
|
|
const routes = [
|
|
{
|
|
path: '/login',
|
|
name: 'Login',
|
|
component: LoginView,
|
|
meta: { requiresAuth: false }
|
|
},
|
|
{
|
|
path: '/reports',
|
|
component: () => import('@/modules/reports/ReportsLayout.vue'),
|
|
children: [
|
|
{
|
|
path: 'dashboard',
|
|
name: 'Dashboard',
|
|
component: () => import('@/modules/reports/views/DashboardView.vue'),
|
|
meta: { requiresAuth: true, title: 'Dashboard - ROA Reports' }
|
|
},
|
|
{
|
|
path: 'invoices',
|
|
name: 'Invoices',
|
|
component: () => import('@/modules/reports/views/InvoicesView.vue'),
|
|
meta: { requiresAuth: true, title: 'Facturi - ROA Reports' }
|
|
},
|
|
// ... more routes
|
|
]
|
|
},
|
|
{
|
|
path: '/data-entry',
|
|
component: () => import('@/modules/data-entry/DataEntryLayout.vue'),
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'ReceiptsList',
|
|
component: () => import('@/modules/data-entry/views/receipts/ReceiptsListView.vue'),
|
|
meta: { requiresAuth: true, title: 'Lista Bonuri' }
|
|
},
|
|
// ... more routes
|
|
]
|
|
},
|
|
{
|
|
path: '/',
|
|
redirect: '/reports/dashboard'
|
|
}
|
|
]
|
|
```
|
|
|
|
### Menu Configuration
|
|
|
|
**config/menu.js**:
|
|
```javascript
|
|
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ță de Verificare' }
|
|
]
|
|
},
|
|
{
|
|
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 Bot' },
|
|
{ to: '/reports/cache-stats', icon: 'pi pi-chart-bar', label: 'Statistici Cache' }
|
|
]
|
|
}
|
|
]
|
|
```
|
|
|
|
### Feature Flags
|
|
|
|
**config/features.js**:
|
|
```javascript
|
|
export const features = {
|
|
reports: {
|
|
enabled: true,
|
|
modules: {
|
|
dashboard: true,
|
|
invoices: true,
|
|
bankCash: true,
|
|
trialBalance: true,
|
|
telegram: true,
|
|
cacheStats: true
|
|
}
|
|
},
|
|
dataEntry: {
|
|
enabled: true,
|
|
modules: {
|
|
receipts: true,
|
|
ocr: true
|
|
}
|
|
}
|
|
}
|
|
|
|
export function isFeatureEnabled(module, subModule = null) {
|
|
if (!features[module]?.enabled) return false
|
|
if (subModule && !features[module]?.modules?.[subModule]) return false
|
|
return true
|
|
}
|
|
```
|
|
|
|
### CSS Architecture
|
|
|
|
**Preserve Reports App CSS System**:
|
|
- Use complete CSS structure from `reports-app/frontend/src/assets/css/`
|
|
- Design tokens in `core/tokens.css`
|
|
- Component patterns in `components/`
|
|
- PrimeVue overrides in `vendor/primevue-overrides.css`
|
|
|
|
**Merge Data Entry CSS**:
|
|
- Extract unique data-entry styles
|
|
- Integrate into existing pattern system
|
|
- Ensure no conflicts with reports CSS
|
|
|
|
**Shared Styles**:
|
|
- Import from `src/shared/styles/` for LoginView, AppHeader, SlideMenu
|
|
- Maintain consistency across modules
|
|
|
|
---
|
|
|
|
## Acceptance Criteria
|
|
|
|
### Functionality
|
|
- [ ] User can log in and access both Reports and Data Entry modules from unified menu
|
|
- [ ] All Reports views (Dashboard, Invoices, Bank/Cash, Trial Balance, Telegram, Cache Stats) work correctly
|
|
- [ ] All Data Entry views (Receipts List, Create Receipt, Edit Receipt) work correctly
|
|
- [ ] Navigation between modules preserves authentication and selected company/period
|
|
- [ ] Error in Reports module does not crash Data Entry module (and vice versa)
|
|
- [ ] Logout works correctly and clears all stores
|
|
|
|
### Performance
|
|
- [ ] Initial page load < 2 seconds on 3G connection
|
|
- [ ] Module switching (Reports ↔ Data Entry) < 500ms (already loaded) or < 1s (first load)
|
|
- [ ] Build produces separate chunks for each module (reports.js, data-entry.js)
|
|
- [ ] Total bundle size ≤ sum of current apps (no regression)
|
|
- [ ] Lighthouse score ≥ 90 for Performance
|
|
|
|
### Build & Deployment
|
|
- [ ] `npm run build` succeeds without errors
|
|
- [ ] Build output contains expected chunks (vendor-core, reports, data-entry)
|
|
- [ ] IIS deployment with single site works correctly
|
|
- [ ] API proxy routes correctly to both backends (8001, 8003)
|
|
- [ ] Production build works on Windows IIS
|
|
- [ ] Cache busting works (new builds force reload)
|
|
|
|
### Error Handling
|
|
- [ ] Error boundary catches component errors
|
|
- [ ] Error boundary displays user-friendly message
|
|
- [ ] User can retry or navigate away from error
|
|
- [ ] Console logs error details for debugging
|
|
- [ ] Error in one module doesn't affect the other
|
|
|
|
### Responsive Design
|
|
- [ ] Works on mobile (375px width)
|
|
- [ ] Works on tablet (768px width)
|
|
- [ ] Works on desktop (1920px width)
|
|
- [ ] Slide menu works on mobile
|
|
- [ ] Company/Period selectors work on mobile
|
|
|
|
### Testing
|
|
- [ ] E2E tests pass for login flow
|
|
- [ ] E2E tests pass for Reports module navigation
|
|
- [ ] E2E tests pass for Data Entry module navigation
|
|
- [ ] E2E tests pass for module switching
|
|
- [ ] E2E tests verify error boundary isolation
|
|
|
|
---
|
|
|
|
## Out of Scope
|
|
|
|
The following are explicitly NOT included in this implementation:
|
|
|
|
### Backend Changes
|
|
- No changes to `reports-app/backend/` (port 8001)
|
|
- No changes to `data-entry-app/backend/` (port 8003)
|
|
- Backends remain separate microservices
|
|
|
|
### Shared Database
|
|
- Each backend keeps its own database (Oracle for Reports, SQLite for Data Entry)
|
|
- No database consolidation
|
|
|
|
### API Consolidation
|
|
- APIs remain at separate ports (8001, 8003)
|
|
- No unified API gateway (using IIS/Vite proxy instead)
|
|
|
|
### Telegram Bot
|
|
- Telegram bot remains in `reports-app/telegram-bot/`
|
|
- No changes to bot architecture
|
|
|
|
### Advanced Features
|
|
- No server-side rendering (SSR)
|
|
- No progressive web app (PWA) features
|
|
- No offline mode
|
|
- No real-time updates (WebSockets)
|
|
|
|
### Future Enhancements
|
|
- Module-level permissions (show/hide based on user role)
|
|
- Module analytics dashboard
|
|
- A/B testing framework
|
|
- Module versioning
|
|
- Micro-frontend migration (if team grows to 20+)
|
|
|
|
---
|
|
|
|
## Risks and Mitigations
|
|
|
|
| Risk | Likelihood | Impact | Mitigation |
|
|
|------|------------|--------|------------|
|
|
| **CSS conflicts between modules** | Medium | Medium | Use CSS modules or scoped styles; test thoroughly; maintain design token system from reports-app |
|
|
| **Large bundle size** | Medium | Medium | Implement aggressive code splitting; lazy load modules; use tree shaking; monitor with webpack-bundle-analyzer |
|
|
| **Error boundary not catching all errors** | Low | High | Test error scenarios thoroughly; add global error handler; log errors to monitoring service |
|
|
| **Deployment complexity on IIS** | Medium | High | Document IIS proxy configuration; create deployment scripts; test on staging first |
|
|
| **Store contamination between modules** | Low | High | Keep stores module-scoped; use namespaced modules; test isolation |
|
|
| **PrimeVue theme conflicts** | Low | Medium | Use single PrimeVue theme (saga-blue from reports-app); override in vendor CSS |
|
|
| **Breaking existing E2E tests** | High | Medium | Update test selectors; test both modules independently; add new tests for unified navigation |
|
|
| **Shared component changes breaking both modules** | Medium | High | Version shared components; add component tests; minimize changes to shared code |
|
|
|
|
---
|
|
|
|
## Implementation Plan
|
|
|
|
### Phase 1: Project Setup (0.5 days)
|
|
|
|
**Tasks**:
|
|
1. Create directory structure in root (`.`)
|
|
2. Create `package.json` with merged dependencies
|
|
3. Create `vite.config.js` with dual proxy and lazy loading
|
|
4. Create `src/main.js` with PrimeVue setup
|
|
5. Create `.env.example` with environment variables
|
|
6. Copy `shared/frontend/` to `src/shared/`
|
|
7. Copy `reports-app/frontend/src/assets/css/` to `src/assets/css/`
|
|
|
|
**Verification**:
|
|
- `npm install` succeeds
|
|
- `npm run dev` starts dev server on port 3000
|
|
- No build errors
|
|
|
|
### Phase 2: Module Migration (1 day)
|
|
|
|
**Tasks**:
|
|
1. Create module structure (`modules/reports/`, `modules/data-entry/`)
|
|
2. Migrate Reports views to `modules/reports/views/`
|
|
3. Migrate Reports stores to `modules/reports/stores/`
|
|
4. Migrate Reports services, adapt API base URL to `/api/reports/`
|
|
5. Migrate Data Entry views to `modules/data-entry/views/`
|
|
6. Migrate Data Entry components to `modules/data-entry/components/`
|
|
7. Migrate Data Entry stores to `modules/data-entry/stores/`
|
|
8. Migrate Data Entry services, adapt API base URL to `/api/data-entry/`
|
|
9. Merge CSS from data-entry-app into main CSS system
|
|
|
|
**Verification**:
|
|
- All views render without errors
|
|
- API calls route to correct backend
|
|
- No import errors
|
|
|
|
### Phase 3: Routing & Navigation (0.5 days)
|
|
|
|
**Tasks**:
|
|
1. Create unified router in `src/router/index.js`
|
|
2. Configure lazy loading for module layouts
|
|
3. Add authentication guard
|
|
4. Create `config/menu.js` with unified menu structure
|
|
5. Create `App.vue` with AppHeader and SlideMenu integration
|
|
6. Create `ReportsLayout.vue` with error boundary
|
|
7. Create `DataEntryLayout.vue` with error boundary
|
|
8. Create `ErrorBoundary.vue` component
|
|
|
|
**Verification**:
|
|
- Navigation works between all routes
|
|
- Lazy loading chunks load correctly
|
|
- Error boundary catches and displays errors
|
|
- Menu highlights active route
|
|
|
|
### Phase 4: Error Boundaries & Resilience (0.25 days)
|
|
|
|
**Tasks**:
|
|
1. Test error boundary with intentional errors
|
|
2. Verify module isolation (error in one doesn't crash other)
|
|
3. Add global error handler
|
|
4. Test feature flags (enable/disable modules)
|
|
5. Add loading states for lazy-loaded routes
|
|
|
|
**Verification**:
|
|
- Error boundary displays user-friendly message
|
|
- User can retry or navigate away
|
|
- Other module continues working
|
|
- Feature flags hide disabled modules
|
|
|
|
### Phase 5: Build & Deployment (0.25 days)
|
|
|
|
**Tasks**:
|
|
1. Run production build: `npm run build`
|
|
2. Verify bundle splitting (check `dist/assets/`)
|
|
3. Test production build locally: `npm run preview`
|
|
4. Create IIS web.config with URL rewrite rules
|
|
5. Deploy to staging IIS site
|
|
6. Test all routes and API calls on staging
|
|
7. Document deployment process
|
|
|
|
**Verification**:
|
|
- Build succeeds without errors
|
|
- Separate chunks generated (vendor-core, reports, data-entry)
|
|
- IIS deployment works
|
|
- API proxy routes correctly
|
|
- All features work in production
|
|
|
|
---
|
|
|
|
## Testing Strategy
|
|
|
|
### Unit Tests
|
|
- Store actions and mutations
|
|
- Service API methods
|
|
- Utility functions
|
|
- Error boundary component
|
|
|
|
### Integration Tests
|
|
- Router navigation
|
|
- Store integration with components
|
|
- API service integration
|
|
- Error boundary with child components
|
|
|
|
### E2E Tests (Playwright)
|
|
|
|
**Critical Paths**:
|
|
1. **Login Flow**
|
|
- Navigate to /login
|
|
- Enter credentials
|
|
- Verify redirect to /reports/dashboard
|
|
|
|
2. **Reports Module Navigation**
|
|
- Navigate to each Reports view
|
|
- Verify data loads
|
|
- Test filters and actions
|
|
|
|
3. **Data Entry Module Navigation**
|
|
- Navigate to receipts list
|
|
- Navigate to create receipt
|
|
- Verify form validation
|
|
|
|
4. **Module Switching**
|
|
- Navigate from Reports to Data Entry
|
|
- Verify state persistence (company, period)
|
|
- Navigate back to Reports
|
|
|
|
5. **Error Isolation**
|
|
- Trigger error in Reports module
|
|
- Verify Data Entry still works
|
|
- Retry error module
|
|
|
|
6. **Logout**
|
|
- Logout from any module
|
|
- Verify redirect to login
|
|
- Verify stores cleared
|
|
|
|
### Performance Tests
|
|
- Lighthouse audit (target: 90+ Performance)
|
|
- Bundle size analysis (webpack-bundle-analyzer)
|
|
- Load time measurement (initial load, module switching)
|
|
|
|
---
|
|
|
|
## Rollback Plan
|
|
|
|
### If Deployment Fails
|
|
|
|
**Option 1: Keep Both Apps Running** (Zero Downtime)
|
|
- Leave existing `/roa2web/` and `/data-entry/` sites running
|
|
- Add new unified app at `/unified/` for testing
|
|
- Switch over when stable
|
|
|
|
**Option 2: Quick Rollback** (15 minutes)
|
|
- Keep backup of current IIS configuration
|
|
- Keep backup of current builds in `dist-backup/`
|
|
- Restore IIS sites from backup
|
|
- Restore builds from backup
|
|
|
|
### Git Strategy
|
|
- Create feature branch: `feature/unified-app-pragmatic-monolith`
|
|
- Tag last stable version before merge: `v1.0-pre-unified`
|
|
- Can revert to tag if needed: `git reset --hard v1.0-pre-unified`
|
|
|
|
### Monitoring
|
|
- Check IIS logs: `C:\inetpub\logs\LogFiles\`
|
|
- Check application errors in browser console
|
|
- Monitor backend logs (both 8001 and 8003)
|
|
- Track user feedback in first 48 hours
|
|
|
|
---
|
|
|
|
## Documentation Updates
|
|
|
|
### Files to Create/Update
|
|
|
|
1. **README.md** (in root directory)
|
|
- Project overview
|
|
- Setup instructions
|
|
- Development commands
|
|
- Deployment guide
|
|
- Architecture overview
|
|
|
|
2. **CLAUDE.md** (root)
|
|
- Update architecture diagram
|
|
- Update deployment instructions
|
|
- Mark old apps as archived
|
|
- Document new root structure
|
|
|
|
3. **DEPLOYMENT_GUIDE.md**
|
|
- Update IIS configuration
|
|
- Update build process
|
|
- Update URL structure
|
|
- Add rollback instructions
|
|
|
|
4. **docs/ARCHITECTURE_SCHEMA.md**
|
|
- Update architecture diagrams
|
|
- Document module structure
|
|
- Add error boundary architecture
|
|
|
|
5. **deployment/windows/README.md**
|
|
- Update deployment steps
|
|
- Update IIS configuration
|
|
- Update proxy rules
|
|
|
|
---
|
|
|
|
## Post-Implementation Tasks
|
|
|
|
### Archiving Old Apps
|
|
|
|
After successful deployment and 1 week of stability:
|
|
|
|
1. Archive old frontends:
|
|
```bash
|
|
mv reports-app/frontend reports-app/frontend-archived
|
|
mv data-entry-app/frontend data-entry-app/frontend-archived
|
|
```
|
|
|
|
2. Update start scripts to use root directory:
|
|
```bash
|
|
# ./start-test.sh (update frontend path to root)
|
|
# ./start-data-entry.sh (update frontend path to root)
|
|
```
|
|
|
|
3. Update CI/CD pipelines (if any)
|
|
|
|
4. Document migration in CHANGELOG.md
|
|
|
|
### Monitoring & Optimization
|
|
|
|
**First Week**:
|
|
- Monitor error logs daily
|
|
- Track bundle load times
|
|
- Gather user feedback
|
|
- Fix critical bugs
|
|
|
|
**First Month**:
|
|
- Optimize bundle sizes
|
|
- Add performance monitoring
|
|
- Consider further code splitting
|
|
- Evaluate feature flag usage
|
|
|
|
---
|
|
|
|
## Dependencies on Other Work
|
|
|
|
### Prerequisites
|
|
- None - can start immediately
|
|
|
|
### Blocking
|
|
- No other work blocked by this
|
|
|
|
### Nice to Have (Not Required)
|
|
- Updated E2E tests (can do after deployment)
|
|
- Performance monitoring setup (can add later)
|
|
- Analytics integration (can add later)
|
|
|
|
---
|
|
|
|
## Success Metrics
|
|
|
|
### Deployment Success
|
|
- ✅ Single IIS site running instead of 2
|
|
- ✅ Single build command instead of 2
|
|
- ✅ Zero downtime during deployment
|
|
|
|
### User Experience
|
|
- ✅ 100% feature parity with old apps
|
|
- ✅ < 2s initial load time
|
|
- ✅ < 500ms module switching (cached)
|
|
- ✅ Zero user-reported bugs in first week
|
|
|
|
### Technical
|
|
- ✅ Bundle size ≤ sum of old apps
|
|
- ✅ Error isolation working (test scenarios)
|
|
- ✅ All E2E tests passing
|
|
- ✅ Lighthouse score ≥ 90
|
|
|
|
---
|
|
|
|
## Open Questions
|
|
|
|
1. **PrimeVue Theme Standardization**: Use `saga-blue` (reports-app) or `lara-light-blue` (data-entry-app)?
|
|
- **Recommendation**: Use `saga-blue` (reports-app is primary)
|
|
|
|
2. **Feature Flag Storage**: Config file or environment variables?
|
|
- **Recommendation**: Config file for simplicity, env vars for production override
|
|
|
|
3. **Module Activation Strategy**: All modules active by default or opt-in?
|
|
- **Recommendation**: All active by default (can disable via config)
|
|
|
|
4. **Monitoring Solution**: Console logs only or add Sentry/similar?
|
|
- **Recommendation**: Console logs for MVP, add monitoring later
|
|
|
|
5. **Progressive Enhancement**: Load Reports first (most used) or parallel?
|
|
- **Recommendation**: Load on-demand (lazy loading), whichever user navigates to first
|
|
|
|
---
|
|
|
|
## Estimated Complexity
|
|
|
|
**Medium Complexity** - Justification:
|
|
|
|
**Factors Increasing Complexity**:
|
|
- Merging two apps with different structures
|
|
- Ensuring error isolation between modules
|
|
- CSS conflicts and PrimeVue theme differences
|
|
- IIS proxy configuration complexity
|
|
- Testing both modules thoroughly
|
|
|
|
**Factors Decreasing Complexity**:
|
|
- No backend changes required
|
|
- Shared components already exist
|
|
- Clear architectural pattern (pragmatic monolith)
|
|
- Lazy loading well-supported by Vue Router
|
|
- Both apps use same tech stack (Vue 3, PrimeVue)
|
|
|
|
**Time Estimate**: 2.5 days (as per implementation plan)
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
### Related Documents
|
|
- `IMPLEMENTATION_PLAN_UNIFIED_APP.md` - Initial plan (this spec expands on it)
|
|
- `CLAUDE.md` - Project documentation (update after implementation)
|
|
- `docs/ONBOARDING_CSS.md` - CSS system guide
|
|
- `docs/CSS_PATTERNS.md` - Available CSS patterns
|
|
- `docs/ARCHITECTURE_SCHEMA.md` - Current architecture (update after)
|
|
|
|
### Key Files to Reference During Implementation
|
|
- `reports-app/frontend/vite.config.js` - Proxy config, build settings (reference for new root `vite.config.js`)
|
|
- `reports-app/frontend/src/router/index.js` - Router patterns (reference for new `src/router/index.js`)
|
|
- `reports-app/frontend/src/App.vue` - AppHeader/SlideMenu integration (reference for new `src/App.vue`)
|
|
- `data-entry-app/frontend/src/App.vue` - Alternative integration pattern
|
|
- `shared/frontend/components/layout/AppHeader.vue` - Header API (copy to `src/shared/components/layout/`)
|
|
- `shared/frontend/components/layout/SlideMenu.vue` - Menu API (copy to `src/shared/components/layout/`)
|
|
|
|
---
|
|
|
|
## Handover Notes
|
|
|
|
This specification is **implementation-ready**. All technical decisions have been made. The implementation plan provides a clear path with verification steps at each phase.
|
|
|
|
**Critical Files to Create First** (in root directory):
|
|
1. `package.json` - Merged dependencies
|
|
2. `vite.config.js` - Dual proxy config
|
|
3. `src/router/index.js` - Unified router with lazy loading
|
|
4. `src/shared/components/ErrorBoundary.vue` - Error isolation
|
|
|
|
**After Implementation**:
|
|
- Archive old frontends after 1 week of stability
|
|
- Update all documentation (CLAUDE.md, DEPLOYMENT_GUIDE.md)
|
|
- Consider adding monitoring/analytics
|
|
- Optimize bundle sizes based on real usage
|
|
|
|
---
|
|
|
|
**Specification Version**: 1.0
|
|
**Created**: 2025-12-22
|
|
**Status**: Ready for Implementation
|
|
**Estimated Effort**: 2.5 days
|