-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Labels
backendbackend stuffbackend stuff
Description
Summary
Implement persistent storage and retrieval of session Q&A history for users to access past conversations.
[Estimated hours: 6-7]
Objectives
- Create GET
/api/users/me/sessionsendpoint (user's session history) - Create GET
/api/sessions/[sessionId]/historyendpoint (full Q&A archive) - Implement session filtering and search functionality
- Add pagination for large histories
- Respect visibility and anonymity rules in historical data
Description
Users need to access Q&A conversations from past sessions for studying and review. When a session ends, the conversation remains accessible to participants based on their course enrollment and role.
User Flow
User visits "My Sessions" or "History" page
→ GET /api/users/me/sessions
→ Returns list of accessible sessions with metadata
→ User clicks on a session
→ GET /api/sessions/:sessionId/history
→ Returns full Q&A thread with nested answers
→ User can search/filter content
Technical Details
File Structure
src/app/api/
├── users/me/
│ └── sessions/
│ └── route.ts # GET user's sessions
└── sessions/[sessionId]/
└── history/
└── route.ts # GET session history
src/lib/
├── sessionHistory.ts # Session retrieval and filtering logic
│ Functions:
│ - getUserSessions(userId, options)
│ - getSessionHistory(sessionId, userId, userRole)
│ - canAccessSession(userId, sessionId)
└── historyValidation.ts # Validation for history queries
Functions:
- validatePaginationParams(page, limit)
- validateSessionFilters(filters)
Session Access Logic
Users can access sessions through:
- Course Enrollment: Any session from courses they're enrolled in
- Created Sessions: Sessions they created (professors)
- Participation: Sessions where they asked questions or gave answers
Access is determined by querying:
CourseEnrollment(user enrolled in session's course)Session.createdById(user created the session)Question.authorIdorAnswer.authorId(user participated)
Database Schema Considerations
Current schema is sufficient. No new models needed. Use existing relationships:
// User → CourseEnrollment → Course → Session (enrolled sessions)
// User → Session (created sessions)
// User → Question (participated sessions)
// User → Answer (participated sessions)Recommended indexes for performance (add to existing models):
model Session {
// ... existing fields ...
@@index([courseId, status]) // Filter by course and status
@@index([createdAt]) // Sort by date
}
model Question {
// ... existing fields ...
@@index([sessionId, createdAt]) // History retrieval
}
model Answer {
// ... existing fields ...
@@index([questionId, createdAt]) // Nested answers retrieval
}API Response Examples
GET /api/users/me/sessions
Query parameters:
page(default: 1)limit(default: 20, max: 100)courseId(optional filter)status(optional: SCHEDULED, ACTIVE, ENDED)search(optional: case-insensitive title search)
Response:
{
sessions: [{
id: string,
title: string,
courseCode: string,
courseName: string,
status: "SCHEDULED" | "ACTIVE" | "ENDED",
startTime: string | null,
endTime: string | null,
questionCount: number,
myQuestionCount: number, // Questions asked by this user
createdBy: { id: string, name: string },
userRole: "STUDENT" | "TA" | "PROFESSOR" // User's role in this session's course
}],
pagination: {
page: number,
limit: number,
total: number,
totalPages: number
}
}GET /api/sessions/[sessionId]/history
Query parameters:
page(default: 1)limit(default: 50, max: 200)visibility(optional: PUBLIC, INSTRUCTOR_ONLY - filters questions)status(optional: OPEN, ANSWERED, RESOLVED - filters questions)
Response:
{
session: {
id: string,
title: string,
status: "SCHEDULED" | "ACTIVE" | "ENDED",
course: { code: string, name: string },
startTime: string | null,
endTime: string | null
},
questions: [{
id: string,
content: string,
visibility: "PUBLIC" | "INSTRUCTOR_ONLY",
status: "OPEN" | "ANSWERED" | "RESOLVED",
isAnonymous: boolean,
upvoteCount: number,
slideId: string | null,
slideNumber: number | null, // For display ("asked on slide 5")
createdAt: string,
// Only shown if not anonymous OR if requester is instructor
author: { id: string, name: string } | null,
answers: [{
id: string,
content: string,
isAccepted: boolean,
createdAt: string,
author: { id: string, name: string }
}]
}],
pagination: {
page: number,
limit: number,
total: number,
totalPages: number
},
userRole: "STUDENT" | "TA" | "PROFESSOR" // User's role for this session's course
}Acceptance Criteria
- User can list all sessions they have access to (enrolled courses + created + participated)
- Sessions sorted by startTime desc (most recent first), nulls last
- Can filter sessions by courseId
- Can filter sessions by status (SCHEDULED, ACTIVE, ENDED)
- Can search session titles (case-insensitive partial match)
- Pagination works correctly (default 20 per page, max 100)
- Response includes question counts (total and user's questions)
- Response includes user's role in each session's course
- Returns 401 if user not authenticated
- Full Q&A history accessible for all accessible sessions
- Questions include nested answers (no separate API call needed)
- Questions sorted by createdAt desc (newest first)
- Answers sorted by createdAt asc (oldest first, chronological)
- Anonymous questions show author as null for students
- Anonymous questions show real author for TAs and professors
- INSTRUCTOR_ONLY questions only visible to TAs and professors
- Includes slide reference (slideId and slideNumber) for each question
- Pagination works correctly (default 50 per page, max 200)
- Can filter by visibility (if user is instructor)
- Can filter by status (OPEN, ANSWERED, RESOLVED)
- Returns 403 if user doesn't have access to session
- Returns 404 if session doesn't exist
- Follow existing validation pattern (ValidationResult interface)
- Error messages follow existing API error format
- Session list query optimized with proper indexes
- History query uses select to avoid over-fetching
- Pagination prevents loading all records at once
- Response time < 500ms for typical history (100 questions)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
backendbackend stuffbackend stuff