Files
where_woof/openspec/changes/renewal-unlock/proposal.md

1.9 KiB

Why

The metering slice (credits) blocks alerts when exhausted, and paid-gating blocks on lapsed orders — but the owner is never told why or what to do. The 2014 system had a late_payment flow ("your payments are suspended"); this change restores that: an unlock notification to the owner when a scan is gated, plus renewal tracking (a renews date with lazy expiry) so lapsed status is computed, not manually maintained.

What Changes

  • orders.renews_at (idempotent): admin sets the next renewal date. Gating treats a paid order with renews_at in the past as lapsed (lazy expiry — no background job needed).
  • Unlock notification: when a scan is blocked because the order is lapsed or credits are exhausted, the owner receives a notice: "Your Where Woof tag was scanned — your plan is lapsed / out of SMS credits. Renew to see the finder's details." with the tag link.
  • Notify channel abstraction (internal/notify): ntfy (self-hosted on .13 — free) by default, SMS optional via env (NOTIFY_CHANNEL=ntfy|sms|both). Email is a documented future channel (SMTP infra absent). Unlock notices are exempt from SMS metering (they're system notices).
  • Admin: OrderResource gains renews_at; a lapsed badge on orders past renewal.

Capabilities

New Capabilities

  • renewal-unlock: renewal date + lazy expiry + owner unlock notification when gated.

Modified Capabilities

  • sms-alerting: ADDED — gated scans notify the owner with the reason + renewal call-to-action.
  • database: ADDED — orders.renews_at.

Impact

  • Go: internal/notify (ntfy + sms channels), scan.go gating calls notify on lapsed/credit blocks, orders query for renews_at, template/message builder.
  • Schema: idempotent ALTER; make db-up.
  • Admin: OrderResource renews_at + lapsed indicator.
  • Config: NOTIFY_CHANNEL env (default ntfy), NTFY_TOPIC env.