fix(reminders): settings UI discloses that automatic sending is disabled (#2033)
* fix(reminders): settings UI discloses that automatic sending is disabled The invoice reminder cron has answered 503 since May 2026 (PR #583), so no automatic reminders are sent, but the settings UI still let users configure reminder day levels as if sending worked. Introduce REMINDERS_SENDING_ENABLED (lib/invoices/reminders-enabled.ts) as the single shared flag read by both sides: the cron route uses it as its 503 gate (with the original sending pipeline restored behind it, so re-enabling later is one flag flip), and the invoice settings form shows an attn notice while the flag is off. Schedule settings stay editable; notice strings added to both sv and en locales. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NtvffGr6uVk2J2Skuz6L98 * docs(reminders): correct the re-enable contract after skeptic review The flag docblock, route docblock, and test header claimed flipping REMINDERS_SENDING_ENABLED alone resumes sending. False on hosted: the route has had no vercel.json cron entry since PR #559 and the crontab ratchet pins it in INTENTIONALLY_UNSCHEDULED, and POST requires the cron secret so no dashboard can trigger it. Rewrite the claims into the real re-enable checklist and record the pre-flip prerequisites surfaced by review: invoice_reminders lacks a unique (invoice_id, reminder_level) constraint and the fee entry is booked before the reminder row, so a run dying mid-batch double-books the fee; the backlog would get highest-level reminders first. Comments and a test name only; no runtime change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NtvffGr6uVk2J2Skuz6L98 --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
341d61131a
commit
e92b5a59b2
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Master switch for automatic invoice reminder sending.
|
||||
*
|
||||
* Sending was deliberately gated off in May 2026 (PR #583): the reminder
|
||||
* cron route answers 503 and no reminder emails go out, while the schedule
|
||||
* settings (send_invoice_reminders, reminder_days_level_1/2/3) remain
|
||||
* editable and are honored per company once sending is on.
|
||||
*
|
||||
* Both sides of that gate read this one constant: the cron route uses it as
|
||||
* its 503 gate, and the invoice settings form uses it to disclose to users
|
||||
* that automatic sending is currently disabled. Flipping it opens the route
|
||||
* and removes the notice in the same change.
|
||||
*
|
||||
* Re-enabling sending is a founder product decision and takes MORE than
|
||||
* this flip. The checklist (verified against the repo 2026-08-30):
|
||||
*
|
||||
* 1. Flip this flag to true.
|
||||
* 2. Hosted: the route has had no vercel.json cron entry since PR #559,
|
||||
* and scripts/__tests__/generate-crontabs.test.ts pins it in
|
||||
* INTENTIONALLY_UNSCHEDULED (the ratchet fails if it is scheduled).
|
||||
* Add the cron entry back and drop the pin together. Self-hosted
|
||||
* crontabs built from docs/SELF-HOSTING.md may already hit the route,
|
||||
* so those installs resume on the flag flip alone.
|
||||
* 3. Before any flip, make the reminder run idempotent: invoice_reminders
|
||||
* has no unique (invoice_id, reminder_level) constraint and
|
||||
* processOverdueReminders books the reminder fee entry BEFORE inserting
|
||||
* the invoice_reminders row, so a run dying mid-batch double-books the
|
||||
* fee (Dr 1510 / Cr 3990) on the next run. Also decide how to handle
|
||||
* the backlog: determineReminderLevel sends the highest eligible level
|
||||
* first, so long-overdue customers would get a final notice with fee
|
||||
* and interest as their first-ever reminder.
|
||||
*
|
||||
* Kept dependency-free on purpose: it is imported from both server code
|
||||
* (the cron route) and client components (the settings form).
|
||||
*/
|
||||
export const REMINDERS_SENDING_ENABLED = false as boolean
|
||||
Reference in New Issue
Block a user