Add GET /api/v1/home for the Home dashboard
CI / ci (push) Successful in 8m28s
CI / ci (pull_request) Successful in 8m20s

home.Service aggregates the Home screen from the services that own each
value, at "now" in the household's zone: the date label, tonight's dinner
from the current week's plan (null with no plan), the pending Side quest
count from the deck, the Supply run status of the upcoming week or else
the current one, and recentUpdates.unread.

unread is whether a notification was stored in notification_outbox after
household_settings.updates_seen_at (or at all while it is null), read
through the new notify.StoredSince over the HasNotificationSince query.
Nothing writes updates_seen_at yet; the updates task adds that.

Tests under America/Chicago show tonight's dinner flips at local
midnight, not UTC midnight, and cover no plan, no suggestions, the
Supply run choice and unread.

Maestro task 9ccfc3a6-cc7b-493a-aa4b-2b455d26f4df.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-09 20:19:33 -04:00
co-authored by Claude Opus 5.5
parent 4dcfc3c27d
commit cdbec3f3a2
27 changed files with 849 additions and 31 deletions
+16
View File
@@ -97,6 +97,22 @@ func (q *Queries) GetNotificationPref(ctx context.Context, event string) (Notifi
return i, err
}
const hasNotificationSince = `-- name: HasNotificationSince :one
SELECT EXISTS (
SELECT 1 FROM notification_outbox
WHERE CAST(?1 AS TEXT) IS NULL OR created_at > CAST(?1 AS TEXT)
) AS found
`
// Reports whether a notification was stored after since, or at all when
// since is NULL.
func (q *Queries) HasNotificationSince(ctx context.Context, since sql.NullString) (bool, error) {
row := q.db.QueryRowContext(ctx, hasNotificationSince, since)
var found bool
err := row.Scan(&found)
return found, err
}
const insertNotification = `-- name: InsertNotification :execrows
INSERT INTO notification_outbox (
id, event_key, channel, payload, status, attempts, next_attempt_at, created_at, updated_at
+3
View File
@@ -179,6 +179,9 @@ type Querier interface {
// them only when a member edited them while it was grounding. Like
// GroundDinner it clears the pasted recipe_url: the recipe replaces the link.
GroundPendingDinner(ctx context.Context, arg GroundPendingDinnerParams) (int64, error)
// Reports whether a notification was stored after since, or at all when
// since is NULL.
HasNotificationSince(ctx context.Context, since sql.NullString) (bool, error)
// Stores a pending notification for one channel, due at once. A row already
// stored for the event key and channel, in any status, is left unchanged and
// no row is inserted.