Skip to content

Add goal completion notifications - #1613

Open
skyfallwastaken wants to merge 1 commit into
mainfrom
goal-completion-notifications
Open

Add goal completion notifications#1613
skyfallwastaken wants to merge 1 commit into
mainfrom
goal-completion-notifications

Conversation

@skyfallwastaken

Copy link
Copy Markdown
Member

Summary of the problem

Goals track progress but do not tell users when they reach a target.

Closes #1587

Describe your changes

Adds optional email and Slack completion notifications to each goal. Heartbeat activity checks enabled goals and a durable per-period record prevents duplicate notifications. Existing goals remain opted out until a user selects a notification channel.

Screenshots / Media

Not included. The visual change adds email and Slack checkboxes to the existing goal form.

Copilot AI lite review requested due to automatic review settings August 20, 2026 13:07

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds opt-in email and Slack notifications when programming goals are completed.

  • Extends goal settings, persisted channel preferences and Inertia/Svelte form props.
  • Schedules completion checks from heartbeat activity and records one completion snapshot per goal period.
  • Adds email and Slack delivery jobs, templates, migrations and coverage across controllers, jobs, models, services and system tests.

Confidence Score: 3/5

The PR should not merge until completion checks cannot be silently dropped and delivery retries cannot send duplicate notifications.

Rapid heartbeat activity can discard the threshold-crossing check under the per-user concurrency limit, while interrupted email or Slack delivery can repeat the external side effect because delivery state is only recorded afterwards.

Files Needing Attention: app/jobs/goal_completion_check_job.rb, app/jobs/goal_completion_email_job.rb and app/jobs/goal_completion_slack_job.rb

Important Files Changed

Filename Overview
app/jobs/goal_completion_check_job.rb Introduces completion detection and period deduplication, but its total concurrency limit can discard the only check that observes a threshold-crossing heartbeat.
app/jobs/goal_completion_email_job.rb Sends completion email before persisting delivery state, allowing duplicate delivery after an interruption.
app/jobs/goal_completion_slack_job.rb Posts directly to Slack before persisting delivery state and has the same retry-idempotency gap as email.
app/services/heartbeat_ingest.rb Schedules checks after successful direct ingestion while the production historical-import path remains excluded through its existing scheduling flag.
app/javascript/pages/Users/Settings/Goals.svelte Adds channel controls and notification status to the existing editable goal form with matching server props.
db/migrate/20260820115209_create_goal_completion_notifications.rb Adds durable per-period notification snapshots with a database uniqueness constraint on goal, period and period start.

Sequence Diagram

sequenceDiagram
  participant HB as Heartbeat ingest
  participant Check as GoalCompletionCheckJob
  participant DB as PostgreSQL
  participant Delivery as Email/Slack job
  participant External as Mail/Slack API
  HB->>Check: schedule_for(user_id)
  Check->>DB: calculate progress
  Check->>DB: create/find period notification
  Check->>Delivery: enqueue selected channels
  Delivery->>External: send completion notification
  Delivery->>DB: set delivered_at
Loading
Prompt To Fix All With AI
### Issue 1
app/jobs/goal_completion_check_job.rb:14-16
**Concurrency drops completion checks**

If heartbeat processing overlaps for one user, the per-user `total_limit` discards later checks while the accepted check can run before the threshold-crossing heartbeat is visible, causing the completed goal to receive no notification until another heartbeat schedules a check.

### Issue 2
app/jobs/goal_completion_email_job.rb:23-24
**Delivery state permits duplicates**

When external delivery succeeds but the subsequent `delivered_at` update fails or the worker stops before it commits, a retry or later completion check sees a nil marker and sends the notification again, causing duplicate email; the Slack job has the same ordering problem.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "Add goal completion notifications" | Re-trigger Greptile

Comment on lines +14 to +16
total_limit: 1, key: -> { "goal_completion_check_job_#{arguments.first}" }
)

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.

P1 Concurrency drops completion checks

If heartbeat processing overlaps for one user, the per-user total_limit discards later checks while the accepted check can run before the threshold-crossing heartbeat is visible, causing the completed goal to receive no notification until another heartbeat schedules a check.

Context Used: AGENTS.md (source)

Knowledge Base Used:

Prompt To Fix With AI
This is a comment left during a code review.
Path: app/jobs/goal_completion_check_job.rb
Line: 14-16

Comment:
**Concurrency drops completion checks**

If heartbeat processing overlaps for one user, the per-user `total_limit` discards later checks while the accepted check can run before the threshold-crossing heartbeat is visible, causing the completed goal to receive no notification until another heartbeat schedules a check.

**Context Used:** AGENTS.md ([source](https://github.com/hackclub/hackatime/blob/main/AGENTS.md))

**Knowledge Base Used:**
- [Background Jobs Infrastructure (GoodJob)](https://app.greptile.com/mahadk/-/custom-context/knowledge-base/hackclub/hackatime/-/docs/background-jobs-infra.md)
- [Heartbeat Ingest](https://app.greptile.com/mahadk/-/custom-context/knowledge-base/hackclub/hackatime/-/docs/heartbeat-ingest.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +23 to +24
GoalCompletionMailer.reached(notification, recipient_email: recipient_email).deliver_now
notification.update!(email_delivered_at: Time.current)

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.

P1 Delivery state permits duplicates

When external delivery succeeds but the subsequent delivered_at update fails or the worker stops before it commits, a retry or later completion check sees a nil marker and sends the notification again, causing duplicate email; the Slack job has the same ordering problem.

Context Used: AGENTS.md (source)

Knowledge Base Used: Background Jobs Infrastructure (GoodJob)

Prompt To Fix With AI
This is a comment left during a code review.
Path: app/jobs/goal_completion_email_job.rb
Line: 23-24

Comment:
**Delivery state permits duplicates**

When external delivery succeeds but the subsequent `delivered_at` update fails or the worker stops before it commits, a retry or later completion check sees a nil marker and sends the notification again, causing duplicate email; the Slack job has the same ordering problem.

**Context Used:** AGENTS.md ([source](https://github.com/hackclub/hackatime/blob/main/AGENTS.md))

**Knowledge Base Used:** [Background Jobs Infrastructure (GoodJob)](https://app.greptile.com/mahadk/-/custom-context/knowledge-base/hackclub/hackatime/-/docs/background-jobs-infra.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

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.

Goal notifications!

2 participants