Red Stet
← Back to Help
Help · For teachers & students · Tier 2 — Day-to-day teaching

Messaging in Red Stet

Three messaging surfaces: per-assignment 1:1 threads, per-assignment updates that fan out to the whole class, and class-wide announcements not tied to any assignment. How each works and when to reach for which.

Three surfaces, one mental model

Each surface answers a different question.

Per-assignment 1:1 thread

Private conversation between one student and teaching staff, scoped to an assignment. "I'm stuck on question 3" belongs here. Other students never see it.

Class-wide assignment update

One-to-many post anchored to a specific assignment. assignmentUpdates.create. "Due date moved to Friday" belongs here.

Class-wide announcement

One-to-many post anchored to the class, no assignment required. classroomAnnouncements.create. "Reading for next week is in your inbox" or "Lab safety briefing Friday" belongs here.

1:1 thread on "Essay 3"
Mr. M — can the source from week 2 count for this?
Ava · Nov 12, 3:14p
Yes — just cite it properly. See the rubric.
You · Nov 12, 3:21p
Class-wide · Nov 13, 9:02a
Update on "Essay 3": I extended the due date to Friday 11:59p. Same prompt, same rubric.

The per-assignment thread assignmentMessages

One private thread per (assignment, student). Created lazily — the first message brings it into existence; assignments with no questions stay clean.

From the student side, the thread lives in the assignment info panel under the Messages tab. Open an assignment, switch tabs, type, send. Student messages are right-aligned red; teacher messages left-aligned grey.

From the teacher side, reach it two ways: the Messages button next to the student's submission on the grading view, or the teacher inbox which aggregates every thread across every assignment you own or staff.

Sending fans out a notification to the other party. Sender is implicitly read; recipient counts as unread until they open the thread.

The thread is per (assignment, student). Same student asking about a different assignment lands in a different thread. No global student-teacher DM — every message is anchored to context.
Messages · Essay 3 · with Ava Chen
I can't tell if footnotes count toward the word limit.
Nov 12, 8:44p
They don't. Body text only.
Nov 12, 9:10p
Got it, thanks!
Nov 12, 9:11p
Send

Who can see a thread

The thread for assignment X + student Y is visible to:

  • Student Y — their own thread, no others.
  • The assignment's owner — every student's thread for this assignment.
  • Co-teachers and TAs with gradeSubmissions — same teacher-side view.

The check is enforced server-side in assignmentMessages.create. With gradeSubmissions off, the UI still shows the thread but the send button errors.

Other students never see this thread. Even with roster visibility on, peers see "who's enrolled," not "messages with the teacher."

Removed staff lose access immediately. Authorship on old messages stays (senderUserId is permanent); they can't read or post.

ViewerReadsReplies
Student Y (the student of record)YesYes
Owner of the assignmentYesYes
Co-teacher (with grade rights)YesYes
TA (with grade rights)YesYes
Other student in same classNoNo
Removed staffNoNo

Class-wide assignment updates assignmentUpdates

Post an assignment update from the assignment view's Updates section. Every active enrollee gets a notification titled Update on "<assignment>" with a snippet. The update also lands in the assignment's Stream entry and each student's info panel.

Use it for:

  • "Typo in question 3 — corrected version is now live."
  • "Due date moved to Friday 11:59."
  • "I uploaded a graphic-organizer template — link in the assignment description."

Updates are text-only. Files: attach to the assignment itself, a class-wide announcement, or a 1:1 thread.

Fan-out is atomic. The update row and every per-student notification land in the same Convex mutation. No bell entries pointing at a post that didn't happen.
Updates on "Essay 3"
Today · 9:02a
I extended the due date to Friday 11:59p. Same prompt, same rubric.
Yesterday · 4:18p
Reminder: footnotes don't count toward the word limit. Body text only.
Mon · 8:30a
I uploaded a graphic-organizer template — link in the assignment description.
Each update goes to every active enrollee's bell + the assignment's Stream entry.

Class-wide announcements classroomAnnouncements

A class-wide post not tied to any assignment. Scope is the whole class; anchor is the class itself.

Compose from the Stream tab. The + Post announcement disclosure opens a textarea with inline attachment chips. Paste, attach if needed, Post. The card lands at top of Stream and fans out to every recipient in the same transaction.

Recipients

