<# AZA – Step 12 Fix: Start LOCAL backend with tokens from deploy\.env (no manual edits) What it does: - Loads deploy\.env - Sets process env: MEDWORK_API_TOKENS / MEDWORK_API_TOKEN (as present in .env) - Attempts to start uvicorn with common app module paths: 1) app:app 2) backend.main:app 3) main:app - Binds to 127.0.0.1:8000 Run from project root: powershell -ExecutionPolicy Bypass -File .\deploy\run_backend_local_with_env.ps1 Then re-run authorized test: cd .\deploy powershell -ExecutionPolicy Bypass -File .\authorized_test.ps1 #> [CmdletBinding()] param( [string]$EnvFile = ".\deploy\.env", [string]$BindHost = "127.0.0.1", [int]$Port = 8000 ) function Load-DotEnv([string]$Path) { if (-not (Test-Path -LiteralPath $Path)) { throw "Missing .env file at: $Path" } $map = @{} Get-Content -LiteralPath $Path | ForEach-Object { $line = $_.Trim() if ($line.Length -eq 0) { return } if ($line.StartsWith("#")) { return } $idx = $line.IndexOf("=") if ($idx -lt 1) { return } $k = $line.Substring(0, $idx).Trim() $v = $line.Substring($idx + 1).Trim() if (($v.StartsWith('"') -and $v.EndsWith('"')) -or ($v.StartsWith("'") -and $v.EndsWith("'"))) { $v = $v.Substring(1, $v.Length - 2) } $map[$k] = $v } return $map } Write-Host "[AZA] Start local backend with env from $EnvFile" try { $envMap = Load-DotEnv $EnvFile } catch { Write-Host "❌ $($_.Exception.Message)" exit 1 } if ($envMap.ContainsKey("MEDWORK_API_TOKENS")) { $env:MEDWORK_API_TOKENS = $envMap["MEDWORK_API_TOKENS"] Write-Host " MEDWORK_API_TOKENS: set" } elseif ($envMap.ContainsKey("MEDWORK_API_TOKEN")) { $env:MEDWORK_API_TOKEN = $envMap["MEDWORK_API_TOKEN"] Write-Host " MEDWORK_API_TOKEN: set" } else { Write-Host "❌ No MEDWORK_API_TOKENS or MEDWORK_API_TOKEN found in $EnvFile" exit 1 } # AZA secret key requirement: # Prefer AZA_SECRET_KEY from .env; otherwise enable dev-mode auto-generated key. if ($envMap.ContainsKey("AZA_SECRET_KEY") -and $envMap["AZA_SECRET_KEY"].Trim().Length -ge 32) { $env:AZA_SECRET_KEY = $envMap["AZA_SECRET_KEY"] Write-Host " AZA_SECRET_KEY: set (from .env)" } else { $env:AZA_ENV = "dev" Write-Host " AZA_ENV: dev (AZA_SECRET_KEY not present/too short in .env)" } # Optional: keep build leak-free if your backend uses AZA_BUILD if ($envMap.ContainsKey("AZA_BUILD")) { $env:AZA_BUILD = $envMap["AZA_BUILD"] } Write-Host " Binding: http://$BindHost`:$Port" Write-Host "" $preferredTarget = "workforce_planner.api.app:app" $candidates = @($preferredTarget, "app:app", "backend.main:app", "main:app") function Try-Start([string]$target) { Write-Host "Trying: uvicorn $target --host $BindHost --port $Port" # Use python -m uvicorn to avoid PATH issues & python -m uvicorn $target --host $BindHost --port $Port if ($LASTEXITCODE -eq 0) { return $true } return $false } Write-Host "NOTE: This will run the server in the foreground. Leave this window open while testing." Write-Host "" function Try-StartFile([string]$filePath) { Write-Host "Trying: python $filePath" & python $filePath if ($LASTEXITCODE -eq 0) { return $true } return $false } function To-ModulePath([string]$filePath) { $p = $filePath.Replace("\", "/") if ($p.StartsWith("./")) { $p = $p.Substring(2) } if ($p.EndsWith(".py")) { $p = $p.Substring(0, $p.Length - 3) } return ($p -replace "/", ".") } function Repo-FastApiCandidates { $paths = @( "main.py", "backend\main.py", "backend\app.py", "server.py", "api.py", "asgi.py", "app.py", "app\main.py", "src\main.py", "src\backend\main.py", "aza_backend\main.py", "aza\main.py" ) $found = @() foreach ($p in $paths) { if (Test-Path -LiteralPath $p) { $found += $p } } # If nothing found, do a shallow-ish search (PS5.1 compatible) for common entry filenames if ($found.Count -eq 0) { $filters = @("main.py","app.py","server.py","api.py","asgi.py") try { $root = (Resolve-Path .).Path $all = Get-ChildItem -Path . -Recurse -File -ErrorAction SilentlyContinue | Where-Object { $filters -contains $_.Name } foreach ($fi in $all) { # approximate depth by counting separators in relative path $rel = Resolve-Path $fi.FullName -Relative $sepCount = ($rel.ToString().Split(@("\","/")) | Where-Object { $_ -ne "." -and $_ -ne "" }).Count - 1 if ($sepCount -le 3) { $found += $rel } } } catch { } } # de-dup return ($found | Select-Object -Unique) } # 1) Try preferred known target first (your repo) Write-Host "Preferred target: $preferredTarget" Write-Host "" foreach ($t in $candidates) { $ok = Try-Start $t if ($ok) { exit 0 } Write-Host " (failed) $t" Write-Host "" } # 2) Try repo-discovered file candidates $files = Repo-FastApiCandidates Write-Host "Discovered candidate backend files: $($files.Count)" if ($files.Count -gt 0) { $files | ForEach-Object { Write-Host " - $_" } } else { Write-Host " (none found within ~3 levels for: main.py/app.py/server.py/api.py/asgi.py)" } Write-Host "" if ($files.Count -gt 0) { foreach ($f in $files) { # First: try running the file directly (in case it self-starts uvicorn) $okFile = Try-StartFile $f if ($okFile) { exit 0 } Write-Host " (failed) python $f" Write-Host "" # Second: try uvicorn with module:app $mod = To-ModulePath $f $target = "$mod`:app" $ok = Try-Start $target if ($ok) { exit 0 } Write-Host " (failed) $target" Write-Host "" } } Write-Host "FAIL Could not start uvicorn with known module targets." Write-Host "Checked module candidates:" $candidates | ForEach-Object { Write-Host " - $_" } if ($files -and $files.Count -gt 0) { Write-Host "Checked discovered files:" $files | ForEach-Object { Write-Host " - $_" } } Write-Host "" Write-Host "Next patch will hard-wire the correct module path once you paste the existing local start command/log line." exit 1