Skip to content

Automated scholarship agreement emails - #2193

Draft
maebeale wants to merge 11 commits into
maebeale/scholarship-decline-emailfrom
maebeale/scholarship-agreement-emails
Draft

Automated scholarship agreement emails#2193
maebeale wants to merge 11 commits into
maebeale/scholarship-decline-emailfrom
maebeale/scholarship-agreement-emails

Conversation

@maebeale

Copy link
Copy Markdown
Collaborator

🤖 suggested review level: 3 Read 📖 additive notification/mailer wiring on top of the decline PR

Stacked on #2178 (base = maebeale/scholarship-decline-email). Merge that first.

What

The automated emails split out of #2178:

  • Decline → admin FYI (scholarship_agreement_declined_fyi) with the reason.
  • Sign → recipient confirmation (with a link back to their ticket) + admin FYI, sent once on the first sign.
  • Contact-us threading: the decline page's "contact us" link carries the registration through to the contact form and the contact FYI email, so the team lands on the right registration.

How

  • New Notification kinds + NotificationMailer methods + HTML/text views + previews, wired through NotificationMailerJob; EMAIL_TOPICS entries for the admin filter.
  • Controller wiring in events/callouts#sign_agreement / #decline_agreement.
  • Contact-us hidden field + mailer lookup + FYI link.

No schema changes — purely additive code on top of the decline feature.

maebeale and others added 11 commits August 13, 2026 11:45
Recipients can decline a scholarship agreement with a reason from their
scholarship page. Declining emails the admin team an FYI, records the
reason, zeroes the allocation so the award drops out of every total, and
shows a Declined badge everywhere scholarships appear. Editing the award
amount re-offers it and clears the decline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Editing the award amount re-offers the scholarship and discards the
recipient's recorded decline; warn the admin before that happens.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the two mutually-exclusive agreement timestamps with a single
agreement_response_status (pending/accepted/declined) + responded_at +
reason, so the states can't contradict and reinstating is a one-field
transition. Add a ScholarshipAgreementResponse audit log capturing each
accept/decline/re-offer, shown as a collapsible timeline on the edit page.
Signing a declined award now cleanly reinstates it; the decline guard warns
before either an amount change or a sign clears a decline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the redundant agreement_responded_at / agreement_response_reason
cache columns — the latest ScholarshipAgreementResponse is the source of
truth (only the status stays denormalized, since totals query it in SQL).
Link a decline's response row to the FYI notification it produced.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The agreement history preserves a decline through any reinstatement, so
the client-side "confirm before clearing a decline" guard is no longer
needed. Drop the Stimulus controller, its form hooks, and system spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Editing a declined award's amount no longer silently reactivates it.
Reinstating is now a deliberate server-side action: a Re-offer button
(button_to POST with Turbo's built-in confirm, no custom JS) sets the
award back to pending and re-funds the allocation. Consolidate the
declined banner onto the edit page beside the button.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…istration

On signing, email the recipient a confirmation with a link back to their
ticket and send the team an FYI (both once, on the first sign). The decline
page's "contact us" now links to the contact form threaded with the
registration, and that FYI email links the team to the registration.

Copy fixes and, when the decline reason box is open, hide the Agree button
via CSS :has() (no JS).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collapse the three iterative migrations (which added, reshaped, then trimmed
the agreement columns) into two clean ones: create scholarship_agreement_responses
(with the notification link), then replace agreement_signed_at with the tri-state
agreement_response_status — seeding each signed award's date onto an "accepted"
response row. Net schema is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
No signed agreements exist in production, so the status migration no longer
backfills or seeds history — it just adds agreement_response_status (default
pending) and drops agreement_signed_at. Zero DML.

Render the agreement history on the registrant scholarship callout too, but
only for admins and with sky "admin only" styling (registrants never see it).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Keep the decline button + reason and the whole decline/status/history/
re-offer feature here; move all the automated-email machinery (the
scholarship agreement signed/declined notification kinds, mailers, views,
previews, the controller code that sends them, the response→notification
link, and the contact-us registration threading) to a stacked follow-up PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stacked on the decline PR. On decline, email the admin team an FYI. On
sign, confirm to the recipient (with a link back to their ticket) and send
the team an FYI. Thread the decline page's "contact us" link through to the
contact form + FYI so the team lands on the right registration.

Adds the notification kinds, mailers + views + previews, the controller
wiring, and the contact-us registration threading.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@maebeale
maebeale force-pushed the maebeale/scholarship-decline-email branch from 2e39756 to 6bf5bf4 Compare August 15, 2026 22:53
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.

1 participant