[CmdletBinding()] param( [int]$WebPort = 8083, [int]$ApiPort = 8082 ) $ErrorActionPreference = "Stop" $projectRoot = Split-Path -Parent $PSScriptRoot $runtimeRoot = Join-Path $projectRoot "runtime" $backendRuntime = Join-Path $runtimeRoot "backend" $frontendRuntime = Join-Path $runtimeRoot "frontend" $binRoot = Join-Path $projectRoot "bin" New-Item -ItemType Directory -Force -Path $backendRuntime, $frontendRuntime | Out-Null $bootIDPath = Join-Path $backendRuntime "boot-id.txt" if (-not (Test-Path -LiteralPath $bootIDPath)) { [System.IO.File]::WriteAllText($bootIDPath, ([guid]::NewGuid().ToString() + [Environment]::NewLine)) } $env:TERA_API_LISTEN_ADDR = "127.0.0.1:$ApiPort" $env:TERA_API_ALLOW_MOCK_ACTORS = "true" $env:TERA_API_PORT_SERVICES_ENABLED = "false" $env:TERA_API_DIAGNOSTICS_ENABLED = "false" $env:TERA_API_LOG_SCHEDULER_ENABLED = "false" $env:TERA_API_PASSWORD_KDF = "pbkdf2-hmac-sha256" $env:TERA_API_CONFIG_STORE = Join-Path $backendRuntime "config.json" $env:TERA_API_OPERATION_STORE = Join-Path $backendRuntime "operations.json" $env:TERA_API_AUTH_STORE = Join-Path $backendRuntime "auth.json" $env:TERA_API_SESSION_STORE = Join-Path $backendRuntime "sessions.json" $env:TERA_API_LOGIN_FAILURE_STORE = Join-Path $backendRuntime "login-failures.json" $env:TERA_API_SECRET_STORE = Join-Path $backendRuntime "secrets.json" $env:TERA_API_AUDIT_LOG = Join-Path $backendRuntime "audit.json" $env:TERA_API_SYSTEM_LOG_STORE = Join-Path $backendRuntime "system-logs.json" $env:TERA_API_PORT_LOG_STORE = Join-Path $backendRuntime "port-logs.json" $env:TERA_API_LINK_LOG_STORE = Join-Path $backendRuntime "link-logs.json" $env:TERA_API_TLS_STORE = Join-Path $backendRuntime "tls\library" $env:TERA_API_TLS_ACTIVE_CERT = Join-Path $backendRuntime "tls\active.crt" $env:TERA_API_TLS_ACTIVE_KEY = Join-Path $backendRuntime "tls\active.key" $env:TERA_API_BOOT_ID_PATH = $bootIDPath $env:TERA_API_BOOT_MARKER_PATH = Join-Path $backendRuntime "last-boot-id.txt" $backendExe = Join-Path $binRoot "tera-api.exe" $frontendExe = Join-Path $binRoot "tera-web.exe" $goCommand = Get-Command go -ErrorAction SilentlyContinue if (Test-Path -LiteralPath $backendExe) { $backendFile = $backendExe $backendArguments = @() } elseif ($goCommand) { $backendFile = $goCommand.Source $backendArguments = @("run", "-mod=vendor", "-buildvcs=false", "./cmd/tera-api") } else { throw "bin\tera-api.exe is missing and Go was not found on PATH." } $backendStartOptions = @{ FilePath = $backendFile WorkingDirectory = Join-Path $projectRoot "backend" RedirectStandardOutput = Join-Path $backendRuntime "stdout.log" RedirectStandardError = Join-Path $backendRuntime "stderr.log" WindowStyle = "Hidden" PassThru = $true } if ($backendArguments.Count -gt 0) { $backendStartOptions.ArgumentList = $backendArguments } $backendProcess = Start-Process @backendStartOptions try { $ready = $false for ($attempt = 0; $attempt -lt 60; $attempt++) { if ($backendProcess.HasExited) { throw "The backend exited during startup. Check runtime\backend\stderr.log." } try { Invoke-WebRequest -UseBasicParsing -Uri "http://127.0.0.1:$ApiPort/api/v1/auth/login-policy" -TimeoutSec 1 | Out-Null $ready = $true break } catch { Start-Sleep -Milliseconds 500 } } if (-not $ready) { throw "Timed out while waiting for the backend." } $env:PORT = "$WebPort" $env:TERACLONE_API_UPSTREAM = "http://127.0.0.1:$ApiPort" $env:TERACLONE_DB_PATH = Join-Path $frontendRuntime "frontend.db" Write-Host "TERA Clone Demo: http://127.0.0.1:$WebPort" Write-Host "Login: admin / mock-admin-secret" Write-Host "Press Ctrl+C to stop both services." if (Test-Path -LiteralPath $frontendExe) { & $frontendExe } elseif ($goCommand) { Push-Location (Join-Path $projectRoot "frontend") try { & $goCommand.Source run -buildvcs=false ./cmd/server } finally { Pop-Location } } else { throw "bin\tera-web.exe is missing and Go was not found on PATH." } } finally { if ($backendProcess -and -not $backendProcess.HasExited) { Stop-Process -Id $backendProcess.Id -Force } }