Design a messaging platform for schools where students and teachers communicate through one-to-one chats and class-wide channels. Teachers can broadcast announcements to an entire class, students can message their teachers, and all parties can view conversation history with accurate unread counts. The system must enforce school-roster-based access controls (only students enrolled in a class can message that class's teacher) and support presence indicators, delivery receipts, and read receipts.
The core engineering challenges are building real-time message delivery over WebSockets, modeling permission-aware conversations tied to school rosters and class enrollments, scaling inbox and history queries as message volume grows, handling broadcast fan-out for class-wide announcements without creating thundering-herd hotspots, and evolving the data model as requirements expand (group chats, attachments, moderation). You will need to reason about full-stack architecture: database schema design, API and component structure, real-time communication, and scaling strategies.
Based on real interview experiences at Clever, these are the areas interviewers probe most deeply. The Clever interview emphasizes full-stack architecture, so expect questions about database tables, component hierarchy, and how you evolve the design as requirements change.
Unlike a generic chat app, this system is permission-gated: a student can only message teachers of classes they are enrolled in. Interviewers expect your schema to enforce these constraints and want to see how you model users, classes, enrollments, conversations, and messages.
Hints to consider:
users (with a role column: student or teacher), classes, and enrollments (user_id, class_id) to represent the rosterconversations table with a type column (DIRECT or CLASS_CHANNEL) and a conversation_participants join table linking users to conversationsChat requires a persistent, low-latency push channel. Interviewers want to see your WebSocket architecture and how you handle message routing, reconnection, and backfill.
Hints to consider:
As message volume grows, listing conversations with unread counts becomes a performance bottleneck. Interviewers look for denormalization and caching strategies.
Hints to consider:
conversation_summaries table with columns for last_message_id, last_message_preview, last_message_at, and per-user unread counts, updated on every new messageClever interviewers often start with a simple one-to-one messaging requirement and progressively add features (class channels, announcements, attachments, moderation). They want to see how you evolve the schema and architecture without breaking existing functionality.
Hints to consider:
attachments table linked to messages by message_id when file sharing is introduced; store files in object storage (S3) with URLs in the databasemessage_flags table and a moderation queue service that reviews flagged content; this is decoupled from the messaging pipelineSince this is a full-stack question, interviewers expect you to describe the client-side structure alongside the backend.
Hints to consider:
ConversationList component (sidebar showing inbox with unread badges), a MessageThread component (scrollable message history with infinite scroll), and a MessageComposer component (text input with send button)Confirm whether the scope is one-to-one only or includes class channels and announcements. Ask about the user base: how many schools, students per school, and concurrent users. Clarify whether the question emphasizes backend architecture, frontend component design, or both (Clever typically asks for both). Determine if file attachments, message editing, or moderation are in scope. Verify latency expectations for message delivery and history loads.
Sketch a full-stack diagram. Backend: an API server (Node.js or similar) handling REST endpoints for conversations, messages, and user management; a WebSocket gateway for real-time delivery; PostgreSQL for persistent storage; Redis for caching (inbox summaries, presence) and pub/sub (message routing); optionally Kafka for decoupling if scale warrants it. Frontend: a single-page application with a conversation list, message thread, and composer component; a WebSocket client that receives real-time updates and dispatches them to the appropriate component via state management.
Walk through what happens when a student sends a message to a teacher. The client posts to POST /api/conversations/:id/messages with the message body. The API server verifies authorization (is the student a participant in this conversation, derived from enrollment data). It inserts the message into the messages table, updates the conversation_summaries row (last message, increment teacher's unread count), and publishes the event to Redis Pub/Sub on the conversation's channel. The WebSocket gateway subscribed to that channel receives the event and pushes it to the teacher's connected devices. If the teacher is offline, the message waits in the database; on next login or reconnection, the client fetches the inbox and sees the updated unread count and latest message preview.
Cover class-channel announcements: the teacher sends a message to the class conversation; it is written once to the database and fanned out via pub/sub to all enrolled students' WebSocket connections. Discuss presence: teachers send periodic heartbeats over WebSocket; the gateway updates a Redis key with TTL; students query presence status when rendering the conversation list. Address search: add Elasticsearch if full-text message search is needed, indexing messages asynchronously via change data capture. Mention monitoring: track message delivery latency, WebSocket connection count, inbox query latency, and unread-count accuracy. Discuss scaling: shard PostgreSQL by school or conversation range, add WebSocket gateway instances behind a load balancer, and use Redis Cluster for pub/sub and caching.