Skip to content

BE_15 - Session History and Conversation Storage #35

@notjackl3

Description

@notjackl3

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/sessions endpoint (user's session history)
  • Create GET /api/sessions/[sessionId]/history endpoint (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:

  1. Course Enrollment: Any session from courses they're enrolled in
  2. Created Sessions: Sessions they created (professors)
  3. 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.authorId or Answer.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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions