<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Avkumar2</id>
	<title>Expertiza_Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Avkumar2"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Avkumar2"/>
	<updated>2026-05-17T20:02:30Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167889</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167889"/>
		<updated>2026-04-13T21:42:29Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems were built:&lt;br /&gt;
&lt;br /&gt;
* '''A task ordering engine''' — a dedicated &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module that knows the correct sequence of tasks for a participant and determines whether a student is eligible to take a quiz at any given moment&lt;br /&gt;
* '''A student-facing task API''' — a &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; 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&lt;br /&gt;
* '''A response management API''' — a &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Why We Are Refactoring ===&lt;br /&gt;
&lt;br /&gt;
After completing the initial implementation, feedback was received that the &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module introduced unnecessary complexity. The module spans five separate files and a dedicated namespace — &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; — yet its logic is only ever called from two controllers. This level of abstraction is harder to trace and maintain than the problem warrants.&lt;br /&gt;
&lt;br /&gt;
The planned refactor will '''remove the &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; namespace entirely''' and move all sequencing logic directly into &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; as private methods, supported by two polymorphic inner classes. Every existing API endpoint, response payload shape, and status code will remain unchanged. The refactor is purely an internal structural simplification.&lt;br /&gt;
&lt;br /&gt;
The sections below describe '''what we built first''' and, within each section, '''how it will change''' after the refactor.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine (Current Implementation) ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it answers three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
==== What Will Change ====&lt;br /&gt;
&lt;br /&gt;
The five &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; files will be deleted. Their responsibilities will be redistributed as follows:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; will be replaced by &amp;lt;code&amp;gt;BaseTaskItem&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; — defined as '''inner classes inside &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt;''', with no separate files or namespace.&lt;br /&gt;
* &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; will be eliminated entirely. Instead of a factory object, &amp;lt;code&amp;gt;build_tasks&amp;lt;/code&amp;gt; — a private controller method — will directly instantiate &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt; based on what response maps and questionnaires exist for the participant.&lt;br /&gt;
* &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; will be eliminated entirely. Its three query methods (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;) will be replaced by equivalent private controller methods: &amp;lt;code&amp;gt;find_task_for_map&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete?&amp;lt;/code&amp;gt;, and a direct &amp;lt;code&amp;gt;tasks.find&amp;lt;/code&amp;gt; call in the &amp;lt;code&amp;gt;next_task&amp;lt;/code&amp;gt; action.&lt;br /&gt;
&lt;br /&gt;
The inner classes will share the following interface via &amp;lt;code&amp;gt;BaseTaskItem&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;response_map&amp;lt;/code&amp;gt; || Returns the associated response map (creates one for &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; if needed)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ensure_response_map!&amp;lt;/code&amp;gt; || Guarantees a response map record exists&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ensure_response!&amp;lt;/code&amp;gt; || Creates or finds the &amp;lt;code&amp;gt;Response&amp;lt;/code&amp;gt; record (&amp;lt;code&amp;gt;round: 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;is_submitted: false&amp;lt;/code&amp;gt; by default)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;completed?&amp;lt;/code&amp;gt; || Returns true when a submitted response exists for this map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;to_h&amp;lt;/code&amp;gt; || Serializes the task to the same stable JSON payload shape as today&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; will implement &amp;lt;code&amp;gt;response_map&amp;lt;/code&amp;gt; as follows: first return a cached map if already loaded; otherwise look for an existing &amp;lt;code&amp;gt;QuizResponseMap&amp;lt;/code&amp;gt; by reviewer and reviewee; if none exists and a quiz questionnaire is present, create one with &amp;lt;code&amp;gt;save!(validate: false)&amp;lt;/code&amp;gt;; if no questionnaire exists either, return &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt; simply returns the &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; it was initialized with.&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API (Current Implementation) ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Currently, every endpoint that involves task ordering resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records and then constructs a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance to answer eligibility questions.&lt;br /&gt;
&lt;br /&gt;
==== What Will Change ====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;view&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;show&amp;lt;/code&amp;gt; actions will remain as-is. The &amp;lt;code&amp;gt;queue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_task&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;start_task&amp;lt;/code&amp;gt; actions will be refactored to call private controller methods instead of &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;code&amp;gt;queue&amp;lt;/code&amp;gt; after refactor:'''&lt;br /&gt;
# Call &amp;lt;code&amp;gt;resolve_context_for_assignment(params[:assignment_id])&amp;lt;/code&amp;gt; to obtain participant, team membership, assignment, and duty. Return 404 if the participant cannot be found.&lt;br /&gt;
# Call &amp;lt;code&amp;gt;build_tasks(context)&amp;lt;/code&amp;gt; to construct the ordered task list.&lt;br /&gt;
# Call &amp;lt;code&amp;gt;ensure_response_objects!(tasks)&amp;lt;/code&amp;gt; to guarantee response maps and response records exist for every task.&lt;br /&gt;
# Render &amp;lt;code&amp;gt;tasks.map(&amp;amp;:to_h)&amp;lt;/code&amp;gt; as JSON.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;code&amp;gt;next_task&amp;lt;/code&amp;gt; after refactor:'''&lt;br /&gt;
# Resolve context and build tasks as above.&lt;br /&gt;
# Find the first task where &amp;lt;code&amp;gt;completed?&amp;lt;/code&amp;gt; returns false.&lt;br /&gt;
# Render that task's &amp;lt;code&amp;gt;to_h&amp;lt;/code&amp;gt; payload, or render &amp;lt;code&amp;gt;{ message: &amp;quot;All tasks completed&amp;quot; }&amp;lt;/code&amp;gt; if all tasks are done.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;code&amp;gt;start_task&amp;lt;/code&amp;gt; after refactor:'''&lt;br /&gt;
# Find the &amp;lt;code&amp;gt;ResponseMap&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;params[:response_map_id]&amp;lt;/code&amp;gt;. Return 404 if not found.&lt;br /&gt;
# Verify &amp;lt;code&amp;gt;map.reviewer.user_id == current_user.id&amp;lt;/code&amp;gt;. Return 403 if not.&lt;br /&gt;
# Call &amp;lt;code&amp;gt;resolve_context_for_participant(map.reviewer)&amp;lt;/code&amp;gt; to build the context.&lt;br /&gt;
# Call &amp;lt;code&amp;gt;build_tasks(context)&amp;lt;/code&amp;gt; and locate the task for this map via &amp;lt;code&amp;gt;find_task_for_map(tasks, map.id)&amp;lt;/code&amp;gt;. Return 404 if the map is not in the participant's queue.&lt;br /&gt;
# Call &amp;lt;code&amp;gt;prior_tasks_complete?(tasks, current_task)&amp;lt;/code&amp;gt;. Return 403 with &amp;quot;Complete previous task first&amp;quot; if any earlier task is still incomplete.&lt;br /&gt;
# Call &amp;lt;code&amp;gt;current_task.ensure_response!&amp;lt;/code&amp;gt; and render the task payload.&lt;br /&gt;
&lt;br /&gt;
The key private methods introduced are:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;resolve_context_for_assignment(assignment_id)&amp;lt;/code&amp;gt; || Finds &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; by current user and assignment, finds &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, resolves duty via &amp;lt;code&amp;gt;team_participant.duty_id&amp;lt;/code&amp;gt; with fallback to &amp;lt;code&amp;gt;participant.duty_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;resolve_context_for_participant(participant)&amp;lt;/code&amp;gt; || Same context resolution starting from a known participant rather than an assignment id&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;build_tasks(context)&amp;lt;/code&amp;gt; || Queries &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt;, quiz questionnaire, and existing &amp;lt;code&amp;gt;QuizResponseMap&amp;lt;/code&amp;gt; records; instantiates &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt; in the correct order based on duty permissions&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ensure_response_objects!(tasks)&amp;lt;/code&amp;gt; || Calls &amp;lt;code&amp;gt;ensure_response_map!&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ensure_response!&amp;lt;/code&amp;gt; on every task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;find_task_for_map(tasks, map_id)&amp;lt;/code&amp;gt; || Returns the task whose &amp;lt;code&amp;gt;response_map.id&amp;lt;/code&amp;gt; matches the given map id&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;prior_tasks_complete?(tasks, target_task)&amp;lt;/code&amp;gt; || Returns false if any task appearing before the target in the list has &amp;lt;code&amp;gt;completed? == false&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Task ordering rules in &amp;lt;code&amp;gt;build_tasks&amp;lt;/code&amp;gt; will be: if review maps exist, append a &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; first (when duty allows and a quiz questionnaire or existing quiz map is present) then a &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt; (when duty allows); if no review maps exist, append a quiz-only &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; when duty allows and a questionnaire exists. Duty permissions are resolved as: &amp;lt;code&amp;gt;duty_allows_quiz?&amp;lt;/code&amp;gt; is true for participant, reader, and mentor roles; &amp;lt;code&amp;gt;duty_allows_review?&amp;lt;/code&amp;gt; is true for participant, reader, reviewer, and mentor roles.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API (Current Implementation) ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation currently enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
==== What Will Change ====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PATCH&amp;lt;/code&amp;gt; endpoints are unaffected. For &amp;lt;code&amp;gt;POST /responses&amp;lt;/code&amp;gt;, the &amp;lt;code&amp;gt;enforce_task_order!&amp;lt;/code&amp;gt; method currently calls &amp;lt;code&amp;gt;TaskOrdering::TaskQueue&amp;lt;/code&amp;gt; directly. After the refactor, it will instead reuse the same &amp;lt;code&amp;gt;build_tasks&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;prior_tasks_complete?&amp;lt;/code&amp;gt; private methods that &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; uses — either by extracting them into a shared concern or by duplicating the minimal logic in &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt;. Either way, the status codes (403 when order is violated, 201 on success) and the ownership check behavior will remain exactly the same.&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works (Current) ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response today, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Task Sequencing Will Work After the Refactor ===&lt;br /&gt;
&lt;br /&gt;
The same logical flow will execute, but entirely inside the controller with no external module:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | resolve_context_for_assignment(assignment_id)&lt;br /&gt;
        v&lt;br /&gt;
  → finds AssignmentParticipant by current_user + assignment_id&lt;br /&gt;
  → finds TeamsParticipant by participant_id&lt;br /&gt;
  → resolves duty (team_participant.duty_id fallback to participant.duty_id)&lt;br /&gt;
        |&lt;br /&gt;
        | build_tasks(context)&lt;br /&gt;
        v&lt;br /&gt;
  → queries ReviewResponseMaps for this participant&lt;br /&gt;
  → loads quiz questionnaire via assignment.quiz_questionnaire_for_review_flow&lt;br /&gt;
  → checks for existing QuizResponseMaps&lt;br /&gt;
  → instantiates QuizTaskItem / ReviewTaskItem in correct order&lt;br /&gt;
        |&lt;br /&gt;
        | prior_tasks_complete?(tasks, current_task)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks before the target&lt;br /&gt;
  → calls task.completed? on each&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The outcome for every request — which status codes are returned, which tasks are blocked, what JSON is rendered — is identical to today. Only the internal path through the code changes.&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
