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

35 KiB

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

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

<!-- 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

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

<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:

<!-- 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:

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:

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:

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:

    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:

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

  • 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