Skip to content

[FEAT] : add Timezone-Aware Weekly Digest (Aesthetics & UX) #3000

Open
hrshjswniii wants to merge 5 commits into
Priyanshu-byte-coder:mainfrom
hrshjswniii:feature/Weekly-Digest
Open

[FEAT] : add Timezone-Aware Weekly Digest (Aesthetics & UX) #3000
hrshjswniii wants to merge 5 commits into
Priyanshu-byte-coder:mainfrom
hrshjswniii:feature/Weekly-Digest

Conversation

@hrshjswniii

Copy link
Copy Markdown
Contributor

Summary

Updates the weekly digest email cron job to deliver digests at Monday 09:00 AM in the user's local timezone instead of a single global UTC slot. It shifts the cron run schedule from once-weekly to hourly, matches users dynamically, and fixes a non-deterministic pagination bug in the users table database query.

Closes #2982


Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that changes existing behavior)
  • 📝 Documentation update
  • ♻️ Refactor / code cleanup (no functional change)
  • ⚡ Performance improvement
  • 🔒 Security fix
  • 🧪 Tests only

What Changed

  • [vercel.json]:
    • Modified the schedule parameter for /api/cron/weekly-digest from once-weekly (0 9 * * 1) to hourly (0 * * * *).
  • [src/app/api/cron/weekly-digest/route.ts]:
    • Added isUserLocalTimeTargetRange helper using Intl.DateTimeFormat to resolve local hours and weekdays for users.
    • Implemented currentWeekLabelInTimezone to compute week labels matching the local Monday date. This resolves skew errors in eastern timezones (e.g. Sydney, Tokyo) where Sunday UTC is already Monday local.
    • Fixed a pagination bug by inserting an explicit .order("id") instruction before the .range() block to ensure deterministic database query paging.
    • Integrated the timezone checks in the execution loop and tracked hourly skips with a new skippedTimezoneCount property.

How to Test

  1. Opt-in a test user to receive weekly digests and set their timezone setting (e.g., America/New_York or Asia/Kolkata).
  2. Run the cron endpoint locally (supplying the Authorization header).
  3. If the current time matches Monday 9 AM in the test user's timezone, verify the email is sent successfully.
  4. If the current time does not match Monday 9 AM, verify that the console outputs skipped_timezone for that user and that the return payload increments skippedTimezoneCount.
  5. Verify that the email's subject line displays the correct date of Monday in the user's timezone.

Expected result: Users only receive digests at Monday 9 AM local time, and week label dates are calculated correctly based on local offsets.


Checklist

  • Linked the related issue above
  • Self-reviewed my own diff
  • No unnecessary console.log, debug code, or commented-out blocks
  • npm run lint passes locally
  • No TypeScript errors (npm run type-check)
  • Added or updated tests where applicable
  • Updated documentation / comments if behavior changed

Accessibility (UI changes only)

N/A - Backend / configuration change.


Additional Context

The idempotency guard cooldown (DIGEST_COOLDOWN_MS = 6 days) is preserved, guaranteeing that even if a user switches timezones or crons overlap, they will never receive duplicate digest emails in the same week.

@github-actions github-actions Bot added type:bug GSSoC type bonus: bug fix type:feature GSSoC type bonus: new feature type:design GSSoC type bonus: UI/design (+10 pts) type:performance GSSoC type bonus: performance (+15 pts) gssoc26 GSSoC 2026 contribution labels Jul 1, 2026
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

GSSoC Label Checklist 🏷️

@Priyanshu-byte-coder — please apply the appropriate labels before merging:

Difficulty (pick one):

  • level:beginner — 20 pts
  • level:intermediate — 35 pts
  • level:advanced — 55 pts
  • level:critical — 80 pts

Quality (optional):

  • quality:clean — ×1.2 multiplier
  • quality:exceptional — ×1.5 multiplier

Validation (required to score):

  • gssoc:approved — counts for points
  • gssoc:invalid / gssoc:spam / gssoc:ai-slop — does not score

Type labels (type:*) are auto-detected from files and title. Review and adjust if needed.
Points formula: (difficulty × quality_multiplier) + type_bonus

@hrshjswniii

Copy link
Copy Markdown
Contributor Author

Hiii @Priyanshu-byte-coder , do review the issue implemented and feel free to merge the Pr !!

@Priyanshu-byte-coder

Copy link
Copy Markdown
Owner

New feature/UI PRs are on hold during the code-quality sprint — see discussion #2651. We'll revisit this after the sprint; meanwhile tests, refactors, and bug-fix PRs are very welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc26 GSSoC 2026 contribution type:bug GSSoC type bonus: bug fix type:design GSSoC type bonus: UI/design (+10 pts) type:feature GSSoC type bonus: new feature type:performance GSSoC type bonus: performance (+15 pts)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] : Timezone-Aware Weekly Digest (Aesthetics & UX)

2 participants