Files

7.2 KiB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

Changed

  • SMS_ENABLED, SMS_REQUIRE_ACTION_CLAIM, and SMS_DEV_ECHO_CODE parse like DEBUG_ENDPOINT: trimmed, case-insensitive, accepting true/1/yes/on and false/0/no/off. (A trailing space from docker run --env-file no longer silently turns SMS off, and an unrecognized SMS_REQUIRE_ACTION_CLAIM keeps the claim required instead of disabling it.)

[0.2.1] - 2026.09.09

Added

  • notifyHourUtc (0-23) and notifyMinuteUtc (0-59) are required on an alert-authorization batch, both integers and both UTC — the field names carry the frame, so no offset or zone travels with them. Stored zero-padded as one HH:MM value in notify_hour_min_utc. Required rather than optional because the alternative default is not "no gate" but "the first tick after midnight UTC", which puts every user in one five-minute window. The scheduler holds a user's whole daily run, search included, until that instant, and reports the held users as deferred. A stored UTC time does not follow the user through a daylight-saving change; a fresh batch carrying the new offset corrects it
  • Both alertSearch schedulers pick their users with one query per pass (listPendingForDay) instead of one per user: it returns everyone holding an unused JWT for the current UTC day, flagged by whether their notify_hour_min_utc has arrived. A user who has already run that day no longer appears, so an idle tick over 2000 users costs 0 queries and ~1ms, down from 3 queries per user and ~141ms
  • Both passes work on ALERT_SEARCH_USER_CONCURRENCY users at a time (src/util/concurrency.ts, default 8) instead of serially; at 50ms of API latency a 2000-user pass drops from ~106s to ~13s, which is what keeps it inside its own tick
  • The notify hour and timezone are accepted on PUT /notifications/alert-authorization as well, and the push scheduler honours the stored hour
  • Optional timezone (IANA name) on an alert-authorization batch, validated and stored beside notify_hour_min_utc and read by nothing. It is recorded for a future mechanism that would re-derive the UTC time across a DST change; the column carries that reason as a SQL comment
  • DELETE /notifications/alert-authorization and DELETE /notify-sms/alert-authorization remove every batch and JWT a DID holds in that channel, so a user can turn alerts off; verified phone numbers and alertSearch cursors survive, and the SMS revocation is logged as alert-authorization-deleted under the revoke-alert-search action claim
  • /notify-sms SMS channel: phone registration with a 6-digit possession check, a per-channel delegated-JWT inventory and cursor, a Twilio sender, an STOP/START/HELP webhook, and a daily digest text alongside the FCM one; off unless SMS_ENABLED
  • Blocks record their origin (opt-out / provider-opt-out / manual) and are never downgraded; a Twilio 21610 refusal auto-blocks as provider-opt-out, and pnpm run sms:blocks lists and manages the list by origin
  • sms_blocked_numbers suppression list: STOP now blocks durably instead of only unverifying, START lifts the block, and a blocked number is refused at registration and verification and skipped by the digest; SMS_BLOCKED_NUMBERS blocks by configuration
  • SMS_ALLOWED_RECIPIENT_DIDS restricts which DIDs an instance may text, guarding both the verification code and the daily digest, so a test server with live Twilio credentials cannot message a restored production database
  • Every log line is prefixed with an ISO-8601 UTC timestamp (src/util/log.ts)
  • pnpm run sms:send and pnpm run sms:smoke exercise the Twilio path and the full /notify-sms route flow against a stub Endorser and unsigned test-local JWTs
  • pnpm run twilio:whoami reports which Twilio account a send would bill and distinguishes a mismatched credential pair from a valid test pair

Changed

  • Alert-authorization batches no longer schedule from a timezone. Days are UTC days: each delegated JWT must be valid for the whole UTC day it names (nbf at or before its midnight, exp at or after the next), the daily run selects by UTC day and reports it as utcDay, and notifyTime supplies its own offset. Removes InvalidAlertAuthorizationTimezoneError
  • loadAlertSearchCursors, advanceAlertSearchCursors, runAlertSearchCycle, and runDailyAlertSearch take a channel ("fcm" default), selecting the JWT inventory and cursor table

[0.1.14] - 2026.09.01

Changed

  • Production runbook: Docker/node dist/index.js is the canonical deploy path; document durable SQLite, single replica, Firebase credential options, and smoke checks

[0.1.13] - 2026.08.31

Added

  • AlertSearch scheduler delivers a TimeSafari FCM digest (type: alert_search) when a completed run consumed today's JWT and digest.hasUpdates is true; WAKEUP_PING and JWT/cursor rules are unchanged

[0.1.12] - 2026.08.31

Added

  • runDailyAlertSearch includes a Phase 6A digest on retrieval attempts (null when no batch or today's JWT is missing); JWT consumption is still based on both sources completing, not hasUpdates

[0.1.11] - 2026.08.28

Added

  • buildAlertSearchDigest turns a completed Endorser+Partner alertSearch retrieve into structured per-bucket records and counts for a future app/plugin payload (no notification message or FCM send)

[0.1.10] - 2026.08.28

Added

  • Dedicated user-level alertSearch scheduler (startAlertSearchScheduler) that calls runDailyAlertSearch once per authorization-batch user, with a process-local in-flight guard; independent of FCM WAKEUP_PING

[0.1.9] - 2026.08.28

Added

  • runDailyAlertSearch selects today's unused delegated JWT from the stored batch timezone, runs runAlertSearchCycle, and consumes that JWT only when both Endorser and Partner complete (success or empty)

[0.1.8] - 2026.08.27

Added

  • runAlertSearchCycle integration of cursor load, alertSearch retrieve, and independent cursor advance

Changed

  • Partner pages of 50 profiles that share the oldest updatedAt are classified incomplete so the cursor cannot skip tied rows

[0.1.7] - 2026.08.27

Added

  • Persistent per-user Endorser and Partner alertSearch cursors (advanced only after complete retrievals)

[0.1.6] - 2026.08.27

Added

  • AlertSearch retrieval layer for Endorser and Partner GET endpoints (pagination, independent cursors; not scheduled yet)

Changed

  • Endorser in-run beforeId is MAX of per-bucket minima; plansNearby hitting the row limit is classified incomplete

[0.1.5] - 2026.08.26

Added

  • PUT /notifications/alert-authorization stores a 100-JWT delegated alert-authorization batch per user (SQLite), authenticated with the current user JWT

[0.1.4] - 2026.08.07

Changed

  • Renamed FCM_TOKEN_DATA_DIR env var to NOTIFY_DATA_DIR

[0.1.3] - 2026.07.30

Changed

  • Persistence changed from file to SQLite

[0.1.2] - 2026.07.16

Added

  • Validation via Endorser service, with new ENDORSER_URL variable

[0.1.1] - 2026.06.28

Added

  • Base functionality