Every active student and active staff member (owner, co-teachers, TAs) gets a bell entry (kind: 'classroom-announcement', deep-linked to the class) plus a transactional email with the body snippet and "Open in Red Stet" button. The author is excluded.

Who can post

Gated by postClassMessages. Owners and co-teachers on by default; TAs off by default but grantable per-class from the People tab. Students don't see the composer.

Attachments

Same pipeline as assignment attachments: signed PUT URL via classroomAnnouncements.generateAttachmentUploadUrl, bytes straight to Convex storage, storageId embedded in the row. Recipients click chips to download via signed URLs from classroomAnnouncements.getAttachmentUrls.

Editing and deleting

The author or classroom owner can soft-delete from the Stream card. The row stays for audit; disappears from every recipient's feed. Already-fanned-out notifications aren't retracted. No edit-in-place — delete and repost.

Decision rule. Whole class, not about an assignment → announcement. Whole class, about an assignment → assignment update. One student → 1:1 thread.
+ Post announcement
lab-safety-worksheet.pdf ×
+ Attach file Post
📣 Announcement · Ms. Hartwell Today · 9:14a

Heads up — the lab safety briefing moved to Friday. Bring the worksheet I attached.

lab-safety-worksheet.pdf
Delete announcement
Every recipient gets a bell entry plus an email mirror.

Notifications and the bell notifications

Every message and every update fans out one row per recipient into the notifications table. The bell flyout reads from this feed.

Each row carries:

  • title — sender + assignment for thread messages; Update on "<assignment>" for updates
  • body — 120-character snippet
  • refKind + refId — deep-link target
  • classroomId — color-coding to source class

Clicking opens the assignment with the right tab pre-selected. Read state is tracked per-user on the notification row, independent of the message's readBy array — dismissing the bell doesn't mark the thread read; opening the thread doesn't clear unrelated bell items.

Email mirror

Every thread message also emails the recipient: subject "Sender: Assignment", body carrying sender name, classroom and assignment context, snippet, and deep link. Attachments are mentioned; the files stay in Red Stet behind auth.

Class-wide announcements mirror the same way — every recipient gets a transactional email with snippet and class deep link.

One source of truth: bell + email fire from the same mutation. Sends are best-effort — a failed SMTP attempt logs without rolling back the message or in-app notifications.

Ava Chen (Essay 3)
Mr. M — can the source from week 2 count for this assignment?
2 min ago
Update on "Essay 3"
I extended the due date to Friday 11:59p. Same prompt, same rubric.
2 hr ago
Diego Reyes (Reflection 4)
Got it, thanks!
Yesterday

Muting notification kinds users.notificationMuteKinds

Customizations → Notifications has a toggle per kind. Off suppresses the bell entry for that kind.

Six muteable kinds:

  • Assignment updates (assignment-update) — teacher follow-ups on an assignment.
  • Assignment messages (assignment-message) — replies on your 1:1 thread.
  • Classroom announcements (classroom-announcement) — class-wide posts.
  • Assignment reminders (assignment-reminder) — teacher nudges about outstanding work.
  • Submission graded (submission-graded) — your work was graded.
  • Submission returned (submission-returned) — teacher returned a submission for revision.

Mute only suppresses the bell — the underlying messages, updates, and reminders still land in their own surfaces. Email mirrors are governed separately.

Stored in users.notificationMuteKinds; mutes follow you across devices.

Notifications
Assignment updates ON
Assignment messages ON
Classroom announcements ON
Assignment reminders MUTED
Submission graded ON
Submission returned ON

Settings sync across devices via Convex.

The teacher inbox

The teacher view has two tabs: Classrooms and Inbox. The Inbox is your cross-class triage — one row per (assignment, student) thread, sorted by most-recent activity. Unread rows carry a red left-border and count badge.

Each row: student name, assignment title, latest snippet, unread count. Click to open in the message modal; opening calls markThreadRead and clears the badge.

The inbox aggregates every assignment you own or staff (co-teacher or TA). A co-teacher on three classes sees the union. assignmentMessages.listForTeacherInbox dedupes.

A top-bar badge shows total unread thread messages (assignmentMessages.unreadCountForMe). Separate from the bell badge, which is broader than messages.

