9.1 KiB
9.1 KiB
Mentorship Communications & Welcome/Reminder Email — Design
- Date: 2026-06-01
- Status: Approved (pending spec review)
- Author: Matt + Claude
- Topic: Make mentor↔team contact effortless and add a re-sendable, instructional "welcome/reminder" email for mentoring rounds.
Context
MOPC already has a working mentorship feature:
- Two-way in-app messaging exists (
MentorMessagemodel;WorkspaceChat+MentorChatcomponents;trpc.mentor.sendMessage/getMessagesandtrpc.applicant.sendMentorMessage/getMentorMessages). Mentors are auto-notified when applicants write. - Contact emails are already visible: mentors see each team member's email as individual
mailto:links (src/app/(mentor)/mentor/projects/[id]/page.tsx); applicants see their mentor's name+email (src/app/(applicant)/applicant/mentor/page.tsx) and teammates' emails (src/app/(applicant)/applicant/team/page.tsx). - Round-open auto emails already fire: flipping a
MENTORINGround draft→active sends a coalesced "you've been assigned to N projects" email to each mentor (getMentorBulkAssignmentTemplate/sendMentorBulkAssignmentEmail) and a "meet your mentors" intro to each team (getTeamMentorIntroductionTemplate/sendTeamMentorIntroductionEmail). These are one-time, gated byMentorAssignment.notificationSentAtandMentorAssignment.teamIntroducedAt(src/server/services/round-engine.ts).
Two gaps remain:
- There is no single "email all team members" affordance for mentors — only per-person
mailto:links. - The round-open emails don't explain how to use the mentorship features, and there is no way to re-send them later as a reminder.
Goals
- A mentor can email their whole team in one click (opens their mail client, all members in
To:). - The round-open assignment emails are upgraded in place to include (a) the relevant contact emails and (b) how-to-use-the-mentorship-features instructions.
- An admin can re-send that same email on demand (a "welcome/reminder" blast) to all mentors + teams in a mentoring round, with an optional custom note.
- The admin can preview the exact email (mentor + team versions) before sending.
Non-goals
- No new in-app messaging surfaces (the chat already exists).
- No new email-provider infrastructure (reuse
src/lib/email.tswrapper, helpers, throttling,NotificationLog). - No mentors-only / teams-only targeting toggle for v1 — the reminder sends to both audiences. (Can be added later if needed.)
Feature 1 — Mentor "Email all team members" button
- Location:
src/app/(mentor)/mentor/projects/[id]/page.tsx, in the existing Team Members card, alongside the per-membermailto:links. - Behavior: builds
mailto:<comma-joined emails>?subject=...with all active team members inTo:(per decision), subject pre-filledMOPC Mentorship — {project title}. Clicking opens the mentor's default mail app. - Edge cases: filter out blank/missing emails defensively (schema makes
User.emailrequired+non-null, but be safe); hide the button when the team has zero emailable members. - Scope: pure client-side; no backend changes.
Feature 2 — Unified mentorship welcome/reminder email
Decision: upgrade in place, don't duplicate
Rather than send a second email on round-open, the existing two templates are enhanced so they carry the instructions + contact emails. The same template code is reused by both trigger paths below. One email per audience; one source of truth.
Content — Mentor version (coalesced per mentor, across their projects in the round)
- Greeting by mentor name.
- Optional custom note (rendered in an info box near the top) — only present on the manual reminder path.
- For each assigned project: project title (linked) + the team members listed with name + email.
- "How to mentor on MOPC" instructions block: where the workspace chat lives, file sharing, the mentor dashboard.
- CTA → Mentor Dashboard.
Content — Team version (per project)
- Greeting by recipient name.
- Optional custom note (info box) — manual path only.
- The assigned mentor(s) listed with name + email.
- The team's own members listed with email (per decision: include teammates too).
- "How to work with your mentor" instructions block: where the in-app chat is, how to reach the mentor, what to expect.
- CTA → mentoring page.
Both reuse getEmailWrapper() and existing helpers (sectionTitle, paragraph, ctaButton, infoBox, escapeHtml) for consistent branding.
Trigger path A — auto on round-open (existing flow, upgraded content)
src/server/services/round-engine.tsdraft→active flow keeps its one-time semantics (notificationSentAt/teamIntroducedAtgating) and coalescing.- It now passes the additional data the upgraded templates need: team-member name+email for the mentor email, and mentor name+email + teammate emails for the team email.
- No custom note on this path.
Trigger path B — manual reminder button (admin, on demand)
- New
adminProcedure:mentor.sendMentorshipWelcome({ roundId, customNote?: string }).- Resolves all current active assignments for the round (
droppedAt: null) → groups by mentor → sends mentor emails; resolves all projects with assignments → sends team emails to all members. - Ignores
notificationSentAt/teamIntroducedAt(deliberate re-send). Does not mutate those flags. - Throttled + fire-and-forget like existing bulk sends; writes
NotificationLogrows + aDecisionAuditLog/audit entry. - Returns counts:
{ mentorCount, teamMemberCount, teamCount }for the success toast.
- Resolves all current active assignments for the round (
Preview
- New query:
mentor.previewMentorshipWelcome({ roundId, customNote?: string })→{ mentor: { subject, html }, team: { subject, html } }.- Calls the same template functions used by the real send.
- Picks a representative recipient: first mentor with assignments + first project/team in the round. If the round has none yet, returns clearly-labeled sample-data output so the layout is still previewable.
- Rendered in the send dialog inside a sandboxed
<iframe srcDoc={html}>(isolates email CSS from the app), with Mentor / Team sub-tabs. The custom-note textarea updates the preview live (debounced).
Admin UI
- New component
src/components/admin/round/send-mentorship-welcome-button.tsx:- Lives in the round detail page's Notifications section (
src/app/(admin)/admin/rounds/[roundId]/page.tsx, nearNotifyAdvancedButton/NotifyRejectedButton/BulkInviteButton), rendered only when the round isMENTORING. - Opens a dialog: recipient summary ("N mentors · M team members across K teams"), optional custom-note textarea, live Preview (Mentor/Team tabs), and a Send button with confirmation.
- Lives in the round detail page's Notifications section (
Files touched
| File | Change |
|---|---|
src/app/(mentor)/mentor/projects/[id]/page.tsx |
Add "Email all team members" button (mailto, all in To:) |
src/lib/email.ts |
Enhance getMentorBulkAssignmentTemplate + getTeamMentorIntroductionTemplate (contacts, instructions, optional customNote); update sendMentorBulkAssignmentEmail / sendTeamMentorIntroductionEmail signatures + all call sites |
src/server/services/round-engine.ts |
Pass team-member/mentor emails into upgraded templates on round-open |
src/server/routers/mentor.ts |
New sendMentorshipWelcome (adminProcedure) + previewMentorshipWelcome (adminProcedure query) |
src/components/admin/round/send-mentorship-welcome-button.tsx (new) |
Dialog: counts, custom note, live iframe preview, send |
src/app/(admin)/admin/rounds/[roundId]/page.tsx |
Wire the button into the Notifications section, gated to mentoring rounds |
Implementation ordering note
Build the templates first and render both to standalone .html files (and/or screenshots) for copy review before wiring the send path — gives an early visual check with zero throwaway work.
Testing
- Template unit tests (
src/lib/email.tsfns return{ subject, html, text }, easy to assert): mentor email contains each team member's email + instructions block; team email contains mentor email(s) + teammate emails + instructions; custom note appears when passed, absent when not. - tRPC test for
sendMentorshipWelcomeon a seeded mentoring round: correct recipient resolution and returned counts; does not flip the one-time flags. - tRPC test for
previewMentorshipWelcome: returns non-empty mentor + team HTML for a seeded round; sample-data fallback for an empty round.
Decisions (resolved during brainstorming)
- Upgrade existing intro emails in place (single source of truth), reused by both auto-open and the manual reminder; fallback would have been a standalone manual-only blast.
- Tailored content per audience (mentor vs team), with contact emails embedded in the relevant spot.
- Manual reminder: fixed branded template + optional custom note.
- "Email all" button: all members in
To:. - Team email includes both the mentor's email and teammates' emails.
- Manual reminder sends to both audiences (no per-audience toggle in v1).
- Preview via an in-app button (live, real-data, iframe) rather than pasted static HTML.