# Sprint 2.4 — Job queue **Status:** Done ## Backend - **SQLite queue:** `SendJob` table with idempotency keys, `pending → processing → completed/failed` - Campaign dispatcher enqueues and claims due jobs before sending - **Job run log:** `JobRunLog` records last run per job name - `GET /api/jobs/status` — last run timestamps for operators ## Dashboard - Settings → Jobs panel shows last run status - Manual trigger buttons: dispatcher, rollover, rescuer, rollup ## Jobs tracked | Name | Schedule | |------|----------| | `campaign-dispatcher` | `dispatcher_cron` setting | | `rescuer` | `rescuer_cron` setting | | `campaign-rollover` | hourly | | `stats-rollup` | hourly at :05 | ## Verification 1. Settings → Jobs — confirm last-run timestamps after manual trigger 2. Check `SendJob` rows created when dispatcher runs with pending sends