2
Ava Chen 2 min
Essay 3 · AP Lit Per. 4
Mr. M — can the source from week 2 count for this assignment?
1
Ben Kowalski 14 min
Reflection 4 · English 11 Per. 2
I'm not sure what counts as "evidence" for the third bullet — is it just citations?
Diego Reyes Yesterday
Reflection 4 · English 11 Per. 2
Got it, thanks!

Unread and mark-read

Each message row carries a readBy array. Opening a thread calls markThreadRead, appending the viewer's ID to every unread row. Senders are implicitly read on their own rows.

That powers:

  • Unread badge on the teacher inbox row and top-bar pill
  • Unread badge on the student-side Messages tab
  • Cross-thread total on the dashboard chip

Mark unread

Any participant can flip a thread back to unread. Two places:

  • On the teacher inbox row — Mark unread for read threads, Mark read to dismiss without opening.
  • Inside the open thread modal — header Mark unread button closes and re-flags.

markThreadUnread strips the caller's ID from every readBy array except rows they sent. Use it for "I'll come back to this" — read during triage, surface again tomorrow.

Dashboard
Inbox 3
Classrooms
Unread count rolls up from every (assignment, student) thread you own.

Who can send what

Two separate capabilities gate the two surfaces:

  • gradeSubmissions — required to reply on a per-student thread. Same capability that gates the rubric and recordings.
  • postClassMessages — required to post an assignment update.

Defaults baked into the role:

ActionOwnerCo-tch.TAStudent
Send a 1:1 thread message to themselvesYes
Reply on a student's 1:1 threadYesYesYes
Post an assignment update (postClassMessages)YesYesNo
Post a class-wide announcement (postClassMessages)YesYesNo
View every student's thread on an assignmentYesYesYes
Defaults can be tightened or loosened per-class from the People tab. See Co-teachers & TAs.

What a TA can do in messages

TA defaults: gradeSubmissions on, postClassMessages off:

  • Replies on per-student threads — yes. Same as the teacher. Reply is attributed to the TA by name.
  • Class-wide broadcast — no by default. No assignment updates, no class-wide announcements. The composer is hidden.

Flip Post class messages on for the TA role in the People tab permissions panel. Takes effect immediately; no save button.

Attribution is permanent. A TA removed from the class keeps their name on old messages; they just can't post new ones.

JR
Jordan Reyes TA
In this class: grade · 1:1 reply
Jordan's messaging surface
● Read every student thread on each assignment ● Reply on any per-student thread ○ Post a class-wide assignment update

What a student sees

Messaging lives inside the assignment — no separate top-level surface. Open an assignment, switch to Messages, type, send. That's the flow.

You see one thread per assignment — yours. No other students' threads, no teacher inboxes.

Where notifications land

Teacher replies and assignment updates land in your bell feed. Each deep-links into the assignment with the right tab pre-selected.

What you can attach

+ Attach sits next to Send. Files upload as chips above Send. Hit Send and they go with the message. Teacher can attach the same way. Attachments render as chips under each bubble — click to download.

Attachments without body text are allowed.

What you can't do

  • Post into another student's thread — only the student of record can.
  • DM the teacher outside an assignment. No unanchored channel. For administrative questions with no relevant assignment, email is the right channel.
Essay 3
AP Lit · Period 4 · Due Fri Nov 15
Assignment Messages 1
Do footnotes count toward the word limit?
You · 8:44p
They don't. Body text only.
Mr. M · 9:10p

When to use which

  • One student needs an answer about their work → 1:1 thread. Attach files if relevant.
  • Whole class, specific assignment → assignment update.
  • Whole class, not about an assignment → class-wide announcement from Stream.
  • Send a file to one student → attach to the 1:1 thread.
  • Send a file to every student → attach to the assignment, or to a class-wide announcement.

Every message has a context. 1:1 thread → (assignment, student). Assignment update → assignment. Class-wide announcement → classroom.

If you want to…Use
Answer one student's question1:1 thread
Tell everyone about an assignment changeAssignment update
Tell everyone something not tied to one assignmentClass-wide announcement
Send a file to one studentAttach to a 1:1 thread message
Send a file to every studentAttach to the assignment or to a class-wide announcement

Related

Creating an assignment — where the assignment-update composer lives.

Co-teachers & TAs — the gradeSubmissions and postClassMessages capabilities in context.

Setting up your first class — the People tab, where per-class permission overrides live.

Back to the help library for more topics.

Missing something? Email feedback.