Scheduling
Wrap any preset in a JobSchedule and fire it on cron. Each fire runs CreateJobUsecase, which materializes a fresh Job through the preset’s server-side step resolution — so multi-step presets just work.
Create a schedule
Via the SDK:
await client.jobs.createSchedule({ slug: 'daily-veille', preset: 'veille', cron: '0 7 * * *',})Or directly: POST /api/jobs/schedules. Names are namespaced server-side as {userId}.{slug}.
Overlap policy
The policy is skip-if-previous-still-running. On each tick the worker checks IJobRepository.findInFlightBySchedule and skips the fire if the prior run hasn’t finished. This prevents two writers racing one export target.
POST /api/jobs/schedules/:name/run (SDK: runScheduleNow(slug)) is the only intentional bypass — don’t add others.
Managing schedules
await client.jobs.listSchedules()await client.jobs.getSchedule('daily-veille')await client.jobs.runScheduleNow('daily-veille')await client.jobs.deleteSchedule('daily-veille')await client.jobs.getScheduleWatermarks('daily-veille') // { lastReadAt }Watermarks let read-based presets advance per-source instead of re-reading a fixed window every run.