- Add deployment/linux/ with deploy.sh for deploying from Claude-Agent LXC to Windows server - Add ServerLogsView.vue for viewing server logs from frontend - Add shared/routes/system.py for system health endpoints - Update CLAUDE.md with quick deploy instructions - Improve Windows deployment scripts (ROA2WEB-Console.ps1) - Fix OCR service validation and worker pool improvements - Update environment config examples - Various script permission and startup fixes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
653 lines
23 KiB
PowerShell
653 lines
23 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
ROA2WEB - Initial Installation Script for Windows Server + IIS
|
|
|
|
.DESCRIPTION
|
|
This script performs complete installation of ROA2WEB on Windows Server:
|
|
- Checks prerequisites (Admin rights, IIS)
|
|
- Installs Python 3.11+ if needed
|
|
- Installs NSSM (service manager)
|
|
- Installs IIS URL Rewrite and ARR modules
|
|
- Creates directory structure
|
|
- Installs Python dependencies
|
|
- Creates Windows Service for backend
|
|
- Configures IIS website
|
|
- Starts all services
|
|
|
|
.PARAMETER InstallPath
|
|
Installation path (default: C:\inetpub\wwwroot\roa2web)
|
|
|
|
.PARAMETER PythonVersion
|
|
Python version to install (default: 3.11.9)
|
|
|
|
.PARAMETER ServicePort
|
|
Backend service port (default: 8000)
|
|
|
|
.PARAMETER SkipPython
|
|
Skip Python installation (use existing Python)
|
|
|
|
.PARAMETER SkipIIS
|
|
Skip IIS configuration
|
|
|
|
.EXAMPLE
|
|
.\Install-ROA2WEB.ps1
|
|
Standard installation with defaults
|
|
|
|
.EXAMPLE
|
|
.\Install-ROA2WEB.ps1 -InstallPath "D:\Apps\roa2web" -ServicePort 8001
|
|
Custom installation path and port
|
|
|
|
.NOTES
|
|
Author: ROA2WEB Team
|
|
Requires: PowerShell 5.1+, Administrator privileges
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[string]$InstallPath = "C:\inetpub\wwwroot\roa2web",
|
|
[string]$PythonVersion = "3.11.9",
|
|
[int]$ServicePort = 8000,
|
|
[string]$IISSiteName = "Default Web Site",
|
|
[string]$IISAppName = "roa2web",
|
|
[switch]$CreateNewSite,
|
|
[switch]$SkipPython,
|
|
[switch]$SkipIIS
|
|
)
|
|
|
|
# Strict error handling
|
|
$ErrorActionPreference = "Stop"
|
|
$ProgressPreference = "SilentlyContinue"
|
|
|
|
# =============================================================================
|
|
# CONFIGURATION
|
|
# =============================================================================
|
|
|
|
$script:Config = @{
|
|
AppName = "ROA2WEB"
|
|
ServiceName = "ROA2WEB-Backend"
|
|
ServiceDisplayName = "ROA2WEB Unified Backend Service"
|
|
ServiceDescription = "Unified FastAPI backend for ROA2WEB ERP - includes Reports, Data Entry, and Telegram modules (Ultrathin Monolith)"
|
|
InstallPath = $InstallPath
|
|
BackendPath = Join-Path $InstallPath "backend"
|
|
FrontendPath = Join-Path $InstallPath "frontend"
|
|
LogsPath = Join-Path $InstallPath "logs"
|
|
TempPath = Join-Path $InstallPath "temp"
|
|
# IMPORTANT: venv is OUTSIDE InstallPath to survive deployments!
|
|
VenvPath = "C:\inetpub\wwwroot\roa2web-venv"
|
|
PythonVersion = $PythonVersion
|
|
ServicePort = $ServicePort
|
|
IISSiteName = $IISSiteName
|
|
IISAppName = $IISAppName
|
|
IISAppPoolName = "ROA2WEB-AppPool"
|
|
CreateNewSite = $CreateNewSite
|
|
}
|
|
|
|
# =============================================================================
|
|
# HELPER FUNCTIONS
|
|
# =============================================================================
|
|
|
|
function Write-Step {
|
|
param([string]$Message)
|
|
Write-Host "`n[*] $Message" -ForegroundColor Cyan
|
|
}
|
|
|
|
function Write-Success {
|
|
param([string]$Message)
|
|
Write-Host " [OK] $Message" -ForegroundColor Green
|
|
}
|
|
|
|
function Write-Error {
|
|
param([string]$Message)
|
|
Write-Host " [ERROR] $Message" -ForegroundColor Red
|
|
}
|
|
|
|
function Write-Warning {
|
|
param([string]$Message)
|
|
Write-Host " [WARN] $Message" -ForegroundColor Yellow
|
|
}
|
|
|
|
function Test-Administrator {
|
|
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
$principal = [Security.Principal.WindowsPrincipal]$identity
|
|
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
|
}
|
|
|
|
function Test-CommandExists {
|
|
param([string]$Command)
|
|
try {
|
|
if (Get-Command $Command -ErrorAction Stop) {
|
|
return $true
|
|
}
|
|
} catch {
|
|
return $false
|
|
}
|
|
}
|
|
|
|
function Install-Chocolatey {
|
|
Write-Step "Installing Chocolatey package manager..."
|
|
|
|
if (Test-CommandExists "choco") {
|
|
Write-Success "Chocolatey already installed"
|
|
return
|
|
}
|
|
|
|
try {
|
|
Set-ExecutionPolicy Bypass -Scope Process -Force
|
|
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
|
|
Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
|
|
|
|
# Refresh environment
|
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
|
|
|
Write-Success "Chocolatey installed successfully"
|
|
} catch {
|
|
throw "Failed to install Chocolatey: $_"
|
|
}
|
|
}
|
|
|
|
function Install-Python {
|
|
Write-Step "Checking Python installation..."
|
|
|
|
if ($SkipPython) {
|
|
Write-Warning "Skipping Python installation (as requested)"
|
|
return
|
|
}
|
|
|
|
# Check if Python is already installed
|
|
try {
|
|
$pythonCmd = Get-Command python -ErrorAction Stop
|
|
$pythonVersionOutput = & python --version 2>&1
|
|
if ($pythonVersionOutput -match "Python (\d+\.\d+\.\d+)") {
|
|
$installedVersion = $matches[1]
|
|
Write-Success "Python $installedVersion already installed at $($pythonCmd.Source)"
|
|
return
|
|
}
|
|
} catch {
|
|
Write-Warning "Python not found, will install..."
|
|
}
|
|
|
|
# Install Python via Chocolatey
|
|
Write-Step "Installing Python $PythonVersion..."
|
|
try {
|
|
choco install python --version=$PythonVersion -y --force
|
|
|
|
# Refresh environment
|
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
|
|
|
Write-Success "Python $PythonVersion installed successfully"
|
|
} catch {
|
|
throw "Failed to install Python: $_"
|
|
}
|
|
}
|
|
|
|
function Install-NSSM {
|
|
Write-Step "Installing NSSM (service manager)..."
|
|
|
|
if (Test-Path "C:\nssm\nssm.exe") {
|
|
Write-Success "NSSM already installed"
|
|
return
|
|
}
|
|
|
|
try {
|
|
choco install nssm -y
|
|
Write-Success "NSSM installed successfully"
|
|
} catch {
|
|
throw "Failed to install NSSM: $_"
|
|
}
|
|
}
|
|
|
|
function Install-IISModules {
|
|
if ($SkipIIS) {
|
|
Write-Warning "Skipping IIS configuration (as requested)"
|
|
return
|
|
}
|
|
|
|
Write-Step "Checking IIS installation..."
|
|
|
|
# Detect OS type (Server vs Desktop)
|
|
$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
|
|
$isServer = $osInfo.ProductType -eq 3 # 1=Workstation, 2=Domain Controller, 3=Server
|
|
|
|
# Check if IIS is installed (different cmdlets for Server vs Desktop)
|
|
$iisInstalled = $false
|
|
|
|
if ($isServer) {
|
|
# Windows Server - use Get-WindowsFeature
|
|
$iisFeature = Get-WindowsFeature -Name Web-Server -ErrorAction SilentlyContinue
|
|
$iisInstalled = $iisFeature -and $iisFeature.InstallState -eq "Installed"
|
|
|
|
if (-not $iisInstalled) {
|
|
Write-Error "IIS is not installed. Please install IIS first:"
|
|
Write-Host " Install-WindowsFeature -Name Web-Server -IncludeManagementTools" -ForegroundColor Yellow
|
|
throw "IIS not installed"
|
|
}
|
|
} else {
|
|
# Windows Desktop (10/11) - use Get-WindowsOptionalFeature
|
|
$iisFeature = Get-WindowsOptionalFeature -Online -FeatureName IIS-WebServer -ErrorAction SilentlyContinue
|
|
$iisInstalled = $iisFeature -and $iisFeature.State -eq "Enabled"
|
|
|
|
if (-not $iisInstalled) {
|
|
Write-Error "IIS is not installed. Please install IIS first:"
|
|
Write-Host " Enable-WindowsOptionalFeature -Online -FeatureName IIS-WebServer -All" -ForegroundColor Yellow
|
|
Write-Host " Or use: Control Panel -> Programs -> Turn Windows features on/off -> Internet Information Services" -ForegroundColor Yellow
|
|
throw "IIS not installed"
|
|
}
|
|
}
|
|
|
|
Write-Success "IIS is installed ($($osInfo.Caption))"
|
|
|
|
# Install URL Rewrite Module
|
|
Write-Step "Installing IIS URL Rewrite Module..."
|
|
$urlRewriteInstalled = Get-WebConfiguration -Filter "/system.webServer/rewrite" -PSPath "IIS:\" -ErrorAction SilentlyContinue
|
|
|
|
if (-not $urlRewriteInstalled) {
|
|
Write-Warning "URL Rewrite not found, installing..."
|
|
try {
|
|
$urlRewriteUrl = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_en-US.msi"
|
|
$urlRewritePath = "$env:TEMP\rewrite_amd64.msi"
|
|
|
|
Invoke-WebRequest -Uri $urlRewriteUrl -OutFile $urlRewritePath
|
|
Start-Process msiexec.exe -ArgumentList "/i", $urlRewritePath, "/quiet", "/norestart" -Wait
|
|
Remove-Item $urlRewritePath -Force
|
|
|
|
Write-Success "URL Rewrite Module installed"
|
|
} catch {
|
|
Write-Error "Failed to install URL Rewrite: $_"
|
|
Write-Warning "You can download it manually from: https://www.iis.net/downloads/microsoft/url-rewrite"
|
|
}
|
|
} else {
|
|
Write-Success "URL Rewrite Module already installed"
|
|
}
|
|
|
|
# Install Application Request Routing (ARR)
|
|
Write-Step "Checking Application Request Routing (ARR)..."
|
|
try {
|
|
choco install iis-arr -y
|
|
Write-Success "ARR installed successfully"
|
|
} catch {
|
|
Write-Warning "Could not install ARR via Chocolatey. Download manually from: https://www.iis.net/downloads/microsoft/application-request-routing"
|
|
}
|
|
}
|
|
|
|
function New-DirectoryStructure {
|
|
Write-Step "Creating directory structure..."
|
|
|
|
$directories = @(
|
|
$Config.InstallPath,
|
|
$Config.BackendPath,
|
|
$Config.FrontendPath,
|
|
$Config.LogsPath,
|
|
$Config.TempPath,
|
|
(Join-Path $Config.BackendPath "logs"),
|
|
(Join-Path $Config.BackendPath "temp")
|
|
)
|
|
|
|
foreach ($dir in $directories) {
|
|
if (-not (Test-Path $dir)) {
|
|
New-Item -ItemType Directory -Path $dir -Force | Out-Null
|
|
Write-Success "Created: $dir"
|
|
} else {
|
|
Write-Success "Already exists: $dir"
|
|
}
|
|
}
|
|
|
|
# Set permissions (IIS user needs read access)
|
|
try {
|
|
$acl = Get-Acl $Config.InstallPath
|
|
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule("IIS_IUSRS", "ReadAndExecute", "ContainerInherit,ObjectInherit", "None", "Allow")
|
|
$acl.SetAccessRule($accessRule)
|
|
Set-Acl -Path $Config.InstallPath -AclObject $acl
|
|
Write-Success "Permissions set for IIS_IUSRS"
|
|
} catch {
|
|
Write-Warning "Could not set permissions: $_"
|
|
}
|
|
}
|
|
|
|
function Install-PythonDependencies {
|
|
Write-Step "Setting up Python virtual environment..."
|
|
|
|
$requirementsPath = Join-Path $Config.BackendPath "requirements.txt"
|
|
$venvPath = $Config.VenvPath
|
|
$venvPython = Join-Path $venvPath "Scripts\python.exe"
|
|
$venvPip = Join-Path $venvPath "Scripts\pip.exe"
|
|
|
|
# Create venv if it doesn't exist
|
|
if (-not (Test-Path $venvPython)) {
|
|
Write-Step "Creating virtual environment at $venvPath..."
|
|
try {
|
|
& python -m venv $venvPath
|
|
Write-Success "Virtual environment created"
|
|
} catch {
|
|
throw "Failed to create virtual environment: $_"
|
|
}
|
|
} else {
|
|
Write-Success "Virtual environment already exists"
|
|
}
|
|
|
|
# Upgrade pip in venv
|
|
Write-Step "Upgrading pip in virtual environment..."
|
|
try {
|
|
& $venvPython -m pip install --upgrade pip
|
|
Write-Success "Pip upgraded"
|
|
} catch {
|
|
Write-Warning "Could not upgrade pip: $_"
|
|
}
|
|
|
|
# Install dependencies
|
|
if (-not (Test-Path $requirementsPath)) {
|
|
Write-Warning "requirements.txt not found at $requirementsPath"
|
|
Write-Warning "Please copy backend files first, then run this script again"
|
|
return
|
|
}
|
|
|
|
Write-Step "Installing Python dependencies in virtual environment..."
|
|
try {
|
|
& $venvPip install -r $requirementsPath
|
|
Write-Success "Python dependencies installed successfully in venv"
|
|
} catch {
|
|
throw "Failed to install Python dependencies: $_"
|
|
}
|
|
}
|
|
|
|
function New-WindowsService {
|
|
Write-Step "Creating Windows Service for backend..."
|
|
|
|
# Check if service already exists using nssm (more reliable than Get-Service)
|
|
# Temporarily disable error action to check service status
|
|
$oldErrorAction = $ErrorActionPreference
|
|
$ErrorActionPreference = "SilentlyContinue"
|
|
|
|
$nssmOutput = & nssm status $Config.ServiceName 2>&1
|
|
$serviceExists = $LASTEXITCODE -eq 0
|
|
|
|
$ErrorActionPreference = $oldErrorAction
|
|
|
|
if ($serviceExists) {
|
|
Write-Warning "Service already exists, stopping and removing..."
|
|
|
|
# Check service status
|
|
$status = & nssm status $Config.ServiceName 2>&1
|
|
|
|
# Only try to stop if service is running
|
|
if ($status -match "SERVICE_RUNNING") {
|
|
Write-Step "Stopping running service..."
|
|
& nssm stop $Config.ServiceName 2>&1 | Out-Null
|
|
Start-Sleep -Seconds 2
|
|
} else {
|
|
Write-Step "Service is not running (status: $status)"
|
|
}
|
|
|
|
# Force remove service
|
|
& nssm remove $Config.ServiceName confirm 2>&1 | Out-Null
|
|
Start-Sleep -Seconds 2
|
|
Write-Success "Existing service removed"
|
|
}
|
|
|
|
# Get Python path from venv
|
|
$venvPython = Join-Path $Config.VenvPath "Scripts\python.exe"
|
|
|
|
if (-not (Test-Path $venvPython)) {
|
|
throw "Virtual environment Python not found at $venvPython. Run Install-PythonDependencies first."
|
|
}
|
|
|
|
$uvicornModule = "uvicorn"
|
|
$appModule = "main:app"
|
|
|
|
# NSSM service creation
|
|
try {
|
|
# Install service using venv Python
|
|
# NOTE: Using --workers 1 because Telegram bot requires single instance (polling conflict)
|
|
& nssm install $Config.ServiceName $venvPython "-m" $uvicornModule $appModule "--host" "127.0.0.1" "--port" $Config.ServicePort.ToString() "--workers" "1"
|
|
|
|
# Set service configuration
|
|
& nssm set $Config.ServiceName DisplayName $Config.ServiceDisplayName
|
|
& nssm set $Config.ServiceName Description $Config.ServiceDescription
|
|
& nssm set $Config.ServiceName Start SERVICE_AUTO_START
|
|
& nssm set $Config.ServiceName AppDirectory $Config.BackendPath
|
|
|
|
# Set environment variables (PYTHONPATH for shared modules)
|
|
# Point to the installation root AND backend/ so both shared/ and app/ modules can be imported
|
|
$pythonPathRoot = $Config.InstallPath
|
|
$pythonPathBackend = $Config.BackendPath
|
|
& nssm set $Config.ServiceName AppEnvironmentExtra "PYTHONPATH=$pythonPathRoot;$pythonPathBackend"
|
|
|
|
# Set logging
|
|
$stdoutLog = Join-Path $Config.LogsPath "backend-stdout.log"
|
|
$stderrLog = Join-Path $Config.LogsPath "backend-stderr.log"
|
|
& nssm set $Config.ServiceName AppStdout $stdoutLog
|
|
& nssm set $Config.ServiceName AppStderr $stderrLog
|
|
& nssm set $Config.ServiceName AppStdoutCreationDisposition 4
|
|
& nssm set $Config.ServiceName AppStderrCreationDisposition 4
|
|
|
|
# Set restart policy
|
|
& nssm set $Config.ServiceName AppExit Default Restart
|
|
& nssm set $Config.ServiceName AppRestartDelay 5000
|
|
|
|
Write-Success "Windows Service created successfully"
|
|
} catch {
|
|
throw "Failed to create Windows Service: $_"
|
|
}
|
|
}
|
|
|
|
function Initialize-IISWebsite {
|
|
if ($SkipIIS) {
|
|
Write-Warning "Skipping IIS website configuration (as requested)"
|
|
return
|
|
}
|
|
|
|
Write-Step "Configuring IIS application..."
|
|
|
|
Import-Module WebAdministration -ErrorAction Stop
|
|
|
|
# Remove existing app pool if present
|
|
if (Test-Path "IIS:\AppPools\$($Config.IISAppPoolName)") {
|
|
Write-Warning "Removing existing app pool..."
|
|
Remove-WebAppPool -Name $Config.IISAppPoolName -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
# Create Application Pool
|
|
Write-Step "Creating IIS Application Pool..."
|
|
New-WebAppPool -Name $Config.IISAppPoolName -Force | Out-Null
|
|
Set-ItemProperty -Path "IIS:\AppPools\$($Config.IISAppPoolName)" -Name "managedRuntimeVersion" -Value ""
|
|
Write-Success "Application Pool created: $($Config.IISAppPoolName)"
|
|
|
|
if ($CreateNewSite) {
|
|
# Create new website (old behavior)
|
|
Write-Step "Creating new IIS Website..."
|
|
|
|
# Stop default website if running
|
|
try {
|
|
Stop-Website -Name "Default Web Site" -ErrorAction SilentlyContinue
|
|
Write-Success "Stopped Default Web Site"
|
|
} catch {
|
|
Write-Warning "Could not stop Default Web Site: $_"
|
|
}
|
|
|
|
# Remove existing site if present
|
|
if (Get-Website -Name $Config.IISSiteName -ErrorAction SilentlyContinue) {
|
|
Write-Warning "Removing existing website..."
|
|
Remove-Website -Name $Config.IISSiteName -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
New-Website -Name $Config.IISSiteName `
|
|
-PhysicalPath $Config.FrontendPath `
|
|
-ApplicationPool $Config.IISAppPoolName `
|
|
-Port 80 `
|
|
-Force | Out-Null
|
|
|
|
Write-Success "Website created: $($Config.IISSiteName)"
|
|
|
|
# Start website
|
|
Start-Website -Name $Config.IISSiteName
|
|
Write-Success "Website started: $($Config.IISSiteName)"
|
|
} else {
|
|
# Create application under existing site (default behavior)
|
|
Write-Step "Creating IIS Application under '$($Config.IISSiteName)'..."
|
|
|
|
# Verify parent site exists
|
|
$parentSite = Get-Website -Name $Config.IISSiteName -ErrorAction SilentlyContinue
|
|
if (-not $parentSite) {
|
|
throw "Parent website '$($Config.IISSiteName)' does not exist. Use -CreateNewSite to create a new site."
|
|
}
|
|
|
|
# Remove existing application if present
|
|
$existingApp = Get-WebApplication -Name $Config.IISAppName -Site $Config.IISSiteName -ErrorAction SilentlyContinue
|
|
if ($existingApp) {
|
|
Write-Warning "Removing existing application..."
|
|
Remove-WebApplication -Name $Config.IISAppName -Site $Config.IISSiteName -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
# Create application
|
|
New-WebApplication -Name $Config.IISAppName `
|
|
-Site $Config.IISSiteName `
|
|
-PhysicalPath $Config.FrontendPath `
|
|
-ApplicationPool $Config.IISAppPoolName `
|
|
-Force | Out-Null
|
|
|
|
Write-Success "Application created: /$($Config.IISAppName) under $($Config.IISSiteName)"
|
|
}
|
|
|
|
# Copy web.config to frontend path
|
|
$webConfigSource = Join-Path $PSScriptRoot "..\config\web.config"
|
|
$webConfigDest = Join-Path $Config.FrontendPath "web.config"
|
|
|
|
if (Test-Path $webConfigSource) {
|
|
Copy-Item -Path $webConfigSource -Destination $webConfigDest -Force
|
|
Write-Success "web.config copied to frontend path"
|
|
} else {
|
|
Write-Warning "web.config not found at $webConfigSource"
|
|
}
|
|
}
|
|
|
|
function Start-Services {
|
|
Write-Step "Starting services..."
|
|
|
|
# Start backend service
|
|
try {
|
|
Start-Service -Name $Config.ServiceName
|
|
Start-Sleep -Seconds 3
|
|
|
|
$service = Get-Service -Name $Config.ServiceName
|
|
if ($service.Status -eq "Running") {
|
|
Write-Success "Backend service started successfully"
|
|
} else {
|
|
Write-Error "Backend service failed to start (Status: $($service.Status))"
|
|
}
|
|
} catch {
|
|
Write-Error "Failed to start backend service: $_"
|
|
}
|
|
|
|
# Test backend health
|
|
Write-Step "Testing backend health..."
|
|
Start-Sleep -Seconds 5
|
|
|
|
try {
|
|
$response = Invoke-WebRequest -Uri "http://localhost:$($Config.ServicePort)/health" -UseBasicParsing -TimeoutSec 10
|
|
if ($response.StatusCode -eq 200) {
|
|
Write-Success "Backend health check passed"
|
|
}
|
|
} catch {
|
|
Write-Warning "Backend health check failed (may need time to start): $_"
|
|
}
|
|
}
|
|
|
|
function Show-Summary {
|
|
Write-Host "`n" + ("=" * 80) -ForegroundColor Cyan
|
|
Write-Host " ROA2WEB INSTALLATION COMPLETED" -ForegroundColor Green
|
|
Write-Host ("=" * 80) -ForegroundColor Cyan
|
|
|
|
Write-Host "`nInstallation Details:" -ForegroundColor Yellow
|
|
Write-Host " Install Path: $($Config.InstallPath)"
|
|
Write-Host " Backend Path: $($Config.BackendPath)"
|
|
Write-Host " Virtual Env: $($Config.VenvPath)"
|
|
Write-Host " Frontend Path: $($Config.FrontendPath)"
|
|
Write-Host " Service Name: $($Config.ServiceName)"
|
|
Write-Host " Service Port: $($Config.ServicePort)"
|
|
Write-Host " IIS Site: $($Config.IISSiteName)"
|
|
|
|
Write-Host "`nAccess Points:" -ForegroundColor Yellow
|
|
if ($Config.CreateNewSite) {
|
|
Write-Host " Web Application: http://localhost"
|
|
} else {
|
|
Write-Host " Web Application: http://localhost/$($Config.IISAppName)"
|
|
}
|
|
Write-Host " API Backend: http://localhost:$($Config.ServicePort)"
|
|
Write-Host " API Docs: http://localhost:$($Config.ServicePort)/docs"
|
|
Write-Host " Health Check: http://localhost:$($Config.ServicePort)/health"
|
|
|
|
Write-Host "`nNext Steps:" -ForegroundColor Yellow
|
|
Write-Host " 1. Copy backend files to: $($Config.BackendPath)"
|
|
Write-Host " 2. Copy frontend files to: $($Config.FrontendPath)"
|
|
Write-Host " 3. Configure .env file at: $($Config.BackendPath)\.env"
|
|
Write-Host ""
|
|
Write-Host " IMPORTANT - Module Control Flags in .env:" -ForegroundColor Cyan
|
|
Write-Host " MODULE_REPORTS_ENABLED=true # Enable/disable Reports module"
|
|
Write-Host " MODULE_DATA_ENTRY_ENABLED=true # Enable/disable Data Entry module"
|
|
Write-Host " MODULE_TELEGRAM_ENABLED=true # Enable/disable Telegram bot module"
|
|
Write-Host ""
|
|
Write-Host " 4. Start service: Start-Service $($Config.ServiceName)"
|
|
|
|
Write-Host "`nManagement Commands:" -ForegroundColor Yellow
|
|
Write-Host " Start Service: Start-Service $($Config.ServiceName)"
|
|
Write-Host " Stop Service: Stop-Service $($Config.ServiceName)"
|
|
Write-Host " Restart Service: Restart-Service $($Config.ServiceName)"
|
|
Write-Host " View Logs: Get-Content $($Config.LogsPath)\backend-stdout.log -Tail 50"
|
|
Write-Host " Check Status: Get-Service $($Config.ServiceName)"
|
|
|
|
Write-Host "`nArchitecture:" -ForegroundColor Yellow
|
|
Write-Host " ULTRATHIN MONOLITH - Single Windows service with multiple modules"
|
|
Write-Host " All modules share Oracle pool, auth, and cache"
|
|
Write-Host " Telegram bot runs as background task (not separate service)"
|
|
|
|
Write-Host "`n" + ("=" * 80) -ForegroundColor Cyan
|
|
}
|
|
|
|
# =============================================================================
|
|
# MAIN INSTALLATION FLOW
|
|
# =============================================================================
|
|
|
|
function Main {
|
|
Write-Host @"
|
|
|
|
====================================================================
|
|
ROA2WEB - Windows Server Installation Script
|
|
Modern ERP Reports Application with FastAPI + Vue.js + IIS
|
|
====================================================================
|
|
|
|
"@ -ForegroundColor Cyan
|
|
|
|
# Check prerequisites
|
|
Write-Step "Checking prerequisites..."
|
|
|
|
if (-not (Test-Administrator)) {
|
|
Write-Error "This script must be run as Administrator"
|
|
Write-Host " Right-click PowerShell and select 'Run as Administrator'" -ForegroundColor Yellow
|
|
exit 1
|
|
}
|
|
Write-Success "Running as Administrator"
|
|
|
|
try {
|
|
# Installation steps
|
|
Install-Chocolatey
|
|
Install-Python
|
|
Install-NSSM
|
|
Install-IISModules
|
|
New-DirectoryStructure
|
|
Install-PythonDependencies
|
|
New-WindowsService
|
|
Initialize-IISWebsite
|
|
Start-Services
|
|
Show-Summary
|
|
|
|
Write-Host "`nInstallation completed successfully!" -ForegroundColor Green
|
|
|
|
} catch {
|
|
Write-Host "`n[FATAL ERROR] Installation failed: $_" -ForegroundColor Red
|
|
Write-Host $_.ScriptStackTrace -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
# Run main installation
|
|
Main
|