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>
This commit is contained in:
2025-12-24 19:06:23 +02:00
parent fed2e68fa2
commit d507a81b0a
112 changed files with 38382 additions and 2382 deletions

170
scripts/service-helpers.sh Normal file
View File

@@ -0,0 +1,170 @@
#!/bin/bash
# Service Helper Functions for ROA2WEB Unified App
# Shared functions for service management scripts
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Wait for a port to become available
# Usage: wait_for_port <port> <service_name> [timeout_seconds]
wait_for_port() {
local port=$1
local service_name=$2
local timeout=${3:-30}
local elapsed=0
local interval=1
echo -e "${BLUE}⏳ Waiting for ${service_name} on port ${port}...${NC}"
while [ $elapsed -lt $timeout ]; do
if netstat -tuln 2>/dev/null | grep -q ":${port} " || ss -tuln 2>/dev/null | grep -q ":${port} "; then
echo -e "${GREEN}${service_name} is ready on port ${port}${NC}"
return 0
fi
sleep $interval
elapsed=$((elapsed + interval))
done
echo -e "${RED}✗ Timeout waiting for ${service_name} on port ${port}${NC}"
return 1
}
# Kill process on a specific port
# Usage: kill_port <port> <service_name>
kill_port() {
local port=$1
local service_name=$2
echo -e "${YELLOW}🛑 Stopping ${service_name} on port ${port}...${NC}"
# Try lsof first
if command -v lsof &> /dev/null; then
local pids=$(lsof -ti:${port} 2>/dev/null)
if [ -n "$pids" ]; then
echo "$pids" | xargs kill -KILL 2>/dev/null
sleep 1
echo -e "${GREEN}${service_name} stopped${NC}"
return 0
fi
fi
# Fallback to netstat/ss
local pids=$(netstat -tlnp 2>/dev/null | grep ":${port} " | awk '{print $7}' | cut -d'/' -f1)
if [ -z "$pids" ]; then
pids=$(ss -tlnp 2>/dev/null | grep ":${port} " | grep -oP 'pid=\K[0-9]+')
fi
if [ -n "$pids" ]; then
echo "$pids" | xargs kill -KILL 2>/dev/null
sleep 1
echo -e "${GREEN}${service_name} stopped${NC}"
return 0
fi
echo -e "${YELLOW}⚠ No process found on port ${port}${NC}"
return 0
}
# Check if a service is running on a port
# Usage: check_service_status <port> <service_name>
check_service_status() {
local port=$1
local service_name=$2
if netstat -tuln 2>/dev/null | grep -q ":${port} " || ss -tuln 2>/dev/null | grep -q ":${port} "; then
echo -e "${GREEN}${service_name} is RUNNING on port ${port}${NC}"
# Try to get process info
if command -v lsof &> /dev/null; then
local pid=$(lsof -ti:${port} 2>/dev/null | head -1)
if [ -n "$pid" ]; then
echo -e " ${BLUE}PID: ${pid}${NC}"
local cmd=$(ps -p $pid -o comm= 2>/dev/null)
if [ -n "$cmd" ]; then
echo -e " ${BLUE}Command: ${cmd}${NC}"
fi
fi
fi
return 0
else
echo -e "${RED}${service_name} is NOT running (port ${port} not in use)${NC}"
return 1
fi
}
# Tail logs with error highlighting
# Usage: tail_logs <log_file> [lines]
tail_logs() {
local log_file=$1
local lines=${2:-20}
if [ ! -f "$log_file" ]; then
echo -e "${RED}✗ Log file not found: ${log_file}${NC}"
return 1
fi
echo -e "${BLUE}📄 Last ${lines} lines from ${log_file}:${NC}"
echo "─────────────────────────────────────────"
# Highlight errors in red
tail -n $lines "$log_file" | sed -e "s/ERROR/${RED}ERROR${NC}/g" \
-e "s/CRITICAL/${RED}CRITICAL${NC}/g" \
-e "s/WARNING/${YELLOW}WARNING${NC}/g" \
-e "s/INFO/${GREEN}INFO${NC}/g"
echo "─────────────────────────────────────────"
}
# Check if port is already in use
# Usage: check_port_available <port> <service_name>
# Returns 0 if port is FREE, 1 if OCCUPIED
check_port_available() {
local port=$1
local service_name=$2
if netstat -tuln 2>/dev/null | grep -q ":${port} " || ss -tuln 2>/dev/null | grep -q ":${port} "; then
echo -e "${YELLOW}⚠ Port ${port} is already in use (${service_name} may already be running)${NC}"
return 1
else
return 0
fi
}
# Display a nice header
# Usage: print_header "Title"
print_header() {
local title=$1
echo ""
echo -e "${BLUE}════════════════════════════════════════${NC}"
echo -e "${BLUE} ${title}${NC}"
echo -e "${BLUE}════════════════════════════════════════${NC}"
echo ""
}
# Display success message
# Usage: print_success "Message"
print_success() {
echo -e "${GREEN}$1${NC}"
}
# Display error message
# Usage: print_error "Message"
print_error() {
echo -e "${RED}$1${NC}"
}
# Display warning message
# Usage: print_warning "Message"
print_warning() {
echo -e "${YELLOW}$1${NC}"
}
# Display info message
# Usage: print_info "Message"
print_info() {
echo -e "${BLUE} $1${NC}"
}