Skip to content

Fix newsletter trigger semantics, Monday roundup gating, roundup idempotency, and website-order section rendering#455

Merged
rvanmaanen merged 7 commits into
mainfrom
copilot/timing-of-roundup-newsletter
May 30, 2026
Merged

Fix newsletter trigger semantics, Monday roundup gating, roundup idempotency, and website-order section rendering#455
rvanmaanen merged 7 commits into
mainfrom
copilot/timing-of-roundup-newsletter

Conversation

Copilot AI commented May 30, 2026

Copy link
Copy Markdown
Contributor

Newsletter sending had two gaps: admin “Send Newsletter” only triggered roundup flow, and roundup dispatch could run at the wrong cycle boundary. This change separates manual trigger modes (roundup vs daily), gates roundup sends to the expected Monday cycle, normalizes section ordering in emails to match website order, and ensures roundup sends are idempotent per cycle with a single send-log row.

  • Manual trigger modes (admin/API)

    • Added kind support to newsletter trigger (roundup default, daily optional).
    • Wired trigger kind through API endpoint, background service, web API client, and admin UI.
    • Replaced single admin action with two explicit actions: Send Roundup and Send Daily.
  • Roundup timing gate

    • Changed roundup selection to load latest roundup per section with (slug, date_epoch).
    • Roundup send now proceeds only when each section’s latest roundup date matches the expected Monday in Brussels time:
      • current Monday if triggered on Monday
      • otherwise the most recent Monday
  • Roundup idempotency + send-log granularity

    • Combined roundup sends are now keyed by the Monday cycle (yyyy-MM-dd) instead of per-section slug.
    • Periodic/manual roundup runs skip when that cycle key is already marked as sent.
    • Send log now records one row per roundup cycle email (instead of one row per section roundup).
  • Section ordering in email content

    • Added ordering helpers in NewsletterService to sort sections/roundups by configured website section order (AppSettings.Content.Sections[*].Order).
    • Applied ordering to:
      • combined weekly digest section blocks
      • test weekly sends
      • daily overview section blocks
  • Focused test updates

    • Added coverage for daily admin trigger path.
    • Added coverage that weekly and daily email sections render in website order.
    • Added client test ensuring trigger kind normalization/query construction.
    • Added roundup-trigger coverage for Monday-gated behavior (send when Monday-aligned, skip when not aligned).
    • Updated weekly send tests to assert cycle-key dedupe and single-row roundup send logging.
// Admin trigger now supports explicit kind
var kind = string.Equals(kindParam?.Trim(), "daily", StringComparison.OrdinalIgnoreCase)
    ? "daily"
    : "roundup";
backgroundService.TriggerImmediateRun(kind);

// Roundup send waits for expected Monday cycle (Brussels time)
var roundupTimeZone = ResolveRoundupTimeZone();
var expectedMonday = GetExpectedRoundupMonday(DateTimeOffset.UtcNow, roundupTimeZone);
if (!latestRoundups.All(r => GetRoundupDate(r.DateEpoch, roundupTimeZone) == expectedMonday))
{
    return; // wait for expected Monday cycle
}

// Use Monday cycle key to prevent duplicate roundup sends and log once per roundup email
await newsletterService.SendCombinedWeeklyAsync(
    slugs,
    sendTargetKey: expectedMonday.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture),
    ct);

Copilot AI linked an issue May 30, 2026 that may be closed by this pull request
Comment thread tests/TechHub.Api.Tests/Endpoints/NewsletterEndpointsTests.cs Fixed
Comment thread tests/TechHub.Api.Tests/Endpoints/NewsletterEndpointsTests.cs Fixed
Copilot AI changed the title [WIP] Update timing and buttons for roundup newsletter Fix newsletter trigger semantics and enforce website-order section rendering May 30, 2026
Copilot AI requested a review from rvanmaanen May 30, 2026 09:44
@rvanmaanen

Copy link
Copy Markdown
Collaborator

@copilot waiting until all roundups have the same date epoch won't work I think, you need to check if they all have a date matching the last Monday, or current Monday if triggered on a Monday

Copilot AI commented May 30, 2026

Copy link
Copy Markdown
Contributor Author

@copilot waiting until all roundups have the same date epoch won't work I think, you need to check if they all have a date matching the last Monday, or current Monday if triggered on a Monday

Updated in commit eaeff7a: roundup gating now checks that each section’s latest roundup date matches the expected Monday in Brussels time (current Monday when run on Monday, otherwise the previous Monday), rather than requiring identical epochs across sections.

