Files
MOPC-Portal/docs/superpowers/specs/2026-06-01-mentorship-comms-and-welcome-email-design.md
2026-06-01 16:08:46 +02:00

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 (MentorMessage model; WorkspaceChat + MentorChat components; trpc.mentor.sendMessage / getMessages and trpc.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 MENTORING round 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 by MentorAssignment.notificationSentAt and MentorAssignment.teamIntroducedAt (src/server/services/round-engine.ts).

Two gaps remain:

  1. There is no single "email all team members" affordance for mentors — only per-person mailto: links.
  2. 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.ts wrapper, 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-member mailto: links.
  • Behavior: builds mailto:<comma-joined emails>?subject=... with all active team members in To: (per decision), subject pre-filled MOPC Mentorship — {project title}. Clicking opens the mentor's default mail app.
  • Edge cases: filter out blank/missing emails defensively (schema makes User.email required+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.ts draft→active flow keeps its one-time semantics (notificationSentAt / teamIntroducedAt gating) 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 NotificationLog rows + a DecisionAuditLog/audit entry.
    • Returns counts: { mentorCount, teamMemberCount, teamCount } for the success toast.

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, near NotifyAdvancedButton / NotifyRejectedButton / BulkInviteButton), rendered only when the round is MENTORING.
    • 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.

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.ts fns 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 sendMentorshipWelcome on 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)

  1. 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.
  2. Tailored content per audience (mentor vs team), with contact emails embedded in the relevant spot.
  3. Manual reminder: fixed branded template + optional custom note.
  4. "Email all" button: all members in To:.
  5. Team email includes both the mentor's email and teammates' emails.
  6. Manual reminder sends to both audiences (no per-audience toggle in v1).
  7. Preview via an in-app button (live, real-data, iframe) rather than pasted static HTML.