Skip to content

feat: add an interval scheduler for auto scan and sync#67

Merged
WhiteMuush merged 1 commit into
mainfrom
feat/53-scheduler
Jun 19, 2026
Merged

feat: add an interval scheduler for auto scan and sync#67
WhiteMuush merged 1 commit into
mainfrom
feat/53-scheduler

Conversation

@WhiteMuush

Copy link
Copy Markdown
Owner

What

Adds interval-based scheduling so exposure scans and directory syncs run in the background, not only on manual POST. Closes #53.

Design

"Internal cron + table", no dedicated worker and no heavy dependency: schedule state lives in the DB and a single tick endpoint advances it; an external cron calls the endpoint.

How

  • Schema: DirectoryConnection.autoSyncIntervalMinutes (per connection), Company.scanIntervalMinutes + lastScanAt (per company). null disables; values are integers ≥ 5 minutes. Migration included.
  • lib/scheduler.runDueSchedules: enqueues a SyncJob for each connection whose interval has elapsed (SCIM excluded, it is push-based), starts a scan for each due company that has providers configured (lastScanAt stamped up front to avoid double-trigger), then drains the sync queue via processSyncJobs (Move sync out of the request cycle: jobs + retry #54 retry/backoff).
  • POST /api/cron: tick endpoint, CRON_SECRET bearer (timing-safe compare), 503 when unconfigured. See docs/scheduler.md for cron setup.
  • Config: PATCH /api/directory/:id (auto-sync interval, rejects SCIM) and PATCH /api/company (scan interval), both admin + company-scoped.

Tests

isDue, runDueSchedules (due/not-due enqueue, scan only with providers, queue drain), cron auth (503/401/200), and both config endpoints (validation, scoping, SCIM rejection, null disable).

Notes

  • Migration authored by hand (no local DB); prisma validate passes, client generates. prisma migrate deploy on deploy.
  • Directory sync is durable (queued/retried). Auto-scan currently runs detached and is retried on the next due tick rather than via a job queue; a scan job queue can follow.

Closes #53

🤖 Generated with Claude Code

Scan and sync were only triggerable manually (#53). Adds an internal
cron + table model so the product does background work.

- Schema: DirectoryConnection.autoSyncIntervalMinutes (per connection)
  and Company.scanIntervalMinutes + lastScanAt (per company), with a
  migration. null disables; values are integers >= 5 minutes.
- lib/scheduler.runDueSchedules: enqueues a SyncJob for every connection
  whose interval has elapsed (SCIM excluded, it is push-based), starts a
  scan for every due company that has providers configured (lastScanAt
  stamped up front), then drains the sync queue.
- POST /api/cron: tick endpoint authenticated with CRON_SECRET
  (timing-safe), meant to be hit by an external cron. Returns 503 when
  unconfigured.
- Config endpoints: PATCH /api/directory/:id (auto-sync interval, SCIM
  rejected) and PATCH /api/company (scan interval), both admin + scoped.
- docs/scheduler.md and CRON_SECRET in .env.example.
- Unit tests for isDue, runDueSchedules, the cron auth, and both config
  endpoints.

Closes #53
@WhiteMuush WhiteMuush merged commit e7b3e9e into main Jun 19, 2026
11 checks passed
@WhiteMuush WhiteMuush deleted the feat/53-scheduler branch June 19, 2026 09:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a periodic scheduler (auto scan + sync)

1 participant