Files
MOPC-Portal/docs/superpowers/specs/2026-06-01-mentorship-comms-and-welcome-email-design.md

123 lines
9.1 KiB
Markdown
Raw Normal View History

# 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.