Merge origin/dev (Feature 20 scheduler) into Feature 21 Home dashboard
CI / ci (push) Successful in 8m7s
CI / ci (pull_request) Successful in 8m7s

Keep both the scheduler registrations and the Home service wiring in
cmd/server, pass the scheduler wake function to plan.NewService in the
Home and server tests, and document that boot catch-up processes every
unclaimed fire time within 24 hours, oldest first (F20-02).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-10 19:46:46 -04:00
co-authored by Claude Opus 5.5
40 changed files with 4461 additions and 230 deletions
+14
View File
@@ -27,6 +27,7 @@ import (
"fmt"
"log/slog"
"net/url"
"slices"
"strings"
"sync"
"time"
@@ -293,6 +294,19 @@ func (s *Service) emitTx(ctx context.Context, tx *sql.Tx, ev Event, channels fun
return nil
}
// ChannelOn reports whether the preference of event type ev switches
// channel ch on. A type with no preference row is an error.
func (s *Service) ChannelOn(ctx context.Context, ev EventType, ch Channel) (bool, error) {
pref, err := db.New(s.st.Reader).GetNotificationPref(ctx, string(ev))
if errors.Is(err, sql.ErrNoRows) {
return false, fmt.Errorf("notify: no notification preference for %s", ev)
}
if err != nil {
return false, fmt.Errorf("notify: read notification preference for %s: %w", ev, err)
}
return slices.Contains(enabledChannels(pref), ch), nil
}
// enabledChannels returns the channels pref switches on.
func enabledChannels(pref db.NotificationPref) []Channel {
var chs []Channel