Files
roa2web-service-auto/.auto-build/specs/unified-app/plan.md
Marius Mutu d507a81b0a feat: Implement unified Vue SPA with granular service control
Consolidate Reports and Data Entry apps into a single Vue.js SPA with:

Architecture:
- Module-based structure with lazy-loaded routes (@reports, @data-entry)
- Error boundaries per module to prevent cascade failures
- Dual API proxy in Vite for microservices (reports:8001, data-entry:8003)
- Pinia store factories for shared auth, company, and period stores
- Vite path aliases for clear module boundaries (@shared, @reports, @data-entry)

Service Management:
- Granular service control scripts (backend-reports.sh, backend-data-entry.sh, bot.sh, frontend.sh)
- 87% faster frontend restart: 7s vs 53s full restart
- 38% faster full startup: 33s vs 53s via parallel backend initialization
- Enhanced start-dev.sh with proper service timeouts (OCR: 30s, Vite: 15s, Bot: 10s)
- status.sh for comprehensive health checks

Features:
- Auto-select first company on login with period auto-load
- Hamburger menu with feature toggle support
- JWT token auto-injection via axios interceptors
- Unified header with company/period selectors
- IIS web.config for production deployment with multi-API routing

UX Improvements:
- Vue watchers for reactive company/period loading
- Lazy store initialization with graceful error handling
- Period persistence per user+company in localStorage
- Feature flags for optional modules

Deployment:
- Single IIS site serves unified frontend with API proxy rules
- Maintains separate backend processes for microservices
- Windows line ending fixes (.env CRLF → LF conversion)

Stats: 112 files changed, 38,342 insertions(+), 2,342 deletions(-)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-24 19:06:23 +02:00

35 KiB

Implementation Plan: unified-app

Overview

This plan consolidates the Reports App and Data Entry App frontends into a single unified SPA. The implementation follows a pragmatic monolith approach with module isolation through error boundaries and lazy loading.