This layer is unchanged by the refactor. All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical constraint is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must remain a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run.&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
This behavior is unchanged by the refactor. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If a response already exists for this map and round, it is updated in place. If none exists, a new one is initialized. This supports quiz retakes and multi-round review scenarios.&lt;br /&gt;
&lt;br /&gt;
== Design Decisions ==&lt;br /&gt;
&lt;br /&gt;
=== Original Design: Separation of Task Logic into a Dedicated Module ===&lt;br /&gt;
&lt;br /&gt;
The initial implementation encapsulated all task sequencing and eligibility logic within the &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module, entirely decoupled from controllers. The reasoning was that controllers should only handle HTTP concerns, while task logic should be independently testable as a pure domain model.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; was introduced so that the correct task class could be instantiated from any response map type without conditional logic in controllers. The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; served as the single orchestration point so that the same ordering rules were guaranteed to apply whether a student was viewing their queue, starting a task, or submitting a response.&lt;br /&gt;
&lt;br /&gt;
=== Why the Design Is Being Simplified ===&lt;br /&gt;
&lt;br /&gt;
In practice, the &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module is only ever called from &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt;. There are no background jobs, rake tasks, or alternative interfaces that reuse it. The five-file namespace therefore adds indirection without providing the reuse benefits that would justify it.&lt;br /&gt;
&lt;br /&gt;
The refactor recognizes that '''polymorphism belongs where it helps''' — quiz and review tasks genuinely behave differently, so inner classes are still the right tool. But '''orchestration does not need its own namespace''' — a set of private controller methods is simpler to read, easier to test through the request layer, and just as correct.&lt;br /&gt;
&lt;br /&gt;
=== Refactored Design: Controller-Owned Orchestration with Inner Classes ===&lt;br /&gt;
&lt;br /&gt;
After the refactor, the design will follow these principles:&lt;br /&gt;
&lt;br /&gt;
* '''Single orchestration owner''' — all task sequencing decisions flow through one set of private methods in &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; will reuse the same logic via a shared concern or equivalent private methods.&lt;br /&gt;
* '''Polymorphism without over-engineering''' — &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt; are inner classes that share a &amp;lt;code&amp;gt;BaseTaskItem&amp;lt;/code&amp;gt; interface. The difference in behavior is encapsulated; the orchestration logic treats both identically.&lt;br /&gt;
* '''No extra namespace''' — everything lives in &amp;lt;code&amp;gt;app/controllers/student_tasks_controller.rb&amp;lt;/code&amp;gt;. A developer reading the &amp;lt;code&amp;gt;queue&amp;lt;/code&amp;gt; action can follow the entire flow without opening any other file.&lt;br /&gt;
* '''High cohesion''' — task lifecycle behavior (response map creation, response initialization, completion detection, serialization) is grouped with the task objects themselves.&lt;br /&gt;
* '''Low coupling''' — the controller works against the shared &amp;lt;code&amp;gt;BaseTaskItem&amp;lt;/code&amp;gt; interface, so adding a new task type requires only a new inner class with no changes to orchestration methods.&lt;br /&gt;
&lt;br /&gt;
=== Layered Authorization and Validation ===&lt;br /&gt;
&lt;br /&gt;
This decision is unchanged. Validation is enforced at three distinct layers: JWT authentication globally in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt;, role-level authorization via the &amp;lt;code&amp;gt;authorize&amp;lt;/code&amp;gt; concern, and map-level ownership checks as controller &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; callbacks. Task-order enforcement is the final layer, applied inside the action itself. This defense-in-depth approach remains intact after the refactor.&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Unchanged. Responses continue to be scoped by &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;, with update-in-place semantics for existing records.&lt;br /&gt;
&lt;br /&gt;
=== Emphasis on RESTful and Stateless Design ===&lt;br /&gt;
&lt;br /&gt;
Unchanged. All endpoints remain resource-based with JWT authentication, compatible with the React frontend and stateless horizontal scaling.&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Current Test Suite ===&lt;br /&gt;
&lt;br /&gt;
The initial implementation is covered by 77 passing examples across model and request specs:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task — response codes 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST, GET, PATCH /responses — response codes 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To run the current suite:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
=== Planned Test Suite After Refactor ===&lt;br /&gt;
&lt;br /&gt;
The five &amp;lt;code&amp;gt;spec/models/task_ordering/*&amp;lt;/code&amp;gt; files will be deleted alongside the source files they test. They will be replaced by the following:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! What It Will Cover&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; (extended) || Queue order — quiz before review when both exist; quiz-only when no review maps; review-only when duty disallows quiz; empty queue; &amp;lt;code&amp;gt;next_task&amp;lt;/code&amp;gt; returns first incomplete task, then review after quiz submitted, then completion message; &amp;lt;code&amp;gt;start_task&amp;lt;/code&amp;gt; blocks when prior task incomplete, rejects map not in queue, rejects map owned by another user, returns 404 for nonexistent map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; (extended) || POST blocked when prior task incomplete; POST allowed when prerequisites complete; PATCH blocked/allowed under same conditions; ownership checks preserved&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/controllers/student_tasks_controller_task_items_spec.rb&amp;lt;/code&amp;gt; (new) || &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt;: reuses existing quiz map for reviewer/reviewee; creates quiz map when questionnaire exists and none is present; returns nil map when questionnaire absent and no existing map; &amp;lt;code&amp;gt;ensure_response!&amp;lt;/code&amp;gt; creates record with &amp;lt;code&amp;gt;round: 1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;is_submitted: false&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt;: returns the given review map; &amp;lt;code&amp;gt;completed?&amp;lt;/code&amp;gt; is true only when a submitted response exists. Shared: &amp;lt;code&amp;gt;to_h&amp;lt;/code&amp;gt; always includes the stable payload keys&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following payload keys must remain present and unchanged across all student task endpoints:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;task_type&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;response_map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;response_map_type&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;reviewee_id&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;team_participant_id&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Response code contracts that must not regress:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint Group !! Status Codes&lt;br /&gt;
|-&lt;br /&gt;
| Student Tasks (list, view, queue, next_task, start_task) || 200, 401, 403, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| Responses (POST, GET, PATCH) || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Migration Plan ==&lt;br /&gt;
&lt;br /&gt;
The refactor will proceed in four phases to avoid breaking the working implementation at any intermediate step.&lt;br /&gt;
&lt;br /&gt;
=== Phase 1 — Add Inner Task Classes ===&lt;br /&gt;
&lt;br /&gt;
Implement &amp;lt;code&amp;gt;BaseTaskItem&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt; as inner classes inside &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt;. The existing &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module remains untouched. No controller behavior changes in this phase — the new classes exist but are not yet wired in.&lt;br /&gt;
&lt;br /&gt;
=== Phase 2 — Move Orchestration Logic into the Controller ===&lt;br /&gt;
&lt;br /&gt;
Add the private controller methods (&amp;lt;code&amp;gt;resolve_context_for_assignment&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;resolve_context_for_participant&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;build_tasks&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ensure_response_objects!&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;find_task_for_map&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete?&amp;lt;/code&amp;gt;) to &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt;. Refactor the &amp;lt;code&amp;gt;queue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_task&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;start_task&amp;lt;/code&amp;gt; actions to call these methods instead of &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt;. Update &amp;lt;code&amp;gt;ResponsesController#enforce_task_order!&amp;lt;/code&amp;gt; to use the same logic. Run the full test suite to confirm no regressions before proceeding.&lt;br /&gt;
&lt;br /&gt;
=== Phase 3 — Remove the Legacy Layer ===&lt;br /&gt;
&lt;br /&gt;
Delete:&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/task_ordering/base_task.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/task_ordering/review_task.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/task_ordering/quiz_task.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/task_ordering/task_factory.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/task_ordering/task_queue.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Phase 4 — Update Tests and Documentation ===&lt;br /&gt;
&lt;br /&gt;
Write the new request specs and the &amp;lt;code&amp;gt;student_tasks_controller_task_items_spec.rb&amp;lt;/code&amp;gt; unit spec as described in the [[#Planned Test Suite After Refactor|Planned Test Suite]] section. Update &amp;lt;code&amp;gt;docs/POSTMAN_STUDENT_TASKS.md&amp;lt;/code&amp;gt; if any wording references &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt;. Update this wiki page to move the &amp;quot;Planned Refactor&amp;quot; content into the past tense once the work is complete.&lt;br /&gt;
&lt;br /&gt;
=== Definition of Done ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; no longer reference &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Sequencing and gating logic lives in private controller methods with no extra namespace.&lt;br /&gt;
* Quiz/review differences are encapsulated by &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt; inner classes.&lt;br /&gt;
* All legacy &amp;lt;code&amp;gt;task_ordering&amp;lt;/code&amp;gt; source and spec files are deleted.&lt;br /&gt;
* All specs pass with no API contract regression.&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' https://youtu.be/Zg-fQmIUCSc&lt;br /&gt;
&lt;br /&gt;
The demo walks through the current (pre-refactor) implementation:&lt;br /&gt;
* The &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; engine enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;build_tasks&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as binary submitted/not-submitted&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Add new inner task classes to &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; to support additional response map types as new workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjeri&lt;br /&gt;
&lt;br /&gt;
'''Mentor:'''&lt;br /&gt;
* Vihar Manojkumar Shah&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: April 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167888</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167888"/>
		<updated>2026-04-13T21:34:39Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems were built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Following feedback received after the initial implementation, a '''simplification refactor''' is planned. The goal is to remove the separate &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module and fold sequencing logic directly into &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt;, reducing the number of files and abstraction layers while preserving all existing behavior. This refactor is described in the [[#Planned Refactor|Planned Refactor]] section below.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Design Decisions ==&lt;br /&gt;
&lt;br /&gt;
The reimplementation of Student Quizzes emphasized modularity, separation of concerns, and extensibility to ensure the system can evolve alongside future Expertiza features.&lt;br /&gt;
&lt;br /&gt;
=== Decoupling Task Logic from Controllers ===&lt;br /&gt;
&lt;br /&gt;
A key architectural decision was to encapsulate all task sequencing and eligibility logic within the &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module, rather than embedding it directly in controllers. Controllers are responsible only for handling HTTP requests and responses, while &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; operates purely on domain objects such as assignments, participants, and response maps.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Use of the Factory Pattern ===&lt;br /&gt;
&lt;br /&gt;
The introduction of &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Centralized Task Orchestration via TaskQueue ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Layered Authorization and Validation ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt;, while resource-specific checks (such as map ownership) are implemented as controller &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; callbacks.&lt;br /&gt;
&lt;br /&gt;
Finally, task-order enforcement is delegated to &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
To support Expertiza's multi-round workflow model, responses are scoped by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
This design avoids redundant data while enabling clean support for quiz retakes and iterative peer review cycles.&lt;br /&gt;
&lt;br /&gt;
=== Emphasis on RESTful and Stateless Design ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This approach ensures compatibility with modern frontend frameworks such as React and simplifies horizontal scaling by eliminating the need for server-side session storage.&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' https://youtu.be/Zg-fQmIUCSc&lt;br /&gt;
&lt;br /&gt;
The demo walks through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Planned Refactor ==&lt;br /&gt;
&lt;br /&gt;
Following feedback on the initial implementation, the &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module will be simplified. Rather than maintaining a separate namespace with five model-layer classes, all sequencing and eligibility logic will be moved directly into &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt;, supported by two polymorphic inner classes. The public API contract and all existing behavior will remain unchanged.&lt;br /&gt;
&lt;br /&gt;
=== Motivation ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module introduced five separate files (&amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt;) to solve a problem that does not require a dedicated namespace. Task sequencing is only ever invoked from two controllers — &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; — and the added abstraction layers make the flow harder to trace without providing meaningful reuse benefits. The refactor aims to make the code simpler to read and maintain while preserving all correctness guarantees.&lt;br /&gt;
&lt;br /&gt;
=== Proposed Design ===&lt;br /&gt;
&lt;br /&gt;
The replacement design uses controller-owned private methods for orchestration, and two inner classes for polymorphic task-type behavior:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Inner Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; || Handles quiz-specific completion detection, response map lookup/creation, and serialization&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt; || Handles review map completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Both classes will share a common interface via a parent &amp;lt;code&amp;gt;BaseTaskItem&amp;lt;/code&amp;gt;, with the following methods:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;response_map&amp;lt;/code&amp;gt; || Returns the associated response map (creates one for quiz tasks if needed)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ensure_response_map!&amp;lt;/code&amp;gt; || Guarantees a response map record exists&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ensure_response!&amp;lt;/code&amp;gt; || Creates or finds the &amp;lt;code&amp;gt;Response&amp;lt;/code&amp;gt; record (&amp;lt;code&amp;gt;round: 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;is_submitted: false&amp;lt;/code&amp;gt; by default)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;completed?&amp;lt;/code&amp;gt; || Returns true when a submitted response exists for this map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;to_h&amp;lt;/code&amp;gt; || Serializes the task to a stable JSON payload shape&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The private controller methods that will orchestrate the task flow are:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;build_tasks(context)&amp;lt;/code&amp;gt; || Builds the ordered task list (quiz before review) for a participant&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ensure_response_objects!(tasks)&amp;lt;/code&amp;gt; || Ensures response maps and responses exist for all tasks&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;prior_tasks_complete?(tasks, target)&amp;lt;/code&amp;gt; || Returns false if any task before the target is incomplete&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;find_task_for_map(tasks, map_id)&amp;lt;/code&amp;gt; || Looks up a task by its response map id&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;resolve_context_for_assignment(assignment_id)&amp;lt;/code&amp;gt; || Resolves participant, team membership, assignment, and duty from a given assignment id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== How Task Sequencing Will Work After the Refactor ===&lt;br /&gt;
&lt;br /&gt;
The request flow through &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; will change from delegating to &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to calling private methods directly:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | resolve_context_for_assignment(assignment_id)&lt;br /&gt;
        v&lt;br /&gt;
  → finds AssignmentParticipant by current_user + assignment_id&lt;br /&gt;
  → finds TeamsParticipant by participant_id&lt;br /&gt;
  → resolves duty (team_participant.duty_id fallback to participant.duty_id)&lt;br /&gt;
        |&lt;br /&gt;
        | build_tasks(context)&lt;br /&gt;
        v&lt;br /&gt;
  → loads ReviewResponseMaps for this participant&lt;br /&gt;
  → loads quiz questionnaire and existing QuizResponseMaps&lt;br /&gt;
  → instantiates QuizTaskItem / ReviewTaskItem in order&lt;br /&gt;
        |&lt;br /&gt;
        | prior_tasks_complete?(tasks, current_task)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks before the target&lt;br /&gt;
  → calls task.completed? on each&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Task ordering rules will remain identical:&lt;br /&gt;
* If review maps exist: quiz task is added first (when duty allows and quiz is available or an existing quiz map is present), then review task (when duty allows).&lt;br /&gt;
* If no review maps exist: a quiz-only task is added when duty allows and a quiz questionnaire exists.&lt;br /&gt;
&lt;br /&gt;
=== Migration Plan ===&lt;br /&gt;
&lt;br /&gt;
The refactor will proceed in four phases to avoid breaking the working implementation at any intermediate step.&lt;br /&gt;
&lt;br /&gt;
'''Phase 1 — Add inner task classes'''&lt;br /&gt;
&lt;br /&gt;
Implement &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt; as inner classes inside &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt;. The existing &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module will remain untouched at this stage.&lt;br /&gt;
&lt;br /&gt;
'''Phase 2 — Move orchestration logic into controller'''&lt;br /&gt;
&lt;br /&gt;
Port queue construction and gating logic into private controller methods (&amp;lt;code&amp;gt;build_tasks&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete?&amp;lt;/code&amp;gt;, etc.). Update &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; to use the new inner classes and private methods instead of &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt;. The JSON payload shape will not change.&lt;br /&gt;
&lt;br /&gt;
'''Phase 3 — Remove the legacy layer'''&lt;br /&gt;
&lt;br /&gt;
Delete the following files once all controllers and specs have been updated:&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/task_ordering/base_task.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/task_ordering/review_task.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/task_ordering/quiz_task.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/task_ordering/task_factory.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/task_ordering/task_queue.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Phase 4 — Update tests and documentation'''&lt;br /&gt;
&lt;br /&gt;
Replace &amp;lt;code&amp;gt;spec/models/task_ordering/*&amp;lt;/code&amp;gt; with:&lt;br /&gt;
* Request/integration specs for &amp;lt;code&amp;gt;queue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_task&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;start_task&amp;lt;/code&amp;gt; covering all ordering scenarios&lt;br /&gt;
* Focused controller unit specs covering &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt; behavior&lt;br /&gt;
&lt;br /&gt;
Update &amp;lt;code&amp;gt;docs/POSTMAN_STUDENT_TASKS.md&amp;lt;/code&amp;gt; if any wording references &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Planned Test Coverage After Refactor ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios to Cover&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || Queue order (quiz before review), quiz-only, review-only, empty queue, &amp;lt;code&amp;gt;start_task&amp;lt;/code&amp;gt; blocking out-of-order attempts, unauthorized map access&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || Response create/update blocked when prior task incomplete, allowed when prerequisites complete, authorization checks preserved&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/controllers/student_tasks_controller_task_items_spec.rb&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt;: reuses existing map, creates map when questionnaire present, returns nil when absent; &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt;: returns given map, completion based on submitted response; shared &amp;lt;code&amp;gt;to_h&amp;lt;/code&amp;gt; payload contract&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following payload keys must remain stable across all student task endpoints after the refactor:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;task_type&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;response_map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;response_map_type&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;reviewee_id&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;team_participant_id&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Definition of Done ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; no longer reference &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Sequencing and gating logic lives in private controller methods with no extra namespace.&lt;br /&gt;
* Quiz/review differences are encapsulated by polymorphic &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt; inner classes.&lt;br /&gt;
* All legacy &amp;lt;code&amp;gt;task_ordering&amp;lt;/code&amp;gt; files are deleted.&lt;br /&gt;
* All specs pass with no API contract regression.&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend task-building logic to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Add new inner task classes to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjeri&lt;br /&gt;
&lt;br /&gt;
'''Mentor:'''&lt;br /&gt;
* Vihar Manojkumar Shah&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: April 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167881</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167881"/>
		<updated>2026-04-13T16:37:07Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, two backend systems needed to be built:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
Task sequencing and eligibility logic lives directly inside &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt;, supported by two polymorphic inner classes (&amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt;) that encapsulate task-type-specific behavior without introducing an extra namespace or layer.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Sequencing (Inside StudentTasksController) ===&lt;br /&gt;
&lt;br /&gt;
Rather than a separate module, all task ordering and eligibility logic is encapsulated in private methods of &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt;, supported by two inner classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; || Inner class for quiz response maps — handles quiz-specific completion detection, response map lookup/creation, and serialization&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt; || Inner class for review response maps — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Both classes share a common interface via their parent &amp;lt;code&amp;gt;BaseTaskItem&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;response_map&amp;lt;/code&amp;gt; || Returns the associated response map (creates one for quiz tasks if needed)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ensure_response_map!&amp;lt;/code&amp;gt; || Guarantees a response map record exists&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ensure_response!&amp;lt;/code&amp;gt; || Creates or finds the &amp;lt;code&amp;gt;Response&amp;lt;/code&amp;gt; record (&amp;lt;code&amp;gt;round: 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;is_submitted: false&amp;lt;/code&amp;gt; by default)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;completed?&amp;lt;/code&amp;gt; || Returns true when a submitted response exists for this map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;to_h&amp;lt;/code&amp;gt; || Serializes the task to a stable JSON payload shape&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The key private controller methods that orchestrate task flow are:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;build_tasks(context)&amp;lt;/code&amp;gt; || Builds the ordered task list (quiz before review) for a participant&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ensure_response_objects!(tasks)&amp;lt;/code&amp;gt; || Ensures response maps and responses exist for all tasks&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;prior_tasks_complete?(tasks, target)&amp;lt;/code&amp;gt; || Returns false if any task before the target is incomplete&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;find_task_for_map(tasks, map_id)&amp;lt;/code&amp;gt; || Looks up a task by its response map id&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;resolve_context_for_assignment(assignment_id)&amp;lt;/code&amp;gt; || Resolves participant, team membership, assignment, and duty from a given assignment id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to the private task-building flow for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the same task-ordering logic used by &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Sequencing Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs inside &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | resolve_context_for_assignment(assignment_id)&lt;br /&gt;
        v&lt;br /&gt;
  → finds AssignmentParticipant by current_user + assignment_id&lt;br /&gt;
  → finds TeamsParticipant by participant_id&lt;br /&gt;
  → resolves duty (team_participant.duty_id fallback to participant.duty_id)&lt;br /&gt;
        |&lt;br /&gt;
        | build_tasks(context)&lt;br /&gt;
        v&lt;br /&gt;
  → loads ReviewResponseMaps for this participant&lt;br /&gt;
  → loads quiz questionnaire and existing QuizResponseMaps&lt;br /&gt;
  → instantiates QuizTaskItem / ReviewTaskItem in order&lt;br /&gt;
        |&lt;br /&gt;
        | prior_tasks_complete?(tasks, current_task)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks before the target&lt;br /&gt;
  → calls task.completed? on each&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Task ordering rules:&lt;br /&gt;
* If review maps exist: quiz task is added first (when duty allows and quiz is available or an existing quiz map is present), then review task (when duty allows).&lt;br /&gt;
* If no review maps exist: a quiz-only task is added when duty allows and a quiz questionnaire exists.&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run.&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Design Decisions ==&lt;br /&gt;
&lt;br /&gt;
=== Keeping Sequencing Logic in the Controller ===&lt;br /&gt;
&lt;br /&gt;
A key architectural decision was to keep all task sequencing and eligibility logic directly inside &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; private methods, rather than in a separate module or namespace. This keeps the flow obvious and readable — a developer can trace the entire request lifecycle without jumping across files.&lt;br /&gt;
&lt;br /&gt;
Controllers are still responsible only for handling HTTP requests and responses. The inner task classes (&amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt;) operate purely on domain objects such as assignments, participants, and response maps, keeping HTTP concerns out of task behavior.&lt;br /&gt;
&lt;br /&gt;
=== Polymorphism Without Over-Engineering ===&lt;br /&gt;
&lt;br /&gt;
Rather than a factory pattern with separate files for each task type, quiz-versus-review differences are encapsulated in two inner classes inside the controller file itself. This preserves polymorphism where it matters — &amp;lt;code&amp;gt;completed?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;response_map&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;to_h&amp;lt;/code&amp;gt; behave differently for quiz and review tasks — without introducing a builder, pipeline, or factory layer.&lt;br /&gt;
&lt;br /&gt;
New task types can still be added by defining a new inner class with the same interface, requiring no changes to orchestration logic.&lt;br /&gt;
&lt;br /&gt;
=== Single Orchestration Owner ===&lt;br /&gt;
&lt;br /&gt;
All task ordering decisions flow through one set of private controller methods. Whether a student is viewing their queue, starting a quiz, or submitting a response, the same &amp;lt;code&amp;gt;build_tasks&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;prior_tasks_complete?&amp;lt;/code&amp;gt; logic is reused. This eliminates the risk of subtle inconsistencies that arise when multiple components implement ordering rules independently.&lt;br /&gt;
&lt;br /&gt;
=== Layered Authorization and Validation ===&lt;br /&gt;
&lt;br /&gt;
Validation is enforced at multiple layers of the request lifecycle. Authentication and high-level authorization are handled globally through concerns in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt;, while resource-specific checks (such as map ownership) are implemented as controller &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; callbacks.&lt;br /&gt;
&lt;br /&gt;
Task-order enforcement is then handled by the private controller flow, 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.&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
To support Expertiza's multi-round workflow model, responses are scoped by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
This design avoids redundant data while enabling clean support for quiz retakes and iterative peer review cycles.&lt;br /&gt;
&lt;br /&gt;
=== Emphasis on RESTful and Stateless Design ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This approach ensures compatibility with modern frontend frameworks such as React and simplifies horizontal scaling by eliminating the need for server-side session storage.&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Controller / Integration Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || Queue order (quiz before review), quiz-only, review-only, empty queue, &amp;lt;code&amp;gt;start_task&amp;lt;/code&amp;gt; blocking out-of-order attempts, unauthorized map access&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || Response create/update blocked when prior task incomplete, allowed when prerequisites complete, authorization checks&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Inner Class Unit Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/controllers/student_tasks_controller_task_items_spec.rb&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt;: reuses existing map, creates map when questionnaire exists, returns nil when questionnaire absent; &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt;: returns given map, completion based on submitted response; shared &amp;lt;code&amp;gt;to_h&amp;lt;/code&amp;gt; payload shape contract&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Response Codes Tested ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint Group !! Codes&lt;br /&gt;
|-&lt;br /&gt;
| Student Tasks (list, view, queue, next_task, start_task) || 200, 401, 403, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| Responses (POST, GET, PATCH) || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/controllers/student_tasks_controller_task_items_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''all examples passing, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' https://youtu.be/Zg-fQmIUCSc&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task sequencing logic enforcing quiz-before-review ordering for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task order enforcement&lt;br /&gt;
* Full RSpec test suite run showing all examples passing&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;build_tasks&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; and add new inner task classes to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjeri&lt;br /&gt;
&lt;br /&gt;
'''Mentor:'''&lt;br /&gt;
* Vihar Manojkumar Shah&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: April 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167655</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167655"/>
		<updated>2026-03-31T02:27:25Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Design Decisions ==&lt;br /&gt;
&lt;br /&gt;
The reimplementation of Student Quizzes emphasized modularity, separation of concerns, and extensibility to ensure the system can evolve alongside future Expertiza features.&lt;br /&gt;
&lt;br /&gt;
=== Decoupling Task Logic from Controllers ===&lt;br /&gt;
&lt;br /&gt;
A key architectural decision was to encapsulate all task sequencing and eligibility logic within the &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module, rather than embedding it directly in controllers. Controllers are responsible only for handling HTTP requests and responses, while &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; operates purely on domain objects such as assignments, participants, and response maps.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Use of the Factory Pattern ===&lt;br /&gt;
&lt;br /&gt;
The introduction of &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Centralized Task Orchestration via TaskQueue ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Layered Authorization and Validation ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt;, while resource-specific checks (such as map ownership) are implemented as controller &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; callbacks.&lt;br /&gt;
&lt;br /&gt;
Finally, task-order enforcement is delegated to &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
To support Expertiza’s multi-round workflow model, responses are scoped by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
This design avoids redundant data while enabling clean support for quiz retakes and iterative peer review cycles.&lt;br /&gt;
&lt;br /&gt;
=== Emphasis on RESTful and Stateless Design ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This approach ensures compatibility with modern frontend frameworks such as React and simplifies horizontal scaling by eliminating the need for server-side session storage.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' https://youtu.be/Zg-fQmIUCSc&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Expand &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjeri&lt;br /&gt;
&lt;br /&gt;
'''Mentor:''' &lt;br /&gt;
* Vihar Manojkumar Shah&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167654</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167654"/>
		<updated>2026-03-31T02:25:33Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Design Decisions ==&lt;br /&gt;
&lt;br /&gt;
The reimplementation of Student Quizzes emphasized modularity, separation of concerns, and extensibility to ensure the system can evolve alongside future Expertiza features.&lt;br /&gt;
&lt;br /&gt;
=== Decoupling Task Logic from Controllers ===&lt;br /&gt;
&lt;br /&gt;
A key architectural decision was to encapsulate all task sequencing and eligibility logic within the &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module, rather than embedding it directly in controllers. Controllers are responsible only for handling HTTP requests and responses, while &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; operates purely on domain objects such as assignments, participants, and response maps.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Use of the Factory Pattern ===&lt;br /&gt;
&lt;br /&gt;
The introduction of &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Centralized Task Orchestration via TaskQueue ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Layered Authorization and Validation ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt;, while resource-specific checks (such as map ownership) are implemented as controller &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; callbacks.&lt;br /&gt;
&lt;br /&gt;
Finally, task-order enforcement is delegated to &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
To support Expertiza’s multi-round workflow model, responses are scoped by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
This design avoids redundant data while enabling clean support for quiz retakes and iterative peer review cycles.&lt;br /&gt;
&lt;br /&gt;
=== Emphasis on RESTful and Stateless Design ===&lt;br /&gt;
&lt;br /&gt;
All APIs were designed following RESTful principles, with clear resource-based endpoints and appropriate use of HTTP methods. Authentication is handled באמצעות JWT tokens, allowing the backend to remain stateless and scalable.&lt;br /&gt;
&lt;br /&gt;
This approach ensures compatibility with modern frontend frameworks such as React and simplifies horizontal scaling by eliminating the need for server-side session storage.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' https://youtu.be/Zg-fQmIUCSc&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Expand &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjeri&lt;br /&gt;
&lt;br /&gt;
'''Mentor:''' &lt;br /&gt;
* Vihar Manojkumar Shah&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167653</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167653"/>
		<updated>2026-03-31T02:24:24Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' https://youtu.be/Zg-fQmIUCSc&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Expand &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjeri&lt;br /&gt;
&lt;br /&gt;
'''Mentor:''' &lt;br /&gt;
* Vihar Manojkumar Shah&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167651</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167651"/>
		<updated>2026-03-31T02:18:59Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Design Decisions ==&lt;br /&gt;
&lt;br /&gt;
The reimplementation of Student Quizzes emphasized modularity, separation of concerns, and extensibility to ensure the system can evolve alongside future Expertiza features.&lt;br /&gt;
&lt;br /&gt;
=== Decoupling Task Logic from Controllers ===&lt;br /&gt;
&lt;br /&gt;
A key architectural decision was to encapsulate all task sequencing and eligibility logic within the &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module, rather than embedding it directly in controllers. Controllers are responsible only for handling HTTP requests and responses, while &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; operates purely on domain objects such as assignments, participants, and response maps.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Use of the Factory Pattern ===&lt;br /&gt;
&lt;br /&gt;
The introduction of &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Centralized Task Orchestration via TaskQueue ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Layered Authorization and Validation ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt;, while resource-specific checks (such as map ownership) are implemented as controller &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; callbacks.&lt;br /&gt;
&lt;br /&gt;
Finally, task-order enforcement is delegated to &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
To support Expertiza’s multi-round workflow model, responses are scoped by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
This design avoids redundant data while enabling clean support for quiz retakes and iterative peer review cycles.&lt;br /&gt;
&lt;br /&gt;
=== Emphasis on RESTful and Stateless Design ===&lt;br /&gt;
&lt;br /&gt;
All APIs were designed following RESTful principles, with clear resource-based endpoints and appropriate use of HTTP methods. Authentication is handled באמצעות JWT tokens, allowing the backend to remain stateless and scalable.&lt;br /&gt;
&lt;br /&gt;
This approach ensures compatibility with modern frontend frameworks such as React and simplifies horizontal scaling by eliminating the need for server-side session storage.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' https://youtu.be/Zg-fQmIUCSc&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Expand &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjeri&lt;br /&gt;
&lt;br /&gt;
'''Mentor:''' &lt;br /&gt;
* Vihar Manojkumar Shah&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167646</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167646"/>
		<updated>2026-03-31T02:14:09Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' https://youtu.be/Zg-fQmIUCSc&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Expand &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjeri&lt;br /&gt;
&lt;br /&gt;
'''Mentor:''' &lt;br /&gt;
* Vihar Manojkumar Shah&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167642</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167642"/>
		<updated>2026-03-31T01:36:36Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Bugs We Fixed ==&lt;br /&gt;
&lt;br /&gt;
During implementation and testing we encountered and resolved several non-trivial bugs. We document them here in detail because they reveal important architectural lessons about how Rails before-action ordering and RSpec let scoping interact.&lt;br /&gt;
&lt;br /&gt;
=== Bug 1: &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; Running Before Authentication ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Every POST to &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; returned 500 with &amp;lt;code&amp;gt;NoMethodError: undefined method 'id' for nil&amp;lt;/code&amp;gt;, even with a valid token.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; was declared with &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt;, which inserts it at the front of the callback chain — before &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; had a chance to set &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt;. The method then called &amp;lt;code&amp;gt;current_user.id&amp;lt;/code&amp;gt; on a nil object.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed the declaration to a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
prepend_before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This ensures the callback chain runs in the correct order: authenticate → authorize → find and check map ownership.&lt;br /&gt;
&lt;br /&gt;
=== Bug 2: Stale RSA Key File Causing Silent 401 Failures ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests with valid tokens were returning 401 even after the before-action ordering was fixed. The error message was &amp;lt;code&amp;gt;Not Authorized&amp;lt;/code&amp;gt; with no further detail.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;JsonWebToken&amp;lt;/code&amp;gt; loads RSA keys at class initialization time. If &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; exists on disk, those keys are used. If the file was written by a previous process with different keys, tokens encoded during the test run (using newly generated in-memory keys) would fail RSA signature verification during decoding.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Deleted the stale &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; and added it to &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm rsa_keys.yml&lt;br /&gt;
echo &amp;quot;rsa_keys.yml&amp;quot; &amp;gt;&amp;gt; .gitignore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bug 3: RSpec &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; Scoping Causing Token/User Mismatch ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests continued to return 401 even after the RSA key fix. &amp;lt;code&amp;gt;User.find(auth_token[:id])&amp;lt;/code&amp;gt; was finding the correct ID but authentication was still failing intermittently.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The responses spec declared the user with &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; (eager) while &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was lazy. Because &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; runs eagerly in its own evaluation context, the user object memoized inside the &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; block could differ from the one referenced when &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was later evaluated. This caused the encoded token to contain a user ID that did not match what was in the database for that example.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed &amp;lt;code&amp;gt;let!(:student)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;let(:student)&amp;lt;/code&amp;gt; and relied on the dependent &amp;lt;code&amp;gt;let!(:reviewer_participant)&amp;lt;/code&amp;gt; — which references &amp;lt;code&amp;gt;student.id&amp;lt;/code&amp;gt; — to force eager creation through the dependency chain:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
let!(:student) { User.create!(...) }&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
let(:student) { User.create!(...) }   # lazy&lt;br /&gt;
let!(:reviewer_participant) do&lt;br /&gt;
  AssignmentParticipant.create!(user_id: student.id, ...)  # forces student creation&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This mirrors the exact pattern used in the passing &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Bug 4: Error Message Mismatch in 401 Test ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' The 401 unauthorized test was failing with &amp;lt;code&amp;gt;expected &amp;quot;Not Authorized&amp;quot; but got &amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The controller's nil-user guard rendered &amp;lt;code&amp;gt;&amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt; while the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; concern (which handles missing/invalid tokens) renders &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt;. The test expected the latter.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Removed the redundant nil-user guard from &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; entirely. Since &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; now always runs first, &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; will never be nil by the time the map ownership check runs — unauthenticated requests are rejected at the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; layer with the correct &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt; message.&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' https://youtu.be/Zg-fQmIUCSc&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Expand &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjeri&lt;br /&gt;
&lt;br /&gt;
'''Mentor:''' &lt;br /&gt;
* Vihar Manojkumar Shah&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167637</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167637"/>
		<updated>2026-03-31T01:29:13Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Bugs We Fixed ==&lt;br /&gt;
&lt;br /&gt;
During implementation and testing we encountered and resolved several non-trivial bugs. We document them here in detail because they reveal important architectural lessons about how Rails before-action ordering and RSpec let scoping interact.&lt;br /&gt;
&lt;br /&gt;
=== Bug 1: &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; Running Before Authentication ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Every POST to &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; returned 500 with &amp;lt;code&amp;gt;NoMethodError: undefined method 'id' for nil&amp;lt;/code&amp;gt;, even with a valid token.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; was declared with &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt;, which inserts it at the front of the callback chain — before &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; had a chance to set &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt;. The method then called &amp;lt;code&amp;gt;current_user.id&amp;lt;/code&amp;gt; on a nil object.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed the declaration to a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
prepend_before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This ensures the callback chain runs in the correct order: authenticate → authorize → find and check map ownership.&lt;br /&gt;
&lt;br /&gt;
=== Bug 2: Stale RSA Key File Causing Silent 401 Failures ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests with valid tokens were returning 401 even after the before-action ordering was fixed. The error message was &amp;lt;code&amp;gt;Not Authorized&amp;lt;/code&amp;gt; with no further detail.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;JsonWebToken&amp;lt;/code&amp;gt; loads RSA keys at class initialization time. If &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; exists on disk, those keys are used. If the file was written by a previous process with different keys, tokens encoded during the test run (using newly generated in-memory keys) would fail RSA signature verification during decoding.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Deleted the stale &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; and added it to &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm rsa_keys.yml&lt;br /&gt;
echo &amp;quot;rsa_keys.yml&amp;quot; &amp;gt;&amp;gt; .gitignore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bug 3: RSpec &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; Scoping Causing Token/User Mismatch ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests continued to return 401 even after the RSA key fix. &amp;lt;code&amp;gt;User.find(auth_token[:id])&amp;lt;/code&amp;gt; was finding the correct ID but authentication was still failing intermittently.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The responses spec declared the user with &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; (eager) while &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was lazy. Because &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; runs eagerly in its own evaluation context, the user object memoized inside the &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; block could differ from the one referenced when &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was later evaluated. This caused the encoded token to contain a user ID that did not match what was in the database for that example.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed &amp;lt;code&amp;gt;let!(:student)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;let(:student)&amp;lt;/code&amp;gt; and relied on the dependent &amp;lt;code&amp;gt;let!(:reviewer_participant)&amp;lt;/code&amp;gt; — which references &amp;lt;code&amp;gt;student.id&amp;lt;/code&amp;gt; — to force eager creation through the dependency chain:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
let!(:student) { User.create!(...) }&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
let(:student) { User.create!(...) }   # lazy&lt;br /&gt;
let!(:reviewer_participant) do&lt;br /&gt;
  AssignmentParticipant.create!(user_id: student.id, ...)  # forces student creation&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This mirrors the exact pattern used in the passing &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Bug 4: Error Message Mismatch in 401 Test ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' The 401 unauthorized test was failing with &amp;lt;code&amp;gt;expected &amp;quot;Not Authorized&amp;quot; but got &amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The controller's nil-user guard rendered &amp;lt;code&amp;gt;&amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt; while the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; concern (which handles missing/invalid tokens) renders &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt;. The test expected the latter.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Removed the redundant nil-user guard from &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; entirely. Since &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; now always runs first, &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; will never be nil by the time the map ownership check runs — unauthenticated requests are rejected at the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; layer with the correct &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt; message.&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' https://youtu.be/Zg-fQmIUCSc&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Expand &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjeri&lt;br /&gt;
&lt;br /&gt;
'''Mentor:''' Dr. Ed Gehringer&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167636</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167636"/>
		<updated>2026-03-31T01:28:05Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Bugs We Fixed ==&lt;br /&gt;
&lt;br /&gt;
During implementation and testing we encountered and resolved several non-trivial bugs. We document them here in detail because they reveal important architectural lessons about how Rails before-action ordering and RSpec let scoping interact.&lt;br /&gt;
&lt;br /&gt;
=== Bug 1: &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; Running Before Authentication ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Every POST to &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; returned 500 with &amp;lt;code&amp;gt;NoMethodError: undefined method 'id' for nil&amp;lt;/code&amp;gt;, even with a valid token.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; was declared with &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt;, which inserts it at the front of the callback chain — before &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; had a chance to set &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt;. The method then called &amp;lt;code&amp;gt;current_user.id&amp;lt;/code&amp;gt; on a nil object.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed the declaration to a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
prepend_before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This ensures the callback chain runs in the correct order: authenticate → authorize → find and check map ownership.&lt;br /&gt;
&lt;br /&gt;
=== Bug 2: Stale RSA Key File Causing Silent 401 Failures ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests with valid tokens were returning 401 even after the before-action ordering was fixed. The error message was &amp;lt;code&amp;gt;Not Authorized&amp;lt;/code&amp;gt; with no further detail.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;JsonWebToken&amp;lt;/code&amp;gt; loads RSA keys at class initialization time. If &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; exists on disk, those keys are used. If the file was written by a previous process with different keys, tokens encoded during the test run (using newly generated in-memory keys) would fail RSA signature verification during decoding.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Deleted the stale &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; and added it to &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm rsa_keys.yml&lt;br /&gt;
echo &amp;quot;rsa_keys.yml&amp;quot; &amp;gt;&amp;gt; .gitignore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bug 3: RSpec &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; Scoping Causing Token/User Mismatch ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests continued to return 401 even after the RSA key fix. &amp;lt;code&amp;gt;User.find(auth_token[:id])&amp;lt;/code&amp;gt; was finding the correct ID but authentication was still failing intermittently.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The responses spec declared the user with &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; (eager) while &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was lazy. Because &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; runs eagerly in its own evaluation context, the user object memoized inside the &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; block could differ from the one referenced when &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was later evaluated. This caused the encoded token to contain a user ID that did not match what was in the database for that example.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed &amp;lt;code&amp;gt;let!(:student)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;let(:student)&amp;lt;/code&amp;gt; and relied on the dependent &amp;lt;code&amp;gt;let!(:reviewer_participant)&amp;lt;/code&amp;gt; — which references &amp;lt;code&amp;gt;student.id&amp;lt;/code&amp;gt; — to force eager creation through the dependency chain:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
let!(:student) { User.create!(...) }&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
let(:student) { User.create!(...) }   # lazy&lt;br /&gt;
let!(:reviewer_participant) do&lt;br /&gt;
  AssignmentParticipant.create!(user_id: student.id, ...)  # forces student creation&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This mirrors the exact pattern used in the passing &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Bug 4: Error Message Mismatch in 401 Test ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' The 401 unauthorized test was failing with &amp;lt;code&amp;gt;expected &amp;quot;Not Authorized&amp;quot; but got &amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The controller's nil-user guard rendered &amp;lt;code&amp;gt;&amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt; while the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; concern (which handles missing/invalid tokens) renders &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt;. The test expected the latter.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Removed the redundant nil-user guard from &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; entirely. Since &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; now always runs first, &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; will never be nil by the time the map ownership check runs — unauthenticated requests are rejected at the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; layer with the correct &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt; message.&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' [https://youtu.be/Zg-fQmIUCSc]&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Expand &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjeri&lt;br /&gt;
&lt;br /&gt;
'''Mentor:''' Dr. Ed Gehringer&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167635</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167635"/>
		<updated>2026-03-31T01:26:51Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Bugs We Fixed ==&lt;br /&gt;
&lt;br /&gt;
During implementation and testing we encountered and resolved several non-trivial bugs. We document them here in detail because they reveal important architectural lessons about how Rails before-action ordering and RSpec let scoping interact.&lt;br /&gt;
&lt;br /&gt;
=== Bug 1: &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; Running Before Authentication ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Every POST to &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; returned 500 with &amp;lt;code&amp;gt;NoMethodError: undefined method 'id' for nil&amp;lt;/code&amp;gt;, even with a valid token.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; was declared with &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt;, which inserts it at the front of the callback chain — before &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; had a chance to set &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt;. The method then called &amp;lt;code&amp;gt;current_user.id&amp;lt;/code&amp;gt; on a nil object.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed the declaration to a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
prepend_before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This ensures the callback chain runs in the correct order: authenticate → authorize → find and check map ownership.&lt;br /&gt;
&lt;br /&gt;
=== Bug 2: Stale RSA Key File Causing Silent 401 Failures ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests with valid tokens were returning 401 even after the before-action ordering was fixed. The error message was &amp;lt;code&amp;gt;Not Authorized&amp;lt;/code&amp;gt; with no further detail.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;JsonWebToken&amp;lt;/code&amp;gt; loads RSA keys at class initialization time. If &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; exists on disk, those keys are used. If the file was written by a previous process with different keys, tokens encoded during the test run (using newly generated in-memory keys) would fail RSA signature verification during decoding.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Deleted the stale &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; and added it to &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm rsa_keys.yml&lt;br /&gt;
echo &amp;quot;rsa_keys.yml&amp;quot; &amp;gt;&amp;gt; .gitignore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bug 3: RSpec &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; Scoping Causing Token/User Mismatch ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests continued to return 401 even after the RSA key fix. &amp;lt;code&amp;gt;User.find(auth_token[:id])&amp;lt;/code&amp;gt; was finding the correct ID but authentication was still failing intermittently.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The responses spec declared the user with &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; (eager) while &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was lazy. Because &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; runs eagerly in its own evaluation context, the user object memoized inside the &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; block could differ from the one referenced when &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was later evaluated. This caused the encoded token to contain a user ID that did not match what was in the database for that example.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed &amp;lt;code&amp;gt;let!(:student)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;let(:student)&amp;lt;/code&amp;gt; and relied on the dependent &amp;lt;code&amp;gt;let!(:reviewer_participant)&amp;lt;/code&amp;gt; — which references &amp;lt;code&amp;gt;student.id&amp;lt;/code&amp;gt; — to force eager creation through the dependency chain:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
let!(:student) { User.create!(...) }&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
let(:student) { User.create!(...) }   # lazy&lt;br /&gt;
let!(:reviewer_participant) do&lt;br /&gt;
  AssignmentParticipant.create!(user_id: student.id, ...)  # forces student creation&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This mirrors the exact pattern used in the passing &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Bug 4: Error Message Mismatch in 401 Test ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' The 401 unauthorized test was failing with &amp;lt;code&amp;gt;expected &amp;quot;Not Authorized&amp;quot; but got &amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The controller's nil-user guard rendered &amp;lt;code&amp;gt;&amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt; while the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; concern (which handles missing/invalid tokens) renders &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt;. The test expected the latter.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Removed the redundant nil-user guard from &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; entirely. Since &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; now always runs first, &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; will never be nil by the time the map ownership check runs — unauthenticated requests are rejected at the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; layer with the correct &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt; message.&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' [Link to be added]&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Expand &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjeri&lt;br /&gt;
&lt;br /&gt;
'''Mentor:''' Dr. Ed Gehringer&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167634</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167634"/>
		<updated>2026-03-31T01:24:21Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= CSC/ECE 517 Spring 2026 - E2601. Reimplement Student Quizzes =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Bugs We Fixed ==&lt;br /&gt;
&lt;br /&gt;
During implementation and testing we encountered and resolved several non-trivial bugs. We document them here in detail because they reveal important architectural lessons about how Rails before-action ordering and RSpec let scoping interact.&lt;br /&gt;
&lt;br /&gt;
=== Bug 1: &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; Running Before Authentication ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Every POST to &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; returned 500 with &amp;lt;code&amp;gt;NoMethodError: undefined method 'id' for nil&amp;lt;/code&amp;gt;, even with a valid token.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; was declared with &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt;, which inserts it at the front of the callback chain — before &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; had a chance to set &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt;. The method then called &amp;lt;code&amp;gt;current_user.id&amp;lt;/code&amp;gt; on a nil object.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed the declaration to a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
prepend_before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This ensures the callback chain runs in the correct order: authenticate → authorize → find and check map ownership.&lt;br /&gt;
&lt;br /&gt;
=== Bug 2: Stale RSA Key File Causing Silent 401 Failures ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests with valid tokens were returning 401 even after the before-action ordering was fixed. The error message was &amp;lt;code&amp;gt;Not Authorized&amp;lt;/code&amp;gt; with no further detail.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;JsonWebToken&amp;lt;/code&amp;gt; loads RSA keys at class initialization time. If &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; exists on disk, those keys are used. If the file was written by a previous process with different keys, tokens encoded during the test run (using newly generated in-memory keys) would fail RSA signature verification during decoding.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Deleted the stale &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; and added it to &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm rsa_keys.yml&lt;br /&gt;
echo &amp;quot;rsa_keys.yml&amp;quot; &amp;gt;&amp;gt; .gitignore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bug 3: RSpec &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; Scoping Causing Token/User Mismatch ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests continued to return 401 even after the RSA key fix. &amp;lt;code&amp;gt;User.find(auth_token[:id])&amp;lt;/code&amp;gt; was finding the correct ID but authentication was still failing intermittently.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The responses spec declared the user with &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; (eager) while &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was lazy. Because &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; runs eagerly in its own evaluation context, the user object memoized inside the &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; block could differ from the one referenced when &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was later evaluated. This caused the encoded token to contain a user ID that did not match what was in the database for that example.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed &amp;lt;code&amp;gt;let!(:student)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;let(:student)&amp;lt;/code&amp;gt; and relied on the dependent &amp;lt;code&amp;gt;let!(:reviewer_participant)&amp;lt;/code&amp;gt; — which references &amp;lt;code&amp;gt;student.id&amp;lt;/code&amp;gt; — to force eager creation through the dependency chain:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
let!(:student) { User.create!(...) }&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
let(:student) { User.create!(...) }   # lazy&lt;br /&gt;
let!(:reviewer_participant) do&lt;br /&gt;
  AssignmentParticipant.create!(user_id: student.id, ...)  # forces student creation&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This mirrors the exact pattern used in the passing &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Bug 4: Error Message Mismatch in 401 Test ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' The 401 unauthorized test was failing with &amp;lt;code&amp;gt;expected &amp;quot;Not Authorized&amp;quot; but got &amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The controller's nil-user guard rendered &amp;lt;code&amp;gt;&amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt; while the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; concern (which handles missing/invalid tokens) renders &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt;. The test expected the latter.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Removed the redundant nil-user guard from &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; entirely. Since &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; now always runs first, &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; will never be nil by the time the map ownership check runs — unauthenticated requests are rejected at the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; layer with the correct &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt; message.&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' [Link to be added]&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Expand &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjeri&lt;br /&gt;
&lt;br /&gt;
'''Mentor:''' Dr. Ed Gehringer&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167633</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167633"/>
		<updated>2026-03-31T01:22:27Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= CSC/ECE 517 Spring 2026 - E2601. Reimplement Student Quizzes =&lt;br /&gt;
&lt;br /&gt;
== Table of Contents ==&lt;br /&gt;
# [[#Important Links|Important Links]]&lt;br /&gt;
# [[#Expertiza Background|Expertiza Background]]&lt;br /&gt;
# [[#Project Description|Project Description]]&lt;br /&gt;
# [[#What We Built|What We Built]]&lt;br /&gt;
# [[#Technical Deep Dive|Technical Deep Dive]]&lt;br /&gt;
# [[#Bugs We Fixed|Bugs We Fixed]]&lt;br /&gt;
# [[#Test Coverage|Test Coverage]]&lt;br /&gt;
# [[#Demo Video|Demo Video]]&lt;br /&gt;
# [[#Future Work|Future Work]]&lt;br /&gt;
# [[#References|References]]&lt;br /&gt;
# [[#Team|Team]]&lt;br /&gt;
&lt;br /&gt;
== Important Links ==&lt;br /&gt;
&lt;br /&gt;
* '''Git PR (back-end):''' [https://github.com/expertiza/reimplementation-back-end/pull/XXX Back-end Pull Request]&lt;br /&gt;
* '''Demo Video:''' [[#Demo Video|See Demo Video Section]]&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Bugs We Fixed ==&lt;br /&gt;
&lt;br /&gt;
During implementation and testing we encountered and resolved several non-trivial bugs. We document them here in detail because they reveal important architectural lessons about how Rails before-action ordering and RSpec let scoping interact.&lt;br /&gt;
&lt;br /&gt;
=== Bug 1: &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; Running Before Authentication ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Every POST to &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; returned 500 with &amp;lt;code&amp;gt;NoMethodError: undefined method 'id' for nil&amp;lt;/code&amp;gt;, even with a valid token.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; was declared with &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt;, which inserts it at the front of the callback chain — before &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; had a chance to set &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt;. The method then called &amp;lt;code&amp;gt;current_user.id&amp;lt;/code&amp;gt; on a nil object.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed the declaration to a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
prepend_before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This ensures the callback chain runs in the correct order: authenticate → authorize → find and check map ownership.&lt;br /&gt;
&lt;br /&gt;
=== Bug 2: Stale RSA Key File Causing Silent 401 Failures ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests with valid tokens were returning 401 even after the before-action ordering was fixed. The error message was &amp;lt;code&amp;gt;Not Authorized&amp;lt;/code&amp;gt; with no further detail.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;JsonWebToken&amp;lt;/code&amp;gt; loads RSA keys at class initialization time. If &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; exists on disk, those keys are used. If the file was written by a previous process with different keys, tokens encoded during the test run (using newly generated in-memory keys) would fail RSA signature verification during decoding.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Deleted the stale &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; and added it to &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm rsa_keys.yml&lt;br /&gt;
echo &amp;quot;rsa_keys.yml&amp;quot; &amp;gt;&amp;gt; .gitignore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bug 3: RSpec &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; Scoping Causing Token/User Mismatch ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests continued to return 401 even after the RSA key fix. &amp;lt;code&amp;gt;User.find(auth_token[:id])&amp;lt;/code&amp;gt; was finding the correct ID but authentication was still failing intermittently.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The responses spec declared the user with &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; (eager) while &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was lazy. Because &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; runs eagerly in its own evaluation context, the user object memoized inside the &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; block could differ from the one referenced when &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was later evaluated. This caused the encoded token to contain a user ID that did not match what was in the database for that example.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed &amp;lt;code&amp;gt;let!(:student)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;let(:student)&amp;lt;/code&amp;gt; and relied on the dependent &amp;lt;code&amp;gt;let!(:reviewer_participant)&amp;lt;/code&amp;gt; — which references &amp;lt;code&amp;gt;student.id&amp;lt;/code&amp;gt; — to force eager creation through the dependency chain:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
let!(:student) { User.create!(...) }&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
let(:student) { User.create!(...) }   # lazy&lt;br /&gt;
let!(:reviewer_participant) do&lt;br /&gt;
  AssignmentParticipant.create!(user_id: student.id, ...)  # forces student creation&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This mirrors the exact pattern used in the passing &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Bug 4: Error Message Mismatch in 401 Test ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' The 401 unauthorized test was failing with &amp;lt;code&amp;gt;expected &amp;quot;Not Authorized&amp;quot; but got &amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The controller's nil-user guard rendered &amp;lt;code&amp;gt;&amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt; while the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; concern (which handles missing/invalid tokens) renders &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt;. The test expected the latter.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Removed the redundant nil-user guard from &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; entirely. Since &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; now always runs first, &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; will never be nil by the time the map ownership check runs — unauthenticated requests are rejected at the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; layer with the correct &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt; message.&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' [Link to be added]&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Expand &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
* North Carolina State University, CSC 517 Course Materials&lt;br /&gt;
* Metz, S. (2018). ''Practical Object-Oriented Design: An Agile Primer Using Ruby'' (2nd ed.). Addison-Wesley.&lt;br /&gt;
* Fowler, M. (2018). ''Refactoring: Improving the Design of Existing Code'' (2nd ed.). Addison-Wesley.&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
&lt;br /&gt;
'''Mentor:''' Dr. Ed Gehringer&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167632</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167632"/>
		<updated>2026-03-31T01:21:46Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= E2601: Reimplementation of the Student Quiz System =&lt;br /&gt;
&lt;br /&gt;
'''E2601: Reimplementation of the Student Quiz System''' is a graduate-level project conducted as part of the CSC/ECE 517 course at [[North Carolina State University]] in Spring 2026. The project focuses on modernizing the quiz subsystem within the [[Expertiza]] peer review platform, ensuring correct sequencing of tasks in multi-step assignment workflows.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
[[Expertiza]] is an open-source platform developed at North Carolina State University that facilitates structured peer reviews, team-based assignments, and multi-stage workflows including submissions, reviews, quizzes, and feedback.&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&lt;br /&gt;
&amp;lt;/ref&amp;gt; In Expertiza, each assignment is organized as a workflow, where students must complete tasks in a prescribed order. Accurate task sequencing is essential to maintain the integrity of these workflows, particularly for quiz tasks, which may depend on prior completion of submission or review stages.&lt;br /&gt;
&lt;br /&gt;
The platform is being reimplemented to separate the backend (Rails API) and frontend (React SPA), emphasizing modularity, test coverage, and adherence to RESTful principles.&amp;lt;ref&amp;gt;https://guides.rubyonrails.org&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Objectives ==&lt;br /&gt;
&lt;br /&gt;
The project addressed three primary challenges:&lt;br /&gt;
&lt;br /&gt;
Implementing reliable task sequencing logic for student workflows.&lt;br /&gt;
Developing a student-facing API for task visibility and management.&lt;br /&gt;
Ensuring secure creation and updating of quiz responses with authentication and prerequisite checks.&lt;br /&gt;
&lt;br /&gt;
== System Architecture ==&lt;br /&gt;
&lt;br /&gt;
The reimplementation separates responsibilities into three layers: task ordering, student task API, and response management API.&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Layer ===&lt;br /&gt;
&lt;br /&gt;
The '''TaskOrdering''' module encapsulates all logic related to task sequencing and eligibility. It is independent of controllers and HTTP requests.&lt;br /&gt;
&lt;br /&gt;
Key components include:&lt;br /&gt;
&lt;br /&gt;
'''BaseTask''': Abstract interface for all task types.&lt;br /&gt;
'''ReviewTask''': Represents review tasks; completion depends on submission status.&lt;br /&gt;
'''QuizTask''': Represents quiz tasks and determines completion state.&lt;br /&gt;
'''TaskFactory''': Maps response maps to task objects.&lt;br /&gt;
'''TaskQueue''': Orchestrates ordered tasks and provides eligibility queries.&lt;br /&gt;
&lt;br /&gt;
The module determines whether a task belongs to a student, verifies completion of prior tasks, and identifies the next actionable task.&lt;br /&gt;
&lt;br /&gt;
=== Student Task API ===&lt;br /&gt;
&lt;br /&gt;
The student task API exposes task information via five endpoints:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; – Lists all tasks for a student.&lt;br /&gt;
&amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; – Provides detailed task information.&lt;br /&gt;
&amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; – Returns the ordered task queue for an assignment.&lt;br /&gt;
&amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; – Retrieves the next incomplete task.&lt;br /&gt;
&amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; – Initiates a task if prerequisites are complete.&lt;br /&gt;
&lt;br /&gt;
All endpoints require JWT authentication and resolve the participant context before delegating to TaskQueue.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
The response management API ensures secure creation and modification of quiz and review responses.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;POST /responses&amp;lt;/code&amp;gt; – Creates a new response.&lt;br /&gt;
&amp;lt;code&amp;gt;GET /responses/:id&amp;lt;/code&amp;gt; – Retrieves an existing response.&lt;br /&gt;
&amp;lt;code&amp;gt;PATCH /responses/:id&amp;lt;/code&amp;gt; – Updates an existing response.&lt;br /&gt;
&lt;br /&gt;
Security measures include ownership verification and task order enforcement to prevent unauthorized or out-of-sequence submissions.&lt;br /&gt;
&lt;br /&gt;
=== Task Enforcement and Workflow ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start or submit a quiz:&lt;br /&gt;
&lt;br /&gt;
A TaskQueue instance is initialized.&lt;br /&gt;
Response maps are converted into task objects.&lt;br /&gt;
Tasks are ordered sequentially.&lt;br /&gt;
Completion of prior tasks is verified.&lt;br /&gt;
Requests failing prerequisite checks are rejected.&lt;br /&gt;
&lt;br /&gt;
This enforces strict task order without embedding logic directly into controllers.&lt;br /&gt;
&lt;br /&gt;
=== Authentication and Authorization ===&lt;br /&gt;
&lt;br /&gt;
All requests follow a layered processing pipeline:&lt;br /&gt;
&lt;br /&gt;
JWT authentication decodes tokens and sets &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt;.&lt;br /&gt;
Authorization verifies permitted actions.&lt;br /&gt;
Controller-level validation confirms resource ownership.&lt;br /&gt;
Business logic execution handles task and response operations.&lt;br /&gt;
&lt;br /&gt;
=== Multi-Round Support ===&lt;br /&gt;
&lt;br /&gt;
The system supports multi-round assignments by scoping responses to both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;. Existing responses are reused when appropriate, while new responses are created only when necessary, supporting quiz retakes and multi-round reviews.&lt;br /&gt;
&lt;br /&gt;
== Implementation Challenges ==&lt;br /&gt;
&lt;br /&gt;
Several issues were encountered and resolved during development:&lt;br /&gt;
&lt;br /&gt;
'''Callback Execution Order''': Using &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; caused authorization to run before authentication. Replaced with &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; to correct the callback sequence.&lt;br /&gt;
'''RSA Key Inconsistencies''': Stale RSA keys caused JWT validation failures. Resolved by removing outdated key files and excluding them from version control.&lt;br /&gt;
'''Test Initialization Conflicts''': Mixed eager and lazy initialization in RSpec caused intermittent failures. Standardized lazy evaluation with dependency chaining.&lt;br /&gt;
'''Consistency of Error Messages''': Different layers returned conflicting 401 messages. Resolved by relying on the authentication layer to handle all unauthorized requests uniformly.&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
&lt;br /&gt;
Model and request tests were implemented to validate:&lt;br /&gt;
&lt;br /&gt;
Task completion logic&lt;br /&gt;
Queue ordering&lt;br /&gt;
Factory behavior&lt;br /&gt;
API endpoint correctness&lt;br /&gt;
Authentication and authorization checks&lt;br /&gt;
&lt;br /&gt;
All tests executed successfully, resulting in 77 passing examples.&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
Potential improvements include:&lt;br /&gt;
&lt;br /&gt;
Deadline-aware task sequencing&lt;br /&gt;
Partial progress tracking for quizzes&lt;br /&gt;
Frontend progress indicators for task completion&lt;br /&gt;
Support for additional task types&lt;br /&gt;
Administrative tools for queue inspection and overrides&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
Akhil Kumar&lt;br /&gt;
Dev Patel&lt;br /&gt;
Arnav Merjari&lt;br /&gt;
&lt;br /&gt;
Mentor: Dr. Ed Gehringer&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt; * [https://github.com/expertiza/expertiza Expertiza GitHub Repository] * [https://guides.rubyonrails.org Ruby on Rails Guides] * [https://rspec.info RSpec Documentation] * [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167631</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167631"/>
		<updated>2026-03-31T01:18:43Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= CSC/ECE 517 Spring 2026 - E2601. Reimplement Student Quizzes =&lt;br /&gt;
&lt;br /&gt;
== Important Links ==&lt;br /&gt;
&lt;br /&gt;
* '''Git PR (back-end):''' [https://github.com/expertiza/reimplementation-back-end/pull/XXX Back-end Pull Request]&lt;br /&gt;
* '''Demo Video:''' [[#Demo Video|See Demo Video Section]]&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Bugs We Fixed ==&lt;br /&gt;
&lt;br /&gt;
During implementation and testing we encountered and resolved several non-trivial bugs. We document them here in detail because they reveal important architectural lessons about how Rails before-action ordering and RSpec let scoping interact.&lt;br /&gt;
&lt;br /&gt;
=== Bug 1: &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; Running Before Authentication ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Every POST to &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; returned 500 with &amp;lt;code&amp;gt;NoMethodError: undefined method 'id' for nil&amp;lt;/code&amp;gt;, even with a valid token.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; was declared with &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt;, which inserts it at the front of the callback chain — before &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; had a chance to set &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt;. The method then called &amp;lt;code&amp;gt;current_user.id&amp;lt;/code&amp;gt; on a nil object.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed the declaration to a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
prepend_before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This ensures the callback chain runs in the correct order: authenticate → authorize → find and check map ownership.&lt;br /&gt;
&lt;br /&gt;
=== Bug 2: Stale RSA Key File Causing Silent 401 Failures ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests with valid tokens were returning 401 even after the before-action ordering was fixed. The error message was &amp;lt;code&amp;gt;Not Authorized&amp;lt;/code&amp;gt; with no further detail.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;JsonWebToken&amp;lt;/code&amp;gt; loads RSA keys at class initialization time. If &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; exists on disk, those keys are used. If the file was written by a previous process with different keys, tokens encoded during the test run (using newly generated in-memory keys) would fail RSA signature verification during decoding.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Deleted the stale &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; and added it to &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm rsa_keys.yml&lt;br /&gt;
echo &amp;quot;rsa_keys.yml&amp;quot; &amp;gt;&amp;gt; .gitignore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bug 3: RSpec &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; Scoping Causing Token/User Mismatch ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests continued to return 401 even after the RSA key fix. &amp;lt;code&amp;gt;User.find(auth_token[:id])&amp;lt;/code&amp;gt; was finding the correct ID but authentication was still failing intermittently.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The responses spec declared the user with &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; (eager) while &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was lazy. Because &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; runs eagerly in its own evaluation context, the user object memoized inside the &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; block could differ from the one referenced when &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was later evaluated. This caused the encoded token to contain a user ID that did not match what was in the database for that example.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed &amp;lt;code&amp;gt;let!(:student)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;let(:student)&amp;lt;/code&amp;gt; and relied on the dependent &amp;lt;code&amp;gt;let!(:reviewer_participant)&amp;lt;/code&amp;gt; — which references &amp;lt;code&amp;gt;student.id&amp;lt;/code&amp;gt; — to force eager creation through the dependency chain:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
let!(:student) { User.create!(...) }&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
let(:student) { User.create!(...) }   # lazy&lt;br /&gt;
let!(:reviewer_participant) do&lt;br /&gt;
  AssignmentParticipant.create!(user_id: student.id, ...)  # forces student creation&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This mirrors the exact pattern used in the passing &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Bug 4: Error Message Mismatch in 401 Test ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' The 401 unauthorized test was failing with &amp;lt;code&amp;gt;expected &amp;quot;Not Authorized&amp;quot; but got &amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The controller's nil-user guard rendered &amp;lt;code&amp;gt;&amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt; while the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; concern (which handles missing/invalid tokens) renders &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt;. The test expected the latter.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Removed the redundant nil-user guard from &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; entirely. Since &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; now always runs first, &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; will never be nil by the time the map ownership check runs — unauthenticated requests are rejected at the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; layer with the correct &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt; message.&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' [Link to be added]&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Expand &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjari&lt;br /&gt;
&lt;br /&gt;
'''Mentor:''' Dr. Ed Gehringer&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167630</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167630"/>
		<updated>2026-03-31T01:17:46Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= CSC/ECE 517 Spring 2026 - E2601. Reimplement Student Quizzes =&lt;br /&gt;
&lt;br /&gt;
== Table of Contents ==&lt;br /&gt;
# [[#Important Links|Important Links]]&lt;br /&gt;
# [[#Expertiza Background|Expertiza Background]]&lt;br /&gt;
# [[#Project Description|Project Description]]&lt;br /&gt;
# [[#What We Built|What We Built]]&lt;br /&gt;
# [[#Technical Deep Dive|Technical Deep Dive]]&lt;br /&gt;
# [[#Bugs We Fixed|Bugs We Fixed]]&lt;br /&gt;
# [[#Test Coverage|Test Coverage]]&lt;br /&gt;
# [[#Demo Video|Demo Video]]&lt;br /&gt;
# [[#Future Work|Future Work]]&lt;br /&gt;
# [[#References|References]]&lt;br /&gt;
# [[#Team|Team]]&lt;br /&gt;
&lt;br /&gt;
== Important Links ==&lt;br /&gt;
&lt;br /&gt;
* '''Git PR (back-end):''' [https://github.com/expertiza/reimplementation-back-end/pull/XXX Back-end Pull Request]&lt;br /&gt;
* '''Demo Video:''' [[#Demo Video|See Demo Video Section]]&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
For quizzes to work correctly in this context, three backend systems needed to be built or significantly repaired:&lt;br /&gt;
&lt;br /&gt;
* '''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&lt;br /&gt;
* '''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&lt;br /&gt;
* '''A response management API''' that handles the creation and updating of quiz responses with proper authentication, ownership checks, and queue-order enforcement&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== What We Built ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering Engine ===&lt;br /&gt;
&lt;br /&gt;
We built a self-contained &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; module under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The module consists of five classes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Abstract base defining the shared interface: &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Concrete task for &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt; — complete when &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt; is true&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Concrete task for quiz response maps — the central task type for this project&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Factory that instantiates the correct task class given a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrator that builds and queries the ordered task list for a participant&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; is the primary interface that controllers use. Given an assignment and a &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt;, it can answer three questions:&lt;br /&gt;
&lt;br /&gt;
* Is this map part of the participant's task queue? (&amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Have all tasks before this one been completed? (&amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;)&lt;br /&gt;
* What is the next task the student should work on? (&amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; with five endpoints that give students full visibility into their task workload:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Returns&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || GET || All tasks for the current user across their assignments&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || GET || Detailed information for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || GET || The full ordered task queue for a given assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || GET || The next incomplete task the student should work on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || POST || Attempts to start a task — blocked if prerequisites are incomplete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every endpoint requires a valid JWT token and resolves the student's &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TeamsParticipant&amp;lt;/code&amp;gt; records before delegating to a &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; instance for eligibility decisions.&lt;br /&gt;
&lt;br /&gt;
=== Response Management API ===&lt;br /&gt;
&lt;br /&gt;
We implemented &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; with three endpoints that handle quiz and review response lifecycle:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Endpoint !! Method !! What It Does&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || POST || Creates a new response for a quiz or review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || GET || Retrieves a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || PATCH || Updates an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Response creation enforces two layers of protection before any data is written:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership check''' — the requesting user must be the reviewer assigned to the response map&lt;br /&gt;
# '''Queue order check''' — the &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; must confirm that all prerequisite tasks are complete before this response can be created&lt;br /&gt;
&lt;br /&gt;
== Technical Deep Dive ==&lt;br /&gt;
&lt;br /&gt;
=== How Task Ordering Works ===&lt;br /&gt;
&lt;br /&gt;
When a student attempts to start a quiz task or create a response, the following sequence occurs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StudentTasksController or ResponsesController&lt;br /&gt;
        |&lt;br /&gt;
        | TaskQueue.new(assignment, teams_participant)&lt;br /&gt;
        v&lt;br /&gt;
TaskQueue&lt;br /&gt;
  → fetches all ResponseMaps for this participant&lt;br /&gt;
  → calls TaskFactory.build(map) for each&lt;br /&gt;
  → builds ordered array of BaseTask subclass instances&lt;br /&gt;
        |&lt;br /&gt;
        | queue.prior_tasks_complete_for?(map_id)&lt;br /&gt;
        v&lt;br /&gt;
  → iterates tasks in order&lt;br /&gt;
  → for each task before the target, calls task.complete?&lt;br /&gt;
  → returns false if any prior task is incomplete&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller either proceeds or renders 403/428&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How Authentication and Authorization Are Layered ===&lt;br /&gt;
&lt;br /&gt;
All requests pass through two concerns registered in &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt; before reaching any controller logic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Incoming Request&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
JwtToken concern → authenticate_request!&lt;br /&gt;
  → reads Authorization: Bearer &amp;lt;token&amp;gt; header&lt;br /&gt;
  → decodes token using RSA public key&lt;br /&gt;
  → sets @current_user via User.find(auth_token[:id])&lt;br /&gt;
  → halts with 401 if token missing, expired, or invalid&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Authorization concern → authorize&lt;br /&gt;
  → calls all_actions_allowed?&lt;br /&gt;
  → checks super-admin privileges OR action_allowed?&lt;br /&gt;
  → halts with 403 if not permitted&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller before_actions (e.g. find_and_authorize_map_for_create)&lt;br /&gt;
  → map-level ownership checks using current_user&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
Controller action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The critical insight here is that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; must be a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; — not a &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; — so that &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is always populated by the time ownership checks run. This was a central bug we fixed (see [[#Bugs We Fixed|Bugs We Fixed]]).&lt;br /&gt;
&lt;br /&gt;
=== Round-Aware Response Handling ===&lt;br /&gt;
&lt;br /&gt;
Expertiza supports multi-round assignment workflows. When a response is created, the controller scopes its lookup by both &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Response.where(map_id: @map.id, round: round)&lt;br /&gt;
        .order(:created_at)&lt;br /&gt;
        .last || Response.new(map_id: @map.id, round: round)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Bugs We Fixed ==&lt;br /&gt;
&lt;br /&gt;
During implementation and testing we encountered and resolved several non-trivial bugs. We document them here in detail because they reveal important architectural lessons about how Rails before-action ordering and RSpec let scoping interact.&lt;br /&gt;
&lt;br /&gt;
=== Bug 1: &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; Running Before Authentication ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Every POST to &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; returned 500 with &amp;lt;code&amp;gt;NoMethodError: undefined method 'id' for nil&amp;lt;/code&amp;gt;, even with a valid token.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; was declared with &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt;, which inserts it at the front of the callback chain — before &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; had a chance to set &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt;. The method then called &amp;lt;code&amp;gt;current_user.id&amp;lt;/code&amp;gt; on a nil object.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed the declaration to a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
prepend_before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
before_action :find_and_authorize_map_for_create, only: %i[create]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This ensures the callback chain runs in the correct order: authenticate → authorize → find and check map ownership.&lt;br /&gt;
&lt;br /&gt;
=== Bug 2: Stale RSA Key File Causing Silent 401 Failures ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests with valid tokens were returning 401 even after the before-action ordering was fixed. The error message was &amp;lt;code&amp;gt;Not Authorized&amp;lt;/code&amp;gt; with no further detail.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' &amp;lt;code&amp;gt;JsonWebToken&amp;lt;/code&amp;gt; loads RSA keys at class initialization time. If &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; exists on disk, those keys are used. If the file was written by a previous process with different keys, tokens encoded during the test run (using newly generated in-memory keys) would fail RSA signature verification during decoding.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Deleted the stale &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt; and added it to &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm rsa_keys.yml&lt;br /&gt;
echo &amp;quot;rsa_keys.yml&amp;quot; &amp;gt;&amp;gt; .gitignore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bug 3: RSpec &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; Scoping Causing Token/User Mismatch ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' Tests continued to return 401 even after the RSA key fix. &amp;lt;code&amp;gt;User.find(auth_token[:id])&amp;lt;/code&amp;gt; was finding the correct ID but authentication was still failing intermittently.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The responses spec declared the user with &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; (eager) while &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was lazy. Because &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; runs eagerly in its own evaluation context, the user object memoized inside the &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; block could differ from the one referenced when &amp;lt;code&amp;gt;let(:token)&amp;lt;/code&amp;gt; was later evaluated. This caused the encoded token to contain a user ID that did not match what was in the database for that example.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Changed &amp;lt;code&amp;gt;let!(:student)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;let(:student)&amp;lt;/code&amp;gt; and relied on the dependent &amp;lt;code&amp;gt;let!(:reviewer_participant)&amp;lt;/code&amp;gt; — which references &amp;lt;code&amp;gt;student.id&amp;lt;/code&amp;gt; — to force eager creation through the dependency chain:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Before (broken)&lt;br /&gt;
let!(:student) { User.create!(...) }&lt;br /&gt;
&lt;br /&gt;
# After (fixed)&lt;br /&gt;
let(:student) { User.create!(...) }   # lazy&lt;br /&gt;
let!(:reviewer_participant) do&lt;br /&gt;
  AssignmentParticipant.create!(user_id: student.id, ...)  # forces student creation&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This mirrors the exact pattern used in the passing &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Bug 4: Error Message Mismatch in 401 Test ===&lt;br /&gt;
&lt;br /&gt;
'''Symptom:''' The 401 unauthorized test was failing with &amp;lt;code&amp;gt;expected &amp;quot;Not Authorized&amp;quot; but got &amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Root cause:''' The controller's nil-user guard rendered &amp;lt;code&amp;gt;&amp;quot;Unauthorized&amp;quot;&amp;lt;/code&amp;gt; while the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; concern (which handles missing/invalid tokens) renders &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt;. The test expected the latter.&lt;br /&gt;
&lt;br /&gt;
'''Fix:''' Removed the redundant nil-user guard from &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; entirely. Since &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; now always runs first, &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; will never be nil by the time the map ownership check runs — unauthenticated requests are rejected at the &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; layer with the correct &amp;lt;code&amp;gt;&amp;quot;Not Authorized&amp;quot;&amp;lt;/code&amp;gt; message.&lt;br /&gt;
&lt;br /&gt;
== Test Coverage ==&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Key Scenarios Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/base_task_spec.rb&amp;lt;/code&amp;gt; || Default &amp;lt;code&amp;gt;complete?&amp;lt;/code&amp;gt; behavior, &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; delegation, interface contract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/review_task_spec.rb&amp;lt;/code&amp;gt; || Completion based on &amp;lt;code&amp;gt;is_submitted&amp;lt;/code&amp;gt;, incomplete when not submitted&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/quiz_task_spec.rb&amp;lt;/code&amp;gt; || Quiz-specific completion detection and eligibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_factory_spec.rb&amp;lt;/code&amp;gt; || Correct class returned for each map type, error on unknown type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/models/task_ordering/task_queue_spec.rb&amp;lt;/code&amp;gt; || Queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;next_incomplete_task&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Endpoints !! Response Codes Tested&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || list, view, queue, next_task, start_task || 200, 401, 404, 500&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;spec/requests/api/v1/responses_controller_spec.rb&amp;lt;/code&amp;gt; || POST /responses, GET /responses/:id, PATCH /responses/:id || 201, 200, 401, 403, 404&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec rspec \&lt;br /&gt;
  spec/requests/api/v1/student_tasks_controller_spec.rb \&lt;br /&gt;
  spec/requests/api/v1/responses_controller_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/base_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/review_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/quiz_task_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_factory_spec.rb \&lt;br /&gt;
  spec/models/task_ordering/task_queue_spec.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result: '''77 examples, 0 failures'''&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' [Link to be added]&lt;br /&gt;
&lt;br /&gt;
The demo will walk through:&lt;br /&gt;
* The task ordering system enforcing sequential task completion for quiz tasks&lt;br /&gt;
* Live API calls to the student tasks endpoints showing queue state and next task resolution&lt;br /&gt;
* Response creation flow including JWT authentication, map ownership verification, and task queue enforcement&lt;br /&gt;
* Full RSpec test suite run showing all 77 passing examples&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* Extend &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to support deadline-aware ordering — tasks past their due date could be automatically skipped or flagged&lt;br /&gt;
* Add per-question completion tracking for quiz responses, rather than treating a response as fully submitted or not&lt;br /&gt;
* Expose a participant-level quiz completion percentage endpoint for frontend progress indicators&lt;br /&gt;
* Expand &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; to support additional response map types as new assignment workflow stages are added to Expertiza&lt;br /&gt;
* Add admin endpoints to inspect or manually override a participant's queue state for debugging and support purposes&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Guides]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
&lt;br /&gt;
'''Members:'''&lt;br /&gt;
* Akhil Kumar&lt;br /&gt;
* Dev Patel&lt;br /&gt;
* Arnav Merjari&lt;br /&gt;
&lt;br /&gt;
'''Mentor:''' Dr. Ed Gehringer&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167629</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167629"/>
		<updated>2026-03-31T01:07:13Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Table of Contents ==&lt;br /&gt;
# [[#Background|Background]]&lt;br /&gt;
# [[#Project Overview|Project Overview]]&lt;br /&gt;
# [[#Implementation|Implementation]]&lt;br /&gt;
# [[#Testing|Testing]]&lt;br /&gt;
# [[#Demo Video|Demo Video]]&lt;br /&gt;
# [[#References|References]]&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza Expertiza] is an open-source, peer-review-based learning management system developed and maintained at '''North Carolina State University'''. It is used in courses across NCSU and other institutions to facilitate collaborative learning through structured peer review, team assignments, and iterative feedback cycles.&lt;br /&gt;
&lt;br /&gt;
The platform allows instructors to create assignments with multi-round review workflows, where students submit work, review their peers' submissions, and receive feedback. Expertiza is built on '''Ruby on Rails''' and has an active community of student contributors who extend and improve its functionality each semester as part of graduate coursework in CSC 517.&lt;br /&gt;
&lt;br /&gt;
The system manages complex entities including assignments, participants, response maps, and responses — all coordinated through a carefully structured authorization and task-ordering pipeline.&lt;br /&gt;
&lt;br /&gt;
== Project Overview ==&lt;br /&gt;
&lt;br /&gt;
This project is a reimplementation of key backend components of Expertiza as part of '''Program 3''' in CSC 517. The goal was to redesign and improve three interconnected areas of the system:&lt;br /&gt;
&lt;br /&gt;
* '''Task Ordering''' — enforcing that participants complete tasks in a defined sequence before proceeding to subsequent ones&lt;br /&gt;
* '''Student Task Management''' — providing students with a clear view of their current tasks, queue position, and next actionable item&lt;br /&gt;
* '''Response Creation &amp;amp; Authorization''' — ensuring that only authorized participants can create or modify responses tied to their assigned review maps&lt;br /&gt;
&lt;br /&gt;
The reimplementation emphasizes clean object-oriented design, proper separation of concerns, RESTful API conventions, and comprehensive test coverage using RSpec and Rswag.&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering ===&lt;br /&gt;
&lt;br /&gt;
A dedicated task ordering module was introduced under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; to encapsulate the logic for determining which tasks a participant is eligible to complete. Key classes include:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Defines the shared interface for all task types, including completion status and map membership checks&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Extends &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; to handle review-specific logic tied to &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Extends &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; to handle quiz participation tasks&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Implements the factory pattern to instantiate the correct task type based on the response map class&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrates the ordered sequence of tasks for a given participant and assignment, exposing &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This design replaces ad-hoc task eligibility checks that were previously scattered across controllers, centralizing the logic in a maintainable and testable module.&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks Controller ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; was implemented to give students visibility into their assignment workload. It exposes the following endpoints:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Path !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || Returns all tasks for the current user&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || Returns details for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || Returns the ordered task queue for an assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || Returns the next incomplete task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || Marks a task as started if queue order allows&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization is handled via JWT token authentication inherited from &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt;, with &amp;lt;code&amp;gt;action_allowed?&amp;lt;/code&amp;gt; overridden to enforce participant-level access control.&lt;br /&gt;
&lt;br /&gt;
=== Responses Controller ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; manages the creation and updating of peer review responses. Key design decisions include:&lt;br /&gt;
&lt;br /&gt;
* '''Authorization via &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;''' — &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; runs after &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; to ensure &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is available before map ownership is verified&lt;br /&gt;
* '''Task order enforcement''' — the &amp;lt;code&amp;gt;enforce_task_order!&amp;lt;/code&amp;gt; helper delegates to &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to confirm the participant is eligible to respond before allowing creation or update&lt;br /&gt;
* '''Round-aware response handling''' — responses are scoped by &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;, supporting multi-round review workflows&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Path !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || Create a new response for a review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || Retrieve a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PATCH&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || Update an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Authorization &amp;amp; JWT Authentication ===&lt;br /&gt;
&lt;br /&gt;
Authentication is handled via RSA-signed JWT tokens using the &amp;lt;code&amp;gt;JsonWebToken&amp;lt;/code&amp;gt; class. The &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; concern decodes the token from the &amp;lt;code&amp;gt;Authorization&amp;lt;/code&amp;gt; header on every request and sets &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;Authorization&amp;lt;/code&amp;gt; concern then runs &amp;lt;code&amp;gt;action_allowed?&amp;lt;/code&amp;gt; to determine whether the authenticated user is permitted to perform the requested action.&lt;br /&gt;
&lt;br /&gt;
A key architectural fix during this implementation was ensuring that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; uses a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; rather than &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt;, so that &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; always runs first and &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is reliably available before ownership checks occur.&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
&lt;br /&gt;
All components were tested using '''RSpec''' for unit and integration testing and '''Rswag''' for API-level request specs that simultaneously generate OpenAPI documentation.&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
Located under &amp;lt;code&amp;gt;spec/models/task_ordering/&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Spec File !! Coverage&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;base_task_spec.rb&amp;lt;/code&amp;gt; || Tests shared task interface and completion logic&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;review_task_spec.rb&amp;lt;/code&amp;gt; || Tests review-specific map membership and completion status&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;quiz_task_spec.rb&amp;lt;/code&amp;gt; || Tests quiz task eligibility and completion detection&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;task_factory_spec.rb&amp;lt;/code&amp;gt; || Tests correct task instantiation by response map type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;task_queue_spec.rb&amp;lt;/code&amp;gt; || Tests queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
Located under &amp;lt;code&amp;gt;spec/requests/api/v1/&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Spec File !! Scenarios Covered&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || 200 success, 401 unauthorized, 404 not found across all five endpoints&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;responses_controller_spec.rb&amp;lt;/code&amp;gt; || 201 created, 401 unauthorized, 403 forbidden, 404 not found for POST; 200, 401, 403 for GET and PATCH&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Notable Testing Challenges &amp;amp; Fixes ===&lt;br /&gt;
&lt;br /&gt;
During development, several non-trivial testing issues were encountered and resolved:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; ordering bug&lt;br /&gt;
: &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; was running before &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt;, causing &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; to always be &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; and returning 401 even for valid tokens. Fixed by switching to a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; Stale &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt;&lt;br /&gt;
: A pre-existing RSA key file caused JWT decode failures in tests because the keys used to encode tokens at spec time differed from those loaded at class initialization. Resolved by deleting the stale file and adding it to &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; vs &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; scoping in RSpec&lt;br /&gt;
: Eager &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; declarations for user records caused token encoding to reference a different object instance than the one persisted in the database, leading to &amp;lt;code&amp;gt;User.find&amp;lt;/code&amp;gt; failures during authentication. Fixed by using lazy &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; dependent that forces creation through the dependency chain, mirroring the pattern used in the passing &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
{{Video placeholder}}&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' [Link to be added]&lt;br /&gt;
&lt;br /&gt;
The demo will cover:&lt;br /&gt;
* A walkthrough of the task ordering system and how it enforces sequential task completion&lt;br /&gt;
* Live API calls demonstrating the student tasks endpoints&lt;br /&gt;
* Response creation and authorization flow including JWT authentication&lt;br /&gt;
* RSpec and Rswag test suite execution showing all passing examples&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Documentation]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | Contributors: Akhil Kumar et al. | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167628</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167628"/>
		<updated>2026-03-31T01:06:54Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Expertiza: Response &amp;amp; Task Ordering System =&lt;br /&gt;
&lt;br /&gt;
'''Course:''' CSC 517 — Object-Oriented Design and Development &amp;lt;br&amp;gt;&lt;br /&gt;
'''Institution:''' North Carolina State University &amp;lt;br&amp;gt;&lt;br /&gt;
'''Semester:''' Spring 2026 &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Table of Contents ==&lt;br /&gt;
# [[#Background|Background]]&lt;br /&gt;
# [[#Project Overview|Project Overview]]&lt;br /&gt;
# [[#Implementation|Implementation]]&lt;br /&gt;
# [[#Testing|Testing]]&lt;br /&gt;
# [[#Demo Video|Demo Video]]&lt;br /&gt;
# [[#References|References]]&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza Expertiza] is an open-source, peer-review-based learning management system developed and maintained at '''North Carolina State University'''. It is used in courses across NCSU and other institutions to facilitate collaborative learning through structured peer review, team assignments, and iterative feedback cycles.&lt;br /&gt;
&lt;br /&gt;
The platform allows instructors to create assignments with multi-round review workflows, where students submit work, review their peers' submissions, and receive feedback. Expertiza is built on '''Ruby on Rails''' and has an active community of student contributors who extend and improve its functionality each semester as part of graduate coursework in CSC 517.&lt;br /&gt;
&lt;br /&gt;
The system manages complex entities including assignments, participants, response maps, and responses — all coordinated through a carefully structured authorization and task-ordering pipeline.&lt;br /&gt;
&lt;br /&gt;
== Project Overview ==&lt;br /&gt;
&lt;br /&gt;
This project is a reimplementation of key backend components of Expertiza as part of '''Program 3''' in CSC 517. The goal was to redesign and improve three interconnected areas of the system:&lt;br /&gt;
&lt;br /&gt;
* '''Task Ordering''' — enforcing that participants complete tasks in a defined sequence before proceeding to subsequent ones&lt;br /&gt;
* '''Student Task Management''' — providing students with a clear view of their current tasks, queue position, and next actionable item&lt;br /&gt;
* '''Response Creation &amp;amp; Authorization''' — ensuring that only authorized participants can create or modify responses tied to their assigned review maps&lt;br /&gt;
&lt;br /&gt;
The reimplementation emphasizes clean object-oriented design, proper separation of concerns, RESTful API conventions, and comprehensive test coverage using RSpec and Rswag.&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering ===&lt;br /&gt;
&lt;br /&gt;
A dedicated task ordering module was introduced under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; to encapsulate the logic for determining which tasks a participant is eligible to complete. Key classes include:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Defines the shared interface for all task types, including completion status and map membership checks&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Extends &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; to handle review-specific logic tied to &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Extends &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; to handle quiz participation tasks&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Implements the factory pattern to instantiate the correct task type based on the response map class&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrates the ordered sequence of tasks for a given participant and assignment, exposing &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This design replaces ad-hoc task eligibility checks that were previously scattered across controllers, centralizing the logic in a maintainable and testable module.&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks Controller ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; was implemented to give students visibility into their assignment workload. It exposes the following endpoints:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Path !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || Returns all tasks for the current user&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || Returns details for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || Returns the ordered task queue for an assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || Returns the next incomplete task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || Marks a task as started if queue order allows&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization is handled via JWT token authentication inherited from &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt;, with &amp;lt;code&amp;gt;action_allowed?&amp;lt;/code&amp;gt; overridden to enforce participant-level access control.&lt;br /&gt;
&lt;br /&gt;
=== Responses Controller ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; manages the creation and updating of peer review responses. Key design decisions include:&lt;br /&gt;
&lt;br /&gt;
* '''Authorization via &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;''' — &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; runs after &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; to ensure &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is available before map ownership is verified&lt;br /&gt;
* '''Task order enforcement''' — the &amp;lt;code&amp;gt;enforce_task_order!&amp;lt;/code&amp;gt; helper delegates to &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to confirm the participant is eligible to respond before allowing creation or update&lt;br /&gt;
* '''Round-aware response handling''' — responses are scoped by &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;, supporting multi-round review workflows&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Path !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || Create a new response for a review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || Retrieve a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PATCH&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || Update an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Authorization &amp;amp; JWT Authentication ===&lt;br /&gt;
&lt;br /&gt;
Authentication is handled via RSA-signed JWT tokens using the &amp;lt;code&amp;gt;JsonWebToken&amp;lt;/code&amp;gt; class. The &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; concern decodes the token from the &amp;lt;code&amp;gt;Authorization&amp;lt;/code&amp;gt; header on every request and sets &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;Authorization&amp;lt;/code&amp;gt; concern then runs &amp;lt;code&amp;gt;action_allowed?&amp;lt;/code&amp;gt; to determine whether the authenticated user is permitted to perform the requested action.&lt;br /&gt;
&lt;br /&gt;
A key architectural fix during this implementation was ensuring that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; uses a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; rather than &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt;, so that &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; always runs first and &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is reliably available before ownership checks occur.&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
&lt;br /&gt;
All components were tested using '''RSpec''' for unit and integration testing and '''Rswag''' for API-level request specs that simultaneously generate OpenAPI documentation.&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
Located under &amp;lt;code&amp;gt;spec/models/task_ordering/&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Spec File !! Coverage&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;base_task_spec.rb&amp;lt;/code&amp;gt; || Tests shared task interface and completion logic&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;review_task_spec.rb&amp;lt;/code&amp;gt; || Tests review-specific map membership and completion status&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;quiz_task_spec.rb&amp;lt;/code&amp;gt; || Tests quiz task eligibility and completion detection&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;task_factory_spec.rb&amp;lt;/code&amp;gt; || Tests correct task instantiation by response map type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;task_queue_spec.rb&amp;lt;/code&amp;gt; || Tests queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
Located under &amp;lt;code&amp;gt;spec/requests/api/v1/&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Spec File !! Scenarios Covered&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || 200 success, 401 unauthorized, 404 not found across all five endpoints&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;responses_controller_spec.rb&amp;lt;/code&amp;gt; || 201 created, 401 unauthorized, 403 forbidden, 404 not found for POST; 200, 401, 403 for GET and PATCH&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Notable Testing Challenges &amp;amp; Fixes ===&lt;br /&gt;
&lt;br /&gt;
During development, several non-trivial testing issues were encountered and resolved:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; ordering bug&lt;br /&gt;
: &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; was running before &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt;, causing &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; to always be &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; and returning 401 even for valid tokens. Fixed by switching to a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; Stale &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt;&lt;br /&gt;
: A pre-existing RSA key file caused JWT decode failures in tests because the keys used to encode tokens at spec time differed from those loaded at class initialization. Resolved by deleting the stale file and adding it to &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; vs &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; scoping in RSpec&lt;br /&gt;
: Eager &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; declarations for user records caused token encoding to reference a different object instance than the one persisted in the database, leading to &amp;lt;code&amp;gt;User.find&amp;lt;/code&amp;gt; failures during authentication. Fixed by using lazy &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; dependent that forces creation through the dependency chain, mirroring the pattern used in the passing &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
{{Video placeholder}}&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' [Link to be added]&lt;br /&gt;
&lt;br /&gt;
The demo will cover:&lt;br /&gt;
* A walkthrough of the task ordering system and how it enforces sequential task completion&lt;br /&gt;
* Live API calls demonstrating the student tasks endpoints&lt;br /&gt;
* Response creation and authorization flow including JWT authentication&lt;br /&gt;
* RSpec and Rswag test suite execution showing all passing examples&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Documentation]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | Contributors: Akhil Kumar et al. | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167627</id>
		<title>CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=167627"/>
		<updated>2026-03-31T01:06:35Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: Created page with &amp;quot;= Expertiza: Response &amp;amp; Task Ordering System =  '''Course:''' CSC 517 — Object-Oriented Design and Development &amp;lt;br&amp;gt; '''Institution:''' North Carolina State University &amp;lt;br&amp;gt; '''Semester:''' Spring 2026 &amp;lt;br&amp;gt;  == Table of Contents == # Background # Project Overview # Implementation # Testing # Demo Video # References  == Background ==  [https://github.com/expertiza/expert...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Expertiza: Response &amp;amp; Task Ordering System =&lt;br /&gt;
&lt;br /&gt;
'''Course:''' CSC 517 — Object-Oriented Design and Development &amp;lt;br&amp;gt;&lt;br /&gt;
'''Institution:''' North Carolina State University &amp;lt;br&amp;gt;&lt;br /&gt;
'''Semester:''' Spring 2026 &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Table of Contents ==&lt;br /&gt;
# [[#Background|Background]]&lt;br /&gt;
# [[#Project Overview|Project Overview]]&lt;br /&gt;
# [[#Implementation|Implementation]]&lt;br /&gt;
# [[#Testing|Testing]]&lt;br /&gt;
# [[#Demo Video|Demo Video]]&lt;br /&gt;
# [[#References|References]]&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
[https://github.com/expertiza/expertiza Expertiza] is an open-source, peer-review-based learning management system developed and maintained at '''North Carolina State University'''. It is used in courses across NCSU and other institutions to facilitate collaborative learning through structured peer review, team assignments, and iterative feedback cycles.&lt;br /&gt;
&lt;br /&gt;
The platform allows instructors to create assignments with multi-round review workflows, where students submit work, review their peers' submissions, and receive feedback. Expertiza is built on '''Ruby on Rails''' and has an active community of student contributors who extend and improve its functionality each semester as part of graduate coursework in CSC 517.&lt;br /&gt;
&lt;br /&gt;
The system manages complex entities including assignments, participants, response maps, and responses — all coordinated through a carefully structured authorization and task-ordering pipeline.&lt;br /&gt;
&lt;br /&gt;
== Project Overview ==&lt;br /&gt;
&lt;br /&gt;
This project is a reimplementation of key backend components of Expertiza as part of '''Program 3''' in CSC 517. The goal was to redesign and improve three interconnected areas of the system:&lt;br /&gt;
&lt;br /&gt;
* '''Task Ordering''' — enforcing that participants complete tasks in a defined sequence before proceeding to subsequent ones&lt;br /&gt;
* '''Student Task Management''' — providing students with a clear view of their current tasks, queue position, and next actionable item&lt;br /&gt;
* '''Response Creation &amp;amp; Authorization''' — ensuring that only authorized participants can create or modify responses tied to their assigned review maps&lt;br /&gt;
&lt;br /&gt;
The reimplementation emphasizes clean object-oriented design, proper separation of concerns, RESTful API conventions, and comprehensive test coverage using RSpec and Rswag.&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== Task Ordering ===&lt;br /&gt;
&lt;br /&gt;
A dedicated task ordering module was introduced under &amp;lt;code&amp;gt;app/models/task_ordering/&amp;lt;/code&amp;gt; to encapsulate the logic for determining which tasks a participant is eligible to complete. Key classes include:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; || Defines the shared interface for all task types, including completion status and map membership checks&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; || Extends &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; to handle review-specific logic tied to &amp;lt;code&amp;gt;ReviewResponseMap&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; || Extends &amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; to handle quiz participation tasks&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; || Implements the factory pattern to instantiate the correct task type based on the response map class&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; || Orchestrates the ordered sequence of tasks for a given participant and assignment, exposing &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This design replaces ad-hoc task eligibility checks that were previously scattered across controllers, centralizing the logic in a maintainable and testable module.&lt;br /&gt;
&lt;br /&gt;
=== Student Tasks Controller ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; was implemented to give students visibility into their assignment workload. It exposes the following endpoints:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Path !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/list&amp;lt;/code&amp;gt; || Returns all tasks for the current user&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/view&amp;lt;/code&amp;gt; || Returns details for a specific participant task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/queue&amp;lt;/code&amp;gt; || Returns the ordered task queue for an assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/next_task&amp;lt;/code&amp;gt; || Returns the next incomplete task&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/student_tasks/start_task&amp;lt;/code&amp;gt; || Marks a task as started if queue order allows&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization is handled via JWT token authentication inherited from &amp;lt;code&amp;gt;ApplicationController&amp;lt;/code&amp;gt;, with &amp;lt;code&amp;gt;action_allowed?&amp;lt;/code&amp;gt; overridden to enforce participant-level access control.&lt;br /&gt;
&lt;br /&gt;
=== Responses Controller ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt; manages the creation and updating of peer review responses. Key design decisions include:&lt;br /&gt;
&lt;br /&gt;
* '''Authorization via &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;''' — &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; runs after &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; to ensure &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is available before map ownership is verified&lt;br /&gt;
* '''Task order enforcement''' — the &amp;lt;code&amp;gt;enforce_task_order!&amp;lt;/code&amp;gt; helper delegates to &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; to confirm the participant is eligible to respond before allowing creation or update&lt;br /&gt;
* '''Round-aware response handling''' — responses are scoped by &amp;lt;code&amp;gt;map_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;, supporting multi-round review workflows&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Path !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/responses&amp;lt;/code&amp;gt; || Create a new response for a review map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || Retrieve a specific response&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PATCH&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/responses/:id&amp;lt;/code&amp;gt; || Update an existing response&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Authorization &amp;amp; JWT Authentication ===&lt;br /&gt;
&lt;br /&gt;
Authentication is handled via RSA-signed JWT tokens using the &amp;lt;code&amp;gt;JsonWebToken&amp;lt;/code&amp;gt; class. The &amp;lt;code&amp;gt;JwtToken&amp;lt;/code&amp;gt; concern decodes the token from the &amp;lt;code&amp;gt;Authorization&amp;lt;/code&amp;gt; header on every request and sets &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;Authorization&amp;lt;/code&amp;gt; concern then runs &amp;lt;code&amp;gt;action_allowed?&amp;lt;/code&amp;gt; to determine whether the authenticated user is permitted to perform the requested action.&lt;br /&gt;
&lt;br /&gt;
A key architectural fix during this implementation was ensuring that &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; uses a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt; rather than &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt;, so that &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt; always runs first and &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; is reliably available before ownership checks occur.&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
&lt;br /&gt;
All components were tested using '''RSpec''' for unit and integration testing and '''Rswag''' for API-level request specs that simultaneously generate OpenAPI documentation.&lt;br /&gt;
&lt;br /&gt;
=== Model Specs ===&lt;br /&gt;
&lt;br /&gt;
Located under &amp;lt;code&amp;gt;spec/models/task_ordering/&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Spec File !! Coverage&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;base_task_spec.rb&amp;lt;/code&amp;gt; || Tests shared task interface and completion logic&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;review_task_spec.rb&amp;lt;/code&amp;gt; || Tests review-specific map membership and completion status&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;quiz_task_spec.rb&amp;lt;/code&amp;gt; || Tests quiz task eligibility and completion detection&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;task_factory_spec.rb&amp;lt;/code&amp;gt; || Tests correct task instantiation by response map type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;task_queue_spec.rb&amp;lt;/code&amp;gt; || Tests queue ordering, &amp;lt;code&amp;gt;map_in_queue?&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;prior_tasks_complete_for?&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Request Specs ===&lt;br /&gt;
&lt;br /&gt;
Located under &amp;lt;code&amp;gt;spec/requests/api/v1/&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Spec File !! Scenarios Covered&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt; || 200 success, 401 unauthorized, 404 not found across all five endpoints&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;responses_controller_spec.rb&amp;lt;/code&amp;gt; || 201 created, 401 unauthorized, 403 forbidden, 404 not found for POST; 200, 401, 403 for GET and PATCH&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Notable Testing Challenges &amp;amp; Fixes ===&lt;br /&gt;
&lt;br /&gt;
During development, several non-trivial testing issues were encountered and resolved:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;prepend_before_action&amp;lt;/code&amp;gt; ordering bug&lt;br /&gt;
: &amp;lt;code&amp;gt;find_and_authorize_map_for_create&amp;lt;/code&amp;gt; was running before &amp;lt;code&amp;gt;authenticate_request!&amp;lt;/code&amp;gt;, causing &amp;lt;code&amp;gt;current_user&amp;lt;/code&amp;gt; to always be &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; and returning 401 even for valid tokens. Fixed by switching to a standard &amp;lt;code&amp;gt;before_action&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; Stale &amp;lt;code&amp;gt;rsa_keys.yml&amp;lt;/code&amp;gt;&lt;br /&gt;
: A pre-existing RSA key file caused JWT decode failures in tests because the keys used to encode tokens at spec time differed from those loaded at class initialization. Resolved by deleting the stale file and adding it to &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; vs &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; scoping in RSpec&lt;br /&gt;
: Eager &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; declarations for user records caused token encoding to reference a different object instance than the one persisted in the database, leading to &amp;lt;code&amp;gt;User.find&amp;lt;/code&amp;gt; failures during authentication. Fixed by using lazy &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;let!&amp;lt;/code&amp;gt; dependent that forces creation through the dependency chain, mirroring the pattern used in the passing &amp;lt;code&amp;gt;student_tasks_controller_spec.rb&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
{{Video placeholder}}&lt;br /&gt;
&lt;br /&gt;
'''Demo Video:''' [Link to be added]&lt;br /&gt;
&lt;br /&gt;
The demo will cover:&lt;br /&gt;
* A walkthrough of the task ordering system and how it enforces sequential task completion&lt;br /&gt;
* Live API calls demonstrating the student tasks endpoints&lt;br /&gt;
* Response creation and authorization flow including JWT authentication&lt;br /&gt;
* RSpec and Rswag test suite execution showing all passing examples&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/expertiza/expertiza Expertiza GitHub Repository]&lt;br /&gt;
* [https://guides.rubyonrails.org Ruby on Rails Documentation]&lt;br /&gt;
* [https://rspec.info RSpec Documentation]&lt;br /&gt;
* [https://github.com/rswag/rswag Rswag GitHub Repository]&lt;br /&gt;
* [https://github.com/jwt/ruby-jwt JWT Ruby Gem]&lt;br /&gt;
* North Carolina State University, CSC 517 Course Page&lt;br /&gt;
* Fowler, M. (2018). ''Refactoring: Improving the Design of Existing Code'' (2nd ed.). Addison-Wesley.&lt;br /&gt;
* Metz, S. (2018). ''Practical Object-Oriented Design: An Agile Primer Using Ruby'' (2nd ed.). Addison-Wesley.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
''Last updated: March 2026 | Contributors: Akhil Kumar et al. | CSC 517, Spring 2026, NCSU''&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026&amp;diff=167626</id>
		<title>CSC/ECE 517 Spring 2026</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026&amp;diff=167626"/>
		<updated>2026-03-31T01:01:03Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2602. Reimplement student task view]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2604. Finish Password Resets]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2606. Finishing Import and Export helper module]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2607. ResponseController Frontend]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2610. Teams hierarchy testing]]&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026&amp;diff=167625</id>
		<title>CSC/ECE 517 Spring 2026</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026&amp;diff=167625"/>
		<updated>2026-03-31T01:00:46Z</updated>

		<summary type="html">&lt;p&gt;Avkumar2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;*  [CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2602. Reimplement student task view]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2604. Finish Password Resets]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2606. Finishing Import and Export helper module]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2607. ResponseController Frontend]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2610. Teams hierarchy testing]]&lt;/div&gt;</summary>
		<author><name>Avkumar2</name></author>
	</entry>
</feed>