• v1.1.0 — paused/resume + bot reliability + UX polish

    yiekheng released this 2026-05-10 16:47:20 +08:00 | 67 commits to master since this release

    Phase 3 (window enforcement + paused/resume lifecycle) shipped:

    • fire-reminder.ts gates per-target sends on the delivery deadline
      via @cmbot/shared/windowEndAt. When the deadline trips mid-fan-
      out, the run resolves 'paused', the reminder lifecycle flips to
      paused, and pending targets stay pending so a resume can pick
      them up. SSE event payload carries sent/total counts.
    • New 'reminder.resume' bot IPC command + enqueueReminderResume
      helper that posts a one-shot pg-boss job carrying { reminderId,
      runId }. fire-reminder ATTACHES to the existing run instead of
      creating a new one and only re-tries the still-pending rows.
    • resumeReminderRunAction + cancelReminderRunAction server actions
      with full ownership / status guards.
    • PausedRunBanner on the reminder detail page (Resume / Cancel run
      CTAs). Activity tab gains a Paused filter + inline resume button.
    • Notification body picks up the paused / "X of Y groups delivered.
      Tap to resume or cancel." copy.

    Bot reliability:

    • sweepStalePendingRuns on startup recovers from the "bot crashed
      mid-run" corner case — runs stuck at status='pending' older than
      5 minutes flip to 'failed' with a clear error_summary; their
      pending run-targets flip to 'skipped'.
    • Duplicate-fire guard: even if pg-boss enqueues two jobs for the
      same reminder, fire-reminder bails out when a recent run for the
      same reminderId already exists. Queue policy raised to 'stately'
      so the duplicate is folded by pg-boss going forward too.

    UX polish:

    • "Pause sending by" deadline is now opt-in: a card-shaped row with
      a visible checkbox + Set/Off label; the hour picker only shows
      when the box is ticked.
    • Reminder status 'ended' renamed to 'inactive' across DB, bot,
      web actions, dashboard counter card, list filter tab, status pill,
      and tests. Migration 0009 backfills existing rows.
    • Client bundle no longer pulls in the node-only rrule shim
      (subpath export added to @cmbot/shared/delivery-window).
    • ThemeToggle no longer hydration-mismatches.

    Tests at the time of release: 60 bot, 39 shared, 372 web — total
    471, all green.

    Downloads