Comment on lines +388 to +390
catch (TimeZoneNotFoundException)
{
}
Comment on lines +391 to +393
catch (InvalidTimeZoneException)
{
}
Copilot AI changed the title Fix newsletter trigger semantics and enforce website-order section rendering Fix newsletter trigger semantics, Monday roundup gating, and website-order section rendering May 30, 2026
@rvanmaanen

Copy link
Copy Markdown
Collaborator

@copilot with our periodic jobs, how do we make sure we don't send out a newsletter for the same roundups twice?

And I think when I tested a roundup email I saw in the send log in the admin screens rows appear for each section. I just want love row for the roundup email (it's only one email after all) and one for a daily email

Copilot AI commented May 30, 2026

Copy link
Copy Markdown
Contributor Author

@copilot with our periodic jobs, how do we make sure we don't send out a newsletter for the same roundups twice?

And I think when I tested a roundup email I saw in the send log in the admin screens r...

Addressed in 11a73c3.

  • Roundup sends are now keyed/logged once per Monday cycle (yyyy-MM-dd) instead of per-section slug.
  • The background job passes that Monday cycle key into the combined roundup send, and the send is skipped if that cycle key is already marked as sent.
  • This gives one send-log row for the roundup email cycle (and daily continues as one row per day).

Copilot AI changed the title Fix newsletter trigger semantics, Monday roundup gating, and website-order section rendering Fix newsletter trigger semantics, Monday roundup gating, roundup idempotency, and website-order section rendering May 30, 2026
@rvanmaanen

Copy link
Copy Markdown
Collaborator

@copilot tests fail

Copilot AI commented May 30, 2026

Copy link
Copy Markdown
Contributor Author

@copilot tests fail

Fixed in 179a1cd. The failing integration test was due to a strict email mock that only allowed one recipient; I updated it to allow sends and capture/assert for the intended test recipient only. TechHub.Infrastructure.Tests now passes.

@github-actions

github-actions Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor

⏰ PR Preview Environment — Nightly Teardown

The preview environment was automatically torn down as part of the nightly cleanup (23:00 Brussels time).

To resume testing:

  • Push a new commit to this branch to automatically re-deploy (full CI + new images), or
  • Trigger the Redeploy PR Environment workflow manually to redeploy using the last-built image (no new commit needed).

@rvanmaanen
rvanmaanen marked this pull request as ready for review May 30, 2026 15:36
@rvanmaanen
rvanmaanen requested a review from rajbos as a code owner May 30, 2026 15:36
Copilot AI review requested due to automatic review settings May 30, 2026 15:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refines newsletter sending semantics across the API, background worker, infrastructure service, web client, admin UI, and tests. It separates roundup vs daily manual triggers, gates roundup dispatch by the expected Brussels-time Monday cycle, and aligns email section ordering with configured website order.

Changes:

  • Added kind-based newsletter triggering for roundup and daily sends across admin/API/client/background paths.
  • Updated weekly roundup sending to use Monday cycle keys for idempotency and single-row send logging.
  • Added ordering helpers/tests so weekly and daily email sections render in configured website order.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/TechHub.Api/Endpoints/NewsletterEndpoints.cs Accepts and normalizes trigger kind, then forwards it to the background service.
src/TechHub.Api/Services/NewsletterBackgroundService.cs Routes manual daily vs roundup sends and gates roundup sends to the expected Monday cycle.
src/TechHub.Core/Interfaces/INewsletterService.cs Extends combined weekly sending with an optional send target key.
src/TechHub.Infrastructure/Services/Newsletter/NewsletterService.cs Implements cycle-key idempotency, single-row roundup logging, and section ordering helpers.
src/TechHub.Web/Services/ITechHubApiClient.cs Updates the newsletter trigger client contract to accept a trigger kind.
src/TechHub.Web/Services/TechHubApiClient.cs Normalizes trigger kind and includes it in the admin trigger request.
src/TechHub.Web/Components/Pages/Admin/AdminNewsletter.razor Splits the admin trigger into explicit Send Roundup and Send Daily actions.
tests/TechHub.Api.Tests/Endpoints/NewsletterEndpointsTests.cs Adds endpoint coverage for daily triggering and Monday-gated roundup behavior.
tests/TechHub.Infrastructure.Tests/Services/NewsletterServiceTests.cs Updates weekly send-log expectations and adds email ordering coverage.
tests/TechHub.Web.Tests/Services/TechHubApiClientTests.cs Verifies trigger kind normalization and query construction.

@rvanmaanen
rvanmaanen merged commit 9dd3eaa into main May 30, 2026
33 of 34 checks passed
@rvanmaanen
rvanmaanen deleted the copilot/timing-of-roundup-newsletter branch May 30, 2026 16:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

timing of roundup newsletter

3 participants