From 66176cbafb08af2cb845527038cfbcf9aae4f8b1 Mon Sep 17 00:00:00 2001 From: Joel Salmon Date: Tue, 16 Jun 2026 21:57:09 -0500 Subject: [PATCH] Add Windows Task Scheduler runner for weekly check-ins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scripts/run-weekly-checkins.ps1: pure-Windows equivalent of the cron script — reads the admin API key from .env and POSTs /discovery/coaching/run via Invoke-RestMethod, logging to data/coaching-cron.log. README documents the Register-ScheduledTask command (weekly, StartWhenAvailable + WakeToRun) for a more robust schedule than WSL cron. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 18 ++++++++++++++++++ scripts/run-weekly-checkins.ps1 | 24 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 scripts/run-weekly-checkins.ps1 diff --git a/README.md b/README.md index e6ed5bc..2a9046f 100644 --- a/README.md +++ b/README.md @@ -886,6 +886,24 @@ Running weekly services all cadences — the endpoint skips users who are not ye due (biweekly/monthly), so a weekly tick is the finest needed. Output is appended to `data/coaching-cron.log`. (On WSL, cron only runs while WSL is up.) +**More robust: Windows Task Scheduler.** `scripts/run-weekly-checkins.ps1` does +the same POST from Windows (reading the key from `.env`, hitting +`localhost:8011`). Register it to run weekly — and to catch up if the machine +was asleep — from PowerShell: + +```powershell +$action = New-ScheduledTaskAction -Execute 'powershell.exe' ` + -Argument '-NoProfile -ExecutionPolicy Bypass -File "C:\syncdata\impactflow-discovery\scripts\run-weekly-checkins.ps1"' +$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At 8am +$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -WakeToRun +Register-ScheduledTask -TaskName 'ImpactFlow Weekly Check-ins' ` + -Action $action -Trigger $trigger -Settings $settings ` + -Description 'Phase 3 weekly coaching check-in batch' +``` + +Use either the WSL cron or the Task Scheduler job — not both is fine, but +running both is harmless since the endpoint dedupes by due-ness. + ## Quick Start With Docker This path requires Docker Desktop or another Docker Engine installation with diff --git a/scripts/run-weekly-checkins.ps1 b/scripts/run-weekly-checkins.ps1 new file mode 100644 index 0000000..c9e5d0d --- /dev/null +++ b/scripts/run-weekly-checkins.ps1 @@ -0,0 +1,24 @@ +# Weekly coaching check-in batch (Phase 3) for Windows Task Scheduler. +# Reads the admin API key from .env and POSTs /discovery/coaching/run, which +# generates a check-in for every eligible user whose cadence is due. +# Override the target with $env:IMPACTFLOW_BASE_URL (default: local container). + +$ErrorActionPreference = 'Stop' +$dir = Split-Path -Parent $PSScriptRoot # repo root (scripts\..) +$envFile = Join-Path $dir '.env' +$log = Join-Path $dir 'data\coaching-cron.log' +$base = if ($env:IMPACTFLOW_BASE_URL) { $env:IMPACTFLOW_BASE_URL } else { 'http://localhost:8011' } +$ts = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + +try { + $line = (Select-String -Path $envFile -Pattern '^IMPACTFLOW_API_KEY=' | Select-Object -First 1).Line + $key = ($line -replace '^IMPACTFLOW_API_KEY=', '').Trim() + if (-not $key) { throw "IMPACTFLOW_API_KEY not found in $envFile" } + + $resp = Invoke-RestMethod -Method Post -Uri "$base/discovery/coaching/run" ` + -Headers @{ 'X-API-Key' = $key } -TimeoutSec 120 + "$ts $($resp | ConvertTo-Json -Compress)" | Add-Content -Path $log +} +catch { + "$ts ERROR: $($_.Exception.Message)" | Add-Content -Path $log +}