CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes

From Expertiza_Wiki
Jump to navigation Jump to search

Expertiza Background

Expertiza is an open-source peer review platform built on Ruby on Rails and maintained at North Carolina State University. It is used across multiple courses at NCSU and other universities to facilitate structured peer feedback, team-based assignments, and multi-round review workflows.

In Expertiza, instructors define assignments that walk students through a sequence of tasks — submitting work, reviewing peers, taking quizzes, and providing feedback. The system tracks participants, teams, response maps, and responses across all of these activities.

The ongoing reimplementation effort modernizes the Expertiza codebase into a clean Rails JSON API backend and a React SPA frontend, with a focus on proper separation of concerns, RESTful conventions, and comprehensive test coverage. Each semester, CSC 517 students contribute targeted reimplementations of specific subsystems as part of their graduate coursework in object-oriented design.

Project Description

This project — E2601: Reimplement Student Quizzes — focused on the backend infrastructure that governs how students interact with quiz tasks within an assignment workflow. Quizzes in Expertiza are not standalone — they are one task type within a larger ordered sequence that may also include submission, peer review, and feedback stages.

For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:

  • A task ordering engine that knows the correct sequence of tasks for a participant and can determine whether a student is eligible to take a quiz at any given moment
  • A student-facing task API that surfaces the current state of a student's task queue, including which tasks are complete, which is next, and how to start a quiz task
  • A response management API that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement

Without all three of these systems working correctly together, a student could take a quiz before completing required prerequisite tasks, or be blocked from taking a quiz they were legitimately eligible for.

What We Built

Task Ordering Engine

We built a self-contained TaskOrdering module under app/models/task_ordering/ that encapsulates all logic for determining task eligibility and sequence. This module is intentionally decoupled from controllers — it knows nothing about HTTP requests or responses, only about assignments, participants, and response maps.

The module consists of five classes:

Class Role
BaseTask Abstract base defining the shared interface: complete? and map_id
ReviewTask Concrete task for ReviewResponseMap — complete when is_submitted is true
QuizTask Concrete task for quiz response maps — the central task type for this project
TaskFactory Factory that instantiates the correct task class given a response map
TaskQueue Orchestrator that builds and queries the ordered task list for a participant

The TaskQueue is the primary interface that controllers use. Given an assignment and a TeamsParticipant, it can answer three questions:

  • Is this map part of the participant's task queue? (map_in_queue?)
  • Have all tasks before this one been completed? (prior_tasks_complete_for?)
  • What is the next task the student should work on? (next_incomplete_task)

Student Tasks API

We implemented StudentTasksController with five endpoints that give students full visibility into their task workload:

Endpoint Method What It Returns
/student_tasks/list GET All tasks for the current user across their assignments
/student_tasks/view GET Detailed information for a specific participant task
/student_tasks/queue GET The full ordered task queue for a given assignment
/student_tasks/next_task GET The next incomplete task the student should work on
/student_tasks/start_task POST Attempts to start a task — blocked if prerequisites are incomplete

Every endpoint requires a valid JWT token and resolves the student's AssignmentParticipant and TeamsParticipant records before delegating to a TaskQueue instance for eligibility decisions.

Response Management API

We implemented ResponsesController with three endpoints that handle quiz and review response lifecycle:

Endpoint Method What It Does
/responses POST Creates a new response for a quiz or review map
/responses/:id GET Retrieves a specific response
/responses/:id PATCH Updates an existing response

Response creation enforces two layers of protection before any data is written:

  1. Ownership check — the requesting user must be the reviewer assigned to the response map
  2. Queue order check — the TaskQueue must confirm that all prerequisite tasks are complete before this response can be created

Technical Deep Dive

How Task Ordering Works

When a student attempts to start a quiz task or create a response, the following sequence occurs:

StudentTasksController or ResponsesController
        |
        | TaskQueue.new(assignment, teams_participant)
        v
TaskQueue
  → fetches all ResponseMaps for this participant
  → calls TaskFactory.build(map) for each
  → builds ordered array of BaseTask subclass instances
        |
        | queue.prior_tasks_complete_for?(map_id)
        v
  → iterates tasks in order
  → for each task before the target, calls task.complete?
  → returns false if any prior task is incomplete
        |
        v
Controller either proceeds or renders 403/428

How Authentication and Authorization Are Layered

All requests pass through two concerns registered in ApplicationController before reaching any controller logic:

Incoming Request
        |
        v
JwtToken concern → authenticate_request!
  → reads Authorization: Bearer <token> header
  → decodes token using RSA public key
  → sets @current_user via User.find(auth_token[:id])
  → halts with 401 if token missing, expired, or invalid
        |
        v
Authorization concern → authorize
  → calls all_actions_allowed?
  → checks super-admin privileges OR action_allowed?
  → halts with 403 if not permitted
        |
        v
Controller before_actions (e.g. find_and_authorize_map_for_create)
  → map-level ownership checks using current_user
        |
        v
Controller action

The critical insight here is that find_and_authorize_map_for_create must be a standard before_action — not a prepend_before_action — so that current_user is always populated by the time ownership checks run. This was a central bug we fixed (see Bugs We Fixed).

Round-Aware Response Handling

Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both map_id and round:

