Files
roa2web-service-auto/src/App.vue
Marius Mutu c5e051ad80 feat: Migrate to ultrathin monolith architecture
Consolidate 3 separate applications (reports-app, data-entry-app, telegram-bot) into a unified
architecture with single backend and frontend:

Backend Changes:
- Unified FastAPI backend at backend/ with modular structure
- Modules: reports, data_entry, telegram in backend/modules/
- Centralized config.py and main.py with all routers registered
- Single worker mode (--workers 1) for Telegram bot compatibility
- Shared Oracle connection pool and JWT authentication
- Unified requirements.txt and environment configuration

Frontend Changes:
- Single Vue.js SPA with module-based routing
- Unified frontend at src/ with modules in src/modules/{reports,data-entry}/
- Shared components and stores in src/shared/
- Error boundaries for module isolation
- Dual API proxy in Vite for module communication

Infrastructure:
- New unified startup scripts: start-prod.sh, start-test.sh, start-backend.sh
- Environment templates: .env.dev.example, .env.test.example, .env.prod.example
- Updated deployment scripts for Windows IIS
- Simplified SSH tunnel management

Documentation:
- Comprehensive CLAUDE.md with architecture overview
- Module-specific docs in docs/{data-entry,telegram}/
- Architecture decision records in docs/ARCHITECTURE-DECISIONS.md
- Deployment guides consolidated in deployment/windows/docs/

This migration reduces complexity, improves maintainability, and enables easier
deployment while maintaining all existing functionality.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-29 23:48:14 +02:00

148 lines
4.6 KiB
Vue

<template>
<div id="app">
<!-- Header -->
<AppHeader
v-if="authStore.isAuthenticated"
title="ROA2WEB"
brand-link="/reports/dashboard"
:menu-open="menuOpen"
:companies-store="companyStore"
:period-store="periodStore"
:current-user="authStore.currentUser"
:show-user="false"
@menu-toggle="menuOpen = !menuOpen"
@company-changed="handleCompanyChanged"
@period-changed="handlePeriodChanged"
/>
<!-- Slide Menu -->
<SlideMenu
v-if="authStore.isAuthenticated"
:is-open="menuOpen"
:menu-items="enabledMenuItems"
:current-user="authStore.currentUser"
@close="menuOpen = false"
@logout="handleLogout"
/>
<!-- Main Content -->
<main class="main-content" :class="{ 'with-navbar': authStore.isAuthenticated }">
<router-view />
</main>
<!-- Global Toast Messages -->
<Toast position="top-right" />
<ConfirmDialog />
</div>
</template>
<script setup>
import { ref, computed, onMounted, watch } from 'vue'
import { useRouter } from 'vue-router'
import AppHeader from '@shared/components/layout/AppHeader.vue'
import SlideMenu from '@shared/components/layout/SlideMenu.vue'
import Toast from 'primevue/toast'
import ConfirmDialog from 'primevue/confirmdialog'
import { createAuthStore } from '@shared/stores/auth.js'
import { createCompaniesStore } from '@shared/stores/companies.js'
import { createAccountingPeriodStore } from '@shared/stores/accountingPeriod.js'
import { menuSections } from '@/config/menu.js'
import { getEnabledMenuSections } from '@/config/features.js'
import axios from 'axios'
const router = useRouter()
// API service for auth and shared endpoints (unified backend)
const authApi = axios.create({
baseURL: import.meta.env.BASE_URL + 'api',
headers: { 'Content-Type': 'application/json' }
})
// Add interceptor to inject auth token from localStorage
authApi.interceptors.request.use(config => {
const token = localStorage.getItem('access_token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
// Store definitions (factories return store definitions)
const useAuthStore = createAuthStore(authApi)
const useCompanyStore = createCompaniesStore(authApi, useAuthStore)
const useAccountingPeriodStore = createAccountingPeriodStore(authApi)
// Store instances (invoke the definitions to get instances)
const authStore = useAuthStore()
const companyStore = useCompanyStore()
const periodStore = useAccountingPeriodStore()
// Menu state
const menuOpen = ref(false)
// Get enabled menu items based on feature flags
const enabledMenuItems = computed(() => {
return getEnabledMenuSections(menuSections)
})
// Watch for company selection changes and auto-load periods
watch(
() => companyStore.selectedCompany,
async (newCompany, oldCompany) => {
// Only load periods if company actually changed and is valid
if (newCompany && newCompany.id_firma && newCompany !== oldCompany) {
console.log('[App] Company changed via watch, loading periods for:', newCompany.id_firma)
await periodStore.loadPeriods(newCompany.id_firma)
console.log('[App] Periods auto-loaded successfully')
}
},
{ immediate: true } // Run immediately with current value
)
// Initialize auth and load companies on mount
onMounted(async () => {
console.log('[App] Mounted - initializing auth...')
await authStore.initializeAuth()
console.log('[App] Auth initialized, isAuthenticated:', authStore.isAuthenticated)
// If authenticated, load companies immediately
if (authStore.isAuthenticated) {
console.log('[App] Loading companies...')
await companyStore.loadCompanies()
console.log('[App] Companies loaded, selectedCompany:', companyStore.selectedCompany)
// Period loading will be triggered by the watcher above
} else {
console.log('[App] Not authenticated, skipping company/period loading')
}
})
// Event handlers
const handleCompanyChanged = async (company) => {
console.log('[App] Company changed:', company)
// Load periods for the selected company
if (company && company.id_firma) {
console.log('[App] Loading periods for company:', company.id_firma)
await periodStore.loadPeriods(company.id_firma)
}
}
const handlePeriodChanged = (period) => {
console.log('[App] Period changed:', period)
}
const handleLogout = async () => {
await authStore.logout()
router.push('/login')
}
</script>
<style>
/* Import shared styles */
@import '@shared/styles/layout/header.css';
@import '@shared/styles/layout/navigation.css';
/* Import global CSS system */
@import './assets/css/main.css';
</style>