Systemd cron (timers)
Production servers use coaching-cron-tick.timer to call POST /api/cron/tick on a fixed interval. The tick loads CronScheduledJob rows from the database and invokes each due job’s HTTP path with the cron secret.
Single timer
Legacy coaching-alerts systemd units were removed from the repo. Scheduled alert generation is configured as jobs executed by the tick (see seed / admin UI).
Quick install
sudo bash deploy/cron/install.sh
Ensure /etc/coaching/cron.env exists with BASE_URL and CRON_SECRET matching the application .env.
Deploy pipeline
The admin Deploy page runs deploy/cron/install-from-deploy.sh after the Next.js build so unit files stay in sync with the repository. The Node process user (often coaching) needs either:
- One manual
sudo bash deploy/cron/install.shafter clone, or - Passwordless sudo for
install.shonly — seedeploy/cron/README.mdin the repo for the exactsudoersline.
If sudo is not configured, the step prints SKIP and deploy still succeeds.
Verification
sudo systemctl list-timers | grep coaching
sudo journalctl -u coaching-cron-tick.service -n 50 --no-pager