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 this | Teachers 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 lives | Teacher 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 features | Notifications · 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_broadcastthread. - Each student, expandable to that student's linked parents. Tap a parent → opens a
directthread.
- Class announcement channel — one tap creates / opens a
- 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.
Entersends;Shift+Enteradds 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_broadcastthread — 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.
Related
- 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