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>
This commit is contained in:
@@ -68,7 +68,7 @@
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[ValidateSet("All", "Frontend", "Backend", "TelegramBot", "DataEntryApp", "DataEntryBackend")]
|
||||
[ValidateSet("All", "Frontend", "Backend")]
|
||||
[string]$Component = "",
|
||||
|
||||
[string]$OutputPath = "./deploy-package",
|
||||
@@ -85,14 +85,9 @@ $ErrorActionPreference = "Stop"
|
||||
# =============================================================================
|
||||
|
||||
$config = @{
|
||||
# Reports App sources
|
||||
BackendSource = "../../reports-app/backend"
|
||||
FrontendSource = "../../reports-app/frontend"
|
||||
TelegramBotSource = "../../reports-app/telegram-bot"
|
||||
# Data Entry App sources
|
||||
DataEntryBackendSource = "../../data-entry-app/backend"
|
||||
DataEntryFrontendSource = "../../data-entry-app/frontend"
|
||||
# Shared sources
|
||||
# Ultrathin Monolith sources (relative to deployment/windows/ directory)
|
||||
BackendSource = "../../backend"
|
||||
FrontendSource = "../../src"
|
||||
SharedSource = "../../shared"
|
||||
ConfigSource = "../config"
|
||||
RequiredNodeVersion = 16
|
||||
@@ -175,29 +170,21 @@ function Clear-BuildCache {
|
||||
function Show-BuildMenu {
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " ROA2WEB - Build Component Selection Menu" -ForegroundColor Cyan
|
||||
Write-Host " Ultrathin Monolith Architecture" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " Select components to build:" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host " [1] All Components" -ForegroundColor White
|
||||
Write-Host " (Reports App + Telegram Bot + Data Entry App)" -ForegroundColor Gray
|
||||
Write-Host " (Unified Backend + Frontend)" -ForegroundColor Gray
|
||||
Write-Host " Includes: Reports, Data Entry, and Telegram modules" -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
Write-Host " --- Reports App ---" -ForegroundColor Cyan
|
||||
Write-Host " [2] Reports Frontend + Backend" -ForegroundColor White
|
||||
Write-Host " (Vue.js build + FastAPI backend files)" -ForegroundColor Gray
|
||||
Write-Host " [2] Frontend + Backend" -ForegroundColor White
|
||||
Write-Host " (Vue.js SPA build + Unified FastAPI backend)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [3] Reports Backend Only" -ForegroundColor White
|
||||
Write-Host " (FastAPI backend files + shared modules)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [4] Telegram Bot Only" -ForegroundColor White
|
||||
Write-Host " (Telegram bot standalone package)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " --- Data Entry App ---" -ForegroundColor Cyan
|
||||
Write-Host " [5] Data Entry Frontend + Backend" -ForegroundColor White
|
||||
Write-Host " (Vue.js build + FastAPI backend files)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [6] Data Entry Backend Only" -ForegroundColor White
|
||||
Write-Host " (FastAPI backend files only)" -ForegroundColor Gray
|
||||
Write-Host " [3] Backend Only" -ForegroundColor White
|
||||
Write-Host " (Unified FastAPI backend + shared modules)" -ForegroundColor Gray
|
||||
Write-Host " All modules included - control via MODULE_*_ENABLED flags" -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
Write-Host " [C] Clean Build Cache" -ForegroundColor Yellow
|
||||
Write-Host " (Remove cached node_modules to free disk space)" -ForegroundColor Gray
|
||||
@@ -214,9 +201,6 @@ function Show-BuildMenu {
|
||||
"1" { return "All" }
|
||||
"2" { return "Frontend" }
|
||||
"3" { return "Backend" }
|
||||
"4" { return "TelegramBot" }
|
||||
"5" { return "DataEntryApp" }
|
||||
"6" { return "DataEntryBackend" }
|
||||
"C" {
|
||||
Clear-BuildCache
|
||||
Write-Host "`nPress any key to return to menu..." -ForegroundColor Gray
|
||||
@@ -228,7 +212,7 @@ function Show-BuildMenu {
|
||||
exit 0
|
||||
}
|
||||
default {
|
||||
Write-Host "Invalid choice. Please select 1-6, C or Q." -ForegroundColor Red
|
||||
Write-Host "Invalid choice. Please select 1-3, C or Q." -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
} while ($true)
|
||||
@@ -273,25 +257,34 @@ function Build-Frontend {
|
||||
throw "Frontend source path not found: $SourcePath"
|
||||
}
|
||||
|
||||
# Determine if this is reports-app or data-entry-app based on source path
|
||||
$appFolder = Split-Path (Split-Path $SourcePath -Parent) -Leaf # "reports-app" or "data-entry-app"
|
||||
# For ultrathin monolith, frontend sources are in src/ directory
|
||||
# but package.json and vite.config.js are in project root
|
||||
$appFolder = "roa2web-ultrathin-monolith"
|
||||
|
||||
# Create temporary build directory with full project structure
|
||||
# Create temporary build directory - this is the project root
|
||||
# Structure:
|
||||
# .temp-frontend-build/
|
||||
# ├── reports-app/frontend/ (or data-entry-app/frontend/)
|
||||
# └── shared/
|
||||
# |- package.json (from project root)
|
||||
# |- vite.config.js (from project root)
|
||||
# |- src/ (frontend source)
|
||||
# \- shared/
|
||||
$tempRootDir = Join-Path $OutputPath ".temp-frontend-build"
|
||||
if (Test-Path $tempRootDir) {
|
||||
Write-Step "Cleaning existing temp build directory..."
|
||||
Remove-Item -Path $tempRootDir -Recurse -Force
|
||||
}
|
||||
|
||||
# Create the app-specific path inside temp
|
||||
$tempBuildDir = Join-Path $tempRootDir "$appFolder\frontend"
|
||||
New-Item -ItemType Directory -Path $tempBuildDir -Force | Out-Null
|
||||
# Create temp root (this will be where npm install runs)
|
||||
New-Item -ItemType Directory -Path $tempRootDir -Force | Out-Null
|
||||
|
||||
# Create src subdirectory
|
||||
$tempSrcDir = Join-Path $tempRootDir "src"
|
||||
New-Item -ItemType Directory -Path $tempSrcDir -Force | Out-Null
|
||||
Write-Success "Created temp build directory (isolated from WSL)"
|
||||
|
||||
# The build directory is the root, not src
|
||||
$tempBuildDir = $tempRootDir
|
||||
|
||||
# Create cache directory for node_modules (OUTSIDE deploy-package)
|
||||
$scriptDir = Split-Path -Parent $PSScriptRoot
|
||||
$cacheDir = Join-Path $scriptDir ".build-cache-$appFolder"
|
||||
@@ -299,7 +292,7 @@ function Build-Frontend {
|
||||
New-Item -ItemType Directory -Path $cacheDir -Force | Out-Null
|
||||
}
|
||||
|
||||
# Copy frontend sources to temp (exclude node_modules, dist, .git)
|
||||
# Copy src/ contents to temp src/ subdirectory
|
||||
Write-Step "Copying frontend sources to temp directory..."
|
||||
$excludeDirs = @("node_modules", "dist", ".git", "__pycache__", ".vscode", ".idea")
|
||||
$excludeFiles = @(".env", ".env.local", "*.log")
|
||||
@@ -327,7 +320,8 @@ function Build-Frontend {
|
||||
}
|
||||
if ($isExcludedFile) { return }
|
||||
|
||||
$destPath = Join-Path $tempBuildDir $relativePath
|
||||
# Copy to src/ subdirectory
|
||||
$destPath = Join-Path $tempSrcDir $relativePath
|
||||
|
||||
if ($_.PSIsContainer) {
|
||||
if (-not (Test-Path $destPath)) {
|
||||
@@ -343,9 +337,25 @@ function Build-Frontend {
|
||||
}
|
||||
Write-Success "Frontend sources copied to temp"
|
||||
|
||||
# Copy shared folder to maintain relative imports (../../../shared/frontend/)
|
||||
# Now shared goes into tempRootDir/shared (same level as reports-app or data-entry-app)
|
||||
$projectRoot = Split-Path (Split-Path $SourcePath -Parent) -Parent
|
||||
# Copy package.json, vite.config.js, package-lock.json, index.html from project root
|
||||
Write-Step "Copying build configuration files..."
|
||||
$projectRoot = Split-Path $SourcePath -Parent
|
||||
$configFiles = @("package.json", "vite.config.js", "package-lock.json", "index.html")
|
||||
foreach ($file in $configFiles) {
|
||||
$srcFile = Join-Path $projectRoot $file
|
||||
if (Test-Path $srcFile) {
|
||||
$destFile = Join-Path $tempBuildDir $file
|
||||
Copy-Item -Path $srcFile -Destination $destFile -Force
|
||||
Write-Success "Copied: $file"
|
||||
} else {
|
||||
Write-Warning "Not found: $file"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Copy shared folder to maintain relative imports (../shared/)
|
||||
# For ultrathin monolith: src/ and shared/ are siblings at project root
|
||||
$projectRoot = Split-Path $SourcePath -Parent
|
||||
$sharedSourcePath = Join-Path $projectRoot "shared"
|
||||
|
||||
if (Test-Path $sharedSourcePath) {
|
||||
@@ -366,7 +376,7 @@ function Build-Frontend {
|
||||
Write-Warning "Shared folder not found at: $sharedSourcePath"
|
||||
}
|
||||
|
||||
# Build in temp directory (now at tempRootDir/appFolder/frontend)
|
||||
# Build in temp directory (now at tempRootDir/src)
|
||||
Push-Location $tempBuildDir
|
||||
try {
|
||||
# Check if dependencies need to be reinstalled
|
||||
@@ -434,23 +444,8 @@ function Build-Frontend {
|
||||
throw "Vite not found in node_modules - devDependencies not installed"
|
||||
}
|
||||
|
||||
# Create junction for node_modules at tempRootDir level
|
||||
# This allows shared folder to resolve npm dependencies
|
||||
$tempRootNodeModules = Join-Path $tempRootDir "node_modules"
|
||||
if (-not (Test-Path $tempRootNodeModules)) {
|
||||
Write-Step "Creating node_modules junction for shared imports..."
|
||||
# Use cmd /c mklink /J for directory junction (works without admin rights)
|
||||
$junctionResult = cmd /c mklink /J "$tempRootNodeModules" "$nodeModulesPath" 2>&1
|
||||
if (Test-Path $tempRootNodeModules) {
|
||||
Write-Success "Node modules junction created for shared folder access"
|
||||
} else {
|
||||
Write-Warning "Could not create junction: $junctionResult"
|
||||
# Fallback: copy node_modules (slower but works)
|
||||
Write-Info "Falling back to copying node_modules..."
|
||||
Copy-Item -Path $nodeModulesPath -Destination $tempRootNodeModules -Recurse -Force
|
||||
Write-Success "Node modules copied to root (fallback)"
|
||||
}
|
||||
}
|
||||
# node_modules is already in tempBuildDir (which is tempRootDir)
|
||||
# No need for junction since we build from project root
|
||||
|
||||
# Build for production
|
||||
Write-Step "Building for production..."
|
||||
@@ -572,201 +567,9 @@ function Copy-BackendFiles {
|
||||
Write-Success "Verified: requirements.txt present"
|
||||
}
|
||||
|
||||
function Copy-TelegramBotFiles {
|
||||
param(
|
||||
[string]$SourcePath,
|
||||
[string]$DestPath
|
||||
)
|
||||
# Copy-TelegramBotFiles function removed - Telegram is now part of unified backend (backend/modules/telegram/)
|
||||
|
||||
Write-Step "Copying Telegram bot files..."
|
||||
|
||||
if (-not (Test-Path $SourcePath)) {
|
||||
throw "Telegram bot source path not found: $SourcePath"
|
||||
}
|
||||
|
||||
if (-not (Test-Path $DestPath)) {
|
||||
New-Item -ItemType Directory -Path $DestPath -Force | Out-Null
|
||||
}
|
||||
|
||||
# Exclude patterns
|
||||
$excludeDirs = @("venv", "data", "logs", "temp", "backups", "__pycache__", ".pytest_cache", "tests", ".git")
|
||||
$excludeFiles = @(".env", "*.pyc", "*.pyo", "*.log", "*.db", ".DS_Store", "Thumbs.db")
|
||||
|
||||
# Copy app/ directory
|
||||
$sourceApp = Join-Path $SourcePath "app"
|
||||
$destApp = Join-Path $DestPath "app"
|
||||
New-Item -ItemType Directory -Path $destApp -Force | Out-Null
|
||||
|
||||
$fileCount = 0
|
||||
Get-ChildItem -Path $sourceApp -Recurse | ForEach-Object {
|
||||
# Check exclusions
|
||||
$inExcludedDir = $false
|
||||
foreach ($excludeDir in $excludeDirs) {
|
||||
if ($_.FullName -like "*\$excludeDir\*" -or $_.FullName -like "*/$excludeDir/*") {
|
||||
$inExcludedDir = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ($inExcludedDir) {
|
||||
return
|
||||
}
|
||||
|
||||
$isExcludedFile = $false
|
||||
foreach ($pattern in $excludeFiles) {
|
||||
if ($_.Name -like $pattern) {
|
||||
$isExcludedFile = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ($isExcludedFile) {
|
||||
return
|
||||
}
|
||||
|
||||
$relativePath = $_.FullName.Substring($sourceApp.Length)
|
||||
$destFile = Join-Path $destApp $relativePath
|
||||
|
||||
if ($_.PSIsContainer) {
|
||||
if (-not (Test-Path $destFile)) {
|
||||
New-Item -ItemType Directory -Path $destFile -Force | Out-Null
|
||||
}
|
||||
} else {
|
||||
$destFileDir = Split-Path $destFile -Parent
|
||||
if (-not (Test-Path $destFileDir)) {
|
||||
New-Item -ItemType Directory -Path $destFileDir -Force | Out-Null
|
||||
}
|
||||
Copy-Item -Path $_.FullName -Destination $destFile -Force
|
||||
$fileCount++
|
||||
}
|
||||
}
|
||||
|
||||
Write-Success "Copied $fileCount app files"
|
||||
|
||||
# Copy requirements.txt
|
||||
$sourceReq = Join-Path $SourcePath "requirements.txt"
|
||||
$destReq = Join-Path $DestPath "requirements.txt"
|
||||
if (Test-Path $sourceReq) {
|
||||
Copy-Item -Path $sourceReq -Destination $destReq -Force
|
||||
Write-Success "requirements.txt copied"
|
||||
}
|
||||
|
||||
# Copy .env.example from source (keeps it synchronized with development)
|
||||
$sourceEnvExample = Join-Path $SourcePath ".env.example"
|
||||
$destEnvExample = Join-Path $DestPath ".env.example"
|
||||
if (Test-Path $sourceEnvExample) {
|
||||
Copy-Item -Path $sourceEnvExample -Destination $destEnvExample -Force
|
||||
Write-Success ".env.example template copied"
|
||||
} else {
|
||||
Write-Warning ".env.example not found in source - manual configuration required"
|
||||
}
|
||||
}
|
||||
|
||||
function Copy-DataEntryBackendFiles {
|
||||
param(
|
||||
[string]$SourcePath,
|
||||
[string]$DestPath
|
||||
)
|
||||
|
||||
Write-Step "Copying Data Entry backend files..."
|
||||
|
||||
if (-not (Test-Path $SourcePath)) {
|
||||
throw "Data Entry backend source path not found: $SourcePath"
|
||||
}
|
||||
|
||||
if (-not (Test-Path $DestPath)) {
|
||||
New-Item -ItemType Directory -Path $DestPath -Force | Out-Null
|
||||
}
|
||||
|
||||
# Exclude patterns
|
||||
$excludeDirs = @("venv", "__pycache__", ".pytest_cache", "logs", "temp", "node_modules", "data")
|
||||
$excludeFiles = @("*.pyc", "*.pyo", "*.log", ".env", ".env.local", "*.db")
|
||||
|
||||
$normalizedSourcePath = $SourcePath.TrimEnd('\', '/') + '\'
|
||||
|
||||
$testExclude = {
|
||||
param([string]$RelativePath, [bool]$IsDirectory, [array]$ExcludeDirs, [array]$ExcludeFiles)
|
||||
|
||||
if ($IsDirectory) {
|
||||
$dirName = Split-Path $RelativePath -Leaf
|
||||
if ($ExcludeDirs -contains $dirName) {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
$pathParts = $RelativePath -split '[\\/]'
|
||||
foreach ($part in $pathParts) {
|
||||
if ($ExcludeDirs -contains $part) {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $IsDirectory) {
|
||||
foreach ($pattern in $ExcludeFiles) {
|
||||
if ($RelativePath -like $pattern) {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
Get-ChildItem -Path $SourcePath -Recurse | ForEach-Object {
|
||||
if ($_.FullName.Length -le $normalizedSourcePath.Length) {
|
||||
return
|
||||
}
|
||||
$relativePath = $_.FullName.Substring($normalizedSourcePath.Length)
|
||||
|
||||
$shouldExclude = & $testExclude -RelativePath $relativePath -IsDirectory $_.PSIsContainer -ExcludeDirs $excludeDirs -ExcludeFiles $excludeFiles
|
||||
if ($shouldExclude) {
|
||||
return
|
||||
}
|
||||
|
||||
$destFile = Join-Path $DestPath $relativePath
|
||||
|
||||
if ($_.PSIsContainer) {
|
||||
if (-not (Test-Path $destFile)) {
|
||||
New-Item -ItemType Directory -Path $destFile -Force | Out-Null
|
||||
}
|
||||
} else {
|
||||
$destDir = Split-Path $destFile -Parent
|
||||
if (-not (Test-Path $destDir)) {
|
||||
New-Item -ItemType Directory -Path $destDir -Force | Out-Null
|
||||
}
|
||||
Copy-Item -Path $_.FullName -Destination $destFile -Force
|
||||
}
|
||||
}
|
||||
|
||||
$backendFiles = Get-ChildItem -Path $DestPath -Recurse -File
|
||||
Write-Success "Copied $(($backendFiles).Count) Data Entry backend files"
|
||||
|
||||
# Copy .env.example explicitly
|
||||
$sourceEnvExample = Join-Path $SourcePath ".env.example"
|
||||
$destEnvExample = Join-Path $DestPath ".env.example"
|
||||
if (Test-Path $sourceEnvExample) {
|
||||
Copy-Item -Path $sourceEnvExample -Destination $destEnvExample -Force
|
||||
Write-Success ".env.example template copied"
|
||||
}
|
||||
|
||||
# Copy .env.prod and .env.test templates
|
||||
foreach ($envFile in @(".env.prod", ".env.test")) {
|
||||
$sourceEnv = Join-Path $SourcePath $envFile
|
||||
$destEnv = Join-Path $DestPath $envFile
|
||||
if (Test-Path $sourceEnv) {
|
||||
Copy-Item -Path $sourceEnv -Destination $destEnv -Force
|
||||
Write-Success "$envFile template copied"
|
||||
}
|
||||
}
|
||||
|
||||
# Verify requirements.txt
|
||||
$requirementsTxt = Join-Path $DestPath "requirements.txt"
|
||||
if (-not (Test-Path $requirementsTxt)) {
|
||||
Write-Error "CRITICAL: requirements.txt not found!"
|
||||
throw "Data Entry backend package incomplete - missing requirements.txt"
|
||||
}
|
||||
Write-Success "Verified: requirements.txt present"
|
||||
}
|
||||
# Copy-DataEntryBackendFiles function removed - Data Entry is now part of unified backend (backend/modules/data_entry/)
|
||||
|
||||
function Copy-SharedModules {
|
||||
param(
|
||||
@@ -898,12 +701,9 @@ function New-DeploymentReadme {
|
||||
Write-Step "Creating deployment README..."
|
||||
|
||||
$componentDesc = switch ($ComponentType) {
|
||||
"All" { "COMPLETE DEPLOYMENT PACKAGE (Reports + Telegram + Data Entry)" }
|
||||
"Frontend" { "REPORTS FRONTEND + BACKEND DEPLOYMENT PACKAGE" }
|
||||
"Backend" { "REPORTS BACKEND DEPLOYMENT PACKAGE" }
|
||||
"TelegramBot" { "TELEGRAM BOT DEPLOYMENT PACKAGE" }
|
||||
"DataEntryApp" { "DATA ENTRY APP DEPLOYMENT PACKAGE (Frontend + Backend)" }
|
||||
"DataEntryBackend" { "DATA ENTRY BACKEND DEPLOYMENT PACKAGE" }
|
||||
"All" { "COMPLETE DEPLOYMENT PACKAGE (Ultrathin Monolith - All Modules)" }
|
||||
"Frontend" { "UNIFIED FRONTEND + BACKEND DEPLOYMENT PACKAGE" }
|
||||
"Backend" { "UNIFIED BACKEND DEPLOYMENT PACKAGE (All Modules)" }
|
||||
}
|
||||
|
||||
$readme = @"
|
||||
@@ -915,68 +715,46 @@ function New-DeploymentReadme {
|
||||
|
||||
CONTENTS:
|
||||
---------
|
||||
"@
|
||||
|
||||
if ($ComponentType -eq "All" -or $ComponentType -eq "Frontend" -or $ComponentType -eq "Backend") {
|
||||
$readme += @"
|
||||
backend/ Unified FastAPI backend (port 8000)
|
||||
|- modules/
|
||||
| |- reports/ Reports module (Oracle)
|
||||
| |- data_entry/ Data Entry module (SQLite)
|
||||
| \- telegram/ Telegram bot module (background task)
|
||||
\- main.py Single entry point (uvicorn)
|
||||
|
||||
backend/ Reports App - FastAPI backend (Python, port 8000)
|
||||
frontend/ Reports App - Vue.js static files (production build)
|
||||
shared/ Shared Python modules (auth, database, utils)
|
||||
config/ Configuration templates (.env, web.config)
|
||||
"@
|
||||
}
|
||||
frontend/ Unified Vue.js SPA (production build)
|
||||
Single-page application with integrated modules
|
||||
|
||||
if ($ComponentType -eq "All" -or $ComponentType -eq "TelegramBot") {
|
||||
$readme += @"
|
||||
shared/ Shared Python modules
|
||||
|- auth/ JWT authentication & middleware
|
||||
|- database/ Oracle connection pool
|
||||
\- routes/ Shared API routes (companies, calendar)
|
||||
|
||||
telegram-bot/ Telegram bot application (port 8002)
|
||||
"@
|
||||
}
|
||||
|
||||
if ($ComponentType -eq "All" -or $ComponentType -eq "DataEntryApp" -or $ComponentType -eq "DataEntryBackend") {
|
||||
$readme += @"
|
||||
|
||||
data-entry-backend/ Data Entry App - FastAPI backend (Python, port 8003)
|
||||
"@
|
||||
}
|
||||
|
||||
if ($ComponentType -eq "All" -or $ComponentType -eq "DataEntryApp") {
|
||||
$readme += @"
|
||||
data-entry-frontend/ Data Entry App - Vue.js static files (production build)
|
||||
"@
|
||||
}
|
||||
|
||||
$readme += @"
|
||||
config/ Configuration templates
|
||||
\- web.config IIS configuration for unified backend
|
||||
|
||||
scripts/ PowerShell deployment scripts
|
||||
|
||||
MODULE CONTROL:
|
||||
---------------
|
||||
Enable/disable modules via environment variables in backend/.env:
|
||||
MODULE_REPORTS_ENABLED=true # Reports module
|
||||
MODULE_DATA_ENTRY_ENABLED=true # Data Entry module
|
||||
MODULE_TELEGRAM_ENABLED=true # Telegram bot module
|
||||
|
||||
|
||||
DEPLOYMENT SCRIPTS:
|
||||
-------------------
|
||||
ROA2WEB-Console.ps1 Unified deployment & management console
|
||||
- Deploy components (Backend/Frontend/TelegramBot)
|
||||
- Manage services (Start/Stop/Restart)
|
||||
- Deploy components (Backend/Frontend)
|
||||
- Manage single unified service
|
||||
- Check system status and health
|
||||
|
||||
Install-ROA2WEB.ps1 First-time backend + frontend setup
|
||||
Install-TelegramBot.ps1 First-time Telegram bot setup
|
||||
"@
|
||||
|
||||
if ($ComponentType -eq "All" -or $ComponentType -eq "TelegramBot") {
|
||||
$readme += @"
|
||||
|
||||
Backup-TelegramDB.ps1 Backup Telegram bot database
|
||||
Setup-DailyBackup.ps1 Schedule automated backups
|
||||
Setup-ClaudeAuth.ps1 Configure Claude API credentials
|
||||
"@
|
||||
}
|
||||
|
||||
if ($ComponentType -eq "All" -or $ComponentType -eq "Frontend") {
|
||||
$readme += @"
|
||||
Install-ROA2WEB.ps1 First-time installation (creates Windows service)
|
||||
|
||||
Enable-HTTPS.ps1 Configure HTTPS/SSL certificates
|
||||
"@
|
||||
}
|
||||
|
||||
$readme += @"
|
||||
|
||||
@@ -987,72 +765,50 @@ DEPLOYMENT WORKFLOW
|
||||
|
||||
>> FIRST TIME INSTALLATION:
|
||||
---------------------------
|
||||
"@
|
||||
|
||||
if ($ComponentType -eq "All" -or $ComponentType -eq "Frontend") {
|
||||
$readme += @"
|
||||
|
||||
1. Install Main Application (Backend + Frontend):
|
||||
1. Install Application (creates Windows service):
|
||||
cd scripts
|
||||
.\Install-ROA2WEB.ps1
|
||||
|
||||
2. Configure environment:
|
||||
2. Configure environment (.env file):
|
||||
notepad C:\inetpub\wwwroot\roa2web\backend\.env
|
||||
|
||||
3. Start services using the unified console:
|
||||
IMPORTANT - Configure module flags:
|
||||
MODULE_REPORTS_ENABLED=true # Enable/disable Reports module
|
||||
MODULE_DATA_ENTRY_ENABLED=true # Enable/disable Data Entry module
|
||||
MODULE_TELEGRAM_ENABLED=true # Enable/disable Telegram bot module
|
||||
|
||||
3. Start the unified backend service:
|
||||
Start-Service ROA2WEB-Backend
|
||||
|
||||
OR using console:
|
||||
.\ROA2WEB-Console.ps1
|
||||
(Select: Manage Services > Start All)
|
||||
"@
|
||||
}
|
||||
(Select: Manage Services > Start Service)
|
||||
|
||||
if ($ComponentType -eq "All" -or $ComponentType -eq "TelegramBot") {
|
||||
$readme += @"
|
||||
4. Verify installation:
|
||||
- Backend API: http://localhost:8000/docs
|
||||
- Health check: http://localhost:8000/health
|
||||
- Frontend: http://localhost/ (via IIS)
|
||||
|
||||
|
||||
4. Install Telegram Bot:
|
||||
.\Install-TelegramBot.ps1
|
||||
|
||||
5. Configure Telegram bot:
|
||||
notepad C:\inetpub\wwwroot\roa2web\telegram-bot\.env
|
||||
|
||||
6. Start Telegram bot:
|
||||
.\ROA2WEB-Console.ps1
|
||||
(Select: Manage Services > Start Telegram Bot)
|
||||
"@
|
||||
}
|
||||
|
||||
$readme += @"
|
||||
|
||||
|
||||
>> UPDATES (Interactive Console):
|
||||
>> UPDATES (Deploy New Version):
|
||||
----------------------------------
|
||||
cd scripts
|
||||
.\ROA2WEB-Console.ps1
|
||||
(Select: Deploy Components > choose what to update)
|
||||
.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployAll
|
||||
(Stops service, updates files, restarts service)
|
||||
|
||||
>> UPDATES (Command Line):
|
||||
---------------------------
|
||||
.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployBackend # Update backend + frontend
|
||||
.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployTelegramBot # Update Telegram bot
|
||||
.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployAll # Update everything
|
||||
>> SERVICE MANAGEMENT:
|
||||
-----------------------
|
||||
# Start service
|
||||
Start-Service ROA2WEB-Backend
|
||||
|
||||
>> SERVICE MANAGEMENT (Interactive):
|
||||
-------------------------------------
|
||||
.\ROA2WEB-Console.ps1
|
||||
(Select: Manage Services > choose action)
|
||||
# Stop service
|
||||
Stop-Service ROA2WEB-Backend
|
||||
|
||||
>> SERVICE MANAGEMENT (Command Line):
|
||||
--------------------------------------
|
||||
# Start all services
|
||||
.\ROA2WEB-Console.ps1 -NonInteractive -Action StartAll
|
||||
|
||||
# Stop all services
|
||||
.\ROA2WEB-Console.ps1 -NonInteractive -Action StopAll
|
||||
|
||||
# Restart all services
|
||||
.\ROA2WEB-Console.ps1 -NonInteractive -Action RestartAll
|
||||
# Restart service
|
||||
Restart-Service ROA2WEB-Backend
|
||||
|
||||
# Check status
|
||||
Get-Service ROA2WEB-Backend
|
||||
.\ROA2WEB-Console.ps1 -NonInteractive -Action Status
|
||||
|
||||
================================================================================
|
||||
@@ -1070,12 +826,21 @@ NOTES:
|
||||
- Automatic backup before each update
|
||||
- Default install location: C:\inetpub\wwwroot\roa2web\
|
||||
- Build cache NOT included in this package (stays on build machine)
|
||||
- Single Windows service: ROA2WEB-Backend (manages all modules)
|
||||
|
||||
ARCHITECTURE:
|
||||
-------------
|
||||
ULTRATHIN MONOLITH: One backend process with multiple modules
|
||||
- Modules controlled via .env flags (MODULE_*_ENABLED)
|
||||
- All modules share: Oracle pool, auth, cache
|
||||
- Telegram bot runs as background task (not separate service)
|
||||
|
||||
TROUBLESHOOTING:
|
||||
----------------
|
||||
Backend logs: C:\inetpub\wwwroot\roa2web\logs\
|
||||
Telegram logs: C:\inetpub\wwwroot\roa2web\telegram-bot\logs\
|
||||
Backend logs: C:\inetpub\wwwroot\roa2web\logs\backend-stdout.log
|
||||
C:\inetpub\wwwroot\roa2web\logs\backend-stderr.log
|
||||
IIS logs: C:\inetpub\logs\LogFiles\
|
||||
Service status: Get-Service ROA2WEB-Backend
|
||||
|
||||
For detailed documentation, see: deployment/windows/docs/WINDOWS_DEPLOYMENT.md
|
||||
|
||||
@@ -1109,15 +874,15 @@ function New-DeploymentPackage {
|
||||
# Build based on component type
|
||||
switch ($ComponentType) {
|
||||
"All" {
|
||||
# Reports Frontend
|
||||
# Unified Frontend (Vue.js SPA)
|
||||
$frontendDistPath = Build-Frontend -SourcePath $Paths.FrontendSource -OutputPath $OutputPath
|
||||
$frontendDest = Join-Path $OutputPath "frontend"
|
||||
New-Item -ItemType Directory -Path $frontendDest -Force | Out-Null
|
||||
Write-Step "Copying Reports frontend files..."
|
||||
Write-Step "Copying Unified Frontend files (SPA)..."
|
||||
Copy-Item -Path "$frontendDistPath\*" -Destination $frontendDest -Recurse -Force
|
||||
Write-Success "Reports frontend files copied"
|
||||
Write-Success "Unified Frontend files copied"
|
||||
|
||||
# Reports Backend
|
||||
# Unified Backend (includes Reports, Data Entry, Telegram modules)
|
||||
$backendDest = Join-Path $OutputPath "backend"
|
||||
Copy-BackendFiles -SourcePath $Paths.BackendSource -DestPath $backendDest
|
||||
|
||||
@@ -1128,34 +893,18 @@ function New-DeploymentPackage {
|
||||
# Config templates
|
||||
$configDest = Join-Path $OutputPath "config"
|
||||
Copy-ConfigTemplates -SourcePath $Paths.ConfigSource -DestPath $configDest
|
||||
|
||||
# Telegram Bot
|
||||
$telegramDest = Join-Path $OutputPath "telegram-bot"
|
||||
Copy-TelegramBotFiles -SourcePath $Paths.TelegramBotSource -DestPath $telegramDest
|
||||
|
||||
# Data Entry Frontend
|
||||
$dataEntryFrontendDistPath = Build-Frontend -SourcePath $Paths.DataEntryFrontendSource -OutputPath $OutputPath
|
||||
$dataEntryFrontendDest = Join-Path $OutputPath "data-entry-frontend"
|
||||
New-Item -ItemType Directory -Path $dataEntryFrontendDest -Force | Out-Null
|
||||
Write-Step "Copying Data Entry frontend files..."
|
||||
Copy-Item -Path "$dataEntryFrontendDistPath\*" -Destination $dataEntryFrontendDest -Recurse -Force
|
||||
Write-Success "Data Entry frontend files copied"
|
||||
|
||||
# Data Entry Backend
|
||||
$dataEntryBackendDest = Join-Path $OutputPath "data-entry-backend"
|
||||
Copy-DataEntryBackendFiles -SourcePath $Paths.DataEntryBackendSource -DestPath $dataEntryBackendDest
|
||||
}
|
||||
|
||||
"Frontend" {
|
||||
# Frontend build
|
||||
# Unified Frontend build (Vue.js SPA)
|
||||
$frontendDistPath = Build-Frontend -SourcePath $Paths.FrontendSource -OutputPath $OutputPath
|
||||
$frontendDest = Join-Path $OutputPath "frontend"
|
||||
New-Item -ItemType Directory -Path $frontendDest -Force | Out-Null
|
||||
Write-Step "Copying frontend files..."
|
||||
Write-Step "Copying Unified Frontend files (SPA)..."
|
||||
Copy-Item -Path "$frontendDistPath\*" -Destination $frontendDest -Recurse -Force
|
||||
Write-Success "Frontend files copied"
|
||||
Write-Success "Unified Frontend files copied"
|
||||
|
||||
# Backend
|
||||
# Unified Backend (includes all modules)
|
||||
$backendDest = Join-Path $OutputPath "backend"
|
||||
Copy-BackendFiles -SourcePath $Paths.BackendSource -DestPath $backendDest
|
||||
|
||||
@@ -1169,7 +918,7 @@ function New-DeploymentPackage {
|
||||
}
|
||||
|
||||
"Backend" {
|
||||
# Backend only
|
||||
# Unified Backend only (includes Reports, Data Entry, Telegram modules)
|
||||
$backendDest = Join-Path $OutputPath "backend"
|
||||
Copy-BackendFiles -SourcePath $Paths.BackendSource -DestPath $backendDest
|
||||
|
||||
@@ -1181,52 +930,10 @@ function New-DeploymentPackage {
|
||||
$configDest = Join-Path $OutputPath "config"
|
||||
Copy-ConfigTemplates -SourcePath $Paths.ConfigSource -DestPath $configDest
|
||||
}
|
||||
|
||||
"TelegramBot" {
|
||||
# Telegram Bot only
|
||||
$telegramDest = Join-Path $OutputPath "telegram-bot"
|
||||
Copy-TelegramBotFiles -SourcePath $Paths.TelegramBotSource -DestPath $telegramDest
|
||||
}
|
||||
|
||||
"DataEntryApp" {
|
||||
# Data Entry Frontend build
|
||||
$dataEntryFrontendDistPath = Build-Frontend -SourcePath $Paths.DataEntryFrontendSource -OutputPath $OutputPath
|
||||
$dataEntryFrontendDest = Join-Path $OutputPath "data-entry-frontend"
|
||||
New-Item -ItemType Directory -Path $dataEntryFrontendDest -Force | Out-Null
|
||||
Write-Step "Copying Data Entry frontend files..."
|
||||
Copy-Item -Path "$dataEntryFrontendDistPath\*" -Destination $dataEntryFrontendDest -Recurse -Force
|
||||
Write-Success "Data Entry frontend files copied"
|
||||
|
||||
# Data Entry Backend
|
||||
$dataEntryBackendDest = Join-Path $OutputPath "data-entry-backend"
|
||||
Copy-DataEntryBackendFiles -SourcePath $Paths.DataEntryBackendSource -DestPath $dataEntryBackendDest
|
||||
|
||||
# Shared modules
|
||||
$sharedDest = Join-Path $OutputPath "shared"
|
||||
Copy-SharedModules -SourcePath $Paths.SharedSource -DestPath $sharedDest
|
||||
|
||||
# Config templates
|
||||
$configDest = Join-Path $OutputPath "config"
|
||||
Copy-ConfigTemplates -SourcePath $Paths.ConfigSource -DestPath $configDest
|
||||
}
|
||||
|
||||
"DataEntryBackend" {
|
||||
# Data Entry Backend only
|
||||
$dataEntryBackendDest = Join-Path $OutputPath "data-entry-backend"
|
||||
Copy-DataEntryBackendFiles -SourcePath $Paths.DataEntryBackendSource -DestPath $dataEntryBackendDest
|
||||
|
||||
# Shared modules
|
||||
$sharedDest = Join-Path $OutputPath "shared"
|
||||
Copy-SharedModules -SourcePath $Paths.SharedSource -DestPath $sharedDest
|
||||
|
||||
# Config templates
|
||||
$configDest = Join-Path $OutputPath "config"
|
||||
Copy-ConfigTemplates -SourcePath $Paths.ConfigSource -DestPath $configDest
|
||||
}
|
||||
}
|
||||
|
||||
# Cleanup temporary directories
|
||||
if ($ComponentType -eq "All" -or $ComponentType -eq "Frontend" -or $ComponentType -eq "DataEntryApp") {
|
||||
if ($ComponentType -eq "All" -or $ComponentType -eq "Frontend") {
|
||||
Remove-TempDirectories -OutputPath $OutputPath
|
||||
}
|
||||
|
||||
@@ -1276,14 +983,9 @@ function Main {
|
||||
try {
|
||||
# Resolve paths
|
||||
$paths = @{
|
||||
# Reports App sources
|
||||
# Ultrathin Monolith sources
|
||||
BackendSource = Resolve-FullPath -Path $config.BackendSource
|
||||
FrontendSource = Resolve-FullPath -Path $config.FrontendSource
|
||||
TelegramBotSource = Resolve-FullPath -Path $config.TelegramBotSource
|
||||
# Data Entry App sources
|
||||
DataEntryBackendSource = Resolve-FullPath -Path $config.DataEntryBackendSource
|
||||
DataEntryFrontendSource = Resolve-FullPath -Path $config.DataEntryFrontendSource
|
||||
# Shared sources
|
||||
SharedSource = Resolve-FullPath -Path $config.SharedSource
|
||||
ConfigSource = Resolve-FullPath -Path $config.ConfigSource
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user