#Requires -Version 5.1 <# .SYNOPSIS ERP dev environment startup script .EXAMPLE .\dev.ps1 # Start backend + frontend .\dev.ps1 -Stop # Stop all .\dev.ps1 -Restart # Restart all .\dev.ps1 -Status # Show port status #> param( [switch]$Stop, [switch]$Restart, [switch]$Status ) $BackendPort = 3000 $FrontendPort = 5174 $LogDir = ".logs" # --- find PID using port --- function Find-PortPid([int]$Port) { try { $c = Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction Stop return $c[0].OwningProcess } catch { return $null } } # --- kill process on port --- function Stop-PortProcess([int]$Port, [string]$Label) { $procId = Find-PortPid $Port if ($null -ne $procId) { try { $pName = (Get-Process -Id $procId -ErrorAction SilentlyContinue).ProcessName } catch { $pName = "?" } Write-Host (" {0,-10} port {1} used by PID {2} ({3}), killing..." -f $Label,$Port,$procId,$pName) -ForegroundColor Yellow -NoNewline try { Stop-Process -Id $procId -Force -ErrorAction Stop $w = 0 while (($w -lt 5) -and (Find-PortPid $Port)) { Start-Sleep -Seconds 1; $w++ } if (Find-PortPid $Port) { Write-Host " still in use" -ForegroundColor Red } else { Write-Host " done" -ForegroundColor Green } } catch { Write-Host " failed" -ForegroundColor Red } } else { Write-Host (" {0,-10} port {1} free" -f $Label,$Port) -ForegroundColor Green } } # --- wait for port --- function Wait-PortReady([int]$Port, [int]$TimeoutSeconds = 60) { $sw = [System.Diagnostics.Stopwatch]::StartNew() while ($sw.ElapsedMilliseconds -lt ($TimeoutSeconds * 1000)) { if (Find-PortPid $Port) { return $true } Start-Sleep -Milliseconds 500 } return $false } # --- stop all --- function Stop-Services { Write-Host "" Write-Host "Stopping..." -ForegroundColor Cyan Write-Host "--------------------------------------------------" -ForegroundColor DarkGray foreach ($svc in @("backend","frontend")) { $pidFile = Join-Path $LogDir "$svc.pid" if (Test-Path $pidFile) { $svcId = Get-Content $pidFile -ErrorAction SilentlyContinue if ($svcId -and (Get-Process -Id $svcId -ErrorAction SilentlyContinue)) { $label = if ($svc -eq "backend") { "Backend" } else { "Frontend" } Write-Host " Stopping $label (PID $svcId)..." -ForegroundColor Cyan -NoNewline Stop-Process -Id $svcId -Force -ErrorAction SilentlyContinue Write-Host " done" -ForegroundColor Green } Remove-Item $pidFile -Force -ErrorAction SilentlyContinue } } Stop-PortProcess $BackendPort "Backend" Stop-PortProcess $FrontendPort "Frontend" Write-Host "" Write-Host "Stopped." -ForegroundColor Green } # --- show status --- function Show-Status { Write-Host "" Write-Host "Status:" -ForegroundColor Cyan Write-Host "--------------------------------------------------" -ForegroundColor DarkGray $bp = Find-PortPid $BackendPort if ($null -ne $bp) { Write-Host " " -NoNewline; Write-Host "+" -ForegroundColor Green -NoNewline Write-Host " Backend port $BackendPort PID $bp" Write-Host " http://localhost:$BackendPort/api/v1/health" -ForegroundColor Cyan } else { Write-Host " " -NoNewline; Write-Host "-" -ForegroundColor Red -NoNewline Write-Host " Backend port $BackendPort stopped" } $fp = Find-PortPid $FrontendPort if ($null -ne $fp) { Write-Host " " -NoNewline; Write-Host "+" -ForegroundColor Green -NoNewline Write-Host " Frontend port $FrontendPort PID $fp" Write-Host " http://localhost:$FrontendPort" -ForegroundColor Cyan } else { Write-Host " " -NoNewline; Write-Host "-" -ForegroundColor Red -NoNewline Write-Host " Frontend port $FrontendPort stopped" } Write-Host "" } # --- start all --- function Start-Services { New-Item -ItemType Directory -Path $LogDir -Force | Out-Null Write-Host "" Write-Host "==================================================" -ForegroundColor Cyan Write-Host " ERP Dev Environment Startup" -ForegroundColor Cyan Write-Host "==================================================" -ForegroundColor Cyan Write-Host "" # 1. clean ports Write-Host "[1/3] Checking ports..." -ForegroundColor Cyan Write-Host "--------------------------------------------------" -ForegroundColor DarkGray Stop-PortProcess $BackendPort "Backend" Stop-PortProcess $FrontendPort "Frontend" Write-Host "" # 2. backend Write-Host "[2/3] Starting backend (Axum :$BackendPort)..." -ForegroundColor Cyan Write-Host "--------------------------------------------------" -ForegroundColor DarkGray $backendLog = Join-Path $LogDir "backend.log" $backendErr = Join-Path $LogDir "backend.err" $proc = Start-Process -FilePath "cargo" -ArgumentList "run","-p","erp-server" ` -RedirectStandardOutput $backendLog -RedirectStandardError $backendErr ` -WindowStyle Hidden -PassThru Write-Host " PID: $($proc.Id) log: $backendLog" -ForegroundColor DarkGray Write-Host " Compiling & starting..." -NoNewline if (Wait-PortReady $BackendPort 180) { Write-Host " ready" -ForegroundColor Green } else { Write-Host " timeout (check $backendLog)" -ForegroundColor Yellow } Write-Host "" # 3. frontend Write-Host "[3/3] Starting frontend (Vite :$FrontendPort)..." -ForegroundColor Cyan Write-Host "--------------------------------------------------" -ForegroundColor DarkGray $webDir = Join-Path $PSScriptRoot "apps\web" if (-not (Test-Path (Join-Path $webDir "node_modules"))) { Write-Host " Installing deps..." -ForegroundColor Yellow Push-Location $webDir pnpm install 2>&1 | ForEach-Object { Write-Host " $_" } Pop-Location } $frontendLog = Join-Path $LogDir "frontend.log" $frontendErr = Join-Path $LogDir "frontend.err" $proc = Start-Process -FilePath "cmd.exe" ` -ArgumentList "/c","cd /d `"$webDir`" && pnpm dev" ` -RedirectStandardOutput $frontendLog -RedirectStandardError $frontendErr ` -WindowStyle Hidden -PassThru Write-Host " PID: $($proc.Id) log: $frontendLog" -ForegroundColor DarkGray Write-Host " Starting..." -NoNewline if (Wait-PortReady $FrontendPort 30) { Write-Host " ready" -ForegroundColor Green } else { Write-Host " timeout" -ForegroundColor Red } Write-Host "" # save PIDs (use port-based PID, not Start-Process PID which may be cmd.exe wrapper) $bp = Find-PortPid $BackendPort $fp = Find-PortPid $FrontendPort if ($bp) { $bp | Set-Content (Join-Path $LogDir "backend.pid") } if ($fp) { $fp | Set-Content (Join-Path $LogDir "frontend.pid") } # done Write-Host "==================================================" -ForegroundColor Green Write-Host " All services started!" -ForegroundColor Green Write-Host "==================================================" -ForegroundColor Green Write-Host "" Write-Host " Frontend: http://localhost:$FrontendPort" -ForegroundColor Cyan Write-Host " Backend: http://localhost:$BackendPort/api/v1" -ForegroundColor Cyan Write-Host " Health: http://localhost:$BackendPort/api/v1/health" -ForegroundColor Cyan Write-Host "" Write-Host " Stop: .\dev.ps1 -Stop" -ForegroundColor DarkGray Write-Host " Restart: .\dev.ps1 -Restart" -ForegroundColor DarkGray Write-Host " Status: .\dev.ps1 -Status" -ForegroundColor DarkGray Write-Host "" } # --- entry --- if ($Stop) { Stop-Services } elseif ($Restart) { Stop-Services; Start-Sleep -Seconds 1; Start-Services } elseif ($Status) { Show-Status } else { Start-Services }