Skip to main content

Messages & Chat

Teachers and parents talk one-on-one in direct chats, and teachers post to a section's parents at once via class broadcast channels. Messages are real-time, can carry attachments, accept reactions, and can be edited or deleted by their author. Students do not have a chat surface.

At a glance

Who can do thisTeachers start direct chats with any parent in their assigned sections, or post to a class broadcast channel · Parents reply in their direct chats and read broadcasts (read-only on broadcast threads)
Where it livesTeacher app /messages (list) · /messages/:id (thread) · Parent app /messages (list) · /messages/:id (thread) · No student surface
Triggers notifications?Yes — push + in-app on every new message; reactions, edits and deletions update silently via socket
Related featuresNotifications · Chat moderation · PTM

How it flows

Status lifecycle

A Deleted message stays in the thread but renders as the placeholder "Message removed" — no body, no attachment, no reactions.

Step-by-step

1. Teacher opens Messages

  • App / route: Teacher app → /messages
  • Two tabs: Direct (1:1 with parents) and Class channels (broadcast threads).
  • Each tab shows an unread count badge (capped at 99+).
  • Threads sort by last message time. Unread threads get a subtle indigo background.

2. Teacher starts a new conversation

  • Tap the + icon → bottom sheet "New conversation".
  • The sheet lists every section the teacher is assigned to. Expand a section to see:
    • Class announcement channel — one tap creates / opens a class_broadcast thread.
    • Each student, expandable to that student's linked parents. Tap a parent → opens a direct thread.
  • If the teacher has no sections, the sheet shows "You're not assigned to any sections."

3. Composing & sending a message

  • Route: /messages/:id
  • Composer accepts:
    • Plain text (max 4 000 chars on edit).
    • One attachment per message (image, PDF, .doc, .docx). Max 25 MB; oversize is rejected client-side with a toast.
  • Enter sends; Shift+Enter adds a newline.
  • Send is disabled while text is empty AND no attachment is staged.
  • After send: the message appears optimistically; recipients get a push notification.

4. Reactions

Allowed reactions (fixed set): 👍 👎 ❤️ 😂 😮 🙏

  • Tap a bubble to open the action popover; tap an emoji to toggle your reaction.
  • Tap an existing reaction chip below a bubble to open the Reactions sheet, which lists who reacted with each emoji and lets you toggle your own.
  • A user has at most one reaction per emoji per message (toggle-style).

5. Edit & delete (own messages only)

  • Edit: text-only messages (no attachment). Opens an editor sheet pre-filled with the body. Saving stamps the message as edited (small "edited" tag near the timestamp).
  • Delete: any of your own messages. Confirms with a browser confirm(). The bubble becomes "Message removed" for everyone.

6. Class broadcast posting

  • Thread type: class_broadcast.
  • Header reads "Class announcements · Class X · Section Y" with a megaphone icon.
  • Composer placeholder: "Announce to the class…"
  • All parents in the section receive the message + push notification.
  • Parents cannot reply on broadcast threads — only the teacher who owns the channel can post. The parent app shows the post but the composer is hidden / disabled.

7. Parent side

  • App / route: Parent app → /messages (list) → /messages/:id (thread).
  • Parent sees:
    • Direct threads with each of their child's teachers.
    • Class channels for each section their child is in (read-only).
  • Parent can reply, attach, react, edit / delete their own messages in direct threads exactly as the teacher can.

8. Reporting & blocking (teacher only)

In a direct thread, the teacher's "⋮" menu offers:

  • Report parent — choose reason (abuse, harassment, inappropriate, spam, impersonation, other) plus optional details. Sends to admin queue (Chat moderation).
  • Block parent — optional reason; both sides see "Messages are blocked." Composer disables. Teacher can Unblock later from the same banner.
  • If admin has restricted the chat, teacher sees "Restricted by admin" and cannot unblock.

Edge cases & things to test

  • Cross-app push tap: tap a chat notification on a backgrounded teacher app — does it deep-link to /messages/:id (not /)?
  • Section reassignment: teacher loses section assignment mid-conversation — composer should swap to "You're not assigned to this section" and disable sending; the existing thread stays readable.
  • Multi-parent student: a student linked to two parents — teacher's "New conversation" sheet should show both; each opens a separate direct thread.
  • Attachment too large: pick a 30 MB PDF — must be rejected with toast before upload.
  • Edit after delete window: try to edit a 24h-old text message — should toast a server error and revert.
  • Edit a message with attachment: the Edit option must not appear (only Delete is allowed).
  • Reactions race: two users tap 👍 simultaneously — count must reconcile to 2 once both sockets settle.
  • Block while parent is typing: teacher blocks; parent's next send must fail gracefully (toast), and the thread shows the blocked banner on next focus.
  • Admin restriction: admin restricts chat from moderation tool — both teacher and parent see "Restricted by admin"; "Unblock" is not offered.
  • Broadcast as parent: parent opens a class_broadcast thread — composer must be hidden; no Send button visible.
  • Older message pagination: scroll a long thread to top — "Load older messages" should fetch the next 50; stops when fewer than 50 return.
  • Offline send: kill network mid-send — the optimistic bubble should error; on reconnect, retry must not duplicate.
  • Chat moderation (admin) — admin reviews reports and can hard-restrict chats
  • Notifications — every new message fans out a push
  • PTM — many chats start as PTM follow-ups
  • Homework — teachers often DM a parent about a missing submission