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>
411 lines
15 KiB
Bash
411 lines
15 KiB
Bash
#!/bin/bash
|
|
|
|
# ROA2WEB Ultrathin Monolith - Comprehensive Test Script
|
|
# Tests all 14 acceptance criteria from the specification
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Test results
|
|
TESTS_PASSED=0
|
|
TESTS_FAILED=0
|
|
TESTS_TOTAL=0
|
|
|
|
# Function to print test header
|
|
test_header() {
|
|
echo ""
|
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo -e "${CYAN}TEST $(($TESTS_TOTAL + 1)): $1${NC}"
|
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
}
|
|
|
|
# Function to check test result
|
|
check_test() {
|
|
TESTS_TOTAL=$((TESTS_TOTAL + 1))
|
|
if [ $1 -eq 0 ]; then
|
|
echo -e "${GREEN}✅ PASS${NC}"
|
|
TESTS_PASSED=$((TESTS_PASSED + 1))
|
|
return 0
|
|
else
|
|
echo -e "${RED}❌ FAIL${NC}"
|
|
TESTS_FAILED=$((TESTS_FAILED + 1))
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Function to check if port is in use
|
|
check_port() {
|
|
lsof -Pi :$1 -sTCP:LISTEN -t >/dev/null 2>&1
|
|
}
|
|
|
|
echo -e "${CYAN}╔══════════════════════════════════════════════════════════╗${NC}"
|
|
echo -e "${CYAN}║ ROA2WEB ULTRATHIN MONOLITH - COMPREHENSIVE TEST SUITE ║${NC}"
|
|
echo -e "${CYAN}╚══════════════════════════════════════════════════════════╝${NC}"
|
|
echo ""
|
|
|
|
# ============================================================================
|
|
# TEST 1: Single command startup
|
|
# ============================================================================
|
|
test_header "Single command startup (python backend/main.py)"
|
|
echo "This test verifies that the backend can be started with a single command."
|
|
echo "Checking if backend/main.py exists..."
|
|
if [ -f "backend/main.py" ]; then
|
|
echo "✓ backend/main.py found"
|
|
check_test 0
|
|
else
|
|
echo "✗ backend/main.py not found"
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# TEST 2: Port 8000 availability
|
|
# ============================================================================
|
|
test_header "Unified backend running on port 8000"
|
|
echo "Checking if backend is running on port 8000..."
|
|
if check_port 8000; then
|
|
echo "✓ Backend is running on port 8000"
|
|
check_test 0
|
|
else
|
|
echo "✗ Backend is NOT running on port 8000"
|
|
echo "Please start the backend with: ./start-dev-unified.sh"
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# TEST 3: Health endpoint
|
|
# ============================================================================
|
|
test_header "Health endpoint responds correctly"
|
|
if check_port 8000; then
|
|
echo "Testing: GET http://localhost:8000/health"
|
|
health_response=$(curl -s http://localhost:8000/health)
|
|
echo "Response:"
|
|
echo "$health_response" | python3 -m json.tool
|
|
|
|
if echo "$health_response" | grep -q "api"; then
|
|
echo "✓ Health endpoint returns valid JSON with api status"
|
|
check_test 0
|
|
else
|
|
echo "✗ Health endpoint does not return expected format"
|
|
check_test 1
|
|
fi
|
|
else
|
|
echo "✗ Backend not running (skipping test)"
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# TEST 4: Module status in health check
|
|
# ============================================================================
|
|
test_header "Health check shows all module statuses"
|
|
if check_port 8000; then
|
|
health_response=$(curl -s http://localhost:8000/health)
|
|
echo "Checking for module statuses in health response..."
|
|
|
|
modules_ok=true
|
|
for module in "oracle" "reports_cache" "data_entry_db" "telegram_bot"; do
|
|
if echo "$health_response" | grep -q "$module"; then
|
|
echo "✓ Module '$module' status present"
|
|
else
|
|
echo "✗ Module '$module' status missing"
|
|
modules_ok=false
|
|
fi
|
|
done
|
|
|
|
if $modules_ok; then
|
|
check_test 0
|
|
else
|
|
check_test 1
|
|
fi
|
|
else
|
|
echo "✗ Backend not running (skipping test)"
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# TEST 5: Reports module endpoints
|
|
# ============================================================================
|
|
test_header "Reports module endpoints accessible"
|
|
if check_port 8000; then
|
|
echo "Testing Reports endpoints..."
|
|
|
|
# Test /api/reports/cache/status (usually accessible without auth)
|
|
reports_test=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/api/reports/cache/status)
|
|
echo "GET /api/reports/cache/status → HTTP $reports_test"
|
|
|
|
# Accept 200 (OK) or 401 (Unauthorized - means endpoint exists but needs auth)
|
|
if [ "$reports_test" = "200" ] || [ "$reports_test" = "401" ]; then
|
|
echo "✓ Reports module endpoint reachable"
|
|
check_test 0
|
|
else
|
|
echo "✗ Reports module endpoint not working (HTTP $reports_test)"
|
|
check_test 1
|
|
fi
|
|
else
|
|
echo "✗ Backend not running (skipping test)"
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# TEST 6: Data Entry module endpoints
|
|
# ============================================================================
|
|
test_header "Data Entry module endpoints accessible"
|
|
if check_port 8000; then
|
|
echo "Testing Data Entry endpoints..."
|
|
|
|
# Test /api/data-entry/receipts (will need auth)
|
|
data_entry_test=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/api/data-entry/receipts)
|
|
echo "GET /api/data-entry/receipts → HTTP $data_entry_test"
|
|
|
|
# Accept 200 (OK), 401 (Unauthorized), or 422 (Validation error - endpoint exists)
|
|
if [ "$data_entry_test" = "200" ] || [ "$data_entry_test" = "401" ] || [ "$data_entry_test" = "422" ]; then
|
|
echo "✓ Data Entry module endpoint reachable"
|
|
check_test 0
|
|
else
|
|
echo "✗ Data Entry module endpoint not working (HTTP $data_entry_test)"
|
|
check_test 1
|
|
fi
|
|
else
|
|
echo "✗ Backend not running (skipping test)"
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# TEST 7: Telegram module endpoints
|
|
# ============================================================================
|
|
test_header "Telegram module endpoints accessible"
|
|
if check_port 8000; then
|
|
echo "Testing Telegram endpoints..."
|
|
|
|
# Test /api/telegram/auth/verify-user (should be in excluded paths)
|
|
telegram_test=$(curl -s -X POST -H "Content-Type: application/json" \
|
|
-d '{"telegram_id":123}' \
|
|
-o /dev/null -w "%{http_code}" \
|
|
http://localhost:8000/api/telegram/auth/verify-user)
|
|
echo "POST /api/telegram/auth/verify-user → HTTP $telegram_test"
|
|
|
|
# Accept 200, 404 (not found in DB), 422 (validation error)
|
|
if [ "$telegram_test" = "200" ] || [ "$telegram_test" = "404" ] || [ "$telegram_test" = "422" ]; then
|
|
echo "✓ Telegram module endpoint reachable"
|
|
check_test 0
|
|
else
|
|
echo "✗ Telegram module endpoint not working (HTTP $telegram_test)"
|
|
check_test 1
|
|
fi
|
|
else
|
|
echo "✗ Backend not running (skipping test)"
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# TEST 8: Auth endpoint (shared)
|
|
# ============================================================================
|
|
test_header "Auth endpoint accessible (shared module)"
|
|
if check_port 8000; then
|
|
echo "Testing Auth endpoint..."
|
|
|
|
# Test /api/auth/login (should return 422 without credentials)
|
|
auth_test=$(curl -s -X POST -H "Content-Type: application/json" \
|
|
-o /dev/null -w "%{http_code}" \
|
|
http://localhost:8000/api/auth/login)
|
|
echo "POST /api/auth/login (no body) → HTTP $auth_test"
|
|
|
|
# Should return 422 (validation error - missing credentials)
|
|
if [ "$auth_test" = "422" ]; then
|
|
echo "✓ Auth endpoint reachable and validates input"
|
|
check_test 0
|
|
else
|
|
echo "✗ Auth endpoint unexpected response (HTTP $auth_test)"
|
|
check_test 1
|
|
fi
|
|
else
|
|
echo "✗ Backend not running (skipping test)"
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# TEST 9: Companies endpoint (shared)
|
|
# ============================================================================
|
|
test_header "Companies endpoint accessible (shared module)"
|
|
if check_port 8000; then
|
|
echo "Testing Companies endpoint..."
|
|
|
|
# Test /api/companies (needs auth)
|
|
companies_test=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/api/companies)
|
|
echo "GET /api/companies → HTTP $companies_test"
|
|
|
|
# Should return 401 (unauthorized - needs JWT)
|
|
if [ "$companies_test" = "401" ]; then
|
|
echo "✓ Companies endpoint reachable and protected by auth"
|
|
check_test 0
|
|
else
|
|
echo "✗ Companies endpoint unexpected response (HTTP $companies_test)"
|
|
check_test 1
|
|
fi
|
|
else
|
|
echo "✗ Backend not running (skipping test)"
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# TEST 10: API documentation available
|
|
# ============================================================================
|
|
test_header "API documentation accessible at /docs"
|
|
if check_port 8000; then
|
|
echo "Testing /docs endpoint..."
|
|
|
|
docs_test=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/docs)
|
|
echo "GET /docs → HTTP $docs_test"
|
|
|
|
if [ "$docs_test" = "200" ]; then
|
|
echo "✓ API documentation available at http://localhost:8000/docs"
|
|
check_test 0
|
|
else
|
|
echo "✗ API documentation not accessible (HTTP $docs_test)"
|
|
check_test 1
|
|
fi
|
|
else
|
|
echo "✗ Backend not running (skipping test)"
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# TEST 11: Configuration files exist
|
|
# ============================================================================
|
|
test_header "Configuration files properly set up"
|
|
echo "Checking configuration files..."
|
|
|
|
config_ok=true
|
|
if [ -f "backend/config.py" ]; then
|
|
echo "✓ backend/config.py exists"
|
|
else
|
|
echo "✗ backend/config.py missing"
|
|
config_ok=false
|
|
fi
|
|
|
|
if [ -f "backend/requirements.txt" ]; then
|
|
echo "✓ backend/requirements.txt exists"
|
|
else
|
|
echo "✗ backend/requirements.txt missing"
|
|
config_ok=false
|
|
fi
|
|
|
|
if [ -f "backend/.env.example" ]; then
|
|
echo "✓ backend/.env.example exists"
|
|
else
|
|
echo "✗ backend/.env.example missing"
|
|
config_ok=false
|
|
fi
|
|
|
|
if $config_ok; then
|
|
check_test 0
|
|
else
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# TEST 12: Module router factories exist
|
|
# ============================================================================
|
|
test_header "Module router factories properly created"
|
|
echo "Checking router factory files..."
|
|
|
|
routers_ok=true
|
|
for module in "reports" "data-entry" "telegram"; do
|
|
router_file="backend/modules/${module}/routers/__init__.py"
|
|
if [ -f "$router_file" ]; then
|
|
echo "✓ ${module} router factory exists"
|
|
# Check for factory function
|
|
if grep -q "create_.*_router" "$router_file"; then
|
|
echo " ✓ Factory function found"
|
|
else
|
|
echo " ✗ Factory function missing"
|
|
routers_ok=false
|
|
fi
|
|
else
|
|
echo "✗ ${module} router factory missing"
|
|
routers_ok=false
|
|
fi
|
|
done
|
|
|
|
if $routers_ok; then
|
|
check_test 0
|
|
else
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# TEST 13: Frontend proxy configured
|
|
# ============================================================================
|
|
test_header "Frontend proxy configured to use port 8000"
|
|
echo "Checking vite.config.js..."
|
|
|
|
if [ -f "vite.config.js" ]; then
|
|
echo "✓ vite.config.js exists"
|
|
|
|
if grep -q "localhost:8000" vite.config.js; then
|
|
echo "✓ Proxy configured for port 8000"
|
|
check_test 0
|
|
else
|
|
echo "✗ Proxy not configured for port 8000"
|
|
check_test 1
|
|
fi
|
|
else
|
|
echo "✗ vite.config.js not found"
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# TEST 14: Startup scripts created
|
|
# ============================================================================
|
|
test_header "New startup scripts created"
|
|
echo "Checking startup scripts..."
|
|
|
|
scripts_ok=true
|
|
for script in "start-backend.sh" "start-frontend.sh" "start-prod.sh" "start-test.sh" "status.sh"; do
|
|
if [ -f "$script" ] && [ -x "$script" ]; then
|
|
echo "✓ $script exists and is executable"
|
|
else
|
|
echo "✗ $script missing or not executable"
|
|
scripts_ok=false
|
|
fi
|
|
done
|
|
|
|
if $scripts_ok; then
|
|
check_test 0
|
|
else
|
|
check_test 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# SUMMARY
|
|
# ============================================================================
|
|
echo ""
|
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo -e "${CYAN}TEST SUMMARY${NC}"
|
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo ""
|
|
echo -e "Total Tests: ${BLUE}${TESTS_TOTAL}${NC}"
|
|
echo -e "Passed: ${GREEN}${TESTS_PASSED}${NC}"
|
|
echo -e "Failed: ${RED}${TESTS_FAILED}${NC}"
|
|
echo ""
|
|
|
|
if [ $TESTS_FAILED -eq 0 ]; then
|
|
echo -e "${GREEN}╔══════════════════════════════════════════════════════╗${NC}"
|
|
echo -e "${GREEN}║ ✅ ALL TESTS PASSED! IMPLEMENTATION COMPLETE! ✅ ║${NC}"
|
|
echo -e "${GREEN}╚══════════════════════════════════════════════════════╝${NC}"
|
|
exit 0
|
|
else
|
|
echo -e "${YELLOW}╔══════════════════════════════════════════════════════╗${NC}"
|
|
echo -e "${YELLOW}║ ⚠️ SOME TESTS FAILED - REVIEW REQUIRED ⚠️ ║${NC}"
|
|
echo -e "${YELLOW}╚══════════════════════════════════════════════════════╝${NC}"
|
|
echo ""
|
|
echo -e "${YELLOW}Tip: Start the backend with ./start-dev-unified.sh if not running${NC}"
|
|
exit 1
|
|
fi
|