Response.where(map_id: @map.id, round: round)
        .order(:created_at)
        .last || Response.new(map_id: @map.id, round: round)

This means that if a response already exists for this map and round, it is updated in place rather than duplicated. If no response exists yet, a new one is initialized. This supports quiz retakes and multi-round review scenarios cleanly.

Design Decisions

The reimplementation of Student Quizzes emphasized modularity, separation of concerns, and extensibility to ensure the system can evolve alongside future Expertiza features.

Decoupling Task Logic from Controllers

A key architectural decision was to encapsulate all task sequencing and eligibility logic within the TaskOrdering module, rather than embedding it directly in controllers. Controllers are responsible only for handling HTTP requests and responses, while TaskOrdering operates purely on domain objects such as assignments, participants, and response maps.

This separation improves testability, as task logic can be validated independently of the API layer, and ensures that future interfaces (e.g., background jobs or alternative frontends) can reuse the same core logic without duplication.

Use of the Factory Pattern

The introduction of TaskFactory allows the system to dynamically instantiate the correct task type based on the underlying response map. This avoids conditional logic scattered throughout the codebase and centralizes object creation in a single location.

By adhering to the factory pattern, the system becomes easier to extend — new task types can be added with minimal modification to existing code, requiring only the addition of a new task class and a corresponding mapping in the factory.

Centralized Task Orchestration via TaskQueue

The TaskQueue class serves as the single source of truth for task ordering and progression. Instead of allowing each controller to independently determine task eligibility, all such decisions are delegated to TaskQueue.

This design ensures consistency across the system: whether a student is viewing their tasks, starting a quiz, or submitting a response, the same ordering rules are enforced. It also reduces duplication and prevents subtle inconsistencies that could arise if multiple components attempted to implement ordering logic independently.

Layered Authorization and Validation

Another important design decision was to enforce validation at multiple layers of the request lifecycle. Authentication and high-level authorization are handled globally through concerns in ApplicationController, while resource-specific checks (such as map ownership) are implemented as controller before_action callbacks.

Finally, task-order enforcement is delegated to TaskQueue, ensuring that even if a request passes authentication and ownership checks, it cannot violate assignment workflow constraints. This layered approach provides defense in depth and reduces the likelihood of invalid state transitions.

Round-Aware Response Handling

To support Expertiza’s multi-round workflow model, responses are scoped by both map_id and round. Instead of creating duplicate responses for the same round, the system updates the most recent response if it exists, or initializes a new one otherwise.

This design avoids redundant data while enabling clean support for quiz retakes and iterative peer review cycles.

Emphasis on RESTful and Stateless Design

All APIs were designed following RESTful principles, with clear resource-based endpoints and appropriate use of HTTP methods. Authentication is handled using JWT tokens, allowing the backend to remain stateless and scalable.

This approach ensures compatibility with modern frontend frameworks such as React and simplifies horizontal scaling by eliminating the need for server-side session storage.


Test Coverage

Model Specs

File Key Scenarios Tested
spec/models/task_ordering/base_task_spec.rb Default complete? behavior, map_id delegation, interface contract
spec/models/task_ordering/review_task_spec.rb Completion based on is_submitted, incomplete when not submitted
spec/models/task_ordering/quiz_task_spec.rb Quiz-specific completion detection and eligibility
spec/models/task_ordering/task_factory_spec.rb Correct class returned for each map type, error on unknown type
spec/models/task_ordering/task_queue_spec.rb Queue ordering, map_in_queue?, prior_tasks_complete_for?, next_incomplete_task

Request Specs

File Endpoints Response Codes Tested
spec/requests/api/v1/student_tasks_controller_spec.rb list, view, queue, next_task, start_task 200, 401, 404, 500
spec/requests/api/v1/responses_controller_spec.rb POST /responses, GET /responses/:id, PATCH /responses/:id 201, 200, 401, 403, 404

Running the Tests

bundle exec rspec \
  spec/requests/api/v1/student_tasks_controller_spec.rb \
  spec/requests/api/v1/responses_controller_spec.rb \
  spec/models/task_ordering/base_task_spec.rb \
  spec/models/task_ordering/review_task_spec.rb \
  spec/models/task_ordering/quiz_task_spec.rb \
  spec/models/task_ordering/task_factory_spec.rb \
  spec/models/task_ordering/task_queue_spec.rb

Expected result: 77 examples, 0 failures

Demo Video

Demo Video: https://youtu.be/Zg-fQmIUCSc

The demo will walk through:

  • The task ordering system enforcing sequential task completion for quiz tasks
  • Live API calls to the student tasks endpoints showing queue state and next task resolution
  • Response creation flow including JWT authentication, map ownership verification, and task queue enforcement
  • Full RSpec test suite run showing all 77 passing examples

Future Work

  • Extend TaskQueue to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged
  • Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not
  • Expose a participant-level quiz completion percentage endpoint for frontend progress indicators
  • Expand TaskFactory to support additional response map types as new assignment workflow stages are added to Expertiza
  • Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes

References

Team

Members:

  • Akhil Kumar
  • Dev Patel
  • Arnav Merjeri

Mentor:

  • Vihar Manojkumar Shah

Last updated: March 2026 | CSC 517, Spring 2026, NCSU