Files
roa2web-service-auto/.auto-build-data/specs/unified-app/spec.md
Marius Mutu 0bdf079a20 docs: Update unified app spec to use root directory structure
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>
2025-12-22 10:51:08 +02:00

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