Files
lms-sb/docs/specs/20260519-student-questions-design.md

5.2 KiB

Student Questions — Design Spec

Created: 20260519

Overview

A support-chat feature inside the LMS. Students ask questions, school staff (admin/curator) answers. Each question is a threaded conversation with open/closed status. Includes file attachments and email notifications for all parties.

Also in scope: email notifications for homework submissions (new + student updates).


Data Model

StudentQuestion

id            String   @id @default(cuid())
userId        String                          -- student who created it
courseId      String?                         -- optional course context
title         String
status        QuestionStatus @default(OPEN)   -- OPEN | CLOSED
closedAt      DateTime?
closedById    String?                         -- admin/curator who closed
createdAt     DateTime @default(now())
updatedAt     DateTime @updatedAt

user          User
course        Course?
messages      StudentQuestionMessage[]

StudentQuestionMessage

id            String   @id @default(cuid())
questionId    String
authorId      String
text          String
files         String[] -- S3 paths: questions/{questionId}/{messageId}/{filename}
isRead        Boolean  @default(false)
createdAt     DateTime @default(now())

question      StudentQuestion
author        User

QuestionStatus (enum)

OPEN
CLOSED

Routes

Student

Route Description
(student)/questions List of own questions with unread indicators
(student)/questions/new Form to create a new question
(student)/questions/[id] Thread view — read messages + reply

Admin / Curator

Route Description
admin/questions Split-view: question list left, thread right
curator/questions Same split-view (curators have same access as admins here)

UI Behaviour

Student — Questions List (/questions)

  • Header: "Мои вопросы" + "+ Задать вопрос" button (→ /questions/new)
  • Each row: title, message count, last activity, status badge (ОТКРЫТ / ЗАКРЫТ)
  • Unread indicator: black dot + "Новый ответ от школы" when school replied since last student visit
  • Closed questions: dimmed (opacity 0.7), grey badge
  • Active (unread) questions: bold border, bold title

Student — Thread (/questions/[id])

  • Header: question title, created date, status, "← Все вопросы" link
  • Message bubbles: student messages left (#E8E8E0), school messages right (#F5F5F0 + green border #E8F0D8)
  • New school message: bold label "🔵 новое" in timestamp
  • File attachments shown inline under message text (📎 filename · size)
  • Reply form at bottom: textarea + attach button + send button
  • Attachment types: jpg, png, pdf, md · max 10 MB
  • Student CAN reply to closed questions (creates new message, does NOT reopen question)

Admin/Curator — Split View (/admin/questions, /curator/questions)

  • Left panel (45%): tab filter "Открытые / Закрытые", question list sorted by last activity
  • Unread: red dot, green-tinted background, bold student name
  • Right panel (55%): selected thread with full message history + reply form + "✓ Закрыть вопрос" button
  • Only admin/curator can close a question
  • Closing a question does NOT prevent further messages

Notifications

→ School (admin + all curators)

Trigger Channel
New question created Email + admin sidebar badge (count of unread questions)
Student adds message to existing question Email

→ Student

Trigger Channel
Admin/curator replies to question Email

Admin Badge

  • Sidebar badge shows count of questions with unread messages (school hasn't seen yet)
  • Separate from homework badge

Email for Homework (added to scope)

Trigger Recipient
New HomeworkSubmission created Admin + all curators
Student updates existing submission (adds text/file) Admin + all curators

File Storage

  • Path pattern: questions/{questionId}/{messageId}/{filename}
  • Reuse existing S3 upload infrastructure (src/lib/s3.ts)
  • Allowed: jpg, png, pdf, md
  • Max size: 10 MB per file
  • No limit on number of files per message (reasonable: 5)

Read Tracking

  • isRead flag per message, set to true when the OTHER party opens the thread
  • Student opens /questions/[id] → all school messages in that thread marked isRead = true
  • Admin/curator opens a question in split-view → all student messages marked isRead = true
  • Admin badge recalculates on each page load (count questions where latest student message is unread)

API Routes

POST   /api/questions                    -- create question
GET    /api/questions                    -- list own questions (student) or all (admin/curator)
GET    /api/questions/[id]               -- get question + messages
POST   /api/questions/[id]/messages      -- add message + files
PATCH  /api/questions/[id]/close         -- close question (admin/curator only)
POST   /api/upload/question-file         -- upload attachment, returns S3 path

Out of Scope (this iteration)

  • Question categories / tags
  • Assigning question to a specific curator
  • Email threading (reply-to email to answer)
  • Push/browser notifications
  • Question templates