0b6c33e59a
Seed gallery_expiring / gallery_expired built-ins and make the live automations flow-owned, with zero feature loss: - New delegating actions (notify_gallery_expiring / notify_gallery_expired / notify_pre_event) call the EXISTING send functions, so the engine path is byte-identical to the legacy hourly checker/pass (same templates, recipients, variables, dedup, per-event overrides, sent_at idempotency). - Cutover built-ins (invoice_dunning, gallery_expiring, gallery_expired, pre_event_email) now ship ENABLED; booking flows stay disabled (stubs). - The legacy paths stand down via existence-based isBuiltinFlowPresent guards: once a built-in is seeded (flag on) the engine is the single switch — flow enabled = it sends, flow disabled = off — so no double-send and reminders/ expiry emails can still be fully turned off. - emitDueEventReminders now honours the per-event reminder controls (disabled / offset / sent_at) so pre-event timing is faithful; fixed a Number(null)===0 offset bug. Settings UI cutover is gated on the `workflows` flag (default off): when the engine is live, the dunning reminder schedule (CRM settings) and the pre-event global toggle (Reminder emails) are replaced with a "now in Workflows" callout; when it's off, the legacy controls stay so flag-off installs lose nothing. The late-fee math and installment-trigger defaults stay (fee math / scheduler-owned). Split/installment invoices intentionally remain scheduler-driven (no flow).