<?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=Amejari</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=Amejari"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Amejari"/>
	<updated>2026-10-06T19:49:05Z</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=168180</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=168180"/>
		<updated>2026-04-29T02:33:46Z</updated>

		<summary type="html">&lt;p&gt;Amejari: &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 Changed ====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; namespace was removed from the application code. Its orchestration responsibilities now live on &amp;lt;code&amp;gt;StudentTask&amp;lt;/code&amp;gt; as shared class methods used by both &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; was replaced by &amp;lt;code&amp;gt;StudentTask::BaseTaskItem&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; were replaced by &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt;, implemented as model classes that inherit from &amp;lt;code&amp;gt;StudentTask::BaseTaskItem&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; were eliminated. Their former responsibilities are now handled by &amp;lt;code&amp;gt;StudentTask.build_tasks&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;StudentTask.find_task_for_map&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;StudentTask.prior_tasks_complete?&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;StudentTask.ensure_response_objects!&amp;lt;/code&amp;gt;.&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;StudentTask.resolve_context_for_assignment(user, assignment_id)&amp;lt;/code&amp;gt; || Finds the participant for the current user and assignment, then resolves the team participant and duty&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.resolve_context_for_participant(participant)&amp;lt;/code&amp;gt; || Builds the same task context starting from a known participant&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.build_tasks(context)&amp;lt;/code&amp;gt; || Builds the ordered quiz/review task list&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.ensure_response_objects!(tasks)&amp;lt;/code&amp;gt; || Ensures response maps and response records exist&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.find_task_for_map(tasks, map_id)&amp;lt;/code&amp;gt; || Finds the task associated with a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.prior_tasks_complete?(tasks, current_task)&amp;lt;/code&amp;gt; || Checks whether all earlier tasks are submitted&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 Changed ====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; endpoint is unaffected. The &amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PATCH&amp;lt;/code&amp;gt; endpoints now both call &amp;lt;code&amp;gt;enforce_task_order!&amp;lt;/code&amp;gt;, which reuses the shared &amp;lt;code&amp;gt;StudentTask&amp;lt;/code&amp;gt; task-building and prerequisite-checking methods.&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 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 shared &amp;lt;code&amp;gt;StudentTask&amp;lt;/code&amp;gt; class methods.&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;.&lt;br /&gt;
