Files
Alarm/src/actions/deliveries.go
T
Admin 6e6a1e9c8a [feat](alarm): add a durable per-device delivery ledger
pg_notify and the socket fan-out are not durable, so an offline phone used to miss a trigger forever and no-auto-stop would leave it ringing at nobody. Write one ledger row per enabled subscription in the trigger transaction, replay what a subscription still owes on every socket connect, and clear a row only on an explicit ack (live socket ack or ackAlarm); alarmStatus is a read-only check-in that answers 409 ERR_ALARM_TRIGGERED_OFFLINE with the missed frame. Ack is idempotent, and a destroyed alert cascades its debt away so a client is never told it missed an alarm that no longer exists.
2026-10-19 02:26:46 +01:00

51 lines
2.3 KiB
Go

// Copyright (C) 2026 Dcntrlized
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package actions
import (
"context"
"errors"
"github.com/google/uuid"
)
// completeAlertDelivery is the decision point for the second half of the
// delivery design: "once every client is removed for an alarm, the alarm is then
// deleted with whichever cascade deletions are relevant".
//
// It is DELIBERATELY UNWIRED — nothing calls it. That sentence has two readings
// and they are different products, so the user has been asked which one is meant:
//
// (a) delete the ALERT. The definition, both tokens, the subscriptions and the
// event history go with it (ON DELETE CASCADE). An alert becomes a
// one-shot event: once every device has acknowledged, it cannot be
// triggered again and the admin token becomes dead.
// (b) retire only the DELIVERY record (and/or the event). The alert survives,
// stays armed, and can be triggered again later; only the ledger bookkeeping
// about this alarm is completed.
//
// Implementing either now would delete or preserve data on a reading nobody
// confirmed, so this function reports that the decision is pending. When the
// answer arrives it gets implemented in exactly one place and called from the
// paths that observe the last outstanding delivery (the alarmStatus check-in and
// the WebSocket ack), where "every client has been told" is decided atomically
// from the ledger rather than from a client's claim.
func completeAlertDelivery(ctx context.Context, alertID uuid.UUID) error {
_ = ctx
_ = alertID
return errors.New("completeAlertDelivery: pending user decision between (a) deleting the alert as a one-shot and (b) retiring only the delivery record")
}