Key principles:

  • Single build, single IIS site deployment
  • Module isolation via error boundaries (errors in one module don't crash the other)
  • Lazy loading for each module (only load what the user navigates to)
  • Shared components from src/shared/ (auth, companies, period selectors)
  • CSS system from reports-app preserved and enhanced

Worktree location: /mnt/e/proiecte/ab-worktrees/roa2web-unified-app


Phase 1: Project Setup (0.5 days)

Task 1: Create Root Directory Structure

Objective: Set up the foundational directory structure for the unified app at the repository root.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/ (create directory)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/ (create directory)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/ (create directory)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/data-entry/ (create directory)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/ (create directory)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/config/ (create directory)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/router/ (create directory)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/assets/ (create directory)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/public/ (create directory)

Description: Create the following directory structure at the repository root (not inside reports-app or data-entry-app):

src/
  modules/
    reports/
      views/
      stores/
      services/
    data-entry/
      views/
        receipts/
      components/
        ocr/
      stores/
      services/
  shared/
    components/
      layout/
    stores/
    styles/
      layout/
  config/
  router/
  assets/
    css/
      core/
      components/
      patterns/
      layout/
      utilities/
      vendor/
public/

Dependencies: None

Completion Criteria:

  • All directories created
  • Directory structure matches specification

Task 2: Create package.json with Merged Dependencies

Objective: Create unified package.json combining dependencies from both apps.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/package.json (create)

Description: Merge dependencies from both reports-app/frontend/package.json and data-entry-app/frontend/package.json:

Dependencies to include:

  • vue: ^3.4.0
  • vue-router: ^4.2.5
  • pinia: ^2.1.7
  • axios: ^1.6.5 (use higher version)
  • primevue: ^3.48.0 (use higher version)
  • primeicons: ^6.0.1
  • chart.js: ^4.5.0 (reports only)
  • vue-chartjs: ^5.3.2 (reports only)
  • date-fns: ^2.30.0
  • jspdf: ^3.0.1
  • jspdf-autotable: ^5.0.2
  • xlsx: ^0.18.5
  • qrcode.vue: ^3.6.0

DevDependencies:

  • @vitejs/plugin-vue: ^5.0.0
  • vite: ^5.0.10
  • @playwright/test: ^1.54.2
  • eslint: ^8.56.0
  • eslint-plugin-vue: ^9.20.0
  • prettier: ^3.1.1

Scripts:

  • dev: vite
  • build: vite build
  • preview: vite preview
  • lint: eslint src/ --ext .vue,.js --fix
  • test:e2e: playwright test

Dependencies: Task 1

Completion Criteria:

  • package.json created with all dependencies
  • Scripts defined correctly
  • npm install succeeds

Task 3: Create vite.config.js with Dual Proxy and Lazy Loading

Objective: Configure Vite for unified app with proxies to both backends.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/vite.config.js (create)

Description: Create Vite configuration with:

  1. Dual proxy configuration:

    • /api/reports/* -> http://localhost:8001/api/*
    • /api/data-entry/* -> http://localhost:8003/api/*
    • /uploads -> http://localhost:8003
  2. Aliases:

    • @ -> ./src
    • @shared -> ./src/shared
    • @reports -> ./src/modules/reports
    • @data-entry -> ./src/modules/data-entry
  3. Build configuration:

    • base: / (single site, no subdirectory)
    • Manual chunks for vendors (vue, primevue, charts, exports)
    • Source maps enabled
    • Cache busting with hashes
  4. dedupe for Vue, vue-router, pinia, primevue

  5. WSL2 file watching (usePolling: true)

Reference: reports-app/frontend/vite.config.js for htmlTimestampPlugin and build settings.

Dependencies: Task 1

Completion Criteria:

  • Vite config created with dual proxy
  • All aliases defined
  • Manual chunks configured
  • npm run dev starts successfully

Task 4: Copy CSS System from Reports App

Objective: Migrate the complete CSS design system to the unified app.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/assets/css/ (copy entire directory)

Description: Copy the entire CSS directory from reports-app/frontend/src/assets/css/ to src/assets/css/:

  • core/ - Design tokens (tokens.css)
  • components/ - Component patterns (cards.css, badges.css, stats.css, etc.)
  • patterns/ - Interactive patterns
  • layout/ - Page structure
  • utilities/ - Utility classes
  • vendor/ - PrimeVue overrides
  • main.css - Main import file
  • global.css - Global styles
  • mobile.css - Mobile responsive styles

This is the authoritative CSS system that both modules will use.

Dependencies: Task 1

Completion Criteria:

  • All CSS files copied
  • Directory structure preserved
  • main.css imports all other CSS files correctly

Task 5: Copy Shared Frontend Components and Stores

Objective: Migrate shared components to unified app's shared directory.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/components/LoginView.vue (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/components/CompanySelector.vue (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/components/PeriodSelector.vue (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/components/layout/AppHeader.vue (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/components/layout/SlideMenu.vue (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/stores/auth.js (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/stores/companies.js (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/stores/accountingPeriod.js (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/styles/login.css (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/styles/layout/header.css (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/styles/layout/navigation.css (copy)

Description: Copy from shared/frontend/:

  1. Components: LoginView.vue, CompanySelector.vue, PeriodSelector.vue, layout/AppHeader.vue, layout/SlideMenu.vue
  2. Stores: auth.js, companies.js, accountingPeriod.js
  3. Styles: login.css, layout/header.css, layout/navigation.css

Update import paths in components to use relative paths within src/shared/.

Dependencies: Task 1

Completion Criteria:

  • All shared components copied
  • All shared stores copied
  • All shared styles copied
  • Import paths updated to work from new location

Task 6: Create .env.example and public/index.html

Objective: Create environment template and HTML entry point.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/.env.example (create)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/public/index.html (create)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/public/favicon.ico (copy from reports-app if exists)

Description:

  1. Create .env.example:
# API URLs (development)
VITE_REPORTS_API_URL=http://localhost:8001/api
VITE_DATA_ENTRY_API_URL=http://localhost:8003/api

# Feature flags
VITE_FEATURE_REPORTS=true
VITE_FEATURE_DATA_ENTRY=true
  1. Create public/index.html (or use Vite's default index.html in root):
<!DOCTYPE html>
<html lang="ro">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>ROA2WEB - Unified App</title>
  <link rel="icon" href="/favicon.ico" />
  <!-- BUILD_TIMESTAMP placeholder for cache busting -->
  <meta name="build-time" content="BUILD_TIMESTAMP" />
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>
</html>

Dependencies: Task 1

Completion Criteria:

  • .env.example created
  • index.html created with proper meta tags
  • Build timestamp placeholder present

Phase 2: Module Migration (1 day)

Task 7: Migrate Reports Module Views

Objective: Copy and adapt Reports views to the modules directory.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/views/DashboardView.vue (copy and adapt)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/views/InvoicesView.vue (copy and adapt)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/views/BankCashRegisterView.vue (copy and adapt)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/views/TrialBalanceView.vue (copy and adapt)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/views/TelegramView.vue (copy and adapt)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/views/CacheStatsView.vue (copy and adapt)

Description: Copy views from reports-app/frontend/src/views/ to src/modules/reports/views/:

  • DashboardView.vue
  • InvoicesView.vue
  • BankCashRegisterView.vue
  • TrialBalanceView.vue
  • TelegramView.vue
  • CacheStatsView.vue

DO NOT copy LoginView.vue - use shared LoginView.

Update imports:

  • Change @/stores/xxx to @reports/stores/xxx for module-specific stores
  • Change @/stores/auth to @shared/stores/auth
  • Change @/stores/companies to @shared/stores/companies
  • Change @/stores/accountingPeriod to @shared/stores/accountingPeriod

Dependencies: Task 4, Task 5

Completion Criteria:

  • All 6 views copied
  • Import paths updated
  • No references to old shared path (../../../shared/)

Task 8: Migrate Reports Module Stores

Objective: Copy and adapt Reports stores to the modules directory.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/stores/dashboard.js (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/stores/invoices.js (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/stores/treasury.js (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/stores/trialBalance.js (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/stores/cacheStore.js (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/stores/index.js (copy and adapt)

Description: Copy module-specific stores from reports-app/frontend/src/stores/:

  • dashboard.js
  • invoices.js
  • treasury.js
  • trialBalance.js
  • cacheStore.js
  • index.js (barrel export)

DO NOT copy auth.js, companies.js, accountingPeriod.js - these are in shared.

Update any internal imports to use module paths.

Dependencies: Task 5

Completion Criteria:

  • All 6 store files copied
  • No references to shared stores (auth, companies, period)
  • index.js exports all module stores

Task 9: Create Reports Module API Service

Objective: Create API service for Reports module with /api/reports/ prefix.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/services/api.js (create/adapt)

Description: Create or adapt the API service from reports-app/frontend/src/services/api.js:

  1. Base URL: /api/reports (proxied to port 8001)
  2. Include auth token interceptor
  3. Include response error handler
  4. Export configured axios instance

Example structure:

import axios from 'axios'

const api = axios.create({
  baseURL: '/api/reports',
  headers: { 'Content-Type': 'application/json' }
})

// Request interceptor for auth token
api.interceptors.request.use((config) => {
  const token = localStorage.getItem('access_token')
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

export default api

Dependencies: Task 1

Completion Criteria:

  • API service created with /api/reports base URL
  • Auth token interceptor configured
  • Error handling interceptor configured

Task 10: Migrate Data Entry Module Views

Objective: Copy and adapt Data Entry views to the modules directory.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/data-entry/views/receipts/ReceiptsListView.vue (copy and adapt)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/data-entry/views/receipts/ReceiptCreateView.vue (copy and adapt)

Description: Copy views from data-entry-app/frontend/src/views/receipts/:

  • ReceiptsListView.vue
  • ReceiptCreateView.vue

DO NOT copy LoginView.vue - use shared LoginView.

Update imports:

  • Change @/stores/xxx to @data-entry/stores/xxx for module-specific stores
  • Change @/stores/auth to @shared/stores/auth
  • Change @/stores/companies to @shared/stores/companies
  • Change @/stores/accountingPeriod to @shared/stores/accountingPeriod
  • Change @/components/xxx to @data-entry/components/xxx
  • Change @/services/api to @data-entry/services/api

Dependencies: Task 4, Task 5

Completion Criteria:

  • Both receipt views copied
  • Import paths updated
  • No references to old shared path

Task 11: Migrate Data Entry Module Components

Objective: Copy Data Entry specific components (OCR).

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/data-entry/components/ocr/OCRUploadZone.vue (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/data-entry/components/ocr/OCRPreview.vue (copy)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/data-entry/components/ocr/OCRConfidenceIndicator.vue (copy)

Description: Copy OCR components from data-entry-app/frontend/src/components/ocr/:

  • OCRUploadZone.vue
  • OCRPreview.vue
  • OCRConfidenceIndicator.vue

Update any imports to use the new module paths.

Dependencies: Task 1

Completion Criteria:

  • All 3 OCR components copied
  • Import paths updated
  • Components work independently

Task 12: Migrate Data Entry Module Stores

Objective: Copy Data Entry specific stores.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/data-entry/stores/receiptsStore.js (copy and adapt)

Description: Copy from data-entry-app/frontend/src/stores/:

  • receiptsStore.js

DO NOT copy auth.js, companies.js, accountingPeriod.js - these are in shared.

Update imports:

  • API service import to @data-entry/services/api

Dependencies: Task 5

Completion Criteria:

  • receiptsStore.js copied
  • Import paths updated
  • No duplicate shared stores

Task 13: Create Data Entry Module API Service

Objective: Create API service for Data Entry module with /api/data-entry/ prefix.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/data-entry/services/api.js (create/adapt)

Description: Create or adapt the API service from data-entry-app/frontend/src/services/api.js:

  1. Base URL: /api/data-entry (proxied to port 8003)
  2. Include auth token interceptor
  3. Include X-Selected-Company header injection
  4. Include response error handler
  5. Export configured axios instance

Reference the existing data-entry-app/frontend/src/services/api.js for company header logic.

Dependencies: Task 1

Completion Criteria:

  • API service created with /api/data-entry base URL
  • Auth token interceptor configured
  • Company header interceptor configured

Task 14: Merge and Adapt CSS from Data Entry

Objective: Integrate any unique Data Entry CSS into the unified CSS system.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/assets/css/modules/data-entry.css (create if needed)

Description:

  1. Review data-entry-app/frontend/src/assets/css/main.css for unique styles
  2. Extract any styles not already covered by the reports-app CSS system
  3. Add to a new modules/data-entry.css file if needed
  4. Import in main.css

Note: Data Entry currently uses lara-light-blue theme while Reports uses saga-blue. Decision: Use saga-blue (reports-app theme) for consistency as per spec.

Dependencies: Task 4

Completion Criteria:

  • Data Entry unique styles identified
  • Styles merged without conflicts
  • PrimeVue theme standardized to saga-blue

Phase 3: Routing & Navigation (0.5 days)

Task 15: Create Unified Router Configuration

Objective: Create unified Vue Router with lazy loading for both modules.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/router/index.js (create)

Description: Create unified router with:

  1. Login route (not lazy loaded - immediate access needed):
{
  path: '/login',
  name: 'Login',
  component: () => import('@shared/components/LoginView.vue'),
  meta: { requiresAuth: false, title: 'Autentificare - ROA2WEB' }
}
  1. Reports module routes (lazy loaded):
{
  path: '/reports',
  component: () => import('@/modules/reports/ReportsLayout.vue'),
  children: [
    { path: 'dashboard', name: 'Dashboard', component: () => import('@reports/views/DashboardView.vue') },
    { path: 'invoices', name: 'Invoices', component: () => import('@reports/views/InvoicesView.vue') },
    { path: 'bank-cash', name: 'BankCash', component: () => import('@reports/views/BankCashRegisterView.vue') },
    { path: 'trial-balance', name: 'TrialBalance', component: () => import('@reports/views/TrialBalanceView.vue') },
    { path: 'telegram', name: 'Telegram', component: () => import('@reports/views/TelegramView.vue') },
    { path: 'cache-stats', name: 'CacheStats', component: () => import('@reports/views/CacheStatsView.vue') },
  ]
}
  1. Data Entry module routes (lazy loaded):
{
  path: '/data-entry',
  component: () => import('@/modules/data-entry/DataEntryLayout.vue'),
  children: [
    { path: '', name: 'ReceiptsList', component: () => import('@data-entry/views/receipts/ReceiptsListView.vue') },
    { path: 'create', name: 'ReceiptCreate', component: () => import('@data-entry/views/receipts/ReceiptCreateView.vue') },
    { path: ':id', name: 'ReceiptDetail', component: () => import('@data-entry/views/receipts/ReceiptCreateView.vue') },
    { path: ':id/edit', name: 'ReceiptEdit', component: () => import('@data-entry/views/receipts/ReceiptCreateView.vue') },
  ]
}
  1. Redirects:
  • / -> /reports/dashboard
  • /:pathMatch(.*)* -> /reports/dashboard
  1. Navigation guards:
  • Check authentication before protected routes
  • Set page title from route meta
  • Scroll to top after navigation

Dependencies: Task 7, Task 10

Completion Criteria:

  • All routes defined with lazy loading
  • Navigation guards implemented
  • Redirects configured
  • Page titles set from meta

Task 16: Create Menu Configuration

Objective: Create unified menu configuration for all modules.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/config/menu.js (create)

Description: Create menu configuration with sections:

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 si Banca' },
      { to: '/reports/trial-balance', icon: 'pi pi-calculator', label: 'Balanta 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' }
    ]
  }
]

Dependencies: None

Completion Criteria:

  • Menu configuration created
  • All routes represented
  • Icons assigned correctly

Task 17: Create Feature Flags Configuration

Objective: Create feature flags for module enable/disable.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/config/features.js (create)

Description: Create feature flags configuration:

export const features = {
  reports: {
    enabled: import.meta.env.VITE_FEATURE_REPORTS !== 'false',
    modules: {
      dashboard: true,
      invoices: true,
      bankCash: true,
      trialBalance: true,
      telegram: true,
      cacheStats: true
    }
  },
  dataEntry: {
    enabled: import.meta.env.VITE_FEATURE_DATA_ENTRY !== 'false',
    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
}

export function getEnabledMenuSections(menuSections) {
  return menuSections.filter(section => {
    if (section.title === 'Rapoarte') return features.reports.enabled
    if (section.title === 'Introduceri Date') return features.dataEntry.enabled
    return true // System section always visible
  })
}

Dependencies: Task 16

Completion Criteria:

  • Feature flags created
  • Environment variable support
  • Helper functions for filtering menu

Task 18: Create App.vue Root Component

Objective: Create unified App.vue with menu integration.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/App.vue (create)

Description: Create App.vue that:

  1. Shows AppHeader and SlideMenu when authenticated
  2. Uses unified menu configuration from config/menu.js
  3. Filters menu based on feature flags
  4. Handles company/period changes
  5. Handles user logout (clears all stores)
  6. Uses Toast and ConfirmDialog globally

Reference reports-app/frontend/src/App.vue for structure but adapt for:

  • Using @shared/ components
  • Using unified menu
  • Using shared stores via aliases

Dependencies: Task 5, Task 15, Task 16, Task 17

Completion Criteria:

  • App.vue created
  • Header and SlideMenu integrated
  • Menu sections from config
  • Company/period handlers work
  • Logout clears all stores

Task 19: Create main.js Entry Point

Objective: Create unified main.js with PrimeVue setup.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/main.js (create)

Description: Create main.js that:

  1. Creates Vue app
  2. Sets up Pinia store
  3. Sets up Vue Router
  4. Configures PrimeVue with saga-blue theme
  5. Registers ToastService, ConfirmationService
  6. Registers common PrimeVue components globally
  7. Imports unified CSS (./assets/css/main.css)

Merge component registrations from both apps:

  • From reports: Button, InputText, Password, DataTable, Column, Card, Toast, ConfirmDialog, Menu, Menubar, Badge, Tag, Dropdown, AutoComplete, Calendar, ProgressSpinner, Dialog
  • From data-entry: InputNumber, Textarea, FileUpload, Image, TabView, TabPanel, Checkbox, RadioButton, Toolbar, Divider, Message

Dependencies: Task 2, Task 4, Task 15

Completion Criteria:

  • main.js created
  • All PrimeVue components registered
  • PrimeVue theme set to saga-blue
  • CSS imports correct
  • App mounts successfully

Phase 4: Error Boundaries & Resilience (0.25 days)

Task 20: Create ErrorBoundary Component

Objective: Create reusable error boundary component.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/components/ErrorBoundary.vue (create)

Description: Create ErrorBoundary.vue component that:

  1. Uses onErrorCaptured to catch child component errors
  2. Displays user-friendly error message in Romanian
  3. Provides "Retry" button (reloads page)
  4. Provides "Go to Dashboard" button
  5. Logs error details to console
  6. Returns false from onErrorCaptured to prevent propagation

Template structure:

<template>
  <div v-if="error" class="module-error">
    <div class="error-icon">
      <i class="pi pi-exclamation-triangle"></i>
    </div>
    <h3>{{ moduleName }} a intampinat o eroare</h3>
    <p class="error-message">{{ error.message }}</p>
    <div class="error-actions">
      <Button label="Reincearca" icon="pi pi-refresh" @click="retry" />
      <Button label="Mergi la Dashboard" icon="pi pi-home" severity="secondary" @click="goHome" />
    </div>
  </div>
  <slot v-else />
</template>

Dependencies: Task 5

Completion Criteria:

  • ErrorBoundary component created
  • Catches errors from children
  • Shows user-friendly message
  • Retry and navigation buttons work

Task 21: Create ReportsLayout Module Wrapper

Objective: Create layout wrapper with error boundary for Reports module.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/reports/ReportsLayout.vue (create)

Description: Create ReportsLayout.vue that wraps module routes with ErrorBoundary:

<template>
  <ErrorBoundary module-name="Rapoarte">
    <router-view />
  </ErrorBoundary>
</template>

<script setup>
import ErrorBoundary from '@shared/components/ErrorBoundary.vue'
</script>

This ensures errors in Reports views don't crash the entire app.

Dependencies: Task 20

Completion Criteria:

  • ReportsLayout created
  • ErrorBoundary wraps router-view
  • Module name set correctly

Task 22: Create DataEntryLayout Module Wrapper

Objective: Create layout wrapper with error boundary for Data Entry module.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/modules/data-entry/DataEntryLayout.vue (create)

Description: Create DataEntryLayout.vue that wraps module routes with ErrorBoundary:

<template>
  <ErrorBoundary module-name="Introduceri Date">
    <router-view />
  </ErrorBoundary>
</template>

<script setup>
import ErrorBoundary from '@shared/components/ErrorBoundary.vue'
</script>

Dependencies: Task 20

Completion Criteria:

  • DataEntryLayout created
  • ErrorBoundary wraps router-view
  • Module name set correctly

Task 23: Add Loading States for Lazy Routes

Objective: Add loading indicators during module loading.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/components/ModuleLoading.vue (create)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/router/index.js (update)

Description:

  1. Create ModuleLoading.vue component with ProgressSpinner
  2. Configure router to show loading state during async component loading

Using Vue Router's built-in async component handling:

component: defineAsyncComponent({
  loader: () => import('@reports/views/DashboardView.vue'),
  loadingComponent: ModuleLoading,
  delay: 200,
  timeout: 10000
})

Or use Suspense in layout components.

Dependencies: Task 15, Task 20

Completion Criteria:

  • Loading component created
  • Shown during module lazy loading
  • Reasonable delay before showing

Phase 5: Build & Deployment (0.25 days)

Task 24: Create IIS web.config for Production

Objective: Create web.config with URL rewrite rules for IIS deployment.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/public/web.config (create)

Description: Create web.config with:

  1. URL Rewrite Rules:

    • /api/reports/* -> http://localhost:8001/api/*
    • /api/data-entry/* -> http://localhost:8003/api/*
    • /uploads/* -> http://localhost:8003/uploads/*
    • SPA fallback: all other routes -> /index.html
  2. Static file handling

  3. Cache headers for assets

  4. MIME types for modern files

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Proxy Reports API" stopProcessing="true">
          <match url="^api/reports/(.*)" />
          <action type="Rewrite" url="http://localhost:8001/api/{R:1}" />
        </rule>
        <rule name="Proxy Data Entry API" stopProcessing="true">
          <match url="^api/data-entry/(.*)" />
          <action type="Rewrite" url="http://localhost:8003/api/{R:1}" />
        </rule>
        <rule name="Proxy Uploads" stopProcessing="true">
          <match url="^uploads/(.*)" />
          <action type="Rewrite" url="http://localhost:8003/uploads/{R:1}" />
        </rule>
        <rule name="SPA Fallback" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite" url="/index.html" />
        </rule>
      </rules>
    </rewrite>
    <staticContent>
      <mimeMap fileExtension=".webmanifest" mimeType="application/manifest+json" />
    </staticContent>
  </system.webServer>
</configuration>

Dependencies: None

Completion Criteria:

  • web.config created
  • API proxy rules correct
  • SPA fallback configured

Task 25: Verify Build and Bundle Splitting

Objective: Run production build and verify output.

Files:

  • (verification task, no file modifications)

Description:

  1. Run npm run build

  2. Verify dist/ output:

    • assets/vendor-core.[hash].js (vue, router, pinia)
    • assets/vendor-primevue.[hash].js (primevue components)
    • assets/vendor-utils.[hash].js (axios, date-fns)
    • assets/vendor-charts.[hash].js (chart.js - lazy)
    • assets/vendor-export.[hash].js (xlsx, jspdf - lazy)
    • Module chunks for reports and data-entry
    • CSS chunk
  3. Check total bundle size <= sum of old apps

  4. Verify source maps generated

Dependencies: Tasks 1-23

Completion Criteria:

  • Build completes without errors
  • Expected chunks generated
  • Bundle size acceptable
  • Source maps present

Task 26: Create README Documentation

Objective: Create README for the unified app.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/unified-app-README.md (create, will be moved to README.md later)

Description: Create documentation covering:

  1. Overview: Unified SPA combining Reports and Data Entry
  2. Quick Start:
    • npm install
    • npm run dev (requires both backends running)
    • npm run build
  3. Architecture:
    • Module structure
    • Shared components
    • Error boundaries
  4. URL Structure
  5. Deployment:
    • IIS configuration
    • Proxy setup
  6. Feature Flags
  7. Development Guide:
    • Adding new routes
    • Adding new components
    • CSS system reference

Dependencies: None

Completion Criteria:

  • README covers all sections
  • Quick start instructions work
  • Architecture explained clearly

Task 27: Update Shared Stores for Dual API Support

Objective: Ensure shared stores work with both API endpoints.

Files:

  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/stores/auth.js (update)
  • /mnt/e/proiecte/ab-worktrees/roa2web-unified-app/src/shared/stores/companies.js (update)

Description: The shared stores (auth, companies) need to work with both backends. Since authentication is handled by the Reports backend (port 8001), update:

  1. auth.js: Use /api/reports/auth/ for login/logout
  2. companies.js: Use /api/reports/companies/ for company list

Ensure the API base URL is correctly configured for the unified app's proxy setup.

Dependencies: Task 5, Task 3

Completion Criteria:

  • Auth store uses correct API path
  • Companies store uses correct API path
  • Login/logout flow works

Task 28: End-to-End Integration Test

Objective: Verify the complete unified app works.

Files:

  • (verification task, manual testing)

Description: Manual testing checklist:

  1. Dev Server:

    • npm run dev starts on port 3000
    • No console errors on load
  2. Login Flow:

    • Navigate to /login
    • Login with valid credentials
    • Redirected to /reports/dashboard
  3. Reports Module:

    • Dashboard loads with data
    • Navigate to Invoices
    • Navigate to Bank/Cash
    • Navigate to Trial Balance
    • Navigate to Telegram
    • Navigate to Cache Stats
  4. Data Entry Module:

    • Navigate to /data-entry (Receipts List)
    • Navigate to /data-entry/create (Create Receipt)
    • Company selector preserved from Reports
  5. Module Switching:

    • Switch from Reports to Data Entry
    • Switch from Data Entry to Reports
    • Selected company/period preserved
  6. Error Boundary:

    • Intentionally break a component
    • Error shows in that module only
    • Other module still works
  7. Logout:

    • Logout works
    • Redirected to login
    • All stores cleared

Dependencies: All previous tasks

Completion Criteria:

  • All manual tests pass
  • No console errors
  • No visual regressions

Testing Strategy

During Implementation

  • After each task, verify no import/build errors
  • Test changed components individually
  • Check browser console for errors

Final Validation

  • Run npm run build - must succeed
  • Run npm run preview - test production build
  • Test on different screen sizes (mobile, tablet, desktop)
  • Verify lazy loading with Network tab (modules load on demand)

Risk Mitigation

Risk Detection Response
CSS conflicts between modules Visual testing shows wrong styles Use scoped styles or module-specific CSS files
Import path errors Build fails or runtime errors Check all import aliases in vite.config.js
PrimeVue theme inconsistency Different component styles Ensure only saga-blue theme imported
Shared store contamination Data appears in wrong module Keep module stores separate, only use shared for auth/company/period
Lazy loading not working Large initial bundle Verify dynamic imports in router
Error boundary not catching App crashes on error Test with intentional errors

Notes for Implementation

  1. Always use absolute paths from worktree root when creating files
  2. Test incrementally - don't wait until the end to test
  3. Preserve existing functionality - this is a migration, not a rewrite
  4. Reference existing files - use reports-app as the primary reference
  5. Use saga-blue theme consistently (reports-app theme)
  6. Login always uses Reports API (port 8001) for authentication
  7. Keep module stores isolated - no cross-module store dependencies