Yearly was a single Month dropdown + a Day number input — one Month and
one Day per rule. That meant "every quarter on the 1st" needed four
separate schedule rows.
Now Yearly mirrors Monthly's grid pattern but with two grids:
Months [Jan][Feb][Mar][Apr][May][Jun]
[Jul][Aug][Sep][Oct][Nov][Dec]
Days [ 1][ 2][ 3]...[31] (7×5 grid)
Both grids are multi-select. Cron output uses the comma-list form on
both DOM and month positions:
months: [1,4,7,10] + days: [1] → "0 9 1 1,4,7,10 *"
months: [12] + days: [24,25,31] → "0 9 24,25,31 12 *"
The cron field is a Cartesian product — every selected day fires in
every selected month. So "every quarter on the 1st" is now one rule.
Round-trip: parser accepts comma-lists for both DOM and month, with
single-element shapes (the old "0 9 13 5 *") still loading fine.
Migration of saved data: old yearly rules with one DOM + one month
parse into monthDays=[X], months=[Y] — identical visual selection in
the new grid, identical cron output. No DB changes needed.
Renamed `Draft.month` to `Draft.months: number[]`. The "Single
day-of-month for yearly" field is gone — yearly now reads
`monthDays` (same as monthly).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>