* Legacy &amp;lt;code&amp;gt;app/models/task_ordering&amp;lt;/code&amp;gt; source files have been removed.&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video for Old Implementation:''' https://youtu.be/Zg-fQmIUCSc&lt;br /&gt;
'''Demo Video for Refactor:''' https://youtu.be/fhK0roDhT7k&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 Mejari&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>Amejari</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=168179</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=168179"/>
		<updated>2026-04-29T02:29:17Z</updated>

		<summary type="html">&lt;p&gt;Amejari: /* Demo Video */&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 Changed ====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; namespace was removed from the application code. Its orchestration responsibilities now live on &amp;lt;code&amp;gt;StudentTask&amp;lt;/code&amp;gt; as shared class methods used by both &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; was replaced by &amp;lt;code&amp;gt;StudentTask::BaseTaskItem&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; were replaced by &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt;, implemented as model classes that inherit from &amp;lt;code&amp;gt;StudentTask::BaseTaskItem&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; were eliminated. Their former responsibilities are now handled by &amp;lt;code&amp;gt;StudentTask.build_tasks&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;StudentTask.find_task_for_map&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;StudentTask.prior_tasks_complete?&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;StudentTask.ensure_response_objects!&amp;lt;/code&amp;gt;.&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;StudentTask.resolve_context_for_assignment(user, assignment_id)&amp;lt;/code&amp;gt; || Finds the participant for the current user and assignment, then resolves the team participant and duty&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.resolve_context_for_participant(participant)&amp;lt;/code&amp;gt; || Builds the same task context starting from a known participant&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.build_tasks(context)&amp;lt;/code&amp;gt; || Builds the ordered quiz/review task list&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.ensure_response_objects!(tasks)&amp;lt;/code&amp;gt; || Ensures response maps and response records exist&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.find_task_for_map(tasks, map_id)&amp;lt;/code&amp;gt; || Finds the task associated with a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.prior_tasks_complete?(tasks, current_task)&amp;lt;/code&amp;gt; || Checks whether all earlier tasks are submitted&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 Changed ====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; endpoint is unaffected. The &amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PATCH&amp;lt;/code&amp;gt; endpoints now both call &amp;lt;code&amp;gt;enforce_task_order!&amp;lt;/code&amp;gt;, which reuses the shared &amp;lt;code&amp;gt;StudentTask&amp;lt;/code&amp;gt; task-building and prerequisite-checking methods.&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 shared &amp;lt;code&amp;gt;StudentTask&amp;lt;/code&amp;gt; class methods.&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;.&lt;br /&gt;
* Legacy &amp;lt;code&amp;gt;app/models/task_ordering&amp;lt;/code&amp;gt; source files have been removed.&lt;br /&gt;
&lt;br /&gt;
== Demo Video ==&lt;br /&gt;
&lt;br /&gt;
'''Demo Video for Old Implementation:''' https://youtu.be/Zg-fQmIUCSc&lt;br /&gt;
'''Demo Video for Refactor:''' https://youtu.be/fhK0roDhT7k&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 Mejari&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>Amejari</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2601._Reimplement_student_quizzes&amp;diff=168174</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=168174"/>
		<updated>2026-04-29T01:57:25Z</updated>

		<summary type="html">&lt;p&gt;Amejari: &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 Changed ====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;TaskOrdering&amp;lt;/code&amp;gt; namespace was removed from the application code. Its orchestration responsibilities now live on &amp;lt;code&amp;gt;StudentTask&amp;lt;/code&amp;gt; as shared class methods used by both &amp;lt;code&amp;gt;StudentTasksController&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ResponsesController&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;BaseTask&amp;lt;/code&amp;gt; was replaced by &amp;lt;code&amp;gt;StudentTask::BaseTaskItem&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;QuizTask&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTask&amp;lt;/code&amp;gt; were replaced by &amp;lt;code&amp;gt;QuizTaskItem&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ReviewTaskItem&amp;lt;/code&amp;gt;, implemented as model classes that inherit from &amp;lt;code&amp;gt;StudentTask::BaseTaskItem&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TaskFactory&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TaskQueue&amp;lt;/code&amp;gt; were eliminated. Their former responsibilities are now handled by &amp;lt;code&amp;gt;StudentTask.build_tasks&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;StudentTask.find_task_for_map&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;StudentTask.prior_tasks_complete?&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;StudentTask.ensure_response_objects!&amp;lt;/code&amp;gt;.&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;StudentTask.resolve_context_for_assignment(user, assignment_id)&amp;lt;/code&amp;gt; || Finds the participant for the current user and assignment, then resolves the team participant and duty&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.resolve_context_for_participant(participant)&amp;lt;/code&amp;gt; || Builds the same task context starting from a known participant&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.build_tasks(context)&amp;lt;/code&amp;gt; || Builds the ordered quiz/review task list&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.ensure_response_objects!(tasks)&amp;lt;/code&amp;gt; || Ensures response maps and response records exist&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.find_task_for_map(tasks, map_id)&amp;lt;/code&amp;gt; || Finds the task associated with a response map&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StudentTask.prior_tasks_complete?(tasks, current_task)&amp;lt;/code&amp;gt; || Checks whether all earlier tasks are submitted&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 Changed ====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; endpoint is unaffected. The &amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PATCH&amp;lt;/code&amp;gt; endpoints now both call &amp;lt;code&amp;gt;enforce_task_order!&amp;lt;/code&amp;gt;, which reuses the shared &amp;lt;code&amp;gt;StudentTask&amp;lt;/code&amp;gt; task-building and prerequisite-checking methods.&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 shared &amp;lt;code&amp;gt;StudentTask&amp;lt;/code&amp;gt; class methods.&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;.&lt;br /&gt;
* Legacy &amp;lt;code&amp;gt;app/models/task_ordering&amp;lt;/code&amp;gt; source files have been removed.&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 Mejari&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>Amejari</name></author>
	</entry>
</feed>