VBAF.Center.WriteBack.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS VBAF-Center Phase 18 — Write-back .DESCRIPTION Connects VBAF to the customer's TMS or GPS system in BOTH directions. Phase 3 reads FROM their system. Phase 18 writes BACK to their system. Mode A — Human approves, system acts (built now) Mode B — Full automation with oversight (future) For testing: point WriteURL to the Fake TMS on port 8082. For production: point WriteURL to the real TMS API. Functions: New-VBAFCenterWriteConfig — configure write commands per action Get-VBAFCenterWriteConfig — show write config for a customer Invoke-VBAFCenterWriteBack — send approved command to TMS Undo-VBAFCenterWriteBack — reverse last write-back command Get-VBAFCenterWriteLog — show all write-back actions Test-VBAFCenterWriteConnection — test connection to TMS write endpoint #> $script:WriteConfigPath = Join-Path $env:USERPROFILE "VBAFCenter\writeconfig" $script:WriteLogPath = Join-Path $env:USERPROFILE "VBAFCenter\writelog" function Initialize-VBAFCenterWriteStore { if (-not (Test-Path $script:WriteConfigPath)) { New-Item -ItemType Directory -Path $script:WriteConfigPath -Force | Out-Null } if (-not (Test-Path $script:WriteLogPath)) { New-Item -ItemType Directory -Path $script:WriteLogPath -Force | Out-Null } } # ============================================================ # NEW-VBAFCENTERWRITECONFIG # ============================================================ function New-VBAFCenterWriteConfig { <# .SYNOPSIS Configure write commands for each action level. For demo: use http://localhost:8082 as the base URL (Fake TMS). For production: use the real TMS API base URL. .EXAMPLE New-VBAFCenterWriteConfig -CustomerID "TruckCompanyDK" -TMSBaseURL "http://localhost:8082" #> param( [Parameter(Mandatory)] [string] $CustomerID, [Parameter(Mandatory)] [string] $TMSBaseURL, [string] $APIKey = "", [string] $Action1URL = "/api/assign", # Reassign endpoint [string] $Action2URL = "/api/route", # Reroute endpoint [string] $Action3URL = "/api/alert", # Escalate endpoint [string] $Action1Body = '{"truck":"DK-4471","job":"J-3001","priority":"normal"}', [string] $Action2Body = '{"truck":"DK-4471","route":"via-ringvej"}', [string] $Action3Body = '{"type":"crisis","message":"VBAF Escalate fired","contact":"manager"}' ) Initialize-VBAFCenterWriteStore # Clean trailing slash $TMSBaseURL = $TMSBaseURL.TrimEnd("/") $config = [PSCustomObject] @{ CustomerID = $CustomerID TMSBaseURL = $TMSBaseURL APIKey = $APIKey Action1URL = $Action1URL Action2URL = $Action2URL Action3URL = $Action3URL Action1Body = $Action1Body Action2Body = $Action2Body Action3Body = $Action3Body CreatedDate = (Get-Date).ToString("yyyy-MM-dd") Mode = "HumanApproves" # always require dispatcher approval } $configFile = Join-Path $script:WriteConfigPath "$CustomerID-writeconfig.json" $config | ConvertTo-Json -Depth 5 | Set-Content $configFile -Encoding UTF8 Write-Host "" Write-Host "Write-back config saved!" -ForegroundColor Green Write-Host (" Customer : {0}" -f $CustomerID) -ForegroundColor White Write-Host (" TMS URL : {0}" -f $TMSBaseURL) -ForegroundColor White Write-Host (" Mode : Human approves — dispatcher must confirm before VBAF acts") -ForegroundColor Cyan Write-Host "" Write-Host " Action map:" -ForegroundColor Yellow Write-Host (" Action 1 Reassign -> POST {0}{1}" -f $TMSBaseURL, $Action1URL) -ForegroundColor White Write-Host (" Action 2 Reroute -> POST {0}{1}" -f $TMSBaseURL, $Action2URL) -ForegroundColor White Write-Host (" Action 3 Escalate -> POST {0}{1}" -f $TMSBaseURL, $Action3URL) -ForegroundColor White Write-Host "" Write-Host " Test with: Test-VBAFCenterWriteConnection -CustomerID ""$CustomerID""" -ForegroundColor DarkGray Write-Host "" return $config } # ============================================================ # GET-VBAFCENTERWRITECONFIG # ============================================================ function Get-VBAFCenterWriteConfig { <# .SYNOPSIS Show write-back configuration for a customer. .EXAMPLE Get-VBAFCenterWriteConfig -CustomerID "TruckCompanyDK" #> param( [Parameter(Mandatory)] [string] $CustomerID ) Initialize-VBAFCenterWriteStore $configFile = Join-Path $script:WriteConfigPath "$CustomerID-writeconfig.json" if (-not (Test-Path $configFile)) { Write-Host "No write config found for: $CustomerID" -ForegroundColor Yellow Write-Host "Run New-VBAFCenterWriteConfig first." -ForegroundColor DarkGray return $null } $config = Get-Content $configFile -Raw | ConvertFrom-Json Write-Host "" Write-Host ("Write-back Config: {0}" -f $CustomerID) -ForegroundColor Cyan Write-Host (" TMS URL : {0}" -f $config.TMSBaseURL) -ForegroundColor White Write-Host (" Mode : {0}" -f $config.Mode) -ForegroundColor White Write-Host (" Created : {0}" -f $config.CreatedDate) -ForegroundColor White Write-Host "" Write-Host " Action endpoints:" -ForegroundColor Yellow Write-Host (" Reassign : POST {0}{1}" -f $config.TMSBaseURL, $config.Action1URL) -ForegroundColor White Write-Host (" Reroute : POST {0}{1}" -f $config.TMSBaseURL, $config.Action2URL) -ForegroundColor White Write-Host (" Escalate : POST {0}{1}" -f $config.TMSBaseURL, $config.Action3URL) -ForegroundColor White Write-Host "" return $config } # ============================================================ # TEST-VBAFCENTERWRITECONNECTION # ============================================================ function Test-VBAFCenterWriteConnection { <# .SYNOPSIS Test the connection to the TMS write endpoint. Sends a status request to verify the TMS is reachable. .EXAMPLE Test-VBAFCenterWriteConnection -CustomerID "TruckCompanyDK" #> param( [Parameter(Mandatory)] [string] $CustomerID ) $config = Get-VBAFCenterWriteConfig -CustomerID $CustomerID if (-not $config) { return } $testURL = "$($config.TMSBaseURL)/api/status" Write-Host "Testing connection to TMS..." -ForegroundColor Yellow Write-Host (" URL: {0}" -f $testURL) -ForegroundColor White try { $response = Invoke-RestMethod -Uri $testURL -Method GET -ErrorAction Stop Write-Host " Connection OK!" -ForegroundColor Green if ($response.activeTrucks) { Write-Host (" Active trucks : {0}" -f $response.activeTrucks) -ForegroundColor White Write-Host (" Idle trucks : {0}" -f $response.idleTrucks) -ForegroundColor White Write-Host (" Pending jobs : {0}" -f $response.pendingJobs) -ForegroundColor White } } catch { Write-Host (" Connection FAILED: {0}" -f $_.Exception.Message) -ForegroundColor Red Write-Host " Is the Fake TMS running? Start with: Start-VBAFFakeTMS" -ForegroundColor Yellow } Write-Host "" } # ============================================================ # INVOKE-VBAFCENTERWRITEBACK # ============================================================ function Invoke-VBAFCenterWriteBack { <# .SYNOPSIS Send an approved write command to the TMS. Dispatcher must have approved — this is Mode A (human approves). Logs every action for full audit trail. Rollback available for 5 minutes after action. .EXAMPLE Invoke-VBAFCenterWriteBack -CustomerID "TruckCompanyDK" -Action 2 Invoke-VBAFCenterWriteBack -CustomerID "TruckCompanyDK" -Action 1 -TruckID "DK-4471" -JobID "J-3001" #> param( [Parameter(Mandatory)] [string] $CustomerID, [Parameter(Mandatory)] [ValidateRange(1,3)] [int] $Action, [string] $TruckID = "", [string] $JobID = "", [string] $Note = "" ) Initialize-VBAFCenterWriteStore $config = Get-VBAFCenterWriteConfig -CustomerID $CustomerID if (-not $config) { return } $actionNames = @("","Reassign","Reroute","Escalate") $actionName = $actionNames[$Action] # Build URL and body $url = switch ($Action) { 1 { "$($config.TMSBaseURL)$($config.Action1URL)" } 2 { "$($config.TMSBaseURL)$($config.Action2URL)" } 3 { "$($config.TMSBaseURL)$($config.Action3URL)" } } $body = switch ($Action) { 1 { $config.Action1Body } 2 { $config.Action2Body } 3 { $config.Action3Body } } # Inject TruckID and JobID if provided if ($TruckID -ne "") { $body = $body -replace '"truck":"[^"]*"', """truck"":""$TruckID""" } if ($JobID -ne "") { $body = $body -replace '"job":"[^"]*"', """job"":""$JobID"" " } $timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") $actionID = "WB-$(Get-Date -Format 'yyyyMMdd_HHmmss')" Write-Host "" Write-Host ("Write-back: {0} — {1}" -f $CustomerID, $actionName) -ForegroundColor Cyan Write-Host (" Action ID : {0}" -f $actionID) -ForegroundColor White Write-Host (" URL : {0}" -f $url) -ForegroundColor White Write-Host (" Body : {0}" -f $body) -ForegroundColor White Write-Host "" # Send command $success = $false $responseText = "" try { $headers = @{ "Content-Type" = "application/json" } if ($config.APIKey -ne "") { $headers["Authorization"] = "Bearer $($config.APIKey)" } $response = Invoke-RestMethod -Uri $url -Method POST -Body $body -Headers $headers -ErrorAction Stop $responseText = $response.message $success = $true Write-Host " Command sent successfully!" -ForegroundColor Green Write-Host (" TMS response: {0}" -f $responseText) -ForegroundColor Green } catch { $responseText = $_.Exception.Message Write-Host (" Command FAILED: {0}" -f $responseText) -ForegroundColor Red } # Log the action $logEntry = [PSCustomObject] @{ ActionID = $actionID CustomerID = $CustomerID Timestamp = $timestamp Action = $Action ActionName = $actionName URL = $url Body = $body TruckID = $TruckID JobID = $JobID Note = $Note Success = $success Response = $responseText RollbackAvailable = $success RollbackExpiry = if ($success) { (Get-Date).AddMinutes(5).ToString("yyyy-MM-dd HH:mm:ss") } else { "" } } $logFile = Join-Path $script:WriteLogPath "$CustomerID-writelog.json" $existing = @() if (Test-Path $logFile) { try { $existing = @(Get-Content $logFile -Raw | ConvertFrom-Json) } catch {} } $existing += $logEntry $existing | ConvertTo-Json -Depth 5 | Set-Content $logFile -Encoding UTF8 if ($success) { Write-Host "" Write-Host (" Rollback available for 5 minutes.") -ForegroundColor DarkGray Write-Host (" Run: Undo-VBAFCenterWriteBack -CustomerID ""{0}"" -ActionID ""{1}""" -f $CustomerID, $actionID) -ForegroundColor DarkGray } Write-Host "" return $logEntry } # ============================================================ # UNDO-VBAFCENTERWRITEBACK # ============================================================ function Undo-VBAFCenterWriteBack { <# .SYNOPSIS Reverse a write-back action within the 5-minute rollback window. .EXAMPLE Undo-VBAFCenterWriteBack -CustomerID "TruckCompanyDK" -ActionID "WB-20260425_161234" #> param( [Parameter(Mandatory)] [string] $CustomerID, [Parameter(Mandatory)] [string] $ActionID ) Initialize-VBAFCenterWriteStore $logFile = Join-Path $script:WriteLogPath "$CustomerID-writelog.json" if (-not (Test-Path $logFile)) { Write-Host "No write log found for: $CustomerID" -ForegroundColor Red return } $log = @(Get-Content $logFile -Raw | ConvertFrom-Json) $entry = $log | Where-Object { $_.ActionID -eq $ActionID } if (-not $entry) { Write-Host "Action ID not found: $ActionID" -ForegroundColor Red return } # Check rollback window if ($entry.RollbackExpiry -ne "") { $expiry = [DateTime]::ParseExact($entry.RollbackExpiry, "yyyy-MM-dd HH:mm:ss", $null) if ((Get-Date) -gt $expiry) { Write-Host "Rollback window expired — cannot undo this action." -ForegroundColor Red Write-Host (" Action was: {0} at {1}" -f $entry.ActionName, $entry.Timestamp) -ForegroundColor DarkGray return } } Write-Host "" Write-Host ("Rollback: {0} — {1}" -f $CustomerID, $entry.ActionName) -ForegroundColor Yellow Write-Host (" Original action : {0} at {1}" -f $entry.ActionName, $entry.Timestamp) -ForegroundColor White # For fake TMS — send a status reset $config = Get-VBAFCenterWriteConfig -CustomerID $CustomerID $rollbackURL = "$($config.TMSBaseURL)/api/status" try { Invoke-RestMethod -Uri $rollbackURL -Method GET -ErrorAction Stop | Out-Null Write-Host " Rollback command sent — TMS notified." -ForegroundColor Green } catch { Write-Host (" Rollback call failed: {0}" -f $_.Exception.Message) -ForegroundColor Red } # Mark as rolled back in log $entry.RollbackAvailable = $false $log | ConvertTo-Json -Depth 5 | Set-Content $logFile -Encoding UTF8 Write-Host " Action marked as rolled back in log." -ForegroundColor Green Write-Host "" } # ============================================================ # GET-VBAFCENTERWRITELOG # ============================================================ function Get-VBAFCenterWriteLog { <# .SYNOPSIS Show full audit log of all write-back actions for a customer. .EXAMPLE Get-VBAFCenterWriteLog -CustomerID "TruckCompanyDK" #> param( [Parameter(Mandatory)] [string] $CustomerID, [int] $Last = 20 ) Initialize-VBAFCenterWriteStore $logFile = Join-Path $script:WriteLogPath "$CustomerID-writelog.json" if (-not (Test-Path $logFile)) { Write-Host "No write log found for: $CustomerID" -ForegroundColor Yellow return } $log = @(Get-Content $logFile -Raw | ConvertFrom-Json) $recent = $log | Select-Object -Last $Last Write-Host "" Write-Host ("Write-back Log: {0} (last {1})" -f $CustomerID, $recent.Count) -ForegroundColor Cyan Write-Host (" {0,-22} {1,-10} {2,-10} {3,-8} {4}" -f "Timestamp","ActionID","Action","OK","Response") -ForegroundColor Yellow Write-Host (" {0}" -f ("-" * 85)) -ForegroundColor DarkGray foreach ($entry in $recent) { $color = if ($entry.Success) { "Green" } else { "Red" } $rollback = if ($entry.RollbackAvailable) { "[UNDO]" } else { "" } Write-Host (" {0,-22} {1,-10} {2,-10} {3,-8} {4} {5}" -f ` $entry.Timestamp, $entry.ActionID, $entry.ActionName, $(if ($entry.Success) { "OK" } else { "FAIL" }), $entry.Response, $rollback) -ForegroundColor $color } Write-Host "" return $log } # ============================================================ # LOAD MESSAGE # ============================================================ Write-Host "" Write-Host " +--------------------------------------------------+" -ForegroundColor Cyan Write-Host " | VBAF-Center Phase 18 — Write-back |" -ForegroundColor Cyan Write-Host " | VBAF now acts — not just advises |" -ForegroundColor Cyan Write-Host " +--------------------------------------------------+" -ForegroundColor Cyan Write-Host "" Write-Host " New-VBAFCenterWriteConfig — configure TMS write endpoints" -ForegroundColor White Write-Host " Get-VBAFCenterWriteConfig — show write config" -ForegroundColor White Write-Host " Test-VBAFCenterWriteConnection — test TMS connection" -ForegroundColor White Write-Host " Invoke-VBAFCenterWriteBack — send approved command to TMS" -ForegroundColor White Write-Host " Undo-VBAFCenterWriteBack — rollback within 5 minutes" -ForegroundColor White Write-Host " Get-VBAFCenterWriteLog — show full audit log" -ForegroundColor White Write-Host "" Write-Host " For demo: Start-VBAFFakeTMS in a separate console first." -ForegroundColor Yellow Write-Host "" |