<?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=Psubram3</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=Psubram3"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Psubram3"/>
	<updated>2026-05-19T09:16:41Z</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_-_E2614._Role-based_reviewing&amp;diff=168176</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168176"/>
		<updated>2026-04-29T01:58:21Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Scoped Role Configuration====&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
====Complete Assignment-Duty API Lifecycle====&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
====Assignment Payload Role Context====&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
====Instructor Workflow in Assignment Editor====&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
====Role-Driven Rubric Behavior====&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
====Student Role Validation by Assignment Scope====&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
====Validation and Regression Coverage====&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
====Data Model Mismatch====&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
====Missing Assignment-Duty Lifecycle API====&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
====Disconnected Role Configuration and Rubric Rendering====&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
====Missing Role Data in Assignment Serializer====&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a consumer of role configuration, but it owns its own rubric variation settings. The &amp;lt;code&amp;gt;review_rubric_varies_by_role&amp;lt;/code&amp;gt; checkbox lives in the Rubrics tab alongside the existing round- and topic-variation checkboxes, because it controls rubric structure rather than role assignment. Role rows (&amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;) appear only when both &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; is enabled in Review Strategy and &amp;lt;code&amp;gt;review_rubric_varies_by_role&amp;lt;/code&amp;gt; is enabled in Rubrics, and at least one duty is assigned. This two-gate design means an instructor explicitly opts into role-specific rubric rows and does not get them as an automatic side-effect of enabling role-based mode.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|thumb|1000px|left|ER Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|left|1000px|Sequence Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls across two tabs: (1) Review Strategy tab owns role assignment — enabling role mode (&amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;), selecting duties from a dropdown, adding/removing duties (optimistically), inline duty creation via DutyEditor modal, and editing per-role member limits via an inline number input in the assigned roles table that fires &amp;lt;code&amp;gt;PATCH .../limit&amp;lt;/code&amp;gt; on blur; (2) Rubrics tab owns &amp;lt;code&amp;gt;review_rubric_varies_by_role&amp;lt;/code&amp;gt; checkbox alongside the existing round- and topic-variation checkboxes, and dynamically renders one teammate review row per assigned role when both that checkbox and role mode are active. Duplicate duty state declarations introduced by an upstream merge were removed; the entire role assignment flow was consolidated into a single consistent state path.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Added Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Added API integration method for duty updates and refreshes team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extended team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
====6) Optimistic add/remove for role assignment====&lt;br /&gt;
When an instructor adds or removes a duty from an assignment, the UI updates immediately without waiting for the API response. If the request fails, the change is rolled back and the previous state is restored. This keeps the editor responsive for operations that are expected to succeed in the common case.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles from the dropdown — they appear immediately in the table (optimistic update).&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, fill in the role name, then confirm.&lt;br /&gt;
# Edit the &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; value inline in the assigned roles table; click away to save.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;review_rubric_varies_by_role&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered for each assigned role.&lt;br /&gt;
# Uncheck &amp;lt;code&amp;gt;review_rubric_varies_by_role&amp;lt;/code&amp;gt; and verify role rows disappear.&lt;br /&gt;
# Return to Review Strategy, disable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;, and verify role controls are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168162</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168162"/>
		<updated>2026-04-28T16:26:22Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Previous Issues */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Scoped Role Configuration====&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
====Complete Assignment-Duty API Lifecycle====&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
====Assignment Payload Role Context====&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
====Instructor Workflow in Assignment Editor====&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
====Role-Driven Rubric Behavior====&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
====Student Role Validation by Assignment Scope====&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
====Validation and Regression Coverage====&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
====Data Model Mismatch====&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
====Missing Assignment-Duty Lifecycle API====&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
====Disconnected Role Configuration and Rubric Rendering====&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
====Missing Role Data in Assignment Serializer====&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|thumb|1000px|left|ER Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|left|1000px|Sequence Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168161</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168161"/>
		<updated>2026-04-28T16:25:54Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Scoped Role Configuration====&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
====Complete Assignment-Duty API Lifecycle====&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
====Assignment Payload Role Context====&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
====Instructor Workflow in Assignment Editor====&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
====Role-Driven Rubric Behavior====&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
====Student Role Validation by Assignment Scope====&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
====Validation and Regression Coverage====&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|thumb|1000px|left|ER Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|left|1000px|Sequence Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168157</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168157"/>
		<updated>2026-04-28T06:50:35Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Sequence Diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|thumb|1000px|left|ER Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|left|1000px|Sequence Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168156</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168156"/>
		<updated>2026-04-28T06:50:19Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Sequence Diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|thumb|1000px|left|ER Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|left|1500px|Sequence Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168155</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168155"/>
		<updated>2026-04-28T06:50:04Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* ER Diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|thumb|1000px|left|ER Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|left|500px|Sequence Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168154</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168154"/>
		<updated>2026-04-28T06:48:56Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* ER Diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|large|left|ER Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|left|500px|Sequence Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168153</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168153"/>
		<updated>2026-04-28T06:48:44Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* ER Diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|thumb|left|ER Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|left|500px|Sequence Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:2614_er.png&amp;diff=168152</id>
		<title>File:2614 er.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:2614_er.png&amp;diff=168152"/>
		<updated>2026-04-28T06:46:39Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: Psubram3 uploaded a new version of File:2614 er.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168151</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168151"/>
		<updated>2026-04-28T06:38:32Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* ER Diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|thumb|500px|left|ER Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|left|500px|Sequence Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168150</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168150"/>
		<updated>2026-04-28T06:38:13Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* ER Diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|thumb|500px|center|ER Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|left|500px|Sequence Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168149</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168149"/>
		<updated>2026-04-28T06:37:41Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Sequence Diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|thumb|500px|center|ER Diagram for Role-based reviewing]]&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|left|500px|Sequence Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168148</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168148"/>
		<updated>2026-04-28T06:37:15Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Sequence Diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|thumb|500px|center|ER Diagram for Role-based reviewing]]&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|left|500px|Sequence Diagram]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168147</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168147"/>
		<updated>2026-04-28T06:35:58Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Sequence Diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|thumb|500px|center|ER Diagram for Role-based reviewing]]&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|500px|Sequence Diagram]]&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168146</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168146"/>
		<updated>2026-04-28T06:35:03Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|thumb|500px|center|ER Diagram for Role-based reviewing]]&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
[[File:2614_seq.png|thumb|500px|center|ER Diagram for Role-based reviewing]]&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168145</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168145"/>
		<updated>2026-04-28T06:33:30Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* ER Diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
[[File:2614_er.png|alt=ER Diagram for Role-based reviewing|center|frame|ER Diagram]]&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sequenceDiagram&lt;br /&gt;
    participant UI as AssignmentEditor (Frontend)&lt;br /&gt;
    participant API as Rails API&lt;br /&gt;
    participant DB as MySQL&lt;br /&gt;
&lt;br /&gt;
    UI-&amp;gt;&amp;gt;API: GET /duties/accessible_duties&lt;br /&gt;
    API-&amp;gt;&amp;gt;DB: Fetch accessible duties&lt;br /&gt;
    DB--&amp;gt;&amp;gt;API: duties[]&lt;br /&gt;
    API--&amp;gt;&amp;gt;UI: duties[]&lt;br /&gt;
&lt;br /&gt;
    UI-&amp;gt;&amp;gt;API: POST /assignments/:id/duties {duty_id}&lt;br /&gt;
    API-&amp;gt;&amp;gt;DB: Upsert assignments_duties&lt;br /&gt;
    DB--&amp;gt;&amp;gt;API: mapping list&lt;br /&gt;
    API--&amp;gt;&amp;gt;UI: assignment_duties[]&lt;br /&gt;
&lt;br /&gt;
    UI-&amp;gt;&amp;gt;API: PATCH /assignments/:id/duties/:duty_id/limit {max_members_for_duty}&lt;br /&gt;
    API-&amp;gt;&amp;gt;DB: Update limit&lt;br /&gt;
    DB--&amp;gt;&amp;gt;API: updated mapping&lt;br /&gt;
    API--&amp;gt;&amp;gt;UI: updated mapping&lt;br /&gt;
&lt;br /&gt;
    UI-&amp;gt;&amp;gt;UI: Recompute Rubrics role rows&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:2614_seq.png&amp;diff=168144</id>
		<title>File:2614 seq.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:2614_seq.png&amp;diff=168144"/>
		<updated>2026-04-28T06:31:38Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:2614_er.png&amp;diff=168143</id>
		<title>File:2614 er.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:2614_er.png&amp;diff=168143"/>
		<updated>2026-04-28T06:30:53Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168142</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168142"/>
		<updated>2026-04-28T06:24:55Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* UI Test Flow */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
# Open Assignment Editor.&lt;br /&gt;
# Go to Review Strategy.&lt;br /&gt;
# Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Assign one or more existing roles.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
# Navigate to Rubrics.&lt;br /&gt;
# Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
# Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
erDiagram&lt;br /&gt;
    ASSIGNMENT ||--o{ ASSIGNMENTS_DUTY : configures&lt;br /&gt;
    DUTY ||--o{ ASSIGNMENTS_DUTY : assigned_as&lt;br /&gt;
    USER ||--o{ DUTY : creates&lt;br /&gt;
    ASSIGNMENT ||--o{ ASSIGNMENT_PARTICIPANT : has&lt;br /&gt;
    DUTY ||--o{ ASSIGNMENT_PARTICIPANT : selected_by&lt;br /&gt;
&lt;br /&gt;
    ASSIGNMENT {&lt;br /&gt;
        int id PK&lt;br /&gt;
        string name&lt;br /&gt;
        int instructor_id&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    DUTY {&lt;br /&gt;
        int id PK&lt;br /&gt;
        string name&lt;br /&gt;
        int instructor_id FK&lt;br /&gt;
        bool private&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ASSIGNMENTS_DUTY {&lt;br /&gt;
        int assignment_id FK&lt;br /&gt;
        int duty_id FK&lt;br /&gt;
        int max_members_for_duty&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ASSIGNMENT_PARTICIPANT {&lt;br /&gt;
        int id PK&lt;br /&gt;
        int parent_id FK&lt;br /&gt;
        int user_id FK&lt;br /&gt;
        int duty_id FK&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sequenceDiagram&lt;br /&gt;
    participant UI as AssignmentEditor (Frontend)&lt;br /&gt;
    participant API as Rails API&lt;br /&gt;
    participant DB as MySQL&lt;br /&gt;
&lt;br /&gt;
    UI-&amp;gt;&amp;gt;API: GET /duties/accessible_duties&lt;br /&gt;
    API-&amp;gt;&amp;gt;DB: Fetch accessible duties&lt;br /&gt;
    DB--&amp;gt;&amp;gt;API: duties[]&lt;br /&gt;
    API--&amp;gt;&amp;gt;UI: duties[]&lt;br /&gt;
&lt;br /&gt;
    UI-&amp;gt;&amp;gt;API: POST /assignments/:id/duties {duty_id}&lt;br /&gt;
    API-&amp;gt;&amp;gt;DB: Upsert assignments_duties&lt;br /&gt;
    DB--&amp;gt;&amp;gt;API: mapping list&lt;br /&gt;
    API--&amp;gt;&amp;gt;UI: assignment_duties[]&lt;br /&gt;
&lt;br /&gt;
    UI-&amp;gt;&amp;gt;API: PATCH /assignments/:id/duties/:duty_id/limit {max_members_for_duty}&lt;br /&gt;
    API-&amp;gt;&amp;gt;DB: Update limit&lt;br /&gt;
    DB--&amp;gt;&amp;gt;API: updated mapping&lt;br /&gt;
    API--&amp;gt;&amp;gt;UI: updated mapping&lt;br /&gt;
&lt;br /&gt;
    UI-&amp;gt;&amp;gt;UI: Recompute Rubrics role rows&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168141</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=168141"/>
		<updated>2026-04-28T06:22:32Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source learning and assessment platform built on [http://rubyonrails.org/ Ruby on Rails], designed around collaborative, project-based courses. Instructors use Expertiza to design assignments, define team structures, configure submission and review stages, and customize rubrics for different pedagogical goals. Students use the platform to form teams, submit artifacts, review peer work, and receive iterative feedback.&lt;br /&gt;
&lt;br /&gt;
One of Expertiza's core strengths is that it treats peer review as a configurable workflow rather than a one-size-fits-all form. In real classroom settings, however, student contributions are often role-specific (for example, frontend, backend, testing, documentation). A generic teammate review model does not always capture this nuance. This project addresses that gap by improving how Expertiza models and configures role-based reviewing at assignment level.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project reimplements role-based reviewing in the new Expertiza system, covering both the instructor-facing configuration workflow and the student-facing role declaration capability. The goal is to make role-aware peer review a first-class, reliable feature rather than a partially implemented concept spread across disconnected parts of the codebase.&lt;br /&gt;
&lt;br /&gt;
On the instructor side, the assignment editor is extended so that when role-based reviewing is enabled, an instructor can attach duty definitions to an assignment, set per-role member limits, create new duties inline, and see the Rubrics tab automatically reflect those choices through dynamically generated role-specific teammate review rows. On the student side, a team participant can declare their assigned duty within a team, with the backend enforcing that only duties the instructor has configured for that assignment are selectable.&lt;br /&gt;
&lt;br /&gt;
To support both workflows coherently, the implementation addresses three core problems: role limits must be stored at assignment-duty granularity rather than globally on the duty, the API must provide a complete and predictable assignment-duty lifecycle, and role configuration must live in one place so that rubric rendering is always driven by persisted state rather than ephemeral client-side logic.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
The reimplementation was shaped by the need to make role-based reviewing functional across data, API, and UI layers, covering both instructors configuring assignments and students participating in teams.&lt;br /&gt;
&lt;br /&gt;
===Assignment-Scoped Role Configuration===&lt;br /&gt;
A duty like &amp;quot;Frontend&amp;quot; carries different meaning across different assignments. In one assignment it may accommodate two team members; in another, only one. Storing role limits globally on the duty record makes it impossible to express this variation without workarounds. The requirement is therefore to model and persist role constraints at the assignment-duty level, not the duty level, so that each assignment's configuration is independent.&lt;br /&gt;
&lt;br /&gt;
===Complete Assignment-Duty API Lifecycle===&lt;br /&gt;
The frontend needs to be able to read which duties are assigned to an assignment, attach a new duty, remove a duty, and update the member limit for an assigned duty — without going through ad hoc endpoints or re-using endpoints built for other purposes. A coherent, RESTful assignment-duty API surface was required so that frontend actions map directly to backend operations.&lt;br /&gt;
&lt;br /&gt;
===Assignment Payload Role Context===&lt;br /&gt;
For the frontend to render role-aware rubric rows deterministically, the assignment serializer must include which duties are attached and what their limits are. Without this, the client would need separate API calls to reconstruct role context on every render — adding latency and creating cache-consistency risk.&lt;br /&gt;
&lt;br /&gt;
===Instructor Workflow in Assignment Editor===&lt;br /&gt;
Instructors should not need to navigate away to a separate roles management page to configure role-based reviewing for an assignment. The assignment editor itself must support enabling role-based mode, selecting from existing duties, creating new duties inline, setting per-role member limits, and removing duties — all from the Review Strategy tab.&lt;br /&gt;
&lt;br /&gt;
===Role-Driven Rubric Behavior===&lt;br /&gt;
When role-based mode is active and duties are assigned, the Rubrics tab should automatically surface per-role teammate review rows (one row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;). If role-based mode is disabled or no duties are assigned, these rows must not appear. The rubric must be a consumer of role configuration, not a place to manage it.&lt;br /&gt;
&lt;br /&gt;
===Student Role Validation by Assignment Scope===&lt;br /&gt;
When a team participant selects their role, the backend must verify that the chosen duty is actually assigned to that participant's assignment. This prevents a student from selecting a role that the instructor never configured, and it ensures that participant duty records remain consistent with the assignment's role setup.&lt;br /&gt;
&lt;br /&gt;
===Validation and Regression Coverage===&lt;br /&gt;
Backend request specs must cover successful operations, invalid input, unauthorized access, and cross-scope validation failures. Frontend tests must confirm that role-based controls and rubric rows appear and disappear correctly as assignment state changes, without breaking existing non-role-based rubric behavior.&lt;br /&gt;
&lt;br /&gt;
==Previous Issues==&lt;br /&gt;
Before this work, the role-based reviewing feature existed in fragments — data model fields, a duty management page, and some controller stubs — but the pieces did not form a working end-to-end workflow. The issues fell into four connected categories.&lt;br /&gt;
&lt;br /&gt;
===Data Model Mismatch===&lt;br /&gt;
The &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table stored a &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field directly on the duty record, treating role limits as global properties of the role itself. This is semantically wrong: how many &amp;quot;Frontend&amp;quot; developers an assignment needs is an assignment-level decision, not a fact about the Frontend role in general. As a consequence, the same duty could not carry different limits across different assignments without data duplication or workarounds. The &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; join table existed but did not carry the limit field, so the actual per-assignment constraint had nowhere clean to live.&lt;br /&gt;
&lt;br /&gt;
===Missing Assignment-Duty Lifecycle API===&lt;br /&gt;
The application had a &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; for managing duty records globally, but there was no scoped controller or endpoint set for managing which duties are attached to a specific assignment. The frontend had no clean path to add, remove, or update the limit for a duty in the context of one assignment. Any integration that existed relied on general-purpose endpoints being used in non-standard ways, making the contract fragile and hard to maintain.&lt;br /&gt;
&lt;br /&gt;
===Disconnected Role Configuration and Rubric Rendering===&lt;br /&gt;
Role setup and rubric behavior were not linked in any defined way. Whether a rubric row appeared for a given role depended on front-end state that was not reliably populated from the assignment payload. Role-related UI controls were scattered, and there was no clear rule about which tab owned role configuration and which tab consumed it. This made it easy for the UI to get into states where role controls were visible but non-functional, or rubric rows appeared when they should not.&lt;br /&gt;
&lt;br /&gt;
===Missing Role Data in Assignment Serializer===&lt;br /&gt;
The assignment serializer returned general assignment metadata but did not include which duties were assigned to the assignment or what their per-assignment limits were. This meant the frontend could not reconstruct role context from the standard assignment payload. Rendering role-aware rubric rows deterministically required either additional API calls or client-side state that could drift out of sync with the backend.&lt;br /&gt;
&lt;br /&gt;
==Design / Proposed Solution==&lt;br /&gt;
&lt;br /&gt;
===Data Model Design===&lt;br /&gt;
The central design decision is where role limits live. The existing &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table held a global &amp;lt;code&amp;gt;max_members&amp;lt;/code&amp;gt; field, which implied a role limit is a property of the role itself. This is incorrect — it is a property of how that role is used within a particular assignment. Two assignments can reuse the same &amp;quot;Frontend&amp;quot; duty and set different limits independently.&lt;br /&gt;
&lt;br /&gt;
The solution is to move the limit into the join table. &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; already models the relationship between assignments and duties; adding &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; to this table gives each assignment its own limit per duty without touching the duty record. The duty remains a reusable, shared definition; the assignment-duty mapping carries the assignment-specific constraint.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;assignment_participants&amp;lt;/code&amp;gt; table already had a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; foreign key column to record a student's declared role. The design retains this and enforces at the API level that any &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; written to a participant record must correspond to a duty that is actually mapped to that participant's assignment via &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;. This keeps the data consistent without adding extra columns or tables.&lt;br /&gt;
&lt;br /&gt;
===API Design===&lt;br /&gt;
The table below lists every new or modified API endpoint introduced by this project, including request parameters and response shape.&lt;br /&gt;
&lt;br /&gt;
====Assignment-Duty Management (&amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
These endpoints are nested under assignments and form the complete lifecycle for managing which roles exist for an assignment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ duty_id, duty_name, max_members_for_duty }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns all duty mappings currently attached to the assignment&lt;br /&gt;
|-&lt;br /&gt;
| POST&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Attaches an existing duty to the assignment; idempotent — repeated calls do not create duplicates&lt;br /&gt;
|-&lt;br /&gt;
| DELETE&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;204 No Content&amp;lt;/code&amp;gt;&lt;br /&gt;
| Removes the duty mapping; &amp;lt;code&amp;gt;:id&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt;; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if the duty is not mapped to this assignment&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/assignments/:assignment_id/duties/:id/limit&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ max_members_for_duty: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id, duty_name, max_members_for_duty }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the per-assignment role limit; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; if limit is less than 1; returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; if duty not mapped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authorization: all four endpoints require the authenticated user to be the instructor of the assignment. Requests from other roles return &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Participant Duty Update (&amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
This endpoint allows a student to declare their role within a team.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| PATCH&lt;br /&gt;
| &amp;lt;code&amp;gt;/teams/:team_id/participants/:id/duty&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ duty_id: integer }&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;{ id, user_id, duty_id, ... }&amp;lt;/code&amp;gt;&lt;br /&gt;
| Updates the participant's declared duty; validates that the selected duty is mapped to the participant's assignment; returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt; on invalid duty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Accessible Duties (&amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;)====&lt;br /&gt;
Used by the assignment editor to populate the role picker with duties the current user has access to.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 100%;&amp;quot;&lt;br /&gt;
! Method !! Endpoint !! Request Body !! Response !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| &amp;lt;code&amp;gt;/duties/accessible_duties&amp;lt;/code&amp;gt;&lt;br /&gt;
| —&lt;br /&gt;
| &amp;lt;code&amp;gt;[{ id, name }]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Returns duties created by the current instructor or marked as public&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Assignment Serializer Contract====&lt;br /&gt;
The assignment payload returned by &amp;lt;code&amp;gt;AssignmentsController#show&amp;lt;/code&amp;gt; is extended with role context so the frontend does not need additional calls to render role-aware Rubrics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Project 1&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;has_role_based_review&amp;quot;: true,&lt;br /&gt;
  &amp;quot;assignment_duties&amp;quot;: [&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 3, &amp;quot;duty_name&amp;quot;: &amp;quot;Frontend&amp;quot;, &amp;quot;max_members_for_duty&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;duty_id&amp;quot;: 5, &amp;quot;duty_name&amp;quot;: &amp;quot;Backend&amp;quot;,  &amp;quot;max_members_for_duty&amp;quot;: 1 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The frontend reads &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; to populate rubric rows and role controls. No separate fetch is needed after the assignment loads.&lt;br /&gt;
&lt;br /&gt;
===UI Design===&lt;br /&gt;
Role configuration is owned entirely by the Review Strategy tab. Enabling the &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt; toggle reveals the role management panel, where the instructor can select an existing duty from a dropdown, add it to the assignment, create a new duty inline if needed, set a per-role member limit, and remove duties. All of this is contained in one place without leaving the assignment editor.&lt;br /&gt;
&lt;br /&gt;
The Rubrics tab is a pure consumer of this configuration. It reads the list of assigned duties from the assignment state and generates one teammate review row per role, named &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt;. If role-based mode is off or no duties are assigned, no role rows appear. The Rubrics tab has no role management widgets of its own. This separation means an instructor cannot accidentally configure roles in two places, and rubric rows always reflect what was actually saved.&lt;br /&gt;
&lt;br /&gt;
===SOLID Principles Applied===&lt;br /&gt;
&lt;br /&gt;
====Single Responsibility====&lt;br /&gt;
Each class and controller has one clearly bounded job. &amp;lt;code&amp;gt;AssignmentsDutiesController&amp;lt;/code&amp;gt; handles only the assignment-duty mapping lifecycle — it does not touch the global duty definition or the assignment itself beyond looking it up. &amp;lt;code&amp;gt;TeamsParticipantsController&amp;lt;/code&amp;gt; handles participant operations and is extended only to validate and persist the duty selection. The &amp;lt;code&amp;gt;AssignmentSerializer&amp;lt;/code&amp;gt; is responsible for shaping the assignment payload; role data is added to it without mixing in any controller logic.&lt;br /&gt;
&lt;br /&gt;
====Open/Closed====&lt;br /&gt;
The system is extended without modifying stable, working code. The &amp;lt;code&amp;gt;AssignmentsController&amp;lt;/code&amp;gt; and its core CRUD behavior are untouched — role context is added through the serializer. New endpoints are introduced in a new, nested controller rather than by adding role-specific actions to the existing &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt;. The Rubrics component in the frontend is extended by reading new fields from the assignment payload, not by coupling it to role management state.&lt;br /&gt;
&lt;br /&gt;
====Liskov Substitution====&lt;br /&gt;
The &amp;lt;code&amp;gt;AssignmentsDuty&amp;lt;/code&amp;gt; model behaves as a standard ActiveRecord join model. It can be substituted anywhere an ActiveRecord object is expected without breaking callers. The validation and limit logic lives in the controller layer, keeping the model interface clean and predictable.&lt;br /&gt;
&lt;br /&gt;
====Interface Segregation====&lt;br /&gt;
The assignment-duty API surface is intentionally narrow and separate from the global duties API. Role management for an assignment is entirely self-contained under &amp;lt;code&amp;gt;/assignments/:id/duties&amp;lt;/code&amp;gt;. The global &amp;lt;code&amp;gt;DutiesController&amp;lt;/code&amp;gt; handles duty creation and listing; the assignment-specific controller handles only the mapping. Frontend components are not forced to consume a large combined interface — the role picker fetches accessible duties, and the assignment editor fetches assignment duties independently.&lt;br /&gt;
&lt;br /&gt;
====Dependency Inversion====&lt;br /&gt;
The Rubrics component does not depend on role management UI state or on specific duty records. It depends on the assignment data contract (specifically the &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array from the serializer). As long as that contract holds, Rubrics renders correctly regardless of how the underlying duties were created or which controller delivered them. This makes the rubric rendering logic testable in isolation and decoupled from the rest of the editor.&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
===Backend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/assignments_duties_controller.rb&amp;lt;/code&amp;gt; - New controller implementing the full assignment-duty lifecycle: index, create, destroy, and update_limit, with authorization checks and input validation on each action.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/controllers/teams_participants_controller.rb&amp;lt;/code&amp;gt; - Extended with an &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; action that validates the selected duty belongs to the participant's assignment before persisting the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/app/serializers/assignment_serializer.rb&amp;lt;/code&amp;gt; - Extended to include &amp;lt;code&amp;gt;has_role_based_review&amp;lt;/code&amp;gt; and a nested &amp;lt;code&amp;gt;assignment_duties&amp;lt;/code&amp;gt; array carrying each duty's id, name, and per-assignment member limit.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/config/routes.rb&amp;lt;/code&amp;gt; - Added nested resource routes for &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; under &amp;lt;code&amp;gt;assignments&amp;lt;/code&amp;gt;, including the custom &amp;lt;code&amp;gt;patch :limit&amp;lt;/code&amp;gt; member route, and the &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; route under team participants.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/db/schema.rb&amp;lt;/code&amp;gt; - Added &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; column to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; to store per-assignment role limits at the correct level of granularity.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs covering successful operations, invalid input (422), unauthorized access (403), and non-mapped duty lookups (404).&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Request specs for the participant duty update path, including cross-assignment validation and auth cases.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Student Teams/StudentTeamView.tsx&amp;lt;/code&amp;gt; - Add Role column and role selector for each team participant so students can declare or update their duty from assignment-scoped duties.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/hooks/useStudentTeam.ts&amp;lt;/code&amp;gt; - Add API integration method for duty updates and refresh team state after role change.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/types&amp;lt;/code&amp;gt; (or related team interfaces) - Extend team member payload typing to include role/duty metadata required by the student UI.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-back-end/spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt; - Expand request specs to cover student-facing UI-driven cases for valid duty updates, invalid assignment duty selection, and authorization edge cases.&lt;br /&gt;
&lt;br /&gt;
===Frontend files changed===&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; - Added role-based controls in Review Strategy for enabling role mode, attaching existing duties, inline duty creation, per-role limit updates, and syncing assignment duties state.&lt;br /&gt;
* &amp;lt;code&amp;gt;reimplementation-front-end/src/pages/Assignments/AssignmentEditor.test.tsx&amp;lt;/code&amp;gt; - Added behavior tests validating conditional role controls and dynamic rubric row rendering for role-based assignments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Key implementation decisions and their rationale===&lt;br /&gt;
&lt;br /&gt;
====1) Assignment-duty as the role-limit owner====&lt;br /&gt;
Role limits are stored at assignment-duty granularity. This supports real course usage where one role can have different limits across assignments.&lt;br /&gt;
&lt;br /&gt;
====2) Enforced relation validation on participant duty updates====&lt;br /&gt;
When a participant duty is updated, backend validation ensures the selected duty is assigned to that participant's assignment. This prevents invalid cross-assignment role references.&lt;br /&gt;
&lt;br /&gt;
====3) Inline role creation in assignment editor====&lt;br /&gt;
Instead of forcing instructors to navigate away to a separate role page, the UI supports creating a role in place. This reduces friction and keeps the assignment configuration flow uninterrupted.&lt;br /&gt;
&lt;br /&gt;
====4) Conditional role UI====&lt;br /&gt;
Role controls appear only when role-based mode is enabled. This keeps the UI minimal in non-role-based assignments and avoids accidental role operations.&lt;br /&gt;
&lt;br /&gt;
====5) Rubric rows generated from assignment role data====&lt;br /&gt;
Rubrics read from configured assignment duties and generate role-specific rows dynamically. This ensures rubric behavior reflects persisted configuration, not stale client-only state.&lt;br /&gt;
&lt;br /&gt;
==Testing Plan==&lt;br /&gt;
&lt;br /&gt;
===Backend testing===&lt;br /&gt;
Request specs cover functional and defensive cases:&lt;br /&gt;
* Assignment payload includes role metadata.&lt;br /&gt;
* Limit update success and persistence.&lt;br /&gt;
* Invalid limit returns &amp;lt;code&amp;gt;422&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Non-assigned duty update returns &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Unauthorized modification returns &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Primary files:&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/assignments_duties_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;spec/requests/api/v1/teams_participants_controller_spec.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Frontend testing===&lt;br /&gt;
Executed test command:&lt;br /&gt;
* &amp;lt;code&amp;gt;npm run test -- src/pages/Assignments/AssignmentEditor.test.tsx --run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behavior validated:&lt;br /&gt;
* Rubrics round-variation behavior remains correct.&lt;br /&gt;
* Role-specific teammate rows appear only when role-based mode is enabled and roles exist.&lt;br /&gt;
* Review Strategy role controls are visible only in role-based mode.&lt;br /&gt;
* Inline create-role entry flow visibility and control behavior are correct.&lt;br /&gt;
&lt;br /&gt;
==UI Test Flow==&lt;br /&gt;
Use the following instructor flow to validate behavior manually:&lt;br /&gt;
1. Open Assignment Editor.&lt;br /&gt;
2. Go to Review Strategy.&lt;br /&gt;
3. Enable &amp;lt;code&amp;gt;Is role based?&amp;lt;/code&amp;gt;.&lt;br /&gt;
4. Assign one or more existing roles.&lt;br /&gt;
5. Click &amp;lt;code&amp;gt;Create a new role&amp;lt;/code&amp;gt; if needed, add role name, then create it.&lt;br /&gt;
6. Set &amp;lt;code&amp;gt;Max members&amp;lt;/code&amp;gt; for assigned roles.&lt;br /&gt;
7. Navigate to Rubrics.&lt;br /&gt;
8. Confirm rows &amp;lt;code&amp;gt;Teammate Review for {RoleName}&amp;lt;/code&amp;gt; are rendered.&lt;br /&gt;
9. Disable role-based mode and verify role controls/rows are hidden.&lt;br /&gt;
&lt;br /&gt;
==ER Diagram==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
erDiagram&lt;br /&gt;
    ASSIGNMENT ||--o{ ASSIGNMENTS_DUTY : configures&lt;br /&gt;
    DUTY ||--o{ ASSIGNMENTS_DUTY : assigned_as&lt;br /&gt;
    USER ||--o{ DUTY : creates&lt;br /&gt;
    ASSIGNMENT ||--o{ ASSIGNMENT_PARTICIPANT : has&lt;br /&gt;
    DUTY ||--o{ ASSIGNMENT_PARTICIPANT : selected_by&lt;br /&gt;
&lt;br /&gt;
    ASSIGNMENT {&lt;br /&gt;
        int id PK&lt;br /&gt;
        string name&lt;br /&gt;
        int instructor_id&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    DUTY {&lt;br /&gt;
        int id PK&lt;br /&gt;
        string name&lt;br /&gt;
        int instructor_id FK&lt;br /&gt;
        bool private&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ASSIGNMENTS_DUTY {&lt;br /&gt;
        int assignment_id FK&lt;br /&gt;
        int duty_id FK&lt;br /&gt;
        int max_members_for_duty&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ASSIGNMENT_PARTICIPANT {&lt;br /&gt;
        int id PK&lt;br /&gt;
        int parent_id FK&lt;br /&gt;
        int user_id FK&lt;br /&gt;
        int duty_id FK&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sequence Diagram==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sequenceDiagram&lt;br /&gt;
    participant UI as AssignmentEditor (Frontend)&lt;br /&gt;
    participant API as Rails API&lt;br /&gt;
    participant DB as MySQL&lt;br /&gt;
&lt;br /&gt;
    UI-&amp;gt;&amp;gt;API: GET /duties/accessible_duties&lt;br /&gt;
    API-&amp;gt;&amp;gt;DB: Fetch accessible duties&lt;br /&gt;
    DB--&amp;gt;&amp;gt;API: duties[]&lt;br /&gt;
    API--&amp;gt;&amp;gt;UI: duties[]&lt;br /&gt;
&lt;br /&gt;
    UI-&amp;gt;&amp;gt;API: POST /assignments/:id/duties {duty_id}&lt;br /&gt;
    API-&amp;gt;&amp;gt;DB: Upsert assignments_duties&lt;br /&gt;
    DB--&amp;gt;&amp;gt;API: mapping list&lt;br /&gt;
    API--&amp;gt;&amp;gt;UI: assignment_duties[]&lt;br /&gt;
&lt;br /&gt;
    UI-&amp;gt;&amp;gt;API: PATCH /assignments/:id/duties/:duty_id/limit {max_members_for_duty}&lt;br /&gt;
    API-&amp;gt;&amp;gt;DB: Update limit&lt;br /&gt;
    DB--&amp;gt;&amp;gt;API: updated mapping&lt;br /&gt;
    API--&amp;gt;&amp;gt;UI: updated mapping&lt;br /&gt;
&lt;br /&gt;
    UI-&amp;gt;&amp;gt;UI: Recompute Rubrics role rows&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Future Work==&lt;br /&gt;
* Student-facing role selection UX in team pages.&lt;br /&gt;
* Team-level role-capacity enforcement UX feedback.&lt;br /&gt;
* Additional integrated end-to-end tests across instructor and student workflows.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* Fall 2016 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing&lt;br /&gt;
* Fall 2017 role-based reviewing: https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=167944</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=167944"/>
		<updated>2026-04-14T02:07:03Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Design Document: E2614. Role-based reviewing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 1. Project Overview ==&lt;br /&gt;
Expertiza currently supports assigning roles (duties) to an assignment (e.g., Frontend, Backend, Tester). These roles can be selected in the Review Strategy tab when creating or editing an assignment. However, the system does not yet fully integrate roles into the review process or student workflow. &lt;br /&gt;
&lt;br /&gt;
The goal of this project is to implement a complete role-based reviewing system in the Expertiza reimplementation, where:&lt;br /&gt;
* Instructors assign roles to an assignment and set limits on how many students can take each role.&lt;br /&gt;
* Students select their specific role within their team from the available options.&lt;br /&gt;
* Rubrics dynamically adapt based on the roles assigned to the team members.&lt;br /&gt;
* Reviews become role-specific, allowing for targeted feedback based on a student's contribution.&lt;br /&gt;
&lt;br /&gt;
== 2. Problem Statement ==&lt;br /&gt;
The current reimplementation has basic support for role-based flags but lacks the functional integration required for a complete workflow:&lt;br /&gt;
* '''UI Gaps:''' The Rubrics tab does not respond to the &amp;quot;Is role based?&amp;quot; setting. Students have no interface to select or view their roles within a team.&lt;br /&gt;
* '''Logic Gaps:''' There is no enforcement of role limits (e.g., only 1 &amp;quot;Tester&amp;quot; per team). Rubrics remain generic regardless of the role being reviewed.&lt;br /&gt;
* '''Schema Issues:''' The &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; field is incorrectly placed in the global &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table instead of the assignment-specific &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; table.&lt;br /&gt;
&lt;br /&gt;
== 3. Proposed Changes ==&lt;br /&gt;
&lt;br /&gt;
=== 3.1. Database Schema Updates ===&lt;br /&gt;
We need to ensure the schema supports assignment-specific role constraints.&lt;br /&gt;
* '''Migration 1:''' Move &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;.&lt;br /&gt;
** &amp;lt;code&amp;gt;remove_column :duties, :max_members_for_duty&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;add_column :assignments_duties, :max_members_for_duty, :integer, default: 1&amp;lt;/code&amp;gt;&lt;br /&gt;
* '''Association Verification:''' Ensure &amp;lt;code&amp;gt;Participant&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt;) has a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; column to store the selected role for that assignment.&lt;br /&gt;
&lt;br /&gt;
=== 3.2. Backend API Enhancements ===&lt;br /&gt;
* '''Assignments Controller:''' &lt;br /&gt;
** Update &amp;lt;code&amp;gt;show&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt; actions to include assigned duties (&amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;) and their constraints in the JSON response.&lt;br /&gt;
** Ensure the &amp;lt;code&amp;gt;update&amp;lt;/code&amp;gt; action correctly handles saving the &amp;lt;code&amp;gt;duty_based&amp;lt;/code&amp;gt; flag and the associated duties.&lt;br /&gt;
* '''Participants Controller:'''&lt;br /&gt;
** Add an action &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; to allow a student to select or change their role.&lt;br /&gt;
** Implement validation logic: Ensure the selected duty belongs to the assignment and the &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; limit for the team has not been reached.&lt;br /&gt;
* '''Questionnaires Controller:'''&lt;br /&gt;
** Expose an endpoint to fetch role-specific teammate review rubrics.&lt;br /&gt;
&lt;br /&gt;
=== 3.3. Instructor Interface (Frontend) ===&lt;br /&gt;
* '''Assignment Editor (Review Strategy Tab):'''&lt;br /&gt;
** Enhance the &amp;quot;Is role based?&amp;quot; section to allow instructors to not only select duties but also set the &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; for each duty in that specific assignment.&lt;br /&gt;
* '''Assignment Editor (Rubrics Tab):'''&lt;br /&gt;
** Implement conditional logic: If &amp;lt;code&amp;gt;duty_based&amp;lt;/code&amp;gt; is true, dynamically render rows for each assigned duty (e.g., &amp;quot;Teammate Review for Frontend&amp;quot;, &amp;quot;Teammate Review for Backend&amp;quot;).&lt;br /&gt;
** Allow the instructor to assign a different questionnaire to each role-based rubric row.&lt;br /&gt;
&lt;br /&gt;
=== 3.4. Student Interface (Frontend) ===&lt;br /&gt;
* '''''Your Team' Page:'''&lt;br /&gt;
** Add a &amp;quot;Role&amp;quot; column to the team members table.&lt;br /&gt;
** For the current user: Display a dropdown containing all roles assigned to the assignment. &lt;br /&gt;
** For teammates: Display their selected role as read-only text (or &amp;quot;Not Selected&amp;quot;).&lt;br /&gt;
** Implement an &amp;quot;Update Role&amp;quot; trigger that calls the backend API and updates the local state/UI upon success.&lt;br /&gt;
&lt;br /&gt;
=== 3.5. Serializer Updates ===&lt;br /&gt;
* '''ParticipantSerializer:'''&lt;br /&gt;
** Include &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;duty_name&amp;lt;/code&amp;gt; in the JSON response so the frontend can display role information.&lt;br /&gt;
** Example: &amp;lt;code&amp;gt;{ id: 5, user: {...}, duty_id: 2, duty_name: &amp;quot;Frontend&amp;quot;, authorization: &amp;quot;student&amp;quot; }&amp;lt;/code&amp;gt;&lt;br /&gt;
* '''AssignmentSerializer:'''&lt;br /&gt;
** Expose the &amp;lt;code&amp;gt;is_role_based&amp;lt;/code&amp;gt; flag so the frontend knows when to show role-related UI.&lt;br /&gt;
** Include the list of assigned duties with their &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; limits.&lt;br /&gt;
** Example: &amp;lt;code&amp;gt;{ id: 1, name: &amp;quot;Assignment 1&amp;quot;, is_role_based: true, duties: [{id: 1, name: &amp;quot;Frontend&amp;quot;, max_members_for_duty: 2}, ...] }&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Design Principles ==&lt;br /&gt;
* '''Consistency:''' Use the same expandable table and modal patterns established in the E2608 hierarchy task.&lt;br /&gt;
* '''Single Responsibility:''' Keep role-selection logic within the &amp;lt;code&amp;gt;Participant&amp;lt;/code&amp;gt; context and rubric-generation logic within the &amp;lt;code&amp;gt;Assignment&amp;lt;/code&amp;gt; context.&lt;br /&gt;
* '''DRY (Don't Repeat Yourself):''' Reuse the existing &amp;lt;code&amp;gt;Table&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Form&amp;lt;/code&amp;gt; components for the new UI elements.&lt;br /&gt;
&lt;br /&gt;
== 5. Testing Plan ==&lt;br /&gt;
&lt;br /&gt;
=== 5.1. Unit &amp;amp; Functional Tests (Backend) ===&lt;br /&gt;
* '''RSpec:'''&lt;br /&gt;
** Verify &amp;lt;code&amp;gt;AssignmentDuty&amp;lt;/code&amp;gt; correctly stores and retrieves &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Test that &amp;lt;code&amp;gt;Participant#update_duty&amp;lt;/code&amp;gt; fails if the role limit is exceeded for the team.&lt;br /&gt;
** Verify API responses contain the necessary nested role data.&lt;br /&gt;
&lt;br /&gt;
=== 5.2. Integration &amp;amp; UI Tests (Frontend) ===&lt;br /&gt;
* '''Instructor Flow:''' &lt;br /&gt;
** Create an assignment, enable &amp;quot;Is role based&amp;quot;, add 2 duties, and verify 2 extra rubric rows appear in the Rubrics tab.&lt;br /&gt;
* '''Student Flow:'''&lt;br /&gt;
** Join a team, navigate to &amp;quot;Your Team&amp;quot;, select a role from the dropdown, refresh the page, and verify the role persists.&lt;br /&gt;
** Attempt to select a role that has already reached its &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; limit (if applicable) and verify the error handling.&lt;br /&gt;
&lt;br /&gt;
== 6. Relevant Links ==&lt;br /&gt;
* '''Historical Reference (Fall 2016):''' [https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing CSC/ECE_517_Fall_2016_E1676]&lt;br /&gt;
* '''Historical Reference (Fall 2017):''' [https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing CSC/ECE_517_Fall_2017/E1798]&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=167943</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=167943"/>
		<updated>2026-04-14T02:05:04Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Design Document: E2614. Role-based reviewing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Design Document: E2614. Role-based reviewing =&lt;br /&gt;
&lt;br /&gt;
== 1. Project Overview ==&lt;br /&gt;
Expertiza currently supports assigning roles (duties) to an assignment (e.g., Frontend, Backend, Tester). These roles can be selected in the Review Strategy tab when creating or editing an assignment. However, the system does not yet fully integrate roles into the review process or student workflow. &lt;br /&gt;
&lt;br /&gt;
The goal of this project is to implement a complete role-based reviewing system in the Expertiza reimplementation, where:&lt;br /&gt;
* Instructors assign roles to an assignment and set limits on how many students can take each role.&lt;br /&gt;
* Students select their specific role within their team from the available options.&lt;br /&gt;
* Rubrics dynamically adapt based on the roles assigned to the team members.&lt;br /&gt;
* Reviews become role-specific, allowing for targeted feedback based on a student's contribution.&lt;br /&gt;
&lt;br /&gt;
== 2. Problem Statement ==&lt;br /&gt;
The current reimplementation has basic support for role-based flags but lacks the functional integration required for a complete workflow:&lt;br /&gt;
* '''UI Gaps:''' The Rubrics tab does not respond to the &amp;quot;Is role based?&amp;quot; setting. Students have no interface to select or view their roles within a team.&lt;br /&gt;
* '''Logic Gaps:''' There is no enforcement of role limits (e.g., only 1 &amp;quot;Tester&amp;quot; per team). Rubrics remain generic regardless of the role being reviewed.&lt;br /&gt;
* '''Schema Issues:''' The &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; field is incorrectly placed in the global &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table instead of the assignment-specific &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; table.&lt;br /&gt;
&lt;br /&gt;
== 3. Proposed Changes ==&lt;br /&gt;
&lt;br /&gt;
=== 3.1. Database Schema Updates ===&lt;br /&gt;
We need to ensure the schema supports assignment-specific role constraints.&lt;br /&gt;
* '''Migration 1:''' Move &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;.&lt;br /&gt;
** &amp;lt;code&amp;gt;remove_column :duties, :max_members_for_duty&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;add_column :assignments_duties, :max_members_for_duty, :integer, default: 1&amp;lt;/code&amp;gt;&lt;br /&gt;
* '''Association Verification:''' Ensure &amp;lt;code&amp;gt;Participant&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt;) has a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; column to store the selected role for that assignment.&lt;br /&gt;
&lt;br /&gt;
=== 3.2. Backend API Enhancements ===&lt;br /&gt;
* '''Assignments Controller:''' &lt;br /&gt;
** Update &amp;lt;code&amp;gt;show&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt; actions to include assigned duties (&amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;) and their constraints in the JSON response.&lt;br /&gt;
** Ensure the &amp;lt;code&amp;gt;update&amp;lt;/code&amp;gt; action correctly handles saving the &amp;lt;code&amp;gt;duty_based&amp;lt;/code&amp;gt; flag and the associated duties.&lt;br /&gt;
* '''Participants Controller:'''&lt;br /&gt;
** Add an action &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; to allow a student to select or change their role.&lt;br /&gt;
** Implement validation logic: Ensure the selected duty belongs to the assignment and the &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; limit for the team has not been reached.&lt;br /&gt;
* '''Questionnaires Controller:'''&lt;br /&gt;
** Expose an endpoint to fetch role-specific teammate review rubrics.&lt;br /&gt;
&lt;br /&gt;
=== 3.3. Instructor Interface (Frontend) ===&lt;br /&gt;
* '''Assignment Editor (Review Strategy Tab):'''&lt;br /&gt;
** Enhance the &amp;quot;Is role based?&amp;quot; section to allow instructors to not only select duties but also set the &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; for each duty in that specific assignment.&lt;br /&gt;
* '''Assignment Editor (Rubrics Tab):'''&lt;br /&gt;
** Implement conditional logic: If &amp;lt;code&amp;gt;duty_based&amp;lt;/code&amp;gt; is true, dynamically render rows for each assigned duty (e.g., &amp;quot;Teammate Review for Frontend&amp;quot;, &amp;quot;Teammate Review for Backend&amp;quot;).&lt;br /&gt;
** Allow the instructor to assign a different questionnaire to each role-based rubric row.&lt;br /&gt;
&lt;br /&gt;
=== 3.4. Student Interface (Frontend) ===&lt;br /&gt;
* '''''Your Team' Page:'''&lt;br /&gt;
** Add a &amp;quot;Role&amp;quot; column to the team members table.&lt;br /&gt;
** For the current user: Display a dropdown containing all roles assigned to the assignment. &lt;br /&gt;
** For teammates: Display their selected role as read-only text (or &amp;quot;Not Selected&amp;quot;).&lt;br /&gt;
** Implement an &amp;quot;Update Role&amp;quot; trigger that calls the backend API and updates the local state/UI upon success.&lt;br /&gt;
&lt;br /&gt;
=== 3.5. Serializer Updates ===&lt;br /&gt;
* '''ParticipantSerializer:'''&lt;br /&gt;
** Include &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;duty_name&amp;lt;/code&amp;gt; in the JSON response so the frontend can display role information.&lt;br /&gt;
** Example: &amp;lt;code&amp;gt;{ id: 5, user: {...}, duty_id: 2, duty_name: &amp;quot;Frontend&amp;quot;, authorization: &amp;quot;student&amp;quot; }&amp;lt;/code&amp;gt;&lt;br /&gt;
* '''AssignmentSerializer:'''&lt;br /&gt;
** Expose the &amp;lt;code&amp;gt;is_role_based&amp;lt;/code&amp;gt; flag so the frontend knows when to show role-related UI.&lt;br /&gt;
** Include the list of assigned duties with their &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; limits.&lt;br /&gt;
** Example: &amp;lt;code&amp;gt;{ id: 1, name: &amp;quot;Assignment 1&amp;quot;, is_role_based: true, duties: [{id: 1, name: &amp;quot;Frontend&amp;quot;, max_members_for_duty: 2}, ...] }&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3.6. API Endpoint Specifications ===&lt;br /&gt;
* '''GET /assignments/:id'''&lt;br /&gt;
** Response: Must include &amp;lt;code&amp;gt;is_role_based&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; array with &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; values.&lt;br /&gt;
* '''POST /participants/:id/duty'''&lt;br /&gt;
** Request: &amp;lt;code&amp;gt;{ duty_id: 2 }&amp;lt;/code&amp;gt;&lt;br /&gt;
** Response: Updated participant with &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;duty_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Validation: Return 422 if duty limit exceeded or duty not assigned to assignment.&lt;br /&gt;
* '''GET /participants/:id'''&lt;br /&gt;
** Response: Must include &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;duty_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 4. Design Principles ==&lt;br /&gt;
* '''Consistency:''' Use the same expandable table and modal patterns established in the E2608 hierarchy task.&lt;br /&gt;
* '''Single Responsibility:''' Keep role-selection logic within the &amp;lt;code&amp;gt;Participant&amp;lt;/code&amp;gt; context and rubric-generation logic within the &amp;lt;code&amp;gt;Assignment&amp;lt;/code&amp;gt; context.&lt;br /&gt;
* '''DRY (Don't Repeat Yourself):''' Reuse the existing &amp;lt;code&amp;gt;Table&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Form&amp;lt;/code&amp;gt; components for the new UI elements.&lt;br /&gt;
&lt;br /&gt;
== 5. Testing Plan ==&lt;br /&gt;
&lt;br /&gt;
=== 5.1. Unit &amp;amp; Functional Tests (Backend) ===&lt;br /&gt;
* '''RSpec:'''&lt;br /&gt;
** Verify &amp;lt;code&amp;gt;AssignmentDuty&amp;lt;/code&amp;gt; correctly stores and retrieves &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Test that &amp;lt;code&amp;gt;Participant#update_duty&amp;lt;/code&amp;gt; fails if the role limit is exceeded for the team.&lt;br /&gt;
** Verify API responses contain the necessary nested role data.&lt;br /&gt;
&lt;br /&gt;
=== 5.2. Integration &amp;amp; UI Tests (Frontend) ===&lt;br /&gt;
* '''Instructor Flow:''' &lt;br /&gt;
** Create an assignment, enable &amp;quot;Is role based&amp;quot;, add 2 duties, and verify 2 extra rubric rows appear in the Rubrics tab.&lt;br /&gt;
* '''Student Flow:'''&lt;br /&gt;
** Join a team, navigate to &amp;quot;Your Team&amp;quot;, select a role from the dropdown, refresh the page, and verify the role persists.&lt;br /&gt;
** Attempt to select a role that has already reached its &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; limit (if applicable) and verify the error handling.&lt;br /&gt;
&lt;br /&gt;
== 6. Relevant Links ==&lt;br /&gt;
* '''Historical Reference (Fall 2016):''' [https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing CSC/ECE_517_Fall_2016_E1676]&lt;br /&gt;
* '''Historical Reference (Fall 2017):''' [https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing CSC/ECE_517_Fall_2017/E1798]&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=167941</id>
		<title>CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2614._Role-based_reviewing&amp;diff=167941"/>
		<updated>2026-04-14T01:58:15Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: Created page with &amp;quot;= Design Document: E2614. Role-based reviewing =  == 1. Project Overview == Expertiza currently supports assigning roles (duties) to an assignment (e.g., Frontend, Backend, Tester). These roles can be selected in the Review Strategy tab when creating or editing an assignment. However, the system does not yet fully integrate roles into the review process or student workflow.   The goal of this project is to implement a complete role-based reviewing system in the Expertiza...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Design Document: E2614. Role-based reviewing =&lt;br /&gt;
&lt;br /&gt;
== 1. Project Overview ==&lt;br /&gt;
Expertiza currently supports assigning roles (duties) to an assignment (e.g., Frontend, Backend, Tester). These roles can be selected in the Review Strategy tab when creating or editing an assignment. However, the system does not yet fully integrate roles into the review process or student workflow. &lt;br /&gt;
&lt;br /&gt;
The goal of this project is to implement a complete role-based reviewing system in the Expertiza reimplementation, where:&lt;br /&gt;
* Instructors assign roles to an assignment and set limits on how many students can take each role.&lt;br /&gt;
* Students select their specific role within their team from the available options.&lt;br /&gt;
* Rubrics dynamically adapt based on the roles assigned to the team members.&lt;br /&gt;
* Reviews become role-specific, allowing for targeted feedback based on a student's contribution.&lt;br /&gt;
&lt;br /&gt;
== 2. Problem Statement ==&lt;br /&gt;
The current reimplementation has basic support for role-based flags but lacks the functional integration required for a complete workflow:&lt;br /&gt;
* '''UI Gaps:''' The Rubrics tab does not respond to the &amp;quot;Is role based?&amp;quot; setting. Students have no interface to select or view their roles within a team.&lt;br /&gt;
* '''Logic Gaps:''' There is no enforcement of role limits (e.g., only 1 &amp;quot;Tester&amp;quot; per team). Rubrics remain generic regardless of the role being reviewed.&lt;br /&gt;
* '''Schema Issues:''' The &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; field is incorrectly placed in the global &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; table instead of the assignment-specific &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt; table.&lt;br /&gt;
&lt;br /&gt;
== 3. Proposed Changes ==&lt;br /&gt;
&lt;br /&gt;
=== 3.1. Database Schema Updates ===&lt;br /&gt;
We need to ensure the schema supports assignment-specific role constraints.&lt;br /&gt;
* '''Migration 1:''' Move &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;.&lt;br /&gt;
** &amp;lt;code&amp;gt;remove_column :duties, :max_members_for_duty&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;add_column :assignments_duties, :max_members_for_duty, :integer, default: 1&amp;lt;/code&amp;gt;&lt;br /&gt;
* '''Association Verification:''' Ensure &amp;lt;code&amp;gt;Participant&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;AssignmentParticipant&amp;lt;/code&amp;gt;) has a &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; column to store the selected role for that assignment.&lt;br /&gt;
&lt;br /&gt;
=== 3.2. Backend API Enhancements ===&lt;br /&gt;
* '''Assignments Controller:''' &lt;br /&gt;
** Update &amp;lt;code&amp;gt;show&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt; actions to include assigned duties (&amp;lt;code&amp;gt;assignments_duties&amp;lt;/code&amp;gt;) and their constraints in the JSON response.&lt;br /&gt;
** Ensure the &amp;lt;code&amp;gt;update&amp;lt;/code&amp;gt; action correctly handles saving the &amp;lt;code&amp;gt;duty_based&amp;lt;/code&amp;gt; flag and the associated duties.&lt;br /&gt;
* '''Participants Controller:'''&lt;br /&gt;
** Add an action &amp;lt;code&amp;gt;update_duty&amp;lt;/code&amp;gt; to allow a student to select or change their role.&lt;br /&gt;
** Implement validation logic: Ensure the selected duty belongs to the assignment and the &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; limit for the team has not been reached.&lt;br /&gt;
* '''Questionnaires Controller:'''&lt;br /&gt;
** Expose an endpoint to fetch role-specific teammate review rubrics.&lt;br /&gt;
&lt;br /&gt;
=== 3.3. Instructor Interface (Frontend) ===&lt;br /&gt;
* '''Assignment Editor (Review Strategy Tab):'''&lt;br /&gt;
** Enhance the &amp;quot;Is role based?&amp;quot; section to allow instructors to not only select duties but also set the &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; for each duty in that specific assignment.&lt;br /&gt;
* '''Assignment Editor (Rubrics Tab):'''&lt;br /&gt;
** Implement conditional logic: If &amp;lt;code&amp;gt;duty_based&amp;lt;/code&amp;gt; is true, dynamically render rows for each assigned duty (e.g., &amp;quot;Teammate Review for Frontend&amp;quot;, &amp;quot;Teammate Review for Backend&amp;quot;).&lt;br /&gt;
** Allow the instructor to assign a different questionnaire to each role-based rubric row.&lt;br /&gt;
&lt;br /&gt;
=== 3.4. Student Interface (Frontend) ===&lt;br /&gt;
* '''''Your Team' Page:'''&lt;br /&gt;
** Add a &amp;quot;Role&amp;quot; column to the team members table.&lt;br /&gt;
** For the current user: Display a dropdown containing all roles assigned to the assignment. &lt;br /&gt;
** For teammates: Display their selected role as read-only text (or &amp;quot;Not Selected&amp;quot;).&lt;br /&gt;
** Implement an &amp;quot;Update Role&amp;quot; trigger that calls the backend API and updates the local state/UI upon success.&lt;br /&gt;
&lt;br /&gt;
=== 3.5. Serializer Updates ===&lt;br /&gt;
* '''ParticipantSerializer:'''&lt;br /&gt;
** Include &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;duty_name&amp;lt;/code&amp;gt; in the JSON response so the frontend can display role information.&lt;br /&gt;
** Example: &amp;lt;code&amp;gt;{ id: 5, user: {...}, duty_id: 2, duty_name: &amp;quot;Frontend&amp;quot;, authorization: &amp;quot;student&amp;quot; }&amp;lt;/code&amp;gt;&lt;br /&gt;
* '''AssignmentSerializer:'''&lt;br /&gt;
** Expose the &amp;lt;code&amp;gt;is_role_based&amp;lt;/code&amp;gt; flag so the frontend knows when to show role-related UI.&lt;br /&gt;
** Include the list of assigned duties with their &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; limits.&lt;br /&gt;
** Example: &amp;lt;code&amp;gt;{ id: 1, name: &amp;quot;Assignment 1&amp;quot;, is_role_based: true, duties: [{id: 1, name: &amp;quot;Frontend&amp;quot;, max_members_for_duty: 2}, ...] }&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3.6. API Endpoint Specifications ===&lt;br /&gt;
* '''GET /assignments/:id'''&lt;br /&gt;
** Response: Must include &amp;lt;code&amp;gt;is_role_based&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;duties&amp;lt;/code&amp;gt; array with &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; values.&lt;br /&gt;
* '''POST /participants/:id/duty'''&lt;br /&gt;
** Request: &amp;lt;code&amp;gt;{ duty_id: 2 }&amp;lt;/code&amp;gt;&lt;br /&gt;
** Response: Updated participant with &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;duty_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Validation: Return 422 if duty limit exceeded or duty not assigned to assignment.&lt;br /&gt;
* '''GET /participants/:id'''&lt;br /&gt;
** Response: Must include &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;duty_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== 3.7. Edge Cases &amp;amp; Conflicts ===&lt;br /&gt;
* '''Role Limit Exceeded:''' If a student attempts to select a role where &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; is already met, return a 422 error with message: &amp;quot;This role has reached its maximum member limit.&amp;quot;&lt;br /&gt;
* '''Role Deleted Mid-Semester:''' If an instructor deletes a role that students have already selected, handle gracefully:&lt;br /&gt;
** Do not allow new students to select that role.&lt;br /&gt;
** Existing students keep their role assignment (soft delete recommended).&lt;br /&gt;
** Display warning in UI: &amp;quot;This role is no longer available for new selections.&amp;quot;&lt;br /&gt;
* '''Role Toggle Off:''' If an instructor disables role-based reviewing after students selected roles:&lt;br /&gt;
** Role data is retained in the database but hidden from the UI.&lt;br /&gt;
** If re-enabled, previously selected roles are restored.&lt;br /&gt;
* '''Multiple Students Same Role:''' System prevents if &amp;lt;code&amp;gt;max_members_for_duty = 1&amp;lt;/code&amp;gt;, but this must be enforced at the database level (transaction safety).&lt;br /&gt;
&lt;br /&gt;
=== 3.8. Backward Compatibility ===&lt;br /&gt;
* '''Non-role-based assignments''' must continue functioning unchanged.&lt;br /&gt;
* All role-related UI components (Role column, dynamic rubric rows) must be '''conditionally rendered''':&lt;br /&gt;
** Only show if &amp;lt;code&amp;gt;is_role_based = true&amp;lt;/code&amp;gt; AND at least one duty is assigned.&lt;br /&gt;
** Instructors who do not enable role-based reviewing see no changes to their workflows.&lt;br /&gt;
* '''Participant serialization:''' Include &amp;lt;code&amp;gt;duty_id&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt; for non-role-based assignments.&lt;br /&gt;
&lt;br /&gt;
== 4. Design Principles ==&lt;br /&gt;
* '''Consistency:''' Use the same expandable table and modal patterns established in the E2608 hierarchy task.&lt;br /&gt;
* '''Single Responsibility:''' Keep role-selection logic within the &amp;lt;code&amp;gt;Participant&amp;lt;/code&amp;gt; context and rubric-generation logic within the &amp;lt;code&amp;gt;Assignment&amp;lt;/code&amp;gt; context.&lt;br /&gt;
* '''DRY (Don't Repeat Yourself):''' Reuse the existing &amp;lt;code&amp;gt;Table&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Form&amp;lt;/code&amp;gt; components for the new UI elements.&lt;br /&gt;
&lt;br /&gt;
== 5. Testing Plan ==&lt;br /&gt;
&lt;br /&gt;
=== 5.1. Unit &amp;amp; Functional Tests (Backend) ===&lt;br /&gt;
* '''RSpec:'''&lt;br /&gt;
** Verify &amp;lt;code&amp;gt;AssignmentDuty&amp;lt;/code&amp;gt; correctly stores and retrieves &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Test that &amp;lt;code&amp;gt;Participant#update_duty&amp;lt;/code&amp;gt; fails if the role limit is exceeded for the team.&lt;br /&gt;
** Verify API responses contain the necessary nested role data.&lt;br /&gt;
&lt;br /&gt;
=== 5.2. Integration &amp;amp; UI Tests (Frontend) ===&lt;br /&gt;
* '''Instructor Flow:''' &lt;br /&gt;
** Create an assignment, enable &amp;quot;Is role based&amp;quot;, add 2 duties, and verify 2 extra rubric rows appear in the Rubrics tab.&lt;br /&gt;
* '''Student Flow:'''&lt;br /&gt;
** Join a team, navigate to &amp;quot;Your Team&amp;quot;, select a role from the dropdown, refresh the page, and verify the role persists.&lt;br /&gt;
** Attempt to select a role that has already reached its &amp;lt;code&amp;gt;max_members_for_duty&amp;lt;/code&amp;gt; limit (if applicable) and verify the error handling.&lt;br /&gt;
&lt;br /&gt;
== 6. Relevant Links ==&lt;br /&gt;
* '''Historical Reference (Fall 2016):''' [https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2016_E1676_Role-based_reviewing CSC/ECE_517_Fall_2016_E1676]&lt;br /&gt;
* '''Historical Reference (Fall 2017):''' [https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1798_Role-based_Reviewing CSC/ECE_517_Fall_2017/E1798]&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026&amp;diff=167940</id>
		<title>CSC/ECE 517 Spring 2026</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026&amp;diff=167940"/>
		<updated>2026-04-14T01:54:52Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[CSC/ECE 517 Spring 2026 - E2600. Reimplement review_mapping_controller]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2601. Reimplement student quizzes]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2602. Reimplement student task view]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2603. Implement ViewSubmissions frontend]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2604. Finish Password Resets]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2606. Finishing Import and Export helper module]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2607. ResponseController Frontend]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2609. Review calibration]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2610. Teams hierarchy testing]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2615. Testing User model and Users controller]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2617. Testing Questionnaire and Course Models]]&lt;br /&gt;
* [[CSC/ECE 517 Spring 2026 - E2614. Role-based reviewing]]&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167742</id>
		<title>CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167742"/>
		<updated>2026-04-06T02:22:36Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Verification and Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
'''Mentors:''' Ed Gehringer and Akhilsai Chittipolu&lt;br /&gt;
&lt;br /&gt;
This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The E2608 requirement was to implement a reusable hierarchical list display template for three specific Expertiza views:&lt;br /&gt;
&lt;br /&gt;
* Course -&amp;gt; Assignments&lt;br /&gt;
* Questionnaire Type -&amp;gt; Questionnaires&lt;br /&gt;
* Team -&amp;gt; Team Members&lt;br /&gt;
&lt;br /&gt;
The project description also identified that existing hierarchy handling relied on Node-based superstructure. The required direction was to reduce that dependency by using direct database queries for parent and child objects, returning hierarchy-ready JSON from the backend, and rendering nested views on the frontend with a consistent template.&lt;br /&gt;
&lt;br /&gt;
In scope, this meant implementing the three hierarchy views above, ensuring they are backed by appropriate parent/child queries, and presenting them in clear expandable/grouped UI patterns.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
Expertiza frequently displays hierarchical data:&lt;br /&gt;
&lt;br /&gt;
* Courses with nested assignments&lt;br /&gt;
* Questionnaire types with nested questionnaires&lt;br /&gt;
* Courses/assignments with nested teams and team members&lt;br /&gt;
&lt;br /&gt;
Historically, these hierarchies were represented with a Node superstructure where each entity had an associated Node and parent pointer. This introduced additional object management and coupling that was not strictly necessary for rendering parent-child lists.&lt;br /&gt;
&lt;br /&gt;
The project objective was to design and implement a reusable hierarchical display template where:&lt;br /&gt;
&lt;br /&gt;
* Backend performs direct database queries for parent and child data.&lt;br /&gt;
* Backend returns JSON payloads suitable for hierarchy rendering.&lt;br /&gt;
* Frontend applies a common expandable-list pattern while allowing view-specific presentation styles.&lt;br /&gt;
&lt;br /&gt;
In short, the project moves hierarchy rendering from Node-centric wiring to query-and-render patterns for maintainability and consistency.&lt;br /&gt;
&lt;br /&gt;
== Current Implementation (Before E2608) ==&lt;br /&gt;
&lt;br /&gt;
Before this work, hierarchical data existed in the domain model but was not consistently presented as a parent-child UI pattern across modules.&lt;br /&gt;
&lt;br /&gt;
Typical behavior before E2608:&lt;br /&gt;
&lt;br /&gt;
* Different pages used different data-loading styles, including separate API fetches for related entities.&lt;br /&gt;
* Some views depended on fallback/static sample structures when complete nested payloads were unavailable.&lt;br /&gt;
* Parent-child relationships were not always exposed in a way that made generic expandable tables straightforward.&lt;br /&gt;
* Hierarchical behavior varied by page rather than following one reusable template.&lt;br /&gt;
&lt;br /&gt;
== Drawbacks in Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
The pre-E2608 behavior created several practical issues:&lt;br /&gt;
&lt;br /&gt;
* Inconsistent user experience: hierarchy expansion behavior differed across pages.&lt;br /&gt;
* Additional client complexity: pages needed extra mapping/fetch orchestration to build nested displays.&lt;br /&gt;
* Higher coupling to page-specific logic instead of reusable table patterns.&lt;br /&gt;
* Harder validation against real backend hierarchy data in some flows.&lt;br /&gt;
* More chance of stale UI state when child lists were refetched separately.&lt;br /&gt;
&lt;br /&gt;
== Shared Team Architecture Decision ==&lt;br /&gt;
&lt;br /&gt;
Before implementation, the team agreed on a common hierarchy approach:&lt;br /&gt;
&lt;br /&gt;
* Use eager loading on the backend to fetch parent-child data in fewer queries.&lt;br /&gt;
* Return hierarchy-ready JSON (parents with embedded child collections) so frontend pages do minimal reshaping.&lt;br /&gt;
* Keep a consistent UX goal for expandable/collapsible hierarchy views, while allowing page-specific rendering style (table expansion or embedded dropdown lists).&lt;br /&gt;
&lt;br /&gt;
This shared approach keeps data retrieval efficient and makes hierarchy rendering consistent with the mentor's requested template style, without forcing a single UI widget across all pages.&lt;br /&gt;
&lt;br /&gt;
== Our Contribution ==&lt;br /&gt;
&lt;br /&gt;
We implemented a unified hierarchical-list strategy across three views and aligned backend payloads with frontend rendering needs.&lt;br /&gt;
&lt;br /&gt;
Summary of what we delivered:&lt;br /&gt;
&lt;br /&gt;
* Unified parent-child rendering approach for three major modules.&lt;br /&gt;
* Backend responses shaped to support hierarchy directly, with eager-loaded associations where applicable.&lt;br /&gt;
* Frontend pages updated to consume nested or hierarchy-aware data using view-appropriate UI patterns.&lt;br /&gt;
* Verification using both UI behavior and real database checks.&lt;br /&gt;
&lt;br /&gt;
== View 1: Course -&amp;gt; Assignment Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Implement a seamless nested display of assignments within the Courses view, removing the need for a separate &amp;quot;All Assignments&amp;quot; fetch and improving UI responsiveness.&lt;br /&gt;
=== Backend Implementation ===&lt;br /&gt;
* Optimized Data Retrieval: Updated the CoursesController#index method to perform eager loading of assignments using Course.includes(:assignments).&lt;br /&gt;
* Hierarchy-Ready JSON: Modified the API response to embed nested assignment data within the course objects using as_json(include: :assignments). This significantly reduces the number of network requests required to render the hierarchy.&lt;br /&gt;
&lt;br /&gt;
=== Frontend Implementation ===&lt;br /&gt;
* Expandable Table Pattern: Integrated a reusable expandable row pattern in the Courses component. Courses now act as parent nodes that can be expanded to reveal their respective assignments.&lt;br /&gt;
* Nested Component Architecture: Developed the CourseAssignments component to handle the rendering of the sub-table. This component provides assignment-specific actions (Edit, Delete, Create Teams, etc.) directly within the course context.&lt;br /&gt;
* State-Aware Deletion: Modified the assignment deletion flow (AssignmentDelete.tsx) to update the parent course data locally upon success. This prevents a full page refetch and ensures the UI remains consistent and performant after data modifications.&lt;br /&gt;
* Unified Action Handlers: Implemented a consistent set of action icons and handlers for assignments, including quick access to Participant management and Team creation, all nested within the parent course row.&lt;br /&gt;
=== Significance ===&lt;br /&gt;
These changes move the application away from a fragmented data-loading model to a unified parent-child relationship. By handling the hierarchy at the database query level and mirroring it in the UI with an expandable pattern, the user experience is more intuitive, and the codebase is more maintainable.&lt;br /&gt;
&lt;br /&gt;
== View 2: Questionnaire Type -&amp;gt; Questionnaire Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Group questionnaires by questionnaire type and display questionnaires nested under each type.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Implemented hierarchical questionnaire list from the Admin view.&lt;br /&gt;
* Admin can create, edit, update, and delete questionnaires in these types:&lt;br /&gt;
** Review&lt;br /&gt;
** Metareview&lt;br /&gt;
** Author feedback&lt;br /&gt;
** Teammate Review&lt;br /&gt;
** Survey&lt;br /&gt;
** Assignment survey&lt;br /&gt;
** Global survey&lt;br /&gt;
** Course survey&lt;br /&gt;
** Bookmark rating&lt;br /&gt;
** Quiz&lt;br /&gt;
* In questionnaire listing, admin can expand a dropdown per type to see the embedded list of questionnaire instances for that category.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Questionnaire browsing follows the same parent-child model used in the other E2608 modules.&lt;br /&gt;
&lt;br /&gt;
== View 3: Team -&amp;gt; Team Member Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display team members nested under teams for a selected assignment context using real backend data.&lt;br /&gt;
&lt;br /&gt;
=== Backend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Teams filtering in index:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; filtering support.&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt; filtering support (&amp;lt;code&amp;gt;AssignmentTeam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MentoredTeam&amp;lt;/code&amp;gt;, etc.).&lt;br /&gt;
#* Added deterministic ordering by &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Added eager loading with users and team-participant associations.&lt;br /&gt;
# Team serialization:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; in team JSON payload for hierarchy-aware consumers.&lt;br /&gt;
# Backward-compatible params:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; acceptance in team params.&lt;br /&gt;
#* Preserved compatibility by mapping &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; when needed.&lt;br /&gt;
&lt;br /&gt;
=== Backend code snippet ===&lt;br /&gt;
&lt;br /&gt;
The following code snippet shows the core backend change that made the teams API hierarchy-aware:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
	@teams = Team.includes(:users, { teams_participants: :participant })&lt;br /&gt;
&lt;br /&gt;
	if params[:parent_id].present?&lt;br /&gt;
		@teams = @teams.where(parent_id: params[:parent_id])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if params[:types].present?&lt;br /&gt;
		requested_types = params[:types].is_a?(Array) ? params[:types] : params[:types].to_s.split(',')&lt;br /&gt;
		normalized_types = requested_types.map(&amp;amp;:strip).reject(&amp;amp;:blank?)&lt;br /&gt;
		@teams = @teams.where(type: normalized_types) if normalized_types.any?&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	@teams = @teams.order(:name, :id)&lt;br /&gt;
	render json: @teams, each_serializer: TeamSerializer&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frontend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Added dedicated Create Teams loader:&lt;br /&gt;
#* Loads teams using assignment context and allowed team types.&lt;br /&gt;
#* Loads assignment participants.&lt;br /&gt;
#* Maps API data into &amp;lt;code&amp;gt;initialTeams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialUnassigned&amp;lt;/code&amp;gt; structures required by the view.&lt;br /&gt;
# Route wiring:&lt;br /&gt;
#* Create Teams route switched to the new loader so it uses real backend data instead of fallback-only behavior.&lt;br /&gt;
&lt;br /&gt;
=== Real-data verification ===&lt;br /&gt;
&lt;br /&gt;
Verified against DB via Docker Rails runner for Assignment id &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Team 1 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** cameron_fahey / Prince Langosh VM&lt;br /&gt;
** rickie.hamill / Rep. Rosena Paucek&lt;br /&gt;
** elease / Myrl Durgan&lt;br /&gt;
* Team 9 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** jacinda / Joshua Raynor&lt;br /&gt;
** lydia.monahan / Edward Jacobi&lt;br /&gt;
** eddie / Halley Schinner VM&lt;br /&gt;
&lt;br /&gt;
This confirmed end-to-end data correctness for the team hierarchy view.&lt;br /&gt;
&lt;br /&gt;
=== Significance of these changes ===&lt;br /&gt;
&lt;br /&gt;
These changes are significant because they move the teams view away from static or fallback-only data and make it reflect the real assignment context from the database. By filtering teams using &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt;, the backend now returns only the teams that actually belong to the selected hierarchy context. The eager loading also improves efficiency by reducing unnecessary queries when team members are rendered.&lt;br /&gt;
&lt;br /&gt;
From a design perspective, this aligns the teams view with the overall E2608 objective of removing unnecessary hierarchy plumbing and replacing it with direct association-based queries and hierarchy-ready responses. It also makes the frontend easier to validate, because the displayed team-member relationships now match the actual persisted data instead of a page-specific mock structure.&lt;br /&gt;
&lt;br /&gt;
== Verification and Testing ==&lt;br /&gt;
&lt;br /&gt;
The hosted deployment for our project is available at:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://152.7.177.90:3000/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Course -&amp;gt; Assignment Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Log in to the hosted system and navigate to the Courses page. Verify that a course row can be expanded to display the assignments that belong to that course. Also verify that after deleting an assignment, the assignment list updates correctly within the course hierarchy.&lt;br /&gt;
[[File:E2608_Courses.png|thumb|center|800px|Verification of Courses]]&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Questionnaire Type -&amp;gt; Questionnaire Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in as an administrator and navigate to the Questionnaires page. Verify that questionnaire types are shown as parent categories and that each type can be expanded to display the questionnaires in that category. Also verify that the admin workflow for creating, editing, updating, and deleting questionnaires works correctly for the supported questionnaire types.&lt;br /&gt;
&lt;br /&gt;
[[File:E2608_questionnaire.png|thumb|center|800px|Verification of Questionnaire]]&lt;br /&gt;
=== UI Testing for Team -&amp;gt; Team Member Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Navigate to an assignment's Create Teams page and verify that the page displays real team data rather than fallback sample data. For Assignment &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, verify that Team 1 and Team 9 are shown with the correct members, and confirm that the correct members appear under the correct team for the selected assignment context.&lt;br /&gt;
[[File:E2608_Teams.png|thumb|center|800px|Verification of Teams]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Expertiza GitHub repository&lt;br /&gt;
* Expertiza project wiki&lt;br /&gt;
* RSpec documentation&lt;br /&gt;
* Vitest documentation&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2608_questionnaire.png&amp;diff=167741</id>
		<title>File:E2608 questionnaire.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2608_questionnaire.png&amp;diff=167741"/>
		<updated>2026-04-06T02:22:09Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167740</id>
		<title>CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167740"/>
		<updated>2026-04-06T02:21:20Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Verification and Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
'''Mentors:''' Ed Gehringer and Akhilsai Chittipolu&lt;br /&gt;
&lt;br /&gt;
This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The E2608 requirement was to implement a reusable hierarchical list display template for three specific Expertiza views:&lt;br /&gt;
&lt;br /&gt;
* Course -&amp;gt; Assignments&lt;br /&gt;
* Questionnaire Type -&amp;gt; Questionnaires&lt;br /&gt;
* Team -&amp;gt; Team Members&lt;br /&gt;
&lt;br /&gt;
The project description also identified that existing hierarchy handling relied on Node-based superstructure. The required direction was to reduce that dependency by using direct database queries for parent and child objects, returning hierarchy-ready JSON from the backend, and rendering nested views on the frontend with a consistent template.&lt;br /&gt;
&lt;br /&gt;
In scope, this meant implementing the three hierarchy views above, ensuring they are backed by appropriate parent/child queries, and presenting them in clear expandable/grouped UI patterns.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
Expertiza frequently displays hierarchical data:&lt;br /&gt;
&lt;br /&gt;
* Courses with nested assignments&lt;br /&gt;
* Questionnaire types with nested questionnaires&lt;br /&gt;
* Courses/assignments with nested teams and team members&lt;br /&gt;
&lt;br /&gt;
Historically, these hierarchies were represented with a Node superstructure where each entity had an associated Node and parent pointer. This introduced additional object management and coupling that was not strictly necessary for rendering parent-child lists.&lt;br /&gt;
&lt;br /&gt;
The project objective was to design and implement a reusable hierarchical display template where:&lt;br /&gt;
&lt;br /&gt;
* Backend performs direct database queries for parent and child data.&lt;br /&gt;
* Backend returns JSON payloads suitable for hierarchy rendering.&lt;br /&gt;
* Frontend applies a common expandable-list pattern while allowing view-specific presentation styles.&lt;br /&gt;
&lt;br /&gt;
In short, the project moves hierarchy rendering from Node-centric wiring to query-and-render patterns for maintainability and consistency.&lt;br /&gt;
&lt;br /&gt;
== Current Implementation (Before E2608) ==&lt;br /&gt;
&lt;br /&gt;
Before this work, hierarchical data existed in the domain model but was not consistently presented as a parent-child UI pattern across modules.&lt;br /&gt;
&lt;br /&gt;
Typical behavior before E2608:&lt;br /&gt;
&lt;br /&gt;
* Different pages used different data-loading styles, including separate API fetches for related entities.&lt;br /&gt;
* Some views depended on fallback/static sample structures when complete nested payloads were unavailable.&lt;br /&gt;
* Parent-child relationships were not always exposed in a way that made generic expandable tables straightforward.&lt;br /&gt;
* Hierarchical behavior varied by page rather than following one reusable template.&lt;br /&gt;
&lt;br /&gt;
== Drawbacks in Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
The pre-E2608 behavior created several practical issues:&lt;br /&gt;
&lt;br /&gt;
* Inconsistent user experience: hierarchy expansion behavior differed across pages.&lt;br /&gt;
* Additional client complexity: pages needed extra mapping/fetch orchestration to build nested displays.&lt;br /&gt;
* Higher coupling to page-specific logic instead of reusable table patterns.&lt;br /&gt;
* Harder validation against real backend hierarchy data in some flows.&lt;br /&gt;
* More chance of stale UI state when child lists were refetched separately.&lt;br /&gt;
&lt;br /&gt;
== Shared Team Architecture Decision ==&lt;br /&gt;
&lt;br /&gt;
Before implementation, the team agreed on a common hierarchy approach:&lt;br /&gt;
&lt;br /&gt;
* Use eager loading on the backend to fetch parent-child data in fewer queries.&lt;br /&gt;
* Return hierarchy-ready JSON (parents with embedded child collections) so frontend pages do minimal reshaping.&lt;br /&gt;
* Keep a consistent UX goal for expandable/collapsible hierarchy views, while allowing page-specific rendering style (table expansion or embedded dropdown lists).&lt;br /&gt;
&lt;br /&gt;
This shared approach keeps data retrieval efficient and makes hierarchy rendering consistent with the mentor's requested template style, without forcing a single UI widget across all pages.&lt;br /&gt;
&lt;br /&gt;
== Our Contribution ==&lt;br /&gt;
&lt;br /&gt;
We implemented a unified hierarchical-list strategy across three views and aligned backend payloads with frontend rendering needs.&lt;br /&gt;
&lt;br /&gt;
Summary of what we delivered:&lt;br /&gt;
&lt;br /&gt;
* Unified parent-child rendering approach for three major modules.&lt;br /&gt;
* Backend responses shaped to support hierarchy directly, with eager-loaded associations where applicable.&lt;br /&gt;
* Frontend pages updated to consume nested or hierarchy-aware data using view-appropriate UI patterns.&lt;br /&gt;
* Verification using both UI behavior and real database checks.&lt;br /&gt;
&lt;br /&gt;
== View 1: Course -&amp;gt; Assignment Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Implement a seamless nested display of assignments within the Courses view, removing the need for a separate &amp;quot;All Assignments&amp;quot; fetch and improving UI responsiveness.&lt;br /&gt;
=== Backend Implementation ===&lt;br /&gt;
* Optimized Data Retrieval: Updated the CoursesController#index method to perform eager loading of assignments using Course.includes(:assignments).&lt;br /&gt;
* Hierarchy-Ready JSON: Modified the API response to embed nested assignment data within the course objects using as_json(include: :assignments). This significantly reduces the number of network requests required to render the hierarchy.&lt;br /&gt;
&lt;br /&gt;
=== Frontend Implementation ===&lt;br /&gt;
* Expandable Table Pattern: Integrated a reusable expandable row pattern in the Courses component. Courses now act as parent nodes that can be expanded to reveal their respective assignments.&lt;br /&gt;
* Nested Component Architecture: Developed the CourseAssignments component to handle the rendering of the sub-table. This component provides assignment-specific actions (Edit, Delete, Create Teams, etc.) directly within the course context.&lt;br /&gt;
* State-Aware Deletion: Modified the assignment deletion flow (AssignmentDelete.tsx) to update the parent course data locally upon success. This prevents a full page refetch and ensures the UI remains consistent and performant after data modifications.&lt;br /&gt;
* Unified Action Handlers: Implemented a consistent set of action icons and handlers for assignments, including quick access to Participant management and Team creation, all nested within the parent course row.&lt;br /&gt;
=== Significance ===&lt;br /&gt;
These changes move the application away from a fragmented data-loading model to a unified parent-child relationship. By handling the hierarchy at the database query level and mirroring it in the UI with an expandable pattern, the user experience is more intuitive, and the codebase is more maintainable.&lt;br /&gt;
&lt;br /&gt;
== View 2: Questionnaire Type -&amp;gt; Questionnaire Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Group questionnaires by questionnaire type and display questionnaires nested under each type.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Implemented hierarchical questionnaire list from the Admin view.&lt;br /&gt;
* Admin can create, edit, update, and delete questionnaires in these types:&lt;br /&gt;
** Review&lt;br /&gt;
** Metareview&lt;br /&gt;
** Author feedback&lt;br /&gt;
** Teammate Review&lt;br /&gt;
** Survey&lt;br /&gt;
** Assignment survey&lt;br /&gt;
** Global survey&lt;br /&gt;
** Course survey&lt;br /&gt;
** Bookmark rating&lt;br /&gt;
** Quiz&lt;br /&gt;
* In questionnaire listing, admin can expand a dropdown per type to see the embedded list of questionnaire instances for that category.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Questionnaire browsing follows the same parent-child model used in the other E2608 modules.&lt;br /&gt;
&lt;br /&gt;
== View 3: Team -&amp;gt; Team Member Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display team members nested under teams for a selected assignment context using real backend data.&lt;br /&gt;
&lt;br /&gt;
=== Backend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Teams filtering in index:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; filtering support.&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt; filtering support (&amp;lt;code&amp;gt;AssignmentTeam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MentoredTeam&amp;lt;/code&amp;gt;, etc.).&lt;br /&gt;
#* Added deterministic ordering by &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Added eager loading with users and team-participant associations.&lt;br /&gt;
# Team serialization:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; in team JSON payload for hierarchy-aware consumers.&lt;br /&gt;
# Backward-compatible params:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; acceptance in team params.&lt;br /&gt;
#* Preserved compatibility by mapping &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; when needed.&lt;br /&gt;
&lt;br /&gt;
=== Backend code snippet ===&lt;br /&gt;
&lt;br /&gt;
The following code snippet shows the core backend change that made the teams API hierarchy-aware:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
	@teams = Team.includes(:users, { teams_participants: :participant })&lt;br /&gt;
&lt;br /&gt;
	if params[:parent_id].present?&lt;br /&gt;
		@teams = @teams.where(parent_id: params[:parent_id])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if params[:types].present?&lt;br /&gt;
		requested_types = params[:types].is_a?(Array) ? params[:types] : params[:types].to_s.split(',')&lt;br /&gt;
		normalized_types = requested_types.map(&amp;amp;:strip).reject(&amp;amp;:blank?)&lt;br /&gt;
		@teams = @teams.where(type: normalized_types) if normalized_types.any?&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	@teams = @teams.order(:name, :id)&lt;br /&gt;
	render json: @teams, each_serializer: TeamSerializer&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frontend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Added dedicated Create Teams loader:&lt;br /&gt;
#* Loads teams using assignment context and allowed team types.&lt;br /&gt;
#* Loads assignment participants.&lt;br /&gt;
#* Maps API data into &amp;lt;code&amp;gt;initialTeams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialUnassigned&amp;lt;/code&amp;gt; structures required by the view.&lt;br /&gt;
# Route wiring:&lt;br /&gt;
#* Create Teams route switched to the new loader so it uses real backend data instead of fallback-only behavior.&lt;br /&gt;
&lt;br /&gt;
=== Real-data verification ===&lt;br /&gt;
&lt;br /&gt;
Verified against DB via Docker Rails runner for Assignment id &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Team 1 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** cameron_fahey / Prince Langosh VM&lt;br /&gt;
** rickie.hamill / Rep. Rosena Paucek&lt;br /&gt;
** elease / Myrl Durgan&lt;br /&gt;
* Team 9 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** jacinda / Joshua Raynor&lt;br /&gt;
** lydia.monahan / Edward Jacobi&lt;br /&gt;
** eddie / Halley Schinner VM&lt;br /&gt;
&lt;br /&gt;
This confirmed end-to-end data correctness for the team hierarchy view.&lt;br /&gt;
&lt;br /&gt;
=== Significance of these changes ===&lt;br /&gt;
&lt;br /&gt;
These changes are significant because they move the teams view away from static or fallback-only data and make it reflect the real assignment context from the database. By filtering teams using &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt;, the backend now returns only the teams that actually belong to the selected hierarchy context. The eager loading also improves efficiency by reducing unnecessary queries when team members are rendered.&lt;br /&gt;
&lt;br /&gt;
From a design perspective, this aligns the teams view with the overall E2608 objective of removing unnecessary hierarchy plumbing and replacing it with direct association-based queries and hierarchy-ready responses. It also makes the frontend easier to validate, because the displayed team-member relationships now match the actual persisted data instead of a page-specific mock structure.&lt;br /&gt;
&lt;br /&gt;
== Verification and Testing ==&lt;br /&gt;
&lt;br /&gt;
The hosted deployment for our project is available at:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://152.7.177.90:3000/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Course -&amp;gt; Assignment Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Log in to the hosted system and navigate to the Courses page. Verify that a course row can be expanded to display the assignments that belong to that course. Also verify that after deleting an assignment, the assignment list updates correctly within the course hierarchy.&lt;br /&gt;
[[File:E2608_Courses.png|thumb|center|800px|Verification of Courses]]&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Questionnaire Type -&amp;gt; Questionnaire Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in as an administrator and navigate to the Questionnaires page. Verify that questionnaire types are shown as parent categories and that each type can be expanded to display the questionnaires in that category. Also verify that the admin workflow for creating, editing, updating, and deleting questionnaires works correctly for the supported questionnaire types.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Team -&amp;gt; Team Member Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Navigate to an assignment's Create Teams page and verify that the page displays real team data rather than fallback sample data. For Assignment &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, verify that Team 1 and Team 9 are shown with the correct members, and confirm that the correct members appear under the correct team for the selected assignment context.&lt;br /&gt;
[[File:E2608_Teams.png|thumb|center|800px|Verification of Teams]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Expertiza GitHub repository&lt;br /&gt;
* Expertiza project wiki&lt;br /&gt;
* RSpec documentation&lt;br /&gt;
* Vitest documentation&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2608_Teams.png&amp;diff=167739</id>
		<title>File:E2608 Teams.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2608_Teams.png&amp;diff=167739"/>
		<updated>2026-04-06T02:19:04Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2608_Courses.png&amp;diff=167738</id>
		<title>File:E2608 Courses.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2608_Courses.png&amp;diff=167738"/>
		<updated>2026-04-06T02:18:42Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167737</id>
		<title>CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167737"/>
		<updated>2026-04-06T02:15:21Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Backend Implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
'''Mentors:''' Ed Gehringer and Akhilsai Chittipolu&lt;br /&gt;
&lt;br /&gt;
This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The E2608 requirement was to implement a reusable hierarchical list display template for three specific Expertiza views:&lt;br /&gt;
&lt;br /&gt;
* Course -&amp;gt; Assignments&lt;br /&gt;
* Questionnaire Type -&amp;gt; Questionnaires&lt;br /&gt;
* Team -&amp;gt; Team Members&lt;br /&gt;
&lt;br /&gt;
The project description also identified that existing hierarchy handling relied on Node-based superstructure. The required direction was to reduce that dependency by using direct database queries for parent and child objects, returning hierarchy-ready JSON from the backend, and rendering nested views on the frontend with a consistent template.&lt;br /&gt;
&lt;br /&gt;
In scope, this meant implementing the three hierarchy views above, ensuring they are backed by appropriate parent/child queries, and presenting them in clear expandable/grouped UI patterns.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
Expertiza frequently displays hierarchical data:&lt;br /&gt;
&lt;br /&gt;
* Courses with nested assignments&lt;br /&gt;
* Questionnaire types with nested questionnaires&lt;br /&gt;
* Courses/assignments with nested teams and team members&lt;br /&gt;
&lt;br /&gt;
Historically, these hierarchies were represented with a Node superstructure where each entity had an associated Node and parent pointer. This introduced additional object management and coupling that was not strictly necessary for rendering parent-child lists.&lt;br /&gt;
&lt;br /&gt;
The project objective was to design and implement a reusable hierarchical display template where:&lt;br /&gt;
&lt;br /&gt;
* Backend performs direct database queries for parent and child data.&lt;br /&gt;
* Backend returns JSON payloads suitable for hierarchy rendering.&lt;br /&gt;
* Frontend applies a common expandable-list pattern while allowing view-specific presentation styles.&lt;br /&gt;
&lt;br /&gt;
In short, the project moves hierarchy rendering from Node-centric wiring to query-and-render patterns for maintainability and consistency.&lt;br /&gt;
&lt;br /&gt;
== Current Implementation (Before E2608) ==&lt;br /&gt;
&lt;br /&gt;
Before this work, hierarchical data existed in the domain model but was not consistently presented as a parent-child UI pattern across modules.&lt;br /&gt;
&lt;br /&gt;
Typical behavior before E2608:&lt;br /&gt;
&lt;br /&gt;
* Different pages used different data-loading styles, including separate API fetches for related entities.&lt;br /&gt;
* Some views depended on fallback/static sample structures when complete nested payloads were unavailable.&lt;br /&gt;
* Parent-child relationships were not always exposed in a way that made generic expandable tables straightforward.&lt;br /&gt;
* Hierarchical behavior varied by page rather than following one reusable template.&lt;br /&gt;
&lt;br /&gt;
== Drawbacks in Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
The pre-E2608 behavior created several practical issues:&lt;br /&gt;
&lt;br /&gt;
* Inconsistent user experience: hierarchy expansion behavior differed across pages.&lt;br /&gt;
* Additional client complexity: pages needed extra mapping/fetch orchestration to build nested displays.&lt;br /&gt;
* Higher coupling to page-specific logic instead of reusable table patterns.&lt;br /&gt;
* Harder validation against real backend hierarchy data in some flows.&lt;br /&gt;
* More chance of stale UI state when child lists were refetched separately.&lt;br /&gt;
&lt;br /&gt;
== Shared Team Architecture Decision ==&lt;br /&gt;
&lt;br /&gt;
Before implementation, the team agreed on a common hierarchy approach:&lt;br /&gt;
&lt;br /&gt;
* Use eager loading on the backend to fetch parent-child data in fewer queries.&lt;br /&gt;
* Return hierarchy-ready JSON (parents with embedded child collections) so frontend pages do minimal reshaping.&lt;br /&gt;
* Keep a consistent UX goal for expandable/collapsible hierarchy views, while allowing page-specific rendering style (table expansion or embedded dropdown lists).&lt;br /&gt;
&lt;br /&gt;
This shared approach keeps data retrieval efficient and makes hierarchy rendering consistent with the mentor's requested template style, without forcing a single UI widget across all pages.&lt;br /&gt;
&lt;br /&gt;
== Our Contribution ==&lt;br /&gt;
&lt;br /&gt;
We implemented a unified hierarchical-list strategy across three views and aligned backend payloads with frontend rendering needs.&lt;br /&gt;
&lt;br /&gt;
Summary of what we delivered:&lt;br /&gt;
&lt;br /&gt;
* Unified parent-child rendering approach for three major modules.&lt;br /&gt;
* Backend responses shaped to support hierarchy directly, with eager-loaded associations where applicable.&lt;br /&gt;
* Frontend pages updated to consume nested or hierarchy-aware data using view-appropriate UI patterns.&lt;br /&gt;
* Verification using both UI behavior and real database checks.&lt;br /&gt;
&lt;br /&gt;
== View 1: Course -&amp;gt; Assignment Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Implement a seamless nested display of assignments within the Courses view, removing the need for a separate &amp;quot;All Assignments&amp;quot; fetch and improving UI responsiveness.&lt;br /&gt;
=== Backend Implementation ===&lt;br /&gt;
* Optimized Data Retrieval: Updated the CoursesController#index method to perform eager loading of assignments using Course.includes(:assignments).&lt;br /&gt;
* Hierarchy-Ready JSON: Modified the API response to embed nested assignment data within the course objects using as_json(include: :assignments). This significantly reduces the number of network requests required to render the hierarchy.&lt;br /&gt;
&lt;br /&gt;
=== Frontend Implementation ===&lt;br /&gt;
* Expandable Table Pattern: Integrated a reusable expandable row pattern in the Courses component. Courses now act as parent nodes that can be expanded to reveal their respective assignments.&lt;br /&gt;
* Nested Component Architecture: Developed the CourseAssignments component to handle the rendering of the sub-table. This component provides assignment-specific actions (Edit, Delete, Create Teams, etc.) directly within the course context.&lt;br /&gt;
* State-Aware Deletion: Modified the assignment deletion flow (AssignmentDelete.tsx) to update the parent course data locally upon success. This prevents a full page refetch and ensures the UI remains consistent and performant after data modifications.&lt;br /&gt;
* Unified Action Handlers: Implemented a consistent set of action icons and handlers for assignments, including quick access to Participant management and Team creation, all nested within the parent course row.&lt;br /&gt;
=== Significance ===&lt;br /&gt;
These changes move the application away from a fragmented data-loading model to a unified parent-child relationship. By handling the hierarchy at the database query level and mirroring it in the UI with an expandable pattern, the user experience is more intuitive, and the codebase is more maintainable.&lt;br /&gt;
&lt;br /&gt;
== View 2: Questionnaire Type -&amp;gt; Questionnaire Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Group questionnaires by questionnaire type and display questionnaires nested under each type.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Implemented hierarchical questionnaire list from the Admin view.&lt;br /&gt;
* Admin can create, edit, update, and delete questionnaires in these types:&lt;br /&gt;
** Review&lt;br /&gt;
** Metareview&lt;br /&gt;
** Author feedback&lt;br /&gt;
** Teammate Review&lt;br /&gt;
** Survey&lt;br /&gt;
** Assignment survey&lt;br /&gt;
** Global survey&lt;br /&gt;
** Course survey&lt;br /&gt;
** Bookmark rating&lt;br /&gt;
** Quiz&lt;br /&gt;
* In questionnaire listing, admin can expand a dropdown per type to see the embedded list of questionnaire instances for that category.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Questionnaire browsing follows the same parent-child model used in the other E2608 modules.&lt;br /&gt;
&lt;br /&gt;
== View 3: Team -&amp;gt; Team Member Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display team members nested under teams for a selected assignment context using real backend data.&lt;br /&gt;
&lt;br /&gt;
=== Backend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Teams filtering in index:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; filtering support.&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt; filtering support (&amp;lt;code&amp;gt;AssignmentTeam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MentoredTeam&amp;lt;/code&amp;gt;, etc.).&lt;br /&gt;
#* Added deterministic ordering by &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Added eager loading with users and team-participant associations.&lt;br /&gt;
# Team serialization:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; in team JSON payload for hierarchy-aware consumers.&lt;br /&gt;
# Backward-compatible params:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; acceptance in team params.&lt;br /&gt;
#* Preserved compatibility by mapping &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; when needed.&lt;br /&gt;
&lt;br /&gt;
=== Backend code snippet ===&lt;br /&gt;
&lt;br /&gt;
The following code snippet shows the core backend change that made the teams API hierarchy-aware:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
	@teams = Team.includes(:users, { teams_participants: :participant })&lt;br /&gt;
&lt;br /&gt;
	if params[:parent_id].present?&lt;br /&gt;
		@teams = @teams.where(parent_id: params[:parent_id])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if params[:types].present?&lt;br /&gt;
		requested_types = params[:types].is_a?(Array) ? params[:types] : params[:types].to_s.split(',')&lt;br /&gt;
		normalized_types = requested_types.map(&amp;amp;:strip).reject(&amp;amp;:blank?)&lt;br /&gt;
		@teams = @teams.where(type: normalized_types) if normalized_types.any?&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	@teams = @teams.order(:name, :id)&lt;br /&gt;
	render json: @teams, each_serializer: TeamSerializer&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frontend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Added dedicated Create Teams loader:&lt;br /&gt;
#* Loads teams using assignment context and allowed team types.&lt;br /&gt;
#* Loads assignment participants.&lt;br /&gt;
#* Maps API data into &amp;lt;code&amp;gt;initialTeams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialUnassigned&amp;lt;/code&amp;gt; structures required by the view.&lt;br /&gt;
# Route wiring:&lt;br /&gt;
#* Create Teams route switched to the new loader so it uses real backend data instead of fallback-only behavior.&lt;br /&gt;
&lt;br /&gt;
=== Real-data verification ===&lt;br /&gt;
&lt;br /&gt;
Verified against DB via Docker Rails runner for Assignment id &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Team 1 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** cameron_fahey / Prince Langosh VM&lt;br /&gt;
** rickie.hamill / Rep. Rosena Paucek&lt;br /&gt;
** elease / Myrl Durgan&lt;br /&gt;
* Team 9 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** jacinda / Joshua Raynor&lt;br /&gt;
** lydia.monahan / Edward Jacobi&lt;br /&gt;
** eddie / Halley Schinner VM&lt;br /&gt;
&lt;br /&gt;
This confirmed end-to-end data correctness for the team hierarchy view.&lt;br /&gt;
&lt;br /&gt;
=== Significance of these changes ===&lt;br /&gt;
&lt;br /&gt;
These changes are significant because they move the teams view away from static or fallback-only data and make it reflect the real assignment context from the database. By filtering teams using &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt;, the backend now returns only the teams that actually belong to the selected hierarchy context. The eager loading also improves efficiency by reducing unnecessary queries when team members are rendered.&lt;br /&gt;
&lt;br /&gt;
From a design perspective, this aligns the teams view with the overall E2608 objective of removing unnecessary hierarchy plumbing and replacing it with direct association-based queries and hierarchy-ready responses. It also makes the frontend easier to validate, because the displayed team-member relationships now match the actual persisted data instead of a page-specific mock structure.&lt;br /&gt;
&lt;br /&gt;
== Verification and Testing ==&lt;br /&gt;
&lt;br /&gt;
The hosted deployment for our project is available at:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://152.7.177.90:3000/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Course -&amp;gt; Assignment Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in to the hosted system and navigate to the Courses page. Verify that a course row can be expanded to display the assignments that belong to that course. Also verify that after deleting an assignment, the assignment list updates correctly within the course hierarchy.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Questionnaire Type -&amp;gt; Questionnaire Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in as an administrator and navigate to the Questionnaires page. Verify that questionnaire types are shown as parent categories and that each type can be expanded to display the questionnaires in that category. Also verify that the admin workflow for creating, editing, updating, and deleting questionnaires works correctly for the supported questionnaire types.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Team -&amp;gt; Team Member Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Navigate to an assignment's Create Teams page and verify that the page displays real team data rather than fallback sample data. For Assignment &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, verify that Team 1 and Team 9 are shown with the correct members, and confirm that the correct members appear under the correct team for the selected assignment context.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Expertiza GitHub repository&lt;br /&gt;
* Expertiza project wiki&lt;br /&gt;
* RSpec documentation&lt;br /&gt;
* Vitest documentation&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167736</id>
		<title>CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167736"/>
		<updated>2026-04-06T02:14:51Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* View 1: Course -&amp;gt; Assignment Hierarchy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
'''Mentors:''' Ed Gehringer and Akhilsai Chittipolu&lt;br /&gt;
&lt;br /&gt;
This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The E2608 requirement was to implement a reusable hierarchical list display template for three specific Expertiza views:&lt;br /&gt;
&lt;br /&gt;
* Course -&amp;gt; Assignments&lt;br /&gt;
* Questionnaire Type -&amp;gt; Questionnaires&lt;br /&gt;
* Team -&amp;gt; Team Members&lt;br /&gt;
&lt;br /&gt;
The project description also identified that existing hierarchy handling relied on Node-based superstructure. The required direction was to reduce that dependency by using direct database queries for parent and child objects, returning hierarchy-ready JSON from the backend, and rendering nested views on the frontend with a consistent template.&lt;br /&gt;
&lt;br /&gt;
In scope, this meant implementing the three hierarchy views above, ensuring they are backed by appropriate parent/child queries, and presenting them in clear expandable/grouped UI patterns.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
Expertiza frequently displays hierarchical data:&lt;br /&gt;
&lt;br /&gt;
* Courses with nested assignments&lt;br /&gt;
* Questionnaire types with nested questionnaires&lt;br /&gt;
* Courses/assignments with nested teams and team members&lt;br /&gt;
&lt;br /&gt;
Historically, these hierarchies were represented with a Node superstructure where each entity had an associated Node and parent pointer. This introduced additional object management and coupling that was not strictly necessary for rendering parent-child lists.&lt;br /&gt;
&lt;br /&gt;
The project objective was to design and implement a reusable hierarchical display template where:&lt;br /&gt;
&lt;br /&gt;
* Backend performs direct database queries for parent and child data.&lt;br /&gt;
* Backend returns JSON payloads suitable for hierarchy rendering.&lt;br /&gt;
* Frontend applies a common expandable-list pattern while allowing view-specific presentation styles.&lt;br /&gt;
&lt;br /&gt;
In short, the project moves hierarchy rendering from Node-centric wiring to query-and-render patterns for maintainability and consistency.&lt;br /&gt;
&lt;br /&gt;
== Current Implementation (Before E2608) ==&lt;br /&gt;
&lt;br /&gt;
Before this work, hierarchical data existed in the domain model but was not consistently presented as a parent-child UI pattern across modules.&lt;br /&gt;
&lt;br /&gt;
Typical behavior before E2608:&lt;br /&gt;
&lt;br /&gt;
* Different pages used different data-loading styles, including separate API fetches for related entities.&lt;br /&gt;
* Some views depended on fallback/static sample structures when complete nested payloads were unavailable.&lt;br /&gt;
* Parent-child relationships were not always exposed in a way that made generic expandable tables straightforward.&lt;br /&gt;
* Hierarchical behavior varied by page rather than following one reusable template.&lt;br /&gt;
&lt;br /&gt;
== Drawbacks in Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
The pre-E2608 behavior created several practical issues:&lt;br /&gt;
&lt;br /&gt;
* Inconsistent user experience: hierarchy expansion behavior differed across pages.&lt;br /&gt;
* Additional client complexity: pages needed extra mapping/fetch orchestration to build nested displays.&lt;br /&gt;
* Higher coupling to page-specific logic instead of reusable table patterns.&lt;br /&gt;
* Harder validation against real backend hierarchy data in some flows.&lt;br /&gt;
* More chance of stale UI state when child lists were refetched separately.&lt;br /&gt;
&lt;br /&gt;
== Shared Team Architecture Decision ==&lt;br /&gt;
&lt;br /&gt;
Before implementation, the team agreed on a common hierarchy approach:&lt;br /&gt;
&lt;br /&gt;
* Use eager loading on the backend to fetch parent-child data in fewer queries.&lt;br /&gt;
* Return hierarchy-ready JSON (parents with embedded child collections) so frontend pages do minimal reshaping.&lt;br /&gt;
* Keep a consistent UX goal for expandable/collapsible hierarchy views, while allowing page-specific rendering style (table expansion or embedded dropdown lists).&lt;br /&gt;
&lt;br /&gt;
This shared approach keeps data retrieval efficient and makes hierarchy rendering consistent with the mentor's requested template style, without forcing a single UI widget across all pages.&lt;br /&gt;
&lt;br /&gt;
== Our Contribution ==&lt;br /&gt;
&lt;br /&gt;
We implemented a unified hierarchical-list strategy across three views and aligned backend payloads with frontend rendering needs.&lt;br /&gt;
&lt;br /&gt;
Summary of what we delivered:&lt;br /&gt;
&lt;br /&gt;
* Unified parent-child rendering approach for three major modules.&lt;br /&gt;
* Backend responses shaped to support hierarchy directly, with eager-loaded associations where applicable.&lt;br /&gt;
* Frontend pages updated to consume nested or hierarchy-aware data using view-appropriate UI patterns.&lt;br /&gt;
* Verification using both UI behavior and real database checks.&lt;br /&gt;
&lt;br /&gt;
== View 1: Course -&amp;gt; Assignment Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Implement a seamless nested display of assignments within the Courses view, removing the need for a separate &amp;quot;All Assignments&amp;quot; fetch and improving UI responsiveness.&lt;br /&gt;
=== Backend Implementation ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 * Optimized Data Retrieval: Updated the CoursesController#index method to perform eager loading of assignments using Course.includes(:assignments).&lt;br /&gt;
 * Hierarchy-Ready JSON: Modified the API response to embed nested assignment data within the course objects using as_json(include: :assignments). This significantly reduces the number of network requests required to render the&lt;br /&gt;
     hierarchy.&lt;br /&gt;
&lt;br /&gt;
=== Frontend Implementation ===&lt;br /&gt;
* Expandable Table Pattern: Integrated a reusable expandable row pattern in the Courses component. Courses now act as parent nodes that can be expanded to reveal their respective assignments.&lt;br /&gt;
* Nested Component Architecture: Developed the CourseAssignments component to handle the rendering of the sub-table. This component provides assignment-specific actions (Edit, Delete, Create Teams, etc.) directly within the course context.&lt;br /&gt;
* State-Aware Deletion: Modified the assignment deletion flow (AssignmentDelete.tsx) to update the parent course data locally upon success. This prevents a full page refetch and ensures the UI remains consistent and performant after data modifications.&lt;br /&gt;
* Unified Action Handlers: Implemented a consistent set of action icons and handlers for assignments, including quick access to Participant management and Team creation, all nested within the parent course row.&lt;br /&gt;
=== Significance ===&lt;br /&gt;
These changes move the application away from a fragmented data-loading model to a unified parent-child relationship. By handling the hierarchy at the database query level and mirroring it in the UI with an expandable pattern, the user experience is more intuitive, and the codebase is more maintainable.&lt;br /&gt;
&lt;br /&gt;
== View 2: Questionnaire Type -&amp;gt; Questionnaire Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Group questionnaires by questionnaire type and display questionnaires nested under each type.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Implemented hierarchical questionnaire list from the Admin view.&lt;br /&gt;
* Admin can create, edit, update, and delete questionnaires in these types:&lt;br /&gt;
** Review&lt;br /&gt;
** Metareview&lt;br /&gt;
** Author feedback&lt;br /&gt;
** Teammate Review&lt;br /&gt;
** Survey&lt;br /&gt;
** Assignment survey&lt;br /&gt;
** Global survey&lt;br /&gt;
** Course survey&lt;br /&gt;
** Bookmark rating&lt;br /&gt;
** Quiz&lt;br /&gt;
* In questionnaire listing, admin can expand a dropdown per type to see the embedded list of questionnaire instances for that category.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Questionnaire browsing follows the same parent-child model used in the other E2608 modules.&lt;br /&gt;
&lt;br /&gt;
== View 3: Team -&amp;gt; Team Member Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display team members nested under teams for a selected assignment context using real backend data.&lt;br /&gt;
&lt;br /&gt;
=== Backend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Teams filtering in index:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; filtering support.&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt; filtering support (&amp;lt;code&amp;gt;AssignmentTeam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MentoredTeam&amp;lt;/code&amp;gt;, etc.).&lt;br /&gt;
#* Added deterministic ordering by &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Added eager loading with users and team-participant associations.&lt;br /&gt;
# Team serialization:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; in team JSON payload for hierarchy-aware consumers.&lt;br /&gt;
# Backward-compatible params:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; acceptance in team params.&lt;br /&gt;
#* Preserved compatibility by mapping &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; when needed.&lt;br /&gt;
&lt;br /&gt;
=== Backend code snippet ===&lt;br /&gt;
&lt;br /&gt;
The following code snippet shows the core backend change that made the teams API hierarchy-aware:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
	@teams = Team.includes(:users, { teams_participants: :participant })&lt;br /&gt;
&lt;br /&gt;
	if params[:parent_id].present?&lt;br /&gt;
		@teams = @teams.where(parent_id: params[:parent_id])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if params[:types].present?&lt;br /&gt;
		requested_types = params[:types].is_a?(Array) ? params[:types] : params[:types].to_s.split(',')&lt;br /&gt;
		normalized_types = requested_types.map(&amp;amp;:strip).reject(&amp;amp;:blank?)&lt;br /&gt;
		@teams = @teams.where(type: normalized_types) if normalized_types.any?&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	@teams = @teams.order(:name, :id)&lt;br /&gt;
	render json: @teams, each_serializer: TeamSerializer&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frontend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Added dedicated Create Teams loader:&lt;br /&gt;
#* Loads teams using assignment context and allowed team types.&lt;br /&gt;
#* Loads assignment participants.&lt;br /&gt;
#* Maps API data into &amp;lt;code&amp;gt;initialTeams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialUnassigned&amp;lt;/code&amp;gt; structures required by the view.&lt;br /&gt;
# Route wiring:&lt;br /&gt;
#* Create Teams route switched to the new loader so it uses real backend data instead of fallback-only behavior.&lt;br /&gt;
&lt;br /&gt;
=== Real-data verification ===&lt;br /&gt;
&lt;br /&gt;
Verified against DB via Docker Rails runner for Assignment id &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Team 1 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** cameron_fahey / Prince Langosh VM&lt;br /&gt;
** rickie.hamill / Rep. Rosena Paucek&lt;br /&gt;
** elease / Myrl Durgan&lt;br /&gt;
* Team 9 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** jacinda / Joshua Raynor&lt;br /&gt;
** lydia.monahan / Edward Jacobi&lt;br /&gt;
** eddie / Halley Schinner VM&lt;br /&gt;
&lt;br /&gt;
This confirmed end-to-end data correctness for the team hierarchy view.&lt;br /&gt;
&lt;br /&gt;
=== Significance of these changes ===&lt;br /&gt;
&lt;br /&gt;
These changes are significant because they move the teams view away from static or fallback-only data and make it reflect the real assignment context from the database. By filtering teams using &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt;, the backend now returns only the teams that actually belong to the selected hierarchy context. The eager loading also improves efficiency by reducing unnecessary queries when team members are rendered.&lt;br /&gt;
&lt;br /&gt;
From a design perspective, this aligns the teams view with the overall E2608 objective of removing unnecessary hierarchy plumbing and replacing it with direct association-based queries and hierarchy-ready responses. It also makes the frontend easier to validate, because the displayed team-member relationships now match the actual persisted data instead of a page-specific mock structure.&lt;br /&gt;
&lt;br /&gt;
== Verification and Testing ==&lt;br /&gt;
&lt;br /&gt;
The hosted deployment for our project is available at:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://152.7.177.90:3000/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Course -&amp;gt; Assignment Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in to the hosted system and navigate to the Courses page. Verify that a course row can be expanded to display the assignments that belong to that course. Also verify that after deleting an assignment, the assignment list updates correctly within the course hierarchy.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Questionnaire Type -&amp;gt; Questionnaire Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in as an administrator and navigate to the Questionnaires page. Verify that questionnaire types are shown as parent categories and that each type can be expanded to display the questionnaires in that category. Also verify that the admin workflow for creating, editing, updating, and deleting questionnaires works correctly for the supported questionnaire types.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Team -&amp;gt; Team Member Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Navigate to an assignment's Create Teams page and verify that the page displays real team data rather than fallback sample data. For Assignment &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, verify that Team 1 and Team 9 are shown with the correct members, and confirm that the correct members appear under the correct team for the selected assignment context.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Expertiza GitHub repository&lt;br /&gt;
* Expertiza project wiki&lt;br /&gt;
* RSpec documentation&lt;br /&gt;
* Vitest documentation&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167670</id>
		<title>CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167670"/>
		<updated>2026-03-31T03:08:07Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Problem Statement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
'''Mentors:''' Ed Gehringer and Akhilsai Chittipolu&lt;br /&gt;
&lt;br /&gt;
This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The E2608 requirement was to implement a reusable hierarchical list display template for three specific Expertiza views:&lt;br /&gt;
&lt;br /&gt;
* Course -&amp;gt; Assignments&lt;br /&gt;
* Questionnaire Type -&amp;gt; Questionnaires&lt;br /&gt;
* Team -&amp;gt; Team Members&lt;br /&gt;
&lt;br /&gt;
The project description also identified that existing hierarchy handling relied on Node-based superstructure. The required direction was to reduce that dependency by using direct database queries for parent and child objects, returning hierarchy-ready JSON from the backend, and rendering nested views on the frontend with a consistent template.&lt;br /&gt;
&lt;br /&gt;
In scope, this meant implementing the three hierarchy views above, ensuring they are backed by appropriate parent/child queries, and presenting them in clear expandable/grouped UI patterns.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
Expertiza frequently displays hierarchical data:&lt;br /&gt;
&lt;br /&gt;
* Courses with nested assignments&lt;br /&gt;
* Questionnaire types with nested questionnaires&lt;br /&gt;
* Courses/assignments with nested teams and team members&lt;br /&gt;
&lt;br /&gt;
Historically, these hierarchies were represented with a Node superstructure where each entity had an associated Node and parent pointer. This introduced additional object management and coupling that was not strictly necessary for rendering parent-child lists.&lt;br /&gt;
&lt;br /&gt;
The project objective was to design and implement a reusable hierarchical display template where:&lt;br /&gt;
&lt;br /&gt;
* Backend performs direct database queries for parent and child data.&lt;br /&gt;
* Backend returns JSON payloads suitable for hierarchy rendering.&lt;br /&gt;
* Frontend applies a common expandable-list pattern while allowing view-specific presentation styles.&lt;br /&gt;
&lt;br /&gt;
In short, the project moves hierarchy rendering from Node-centric wiring to query-and-render patterns for maintainability and consistency.&lt;br /&gt;
&lt;br /&gt;
== Current Implementation (Before E2608) ==&lt;br /&gt;
&lt;br /&gt;
Before this work, hierarchical data existed in the domain model but was not consistently presented as a parent-child UI pattern across modules.&lt;br /&gt;
&lt;br /&gt;
Typical behavior before E2608:&lt;br /&gt;
&lt;br /&gt;
* Different pages used different data-loading styles, including separate API fetches for related entities.&lt;br /&gt;
* Some views depended on fallback/static sample structures when complete nested payloads were unavailable.&lt;br /&gt;
* Parent-child relationships were not always exposed in a way that made generic expandable tables straightforward.&lt;br /&gt;
* Hierarchical behavior varied by page rather than following one reusable template.&lt;br /&gt;
&lt;br /&gt;
== Drawbacks in Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
The pre-E2608 behavior created several practical issues:&lt;br /&gt;
&lt;br /&gt;
* Inconsistent user experience: hierarchy expansion behavior differed across pages.&lt;br /&gt;
* Additional client complexity: pages needed extra mapping/fetch orchestration to build nested displays.&lt;br /&gt;
* Higher coupling to page-specific logic instead of reusable table patterns.&lt;br /&gt;
* Harder validation against real backend hierarchy data in some flows.&lt;br /&gt;
* More chance of stale UI state when child lists were refetched separately.&lt;br /&gt;
&lt;br /&gt;
== Shared Team Architecture Decision ==&lt;br /&gt;
&lt;br /&gt;
Before implementation, the team agreed on a common hierarchy approach:&lt;br /&gt;
&lt;br /&gt;
* Use eager loading on the backend to fetch parent-child data in fewer queries.&lt;br /&gt;
* Return hierarchy-ready JSON (parents with embedded child collections) so frontend pages do minimal reshaping.&lt;br /&gt;
* Keep a consistent UX goal for expandable/collapsible hierarchy views, while allowing page-specific rendering style (table expansion or embedded dropdown lists).&lt;br /&gt;
&lt;br /&gt;
This shared approach keeps data retrieval efficient and makes hierarchy rendering consistent with the mentor's requested template style, without forcing a single UI widget across all pages.&lt;br /&gt;
&lt;br /&gt;
== Our Contribution ==&lt;br /&gt;
&lt;br /&gt;
We implemented a unified hierarchical-list strategy across three views and aligned backend payloads with frontend rendering needs.&lt;br /&gt;
&lt;br /&gt;
Summary of what we delivered:&lt;br /&gt;
&lt;br /&gt;
* Unified parent-child rendering approach for three major modules.&lt;br /&gt;
* Backend responses shaped to support hierarchy directly, with eager-loaded associations where applicable.&lt;br /&gt;
* Frontend pages updated to consume nested or hierarchy-aware data using view-appropriate UI patterns.&lt;br /&gt;
* Verification using both UI behavior and real database checks.&lt;br /&gt;
&lt;br /&gt;
== View 1: Course -&amp;gt; Assignment Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display assignments nested under their parent courses without CourseNode/AssignmentNode style custom hierarchy components.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Backend updated to return courses with associated assignments in one response.&lt;br /&gt;
* Frontend updated to consume nested assignment data from course payload.&lt;br /&gt;
* Frontend no longer depends on separate all-assignments fetch for this view.&lt;br /&gt;
* Minor delete-flow refinement: after successful assignment delete, assignment is removed from local frontend data instead of refetching assignments only.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Course rows can expand into assignment lists through the common hierarchy pattern.&lt;br /&gt;
&lt;br /&gt;
== View 2: Questionnaire Type -&amp;gt; Questionnaire Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Group questionnaires by questionnaire type and display questionnaires nested under each type.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Implemented hierarchical questionnaire list from the Admin view.&lt;br /&gt;
* Admin can create, edit, update, and delete questionnaires in these types:&lt;br /&gt;
** Review&lt;br /&gt;
** Metareview&lt;br /&gt;
** Author feedback&lt;br /&gt;
** Teammate Review&lt;br /&gt;
** Survey&lt;br /&gt;
** Assignment survey&lt;br /&gt;
** Global survey&lt;br /&gt;
** Course survey&lt;br /&gt;
** Bookmark rating&lt;br /&gt;
** Quiz&lt;br /&gt;
* In questionnaire listing, admin can expand a dropdown per type to see the embedded list of questionnaire instances for that category.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Questionnaire browsing follows the same parent-child model used in the other E2608 modules.&lt;br /&gt;
&lt;br /&gt;
== View 3: Team -&amp;gt; Team Member Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display team members nested under teams for a selected assignment context using real backend data.&lt;br /&gt;
&lt;br /&gt;
=== Backend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Teams filtering in index:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; filtering support.&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt; filtering support (&amp;lt;code&amp;gt;AssignmentTeam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MentoredTeam&amp;lt;/code&amp;gt;, etc.).&lt;br /&gt;
#* Added deterministic ordering by &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Added eager loading with users and team-participant associations.&lt;br /&gt;
# Team serialization:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; in team JSON payload for hierarchy-aware consumers.&lt;br /&gt;
# Backward-compatible params:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; acceptance in team params.&lt;br /&gt;
#* Preserved compatibility by mapping &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; when needed.&lt;br /&gt;
&lt;br /&gt;
=== Backend code snippet ===&lt;br /&gt;
&lt;br /&gt;
The following code snippet shows the core backend change that made the teams API hierarchy-aware:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
	@teams = Team.includes(:users, { teams_participants: :participant })&lt;br /&gt;
&lt;br /&gt;
	if params[:parent_id].present?&lt;br /&gt;
		@teams = @teams.where(parent_id: params[:parent_id])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if params[:types].present?&lt;br /&gt;
		requested_types = params[:types].is_a?(Array) ? params[:types] : params[:types].to_s.split(',')&lt;br /&gt;
		normalized_types = requested_types.map(&amp;amp;:strip).reject(&amp;amp;:blank?)&lt;br /&gt;
		@teams = @teams.where(type: normalized_types) if normalized_types.any?&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	@teams = @teams.order(:name, :id)&lt;br /&gt;
	render json: @teams, each_serializer: TeamSerializer&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frontend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Added dedicated Create Teams loader:&lt;br /&gt;
#* Loads teams using assignment context and allowed team types.&lt;br /&gt;
#* Loads assignment participants.&lt;br /&gt;
#* Maps API data into &amp;lt;code&amp;gt;initialTeams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialUnassigned&amp;lt;/code&amp;gt; structures required by the view.&lt;br /&gt;
# Route wiring:&lt;br /&gt;
#* Create Teams route switched to the new loader so it uses real backend data instead of fallback-only behavior.&lt;br /&gt;
&lt;br /&gt;
=== Real-data verification ===&lt;br /&gt;
&lt;br /&gt;
Verified against DB via Docker Rails runner for Assignment id &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Team 1 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** cameron_fahey / Prince Langosh VM&lt;br /&gt;
** rickie.hamill / Rep. Rosena Paucek&lt;br /&gt;
** elease / Myrl Durgan&lt;br /&gt;
* Team 9 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** jacinda / Joshua Raynor&lt;br /&gt;
** lydia.monahan / Edward Jacobi&lt;br /&gt;
** eddie / Halley Schinner VM&lt;br /&gt;
&lt;br /&gt;
This confirmed end-to-end data correctness for the team hierarchy view.&lt;br /&gt;
&lt;br /&gt;
=== Significance of these changes ===&lt;br /&gt;
&lt;br /&gt;
These changes are significant because they move the teams view away from static or fallback-only data and make it reflect the real assignment context from the database. By filtering teams using &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt;, the backend now returns only the teams that actually belong to the selected hierarchy context. The eager loading also improves efficiency by reducing unnecessary queries when team members are rendered.&lt;br /&gt;
&lt;br /&gt;
From a design perspective, this aligns the teams view with the overall E2608 objective of removing unnecessary hierarchy plumbing and replacing it with direct association-based queries and hierarchy-ready responses. It also makes the frontend easier to validate, because the displayed team-member relationships now match the actual persisted data instead of a page-specific mock structure.&lt;br /&gt;
&lt;br /&gt;
== Verification and Testing ==&lt;br /&gt;
&lt;br /&gt;
The hosted deployment for our project is available at:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://152.7.177.90:3000/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Course -&amp;gt; Assignment Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in to the hosted system and navigate to the Courses page. Verify that a course row can be expanded to display the assignments that belong to that course. Also verify that after deleting an assignment, the assignment list updates correctly within the course hierarchy.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Questionnaire Type -&amp;gt; Questionnaire Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in as an administrator and navigate to the Questionnaires page. Verify that questionnaire types are shown as parent categories and that each type can be expanded to display the questionnaires in that category. Also verify that the admin workflow for creating, editing, updating, and deleting questionnaires works correctly for the supported questionnaire types.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Team -&amp;gt; Team Member Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Navigate to an assignment's Create Teams page and verify that the page displays real team data rather than fallback sample data. For Assignment &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, verify that Team 1 and Team 9 are shown with the correct members, and confirm that the correct members appear under the correct team for the selected assignment context.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Expertiza GitHub repository&lt;br /&gt;
* Expertiza project wiki&lt;br /&gt;
* RSpec documentation&lt;br /&gt;
* Vitest documentation&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167667</id>
		<title>CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167667"/>
		<updated>2026-03-31T03:06:34Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Project Description (E2608) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
'''Mentors:''' Ed Gehringer and Akhilsai Chittipolu&lt;br /&gt;
&lt;br /&gt;
This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
The requirement for E2608 was to implement hierarchical list rendering in a consistent pattern across major modules.&lt;br /&gt;
&lt;br /&gt;
Required hierarchy views:&lt;br /&gt;
&lt;br /&gt;
* Course -&amp;gt; Assignments&lt;br /&gt;
* Questionnaire Type -&amp;gt; Questionnaires&lt;br /&gt;
* Team -&amp;gt; Team Members&lt;br /&gt;
&lt;br /&gt;
The goal was to avoid one-off custom node components and instead apply a reusable hierarchical table pattern.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
&lt;br /&gt;
Expertiza frequently displays hierarchical data:&lt;br /&gt;
&lt;br /&gt;
* Courses with nested assignments&lt;br /&gt;
* Questionnaire types with nested questionnaires&lt;br /&gt;
* Courses/assignments with nested teams and team members&lt;br /&gt;
&lt;br /&gt;
Historically, these hierarchies were represented with a Node superstructure where each entity had an associated Node and parent pointer. This introduced additional object management and coupling that was not strictly necessary for rendering parent-child lists.&lt;br /&gt;
&lt;br /&gt;
The project objective was to design and implement a reusable hierarchical display template where:&lt;br /&gt;
&lt;br /&gt;
* Backend performs direct database queries for parent and child data.&lt;br /&gt;
* Backend returns JSON payloads suitable for hierarchy rendering.&lt;br /&gt;
* Frontend applies a common expandable-list pattern while allowing view-specific presentation styles.&lt;br /&gt;
&lt;br /&gt;
In short, the project moves hierarchy rendering from Node-centric wiring to query-and-render patterns for maintainability and consistency.&lt;br /&gt;
&lt;br /&gt;
== Current Implementation (Before E2608) ==&lt;br /&gt;
&lt;br /&gt;
Before this work, hierarchical data existed in the domain model but was not consistently presented as a parent-child UI pattern across modules.&lt;br /&gt;
&lt;br /&gt;
Typical behavior before E2608:&lt;br /&gt;
&lt;br /&gt;
* Different pages used different data-loading styles, including separate API fetches for related entities.&lt;br /&gt;
* Some views depended on fallback/static sample structures when complete nested payloads were unavailable.&lt;br /&gt;
* Parent-child relationships were not always exposed in a way that made generic expandable tables straightforward.&lt;br /&gt;
* Hierarchical behavior varied by page rather than following one reusable template.&lt;br /&gt;
&lt;br /&gt;
== Drawbacks in Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
The pre-E2608 behavior created several practical issues:&lt;br /&gt;
&lt;br /&gt;
* Inconsistent user experience: hierarchy expansion behavior differed across pages.&lt;br /&gt;
* Additional client complexity: pages needed extra mapping/fetch orchestration to build nested displays.&lt;br /&gt;
* Higher coupling to page-specific logic instead of reusable table patterns.&lt;br /&gt;
* Harder validation against real backend hierarchy data in some flows.&lt;br /&gt;
* More chance of stale UI state when child lists were refetched separately.&lt;br /&gt;
&lt;br /&gt;
== Shared Team Architecture Decision ==&lt;br /&gt;
&lt;br /&gt;
Before implementation, the team agreed on a common hierarchy approach:&lt;br /&gt;
&lt;br /&gt;
* Use eager loading on the backend to fetch parent-child data in fewer queries.&lt;br /&gt;
* Return hierarchy-ready JSON (parents with embedded child collections) so frontend pages do minimal reshaping.&lt;br /&gt;
* Keep a consistent UX goal for expandable/collapsible hierarchy views, while allowing page-specific rendering style (table expansion or embedded dropdown lists).&lt;br /&gt;
&lt;br /&gt;
This shared approach keeps data retrieval efficient and makes hierarchy rendering consistent with the mentor's requested template style, without forcing a single UI widget across all pages.&lt;br /&gt;
&lt;br /&gt;
== Our Contribution ==&lt;br /&gt;
&lt;br /&gt;
We implemented a unified hierarchical-list strategy across three views and aligned backend payloads with frontend rendering needs.&lt;br /&gt;
&lt;br /&gt;
Summary of what we delivered:&lt;br /&gt;
&lt;br /&gt;
* Unified parent-child rendering approach for three major modules.&lt;br /&gt;
* Backend responses shaped to support hierarchy directly, with eager-loaded associations where applicable.&lt;br /&gt;
* Frontend pages updated to consume nested or hierarchy-aware data using view-appropriate UI patterns.&lt;br /&gt;
* Verification using both UI behavior and real database checks.&lt;br /&gt;
&lt;br /&gt;
== View 1: Course -&amp;gt; Assignment Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display assignments nested under their parent courses without CourseNode/AssignmentNode style custom hierarchy components.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Backend updated to return courses with associated assignments in one response.&lt;br /&gt;
* Frontend updated to consume nested assignment data from course payload.&lt;br /&gt;
* Frontend no longer depends on separate all-assignments fetch for this view.&lt;br /&gt;
* Minor delete-flow refinement: after successful assignment delete, assignment is removed from local frontend data instead of refetching assignments only.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Course rows can expand into assignment lists through the common hierarchy pattern.&lt;br /&gt;
&lt;br /&gt;
== View 2: Questionnaire Type -&amp;gt; Questionnaire Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Group questionnaires by questionnaire type and display questionnaires nested under each type.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Implemented hierarchical questionnaire list from the Admin view.&lt;br /&gt;
* Admin can create, edit, update, and delete questionnaires in these types:&lt;br /&gt;
** Review&lt;br /&gt;
** Metareview&lt;br /&gt;
** Author feedback&lt;br /&gt;
** Teammate Review&lt;br /&gt;
** Survey&lt;br /&gt;
** Assignment survey&lt;br /&gt;
** Global survey&lt;br /&gt;
** Course survey&lt;br /&gt;
** Bookmark rating&lt;br /&gt;
** Quiz&lt;br /&gt;
* In questionnaire listing, admin can expand a dropdown per type to see the embedded list of questionnaire instances for that category.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Questionnaire browsing follows the same parent-child model used in the other E2608 modules.&lt;br /&gt;
&lt;br /&gt;
== View 3: Team -&amp;gt; Team Member Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display team members nested under teams for a selected assignment context using real backend data.&lt;br /&gt;
&lt;br /&gt;
=== Backend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Teams filtering in index:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; filtering support.&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt; filtering support (&amp;lt;code&amp;gt;AssignmentTeam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MentoredTeam&amp;lt;/code&amp;gt;, etc.).&lt;br /&gt;
#* Added deterministic ordering by &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Added eager loading with users and team-participant associations.&lt;br /&gt;
# Team serialization:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; in team JSON payload for hierarchy-aware consumers.&lt;br /&gt;
# Backward-compatible params:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; acceptance in team params.&lt;br /&gt;
#* Preserved compatibility by mapping &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; when needed.&lt;br /&gt;
&lt;br /&gt;
=== Backend code snippet ===&lt;br /&gt;
&lt;br /&gt;
The following code snippet shows the core backend change that made the teams API hierarchy-aware:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
	@teams = Team.includes(:users, { teams_participants: :participant })&lt;br /&gt;
&lt;br /&gt;
	if params[:parent_id].present?&lt;br /&gt;
		@teams = @teams.where(parent_id: params[:parent_id])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if params[:types].present?&lt;br /&gt;
		requested_types = params[:types].is_a?(Array) ? params[:types] : params[:types].to_s.split(',')&lt;br /&gt;
		normalized_types = requested_types.map(&amp;amp;:strip).reject(&amp;amp;:blank?)&lt;br /&gt;
		@teams = @teams.where(type: normalized_types) if normalized_types.any?&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	@teams = @teams.order(:name, :id)&lt;br /&gt;
	render json: @teams, each_serializer: TeamSerializer&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frontend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Added dedicated Create Teams loader:&lt;br /&gt;
#* Loads teams using assignment context and allowed team types.&lt;br /&gt;
#* Loads assignment participants.&lt;br /&gt;
#* Maps API data into &amp;lt;code&amp;gt;initialTeams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialUnassigned&amp;lt;/code&amp;gt; structures required by the view.&lt;br /&gt;
# Route wiring:&lt;br /&gt;
#* Create Teams route switched to the new loader so it uses real backend data instead of fallback-only behavior.&lt;br /&gt;
&lt;br /&gt;
=== Real-data verification ===&lt;br /&gt;
&lt;br /&gt;
Verified against DB via Docker Rails runner for Assignment id &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Team 1 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** cameron_fahey / Prince Langosh VM&lt;br /&gt;
** rickie.hamill / Rep. Rosena Paucek&lt;br /&gt;
** elease / Myrl Durgan&lt;br /&gt;
* Team 9 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** jacinda / Joshua Raynor&lt;br /&gt;
** lydia.monahan / Edward Jacobi&lt;br /&gt;
** eddie / Halley Schinner VM&lt;br /&gt;
&lt;br /&gt;
This confirmed end-to-end data correctness for the team hierarchy view.&lt;br /&gt;
&lt;br /&gt;
=== Significance of these changes ===&lt;br /&gt;
&lt;br /&gt;
These changes are significant because they move the teams view away from static or fallback-only data and make it reflect the real assignment context from the database. By filtering teams using &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt;, the backend now returns only the teams that actually belong to the selected hierarchy context. The eager loading also improves efficiency by reducing unnecessary queries when team members are rendered.&lt;br /&gt;
&lt;br /&gt;
From a design perspective, this aligns the teams view with the overall E2608 objective of removing unnecessary hierarchy plumbing and replacing it with direct association-based queries and hierarchy-ready responses. It also makes the frontend easier to validate, because the displayed team-member relationships now match the actual persisted data instead of a page-specific mock structure.&lt;br /&gt;
&lt;br /&gt;
== Verification and Testing ==&lt;br /&gt;
&lt;br /&gt;
The hosted deployment for our project is available at:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://152.7.177.90:3000/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Course -&amp;gt; Assignment Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in to the hosted system and navigate to the Courses page. Verify that a course row can be expanded to display the assignments that belong to that course. Also verify that after deleting an assignment, the assignment list updates correctly within the course hierarchy.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Questionnaire Type -&amp;gt; Questionnaire Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in as an administrator and navigate to the Questionnaires page. Verify that questionnaire types are shown as parent categories and that each type can be expanded to display the questionnaires in that category. Also verify that the admin workflow for creating, editing, updating, and deleting questionnaires works correctly for the supported questionnaire types.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Team -&amp;gt; Team Member Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Navigate to an assignment's Create Teams page and verify that the page displays real team data rather than fallback sample data. For Assignment &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, verify that Team 1 and Team 9 are shown with the correct members, and confirm that the correct members appear under the correct team for the selected assignment context.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Expertiza GitHub repository&lt;br /&gt;
* Expertiza project wiki&lt;br /&gt;
* RSpec documentation&lt;br /&gt;
* Vitest documentation&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167664</id>
		<title>CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167664"/>
		<updated>2026-03-31T02:56:56Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Problem Statement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
'''Mentors:''' Ed Gehringer and Akhilsai Chittipolu&lt;br /&gt;
&lt;br /&gt;
This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
The requirement for E2608 was to implement hierarchical list rendering in a consistent pattern across major modules.&lt;br /&gt;
&lt;br /&gt;
Required hierarchy views:&lt;br /&gt;
&lt;br /&gt;
* Course -&amp;gt; Assignments&lt;br /&gt;
* Questionnaire Type -&amp;gt; Questionnaires&lt;br /&gt;
* Team -&amp;gt; Team Members&lt;br /&gt;
&lt;br /&gt;
The goal was to avoid one-off custom node components and instead apply a reusable hierarchical table pattern.&lt;br /&gt;
&lt;br /&gt;
== Project Description (E2608) ==&lt;br /&gt;
&lt;br /&gt;
Expertiza frequently displays hierarchical data:&lt;br /&gt;
&lt;br /&gt;
* Courses with nested assignments&lt;br /&gt;
* Questionnaire types with nested questionnaires&lt;br /&gt;
* Courses/assignments with nested teams and team members&lt;br /&gt;
&lt;br /&gt;
Historically, these hierarchies were represented with a Node superstructure where each entity had an associated Node and parent pointer. This introduced additional object management and coupling that was not strictly necessary for rendering parent-child lists.&lt;br /&gt;
&lt;br /&gt;
The project objective was to design and implement a reusable hierarchical display template where:&lt;br /&gt;
&lt;br /&gt;
* Backend performs direct database queries for parent and child data.&lt;br /&gt;
* Backend returns JSON payloads suitable for hierarchy rendering.&lt;br /&gt;
* Frontend applies a common expandable-list pattern while allowing view-specific presentation styles.&lt;br /&gt;
&lt;br /&gt;
In short, the project moves hierarchy rendering from Node-centric wiring to query-and-render patterns for maintainability and consistency.&lt;br /&gt;
&lt;br /&gt;
== Current Implementation (Before E2608) ==&lt;br /&gt;
&lt;br /&gt;
Before this work, hierarchical data existed in the domain model but was not consistently presented as a parent-child UI pattern across modules.&lt;br /&gt;
&lt;br /&gt;
Typical behavior before E2608:&lt;br /&gt;
&lt;br /&gt;
* Different pages used different data-loading styles, including separate API fetches for related entities.&lt;br /&gt;
* Some views depended on fallback/static sample structures when complete nested payloads were unavailable.&lt;br /&gt;
* Parent-child relationships were not always exposed in a way that made generic expandable tables straightforward.&lt;br /&gt;
* Hierarchical behavior varied by page rather than following one reusable template.&lt;br /&gt;
&lt;br /&gt;
== Drawbacks in Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
The pre-E2608 behavior created several practical issues:&lt;br /&gt;
&lt;br /&gt;
* Inconsistent user experience: hierarchy expansion behavior differed across pages.&lt;br /&gt;
* Additional client complexity: pages needed extra mapping/fetch orchestration to build nested displays.&lt;br /&gt;
* Higher coupling to page-specific logic instead of reusable table patterns.&lt;br /&gt;
* Harder validation against real backend hierarchy data in some flows.&lt;br /&gt;
* More chance of stale UI state when child lists were refetched separately.&lt;br /&gt;
&lt;br /&gt;
== Shared Team Architecture Decision ==&lt;br /&gt;
&lt;br /&gt;
Before implementation, the team agreed on a common hierarchy approach:&lt;br /&gt;
&lt;br /&gt;
* Use eager loading on the backend to fetch parent-child data in fewer queries.&lt;br /&gt;
* Return hierarchy-ready JSON (parents with embedded child collections) so frontend pages do minimal reshaping.&lt;br /&gt;
* Keep a consistent UX goal for expandable/collapsible hierarchy views, while allowing page-specific rendering style (table expansion or embedded dropdown lists).&lt;br /&gt;
&lt;br /&gt;
This shared approach keeps data retrieval efficient and makes hierarchy rendering consistent with the mentor's requested template style, without forcing a single UI widget across all pages.&lt;br /&gt;
&lt;br /&gt;
== Our Contribution ==&lt;br /&gt;
&lt;br /&gt;
We implemented a unified hierarchical-list strategy across three views and aligned backend payloads with frontend rendering needs.&lt;br /&gt;
&lt;br /&gt;
Summary of what we delivered:&lt;br /&gt;
&lt;br /&gt;
* Unified parent-child rendering approach for three major modules.&lt;br /&gt;
* Backend responses shaped to support hierarchy directly, with eager-loaded associations where applicable.&lt;br /&gt;
* Frontend pages updated to consume nested or hierarchy-aware data using view-appropriate UI patterns.&lt;br /&gt;
* Verification using both UI behavior and real database checks.&lt;br /&gt;
&lt;br /&gt;
== View 1: Course -&amp;gt; Assignment Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display assignments nested under their parent courses without CourseNode/AssignmentNode style custom hierarchy components.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Backend updated to return courses with associated assignments in one response.&lt;br /&gt;
* Frontend updated to consume nested assignment data from course payload.&lt;br /&gt;
* Frontend no longer depends on separate all-assignments fetch for this view.&lt;br /&gt;
* Minor delete-flow refinement: after successful assignment delete, assignment is removed from local frontend data instead of refetching assignments only.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Course rows can expand into assignment lists through the common hierarchy pattern.&lt;br /&gt;
&lt;br /&gt;
== View 2: Questionnaire Type -&amp;gt; Questionnaire Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Group questionnaires by questionnaire type and display questionnaires nested under each type.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Implemented hierarchical questionnaire list from the Admin view.&lt;br /&gt;
* Admin can create, edit, update, and delete questionnaires in these types:&lt;br /&gt;
** Review&lt;br /&gt;
** Metareview&lt;br /&gt;
** Author feedback&lt;br /&gt;
** Teammate Review&lt;br /&gt;
** Survey&lt;br /&gt;
** Assignment survey&lt;br /&gt;
** Global survey&lt;br /&gt;
** Course survey&lt;br /&gt;
** Bookmark rating&lt;br /&gt;
** Quiz&lt;br /&gt;
* In questionnaire listing, admin can expand a dropdown per type to see the embedded list of questionnaire instances for that category.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Questionnaire browsing follows the same parent-child model used in the other E2608 modules.&lt;br /&gt;
&lt;br /&gt;
== View 3: Team -&amp;gt; Team Member Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display team members nested under teams for a selected assignment context using real backend data.&lt;br /&gt;
&lt;br /&gt;
=== Backend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Teams filtering in index:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; filtering support.&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt; filtering support (&amp;lt;code&amp;gt;AssignmentTeam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MentoredTeam&amp;lt;/code&amp;gt;, etc.).&lt;br /&gt;
#* Added deterministic ordering by &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Added eager loading with users and team-participant associations.&lt;br /&gt;
# Team serialization:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; in team JSON payload for hierarchy-aware consumers.&lt;br /&gt;
# Backward-compatible params:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; acceptance in team params.&lt;br /&gt;
#* Preserved compatibility by mapping &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; when needed.&lt;br /&gt;
&lt;br /&gt;
=== Backend code snippet ===&lt;br /&gt;
&lt;br /&gt;
The following code snippet shows the core backend change that made the teams API hierarchy-aware:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
	@teams = Team.includes(:users, { teams_participants: :participant })&lt;br /&gt;
&lt;br /&gt;
	if params[:parent_id].present?&lt;br /&gt;
		@teams = @teams.where(parent_id: params[:parent_id])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if params[:types].present?&lt;br /&gt;
		requested_types = params[:types].is_a?(Array) ? params[:types] : params[:types].to_s.split(',')&lt;br /&gt;
		normalized_types = requested_types.map(&amp;amp;:strip).reject(&amp;amp;:blank?)&lt;br /&gt;
		@teams = @teams.where(type: normalized_types) if normalized_types.any?&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	@teams = @teams.order(:name, :id)&lt;br /&gt;
	render json: @teams, each_serializer: TeamSerializer&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frontend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Added dedicated Create Teams loader:&lt;br /&gt;
#* Loads teams using assignment context and allowed team types.&lt;br /&gt;
#* Loads assignment participants.&lt;br /&gt;
#* Maps API data into &amp;lt;code&amp;gt;initialTeams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialUnassigned&amp;lt;/code&amp;gt; structures required by the view.&lt;br /&gt;
# Route wiring:&lt;br /&gt;
#* Create Teams route switched to the new loader so it uses real backend data instead of fallback-only behavior.&lt;br /&gt;
&lt;br /&gt;
=== Real-data verification ===&lt;br /&gt;
&lt;br /&gt;
Verified against DB via Docker Rails runner for Assignment id &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Team 1 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** cameron_fahey / Prince Langosh VM&lt;br /&gt;
** rickie.hamill / Rep. Rosena Paucek&lt;br /&gt;
** elease / Myrl Durgan&lt;br /&gt;
* Team 9 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** jacinda / Joshua Raynor&lt;br /&gt;
** lydia.monahan / Edward Jacobi&lt;br /&gt;
** eddie / Halley Schinner VM&lt;br /&gt;
&lt;br /&gt;
This confirmed end-to-end data correctness for the team hierarchy view.&lt;br /&gt;
&lt;br /&gt;
=== Significance of these changes ===&lt;br /&gt;
&lt;br /&gt;
These changes are significant because they move the teams view away from static or fallback-only data and make it reflect the real assignment context from the database. By filtering teams using &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt;, the backend now returns only the teams that actually belong to the selected hierarchy context. The eager loading also improves efficiency by reducing unnecessary queries when team members are rendered.&lt;br /&gt;
&lt;br /&gt;
From a design perspective, this aligns the teams view with the overall E2608 objective of removing unnecessary hierarchy plumbing and replacing it with direct association-based queries and hierarchy-ready responses. It also makes the frontend easier to validate, because the displayed team-member relationships now match the actual persisted data instead of a page-specific mock structure.&lt;br /&gt;
&lt;br /&gt;
== Verification and Testing ==&lt;br /&gt;
&lt;br /&gt;
The hosted deployment for our project is available at:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://152.7.177.90:3000/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Course -&amp;gt; Assignment Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in to the hosted system and navigate to the Courses page. Verify that a course row can be expanded to display the assignments that belong to that course. Also verify that after deleting an assignment, the assignment list updates correctly within the course hierarchy.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Questionnaire Type -&amp;gt; Questionnaire Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in as an administrator and navigate to the Questionnaires page. Verify that questionnaire types are shown as parent categories and that each type can be expanded to display the questionnaires in that category. Also verify that the admin workflow for creating, editing, updating, and deleting questionnaires works correctly for the supported questionnaire types.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Team -&amp;gt; Team Member Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Navigate to an assignment's Create Teams page and verify that the page displays real team data rather than fallback sample data. For Assignment &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, verify that Team 1 and Team 9 are shown with the correct members, and confirm that the correct members appear under the correct team for the selected assignment context.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Expertiza GitHub repository&lt;br /&gt;
* Expertiza project wiki&lt;br /&gt;
* RSpec documentation&lt;br /&gt;
* Vitest documentation&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167663</id>
		<title>CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167663"/>
		<updated>2026-03-31T02:56:41Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
'''Mentors:''' Ed Gehringer and Akhilsai Chittipolu&lt;br /&gt;
&lt;br /&gt;
This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
The mentor requirement for E2608 was to implement hierarchical list rendering in a consistent pattern across major modules.&lt;br /&gt;
&lt;br /&gt;
Required hierarchy views:&lt;br /&gt;
&lt;br /&gt;
* Course -&amp;gt; Assignments&lt;br /&gt;
* Questionnaire Type -&amp;gt; Questionnaires&lt;br /&gt;
* Team -&amp;gt; Team Members&lt;br /&gt;
&lt;br /&gt;
The goal was to avoid one-off custom node components and instead apply a reusable hierarchical table pattern.&lt;br /&gt;
&lt;br /&gt;
== Project Description (E2608) ==&lt;br /&gt;
&lt;br /&gt;
Expertiza frequently displays hierarchical data:&lt;br /&gt;
&lt;br /&gt;
* Courses with nested assignments&lt;br /&gt;
* Questionnaire types with nested questionnaires&lt;br /&gt;
* Courses/assignments with nested teams and team members&lt;br /&gt;
&lt;br /&gt;
Historically, these hierarchies were represented with a Node superstructure where each entity had an associated Node and parent pointer. This introduced additional object management and coupling that was not strictly necessary for rendering parent-child lists.&lt;br /&gt;
&lt;br /&gt;
The project objective was to design and implement a reusable hierarchical display template where:&lt;br /&gt;
&lt;br /&gt;
* Backend performs direct database queries for parent and child data.&lt;br /&gt;
* Backend returns JSON payloads suitable for hierarchy rendering.&lt;br /&gt;
* Frontend applies a common expandable-list pattern while allowing view-specific presentation styles.&lt;br /&gt;
&lt;br /&gt;
In short, the project moves hierarchy rendering from Node-centric wiring to query-and-render patterns for maintainability and consistency.&lt;br /&gt;
&lt;br /&gt;
== Current Implementation (Before E2608) ==&lt;br /&gt;
&lt;br /&gt;
Before this work, hierarchical data existed in the domain model but was not consistently presented as a parent-child UI pattern across modules.&lt;br /&gt;
&lt;br /&gt;
Typical behavior before E2608:&lt;br /&gt;
&lt;br /&gt;
* Different pages used different data-loading styles, including separate API fetches for related entities.&lt;br /&gt;
* Some views depended on fallback/static sample structures when complete nested payloads were unavailable.&lt;br /&gt;
* Parent-child relationships were not always exposed in a way that made generic expandable tables straightforward.&lt;br /&gt;
* Hierarchical behavior varied by page rather than following one reusable template.&lt;br /&gt;
&lt;br /&gt;
== Drawbacks in Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
The pre-E2608 behavior created several practical issues:&lt;br /&gt;
&lt;br /&gt;
* Inconsistent user experience: hierarchy expansion behavior differed across pages.&lt;br /&gt;
* Additional client complexity: pages needed extra mapping/fetch orchestration to build nested displays.&lt;br /&gt;
* Higher coupling to page-specific logic instead of reusable table patterns.&lt;br /&gt;
* Harder validation against real backend hierarchy data in some flows.&lt;br /&gt;
* More chance of stale UI state when child lists were refetched separately.&lt;br /&gt;
&lt;br /&gt;
== Shared Team Architecture Decision ==&lt;br /&gt;
&lt;br /&gt;
Before implementation, the team agreed on a common hierarchy approach:&lt;br /&gt;
&lt;br /&gt;
* Use eager loading on the backend to fetch parent-child data in fewer queries.&lt;br /&gt;
* Return hierarchy-ready JSON (parents with embedded child collections) so frontend pages do minimal reshaping.&lt;br /&gt;
* Keep a consistent UX goal for expandable/collapsible hierarchy views, while allowing page-specific rendering style (table expansion or embedded dropdown lists).&lt;br /&gt;
&lt;br /&gt;
This shared approach keeps data retrieval efficient and makes hierarchy rendering consistent with the mentor's requested template style, without forcing a single UI widget across all pages.&lt;br /&gt;
&lt;br /&gt;
== Our Contribution ==&lt;br /&gt;
&lt;br /&gt;
We implemented a unified hierarchical-list strategy across three views and aligned backend payloads with frontend rendering needs.&lt;br /&gt;
&lt;br /&gt;
Summary of what we delivered:&lt;br /&gt;
&lt;br /&gt;
* Unified parent-child rendering approach for three major modules.&lt;br /&gt;
* Backend responses shaped to support hierarchy directly, with eager-loaded associations where applicable.&lt;br /&gt;
* Frontend pages updated to consume nested or hierarchy-aware data using view-appropriate UI patterns.&lt;br /&gt;
* Verification using both UI behavior and real database checks.&lt;br /&gt;
&lt;br /&gt;
== View 1: Course -&amp;gt; Assignment Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display assignments nested under their parent courses without CourseNode/AssignmentNode style custom hierarchy components.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Backend updated to return courses with associated assignments in one response.&lt;br /&gt;
* Frontend updated to consume nested assignment data from course payload.&lt;br /&gt;
* Frontend no longer depends on separate all-assignments fetch for this view.&lt;br /&gt;
* Minor delete-flow refinement: after successful assignment delete, assignment is removed from local frontend data instead of refetching assignments only.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Course rows can expand into assignment lists through the common hierarchy pattern.&lt;br /&gt;
&lt;br /&gt;
== View 2: Questionnaire Type -&amp;gt; Questionnaire Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Group questionnaires by questionnaire type and display questionnaires nested under each type.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Implemented hierarchical questionnaire list from the Admin view.&lt;br /&gt;
* Admin can create, edit, update, and delete questionnaires in these types:&lt;br /&gt;
** Review&lt;br /&gt;
** Metareview&lt;br /&gt;
** Author feedback&lt;br /&gt;
** Teammate Review&lt;br /&gt;
** Survey&lt;br /&gt;
** Assignment survey&lt;br /&gt;
** Global survey&lt;br /&gt;
** Course survey&lt;br /&gt;
** Bookmark rating&lt;br /&gt;
** Quiz&lt;br /&gt;
* In questionnaire listing, admin can expand a dropdown per type to see the embedded list of questionnaire instances for that category.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Questionnaire browsing follows the same parent-child model used in the other E2608 modules.&lt;br /&gt;
&lt;br /&gt;
== View 3: Team -&amp;gt; Team Member Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display team members nested under teams for a selected assignment context using real backend data.&lt;br /&gt;
&lt;br /&gt;
=== Backend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Teams filtering in index:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; filtering support.&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt; filtering support (&amp;lt;code&amp;gt;AssignmentTeam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MentoredTeam&amp;lt;/code&amp;gt;, etc.).&lt;br /&gt;
#* Added deterministic ordering by &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Added eager loading with users and team-participant associations.&lt;br /&gt;
# Team serialization:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; in team JSON payload for hierarchy-aware consumers.&lt;br /&gt;
# Backward-compatible params:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; acceptance in team params.&lt;br /&gt;
#* Preserved compatibility by mapping &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; when needed.&lt;br /&gt;
&lt;br /&gt;
=== Backend code snippet ===&lt;br /&gt;
&lt;br /&gt;
The following code snippet shows the core backend change that made the teams API hierarchy-aware:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
	@teams = Team.includes(:users, { teams_participants: :participant })&lt;br /&gt;
&lt;br /&gt;
	if params[:parent_id].present?&lt;br /&gt;
		@teams = @teams.where(parent_id: params[:parent_id])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if params[:types].present?&lt;br /&gt;
		requested_types = params[:types].is_a?(Array) ? params[:types] : params[:types].to_s.split(',')&lt;br /&gt;
		normalized_types = requested_types.map(&amp;amp;:strip).reject(&amp;amp;:blank?)&lt;br /&gt;
		@teams = @teams.where(type: normalized_types) if normalized_types.any?&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	@teams = @teams.order(:name, :id)&lt;br /&gt;
	render json: @teams, each_serializer: TeamSerializer&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frontend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Added dedicated Create Teams loader:&lt;br /&gt;
#* Loads teams using assignment context and allowed team types.&lt;br /&gt;
#* Loads assignment participants.&lt;br /&gt;
#* Maps API data into &amp;lt;code&amp;gt;initialTeams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialUnassigned&amp;lt;/code&amp;gt; structures required by the view.&lt;br /&gt;
# Route wiring:&lt;br /&gt;
#* Create Teams route switched to the new loader so it uses real backend data instead of fallback-only behavior.&lt;br /&gt;
&lt;br /&gt;
=== Real-data verification ===&lt;br /&gt;
&lt;br /&gt;
Verified against DB via Docker Rails runner for Assignment id &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Team 1 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** cameron_fahey / Prince Langosh VM&lt;br /&gt;
** rickie.hamill / Rep. Rosena Paucek&lt;br /&gt;
** elease / Myrl Durgan&lt;br /&gt;
* Team 9 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** jacinda / Joshua Raynor&lt;br /&gt;
** lydia.monahan / Edward Jacobi&lt;br /&gt;
** eddie / Halley Schinner VM&lt;br /&gt;
&lt;br /&gt;
This confirmed end-to-end data correctness for the team hierarchy view.&lt;br /&gt;
&lt;br /&gt;
=== Significance of these changes ===&lt;br /&gt;
&lt;br /&gt;
These changes are significant because they move the teams view away from static or fallback-only data and make it reflect the real assignment context from the database. By filtering teams using &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt;, the backend now returns only the teams that actually belong to the selected hierarchy context. The eager loading also improves efficiency by reducing unnecessary queries when team members are rendered.&lt;br /&gt;
&lt;br /&gt;
From a design perspective, this aligns the teams view with the overall E2608 objective of removing unnecessary hierarchy plumbing and replacing it with direct association-based queries and hierarchy-ready responses. It also makes the frontend easier to validate, because the displayed team-member relationships now match the actual persisted data instead of a page-specific mock structure.&lt;br /&gt;
&lt;br /&gt;
== Verification and Testing ==&lt;br /&gt;
&lt;br /&gt;
The hosted deployment for our project is available at:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://152.7.177.90:3000/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Course -&amp;gt; Assignment Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in to the hosted system and navigate to the Courses page. Verify that a course row can be expanded to display the assignments that belong to that course. Also verify that after deleting an assignment, the assignment list updates correctly within the course hierarchy.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Questionnaire Type -&amp;gt; Questionnaire Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in as an administrator and navigate to the Questionnaires page. Verify that questionnaire types are shown as parent categories and that each type can be expanded to display the questionnaires in that category. Also verify that the admin workflow for creating, editing, updating, and deleting questionnaires works correctly for the supported questionnaire types.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Team -&amp;gt; Team Member Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Navigate to an assignment's Create Teams page and verify that the page displays real team data rather than fallback sample data. For Assignment &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, verify that Team 1 and Team 9 are shown with the correct members, and confirm that the correct members appear under the correct team for the selected assignment context.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Expertiza GitHub repository&lt;br /&gt;
* Expertiza project wiki&lt;br /&gt;
* RSpec documentation&lt;br /&gt;
* Vitest documentation&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167661</id>
		<title>CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167661"/>
		<updated>2026-03-31T02:54:47Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* View 3: Team -&amp;gt; Team Member Hierarchy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
'''Mentors:''' Ed Gehringer and Akhilsai Chittipolu&lt;br /&gt;
&lt;br /&gt;
This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== About Expertiza ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source Ruby on Rails platform for assignment management, team formation, topic signup, submissions, and peer review workflows. The system supports multiple user roles (students, TAs, instructors, admins) and complex assignment structures.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
The mentor requirement for E2608 was to implement hierarchical list rendering in a consistent pattern across major modules.&lt;br /&gt;
&lt;br /&gt;
Required hierarchy views:&lt;br /&gt;
&lt;br /&gt;
* Course -&amp;gt; Assignments&lt;br /&gt;
* Questionnaire Type -&amp;gt; Questionnaires&lt;br /&gt;
* Team -&amp;gt; Team Members&lt;br /&gt;
&lt;br /&gt;
The goal was to avoid one-off custom node components and instead apply a reusable hierarchical table pattern.&lt;br /&gt;
&lt;br /&gt;
== Project Description (E2608) ==&lt;br /&gt;
&lt;br /&gt;
Expertiza frequently displays hierarchical data:&lt;br /&gt;
&lt;br /&gt;
* Courses with nested assignments&lt;br /&gt;
* Questionnaire types with nested questionnaires&lt;br /&gt;
* Courses/assignments with nested teams and team members&lt;br /&gt;
&lt;br /&gt;
Historically, these hierarchies were represented with a Node superstructure where each entity had an associated Node and parent pointer. This introduced additional object management and coupling that was not strictly necessary for rendering parent-child lists.&lt;br /&gt;
&lt;br /&gt;
The project objective was to design and implement a reusable hierarchical display template where:&lt;br /&gt;
&lt;br /&gt;
* Backend performs direct database queries for parent and child data.&lt;br /&gt;
* Backend returns JSON payloads suitable for hierarchy rendering.&lt;br /&gt;
* Frontend applies a common expandable-list pattern while allowing view-specific presentation styles.&lt;br /&gt;
&lt;br /&gt;
In short, the project moves hierarchy rendering from Node-centric wiring to query-and-render patterns for maintainability and consistency.&lt;br /&gt;
&lt;br /&gt;
== Current Implementation (Before E2608) ==&lt;br /&gt;
&lt;br /&gt;
Before this work, hierarchical data existed in the domain model but was not consistently presented as a parent-child UI pattern across modules.&lt;br /&gt;
&lt;br /&gt;
Typical behavior before E2608:&lt;br /&gt;
&lt;br /&gt;
* Different pages used different data-loading styles, including separate API fetches for related entities.&lt;br /&gt;
* Some views depended on fallback/static sample structures when complete nested payloads were unavailable.&lt;br /&gt;
* Parent-child relationships were not always exposed in a way that made generic expandable tables straightforward.&lt;br /&gt;
* Hierarchical behavior varied by page rather than following one reusable template.&lt;br /&gt;
&lt;br /&gt;
== Drawbacks in Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
The pre-E2608 behavior created several practical issues:&lt;br /&gt;
&lt;br /&gt;
* Inconsistent user experience: hierarchy expansion behavior differed across pages.&lt;br /&gt;
* Additional client complexity: pages needed extra mapping/fetch orchestration to build nested displays.&lt;br /&gt;
* Higher coupling to page-specific logic instead of reusable table patterns.&lt;br /&gt;
* Harder validation against real backend hierarchy data in some flows.&lt;br /&gt;
* More chance of stale UI state when child lists were refetched separately.&lt;br /&gt;
&lt;br /&gt;
== Shared Team Architecture Decision ==&lt;br /&gt;
&lt;br /&gt;
Before implementation, the team agreed on a common hierarchy approach:&lt;br /&gt;
&lt;br /&gt;
* Use eager loading on the backend to fetch parent-child data in fewer queries.&lt;br /&gt;
* Return hierarchy-ready JSON (parents with embedded child collections) so frontend pages do minimal reshaping.&lt;br /&gt;
* Keep a consistent UX goal for expandable/collapsible hierarchy views, while allowing page-specific rendering style (table expansion or embedded dropdown lists).&lt;br /&gt;
&lt;br /&gt;
This shared approach keeps data retrieval efficient and makes hierarchy rendering consistent with the mentor's requested template style, without forcing a single UI widget across all pages.&lt;br /&gt;
&lt;br /&gt;
== Our Contribution ==&lt;br /&gt;
&lt;br /&gt;
We implemented a unified hierarchical-list strategy across three views and aligned backend payloads with frontend rendering needs.&lt;br /&gt;
&lt;br /&gt;
Summary of what we delivered:&lt;br /&gt;
&lt;br /&gt;
* Unified parent-child rendering approach for three major modules.&lt;br /&gt;
* Backend responses shaped to support hierarchy directly, with eager-loaded associations where applicable.&lt;br /&gt;
* Frontend pages updated to consume nested or hierarchy-aware data using view-appropriate UI patterns.&lt;br /&gt;
* Verification using both UI behavior and real database checks.&lt;br /&gt;
&lt;br /&gt;
== View 1: Course -&amp;gt; Assignment Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display assignments nested under their parent courses without CourseNode/AssignmentNode style custom hierarchy components.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Backend updated to return courses with associated assignments in one response.&lt;br /&gt;
* Frontend updated to consume nested assignment data from course payload.&lt;br /&gt;
* Frontend no longer depends on separate all-assignments fetch for this view.&lt;br /&gt;
* Minor delete-flow refinement: after successful assignment delete, assignment is removed from local frontend data instead of refetching assignments only.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Course rows can expand into assignment lists through the common hierarchy pattern.&lt;br /&gt;
&lt;br /&gt;
== View 2: Questionnaire Type -&amp;gt; Questionnaire Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Group questionnaires by questionnaire type and display questionnaires nested under each type.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Implemented hierarchical questionnaire list from the Admin view.&lt;br /&gt;
* Admin can create, edit, update, and delete questionnaires in these types:&lt;br /&gt;
** Review&lt;br /&gt;
** Metareview&lt;br /&gt;
** Author feedback&lt;br /&gt;
** Teammate Review&lt;br /&gt;
** Survey&lt;br /&gt;
** Assignment survey&lt;br /&gt;
** Global survey&lt;br /&gt;
** Course survey&lt;br /&gt;
** Bookmark rating&lt;br /&gt;
** Quiz&lt;br /&gt;
* In questionnaire listing, admin can expand a dropdown per type to see the embedded list of questionnaire instances for that category.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Questionnaire browsing follows the same parent-child model used in the other E2608 modules.&lt;br /&gt;
&lt;br /&gt;
== View 3: Team -&amp;gt; Team Member Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display team members nested under teams for a selected assignment context using real backend data.&lt;br /&gt;
&lt;br /&gt;
=== Backend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Teams filtering in index:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; filtering support.&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt; filtering support (&amp;lt;code&amp;gt;AssignmentTeam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MentoredTeam&amp;lt;/code&amp;gt;, etc.).&lt;br /&gt;
#* Added deterministic ordering by &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Added eager loading with users and team-participant associations.&lt;br /&gt;
# Team serialization:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; in team JSON payload for hierarchy-aware consumers.&lt;br /&gt;
# Backward-compatible params:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; acceptance in team params.&lt;br /&gt;
#* Preserved compatibility by mapping &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; when needed.&lt;br /&gt;
&lt;br /&gt;
=== Backend code snippet ===&lt;br /&gt;
&lt;br /&gt;
The following code snippet shows the core backend change that made the teams API hierarchy-aware:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
	@teams = Team.includes(:users, { teams_participants: :participant })&lt;br /&gt;
&lt;br /&gt;
	if params[:parent_id].present?&lt;br /&gt;
		@teams = @teams.where(parent_id: params[:parent_id])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if params[:types].present?&lt;br /&gt;
		requested_types = params[:types].is_a?(Array) ? params[:types] : params[:types].to_s.split(',')&lt;br /&gt;
		normalized_types = requested_types.map(&amp;amp;:strip).reject(&amp;amp;:blank?)&lt;br /&gt;
		@teams = @teams.where(type: normalized_types) if normalized_types.any?&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	@teams = @teams.order(:name, :id)&lt;br /&gt;
	render json: @teams, each_serializer: TeamSerializer&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frontend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Added dedicated Create Teams loader:&lt;br /&gt;
#* Loads teams using assignment context and allowed team types.&lt;br /&gt;
#* Loads assignment participants.&lt;br /&gt;
#* Maps API data into &amp;lt;code&amp;gt;initialTeams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialUnassigned&amp;lt;/code&amp;gt; structures required by the view.&lt;br /&gt;
# Route wiring:&lt;br /&gt;
#* Create Teams route switched to the new loader so it uses real backend data instead of fallback-only behavior.&lt;br /&gt;
&lt;br /&gt;
=== Real-data verification ===&lt;br /&gt;
&lt;br /&gt;
Verified against DB via Docker Rails runner for Assignment id &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Team 1 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** cameron_fahey / Prince Langosh VM&lt;br /&gt;
** rickie.hamill / Rep. Rosena Paucek&lt;br /&gt;
** elease / Myrl Durgan&lt;br /&gt;
* Team 9 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** jacinda / Joshua Raynor&lt;br /&gt;
** lydia.monahan / Edward Jacobi&lt;br /&gt;
** eddie / Halley Schinner VM&lt;br /&gt;
&lt;br /&gt;
This confirmed end-to-end data correctness for the team hierarchy view.&lt;br /&gt;
&lt;br /&gt;
=== Significance of these changes ===&lt;br /&gt;
&lt;br /&gt;
These changes are significant because they move the teams view away from static or fallback-only data and make it reflect the real assignment context from the database. By filtering teams using &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt;, the backend now returns only the teams that actually belong to the selected hierarchy context. The eager loading also improves efficiency by reducing unnecessary queries when team members are rendered.&lt;br /&gt;
&lt;br /&gt;
From a design perspective, this aligns the teams view with the overall E2608 objective of removing unnecessary hierarchy plumbing and replacing it with direct association-based queries and hierarchy-ready responses. It also makes the frontend easier to validate, because the displayed team-member relationships now match the actual persisted data instead of a page-specific mock structure.&lt;br /&gt;
&lt;br /&gt;
== Verification and Testing ==&lt;br /&gt;
&lt;br /&gt;
The hosted deployment for our project is available at:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://152.7.177.90:3000/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Course -&amp;gt; Assignment Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in to the hosted system and navigate to the Courses page. Verify that a course row can be expanded to display the assignments that belong to that course. Also verify that after deleting an assignment, the assignment list updates correctly within the course hierarchy.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Questionnaire Type -&amp;gt; Questionnaire Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in as an administrator and navigate to the Questionnaires page. Verify that questionnaire types are shown as parent categories and that each type can be expanded to display the questionnaires in that category. Also verify that the admin workflow for creating, editing, updating, and deleting questionnaires works correctly for the supported questionnaire types.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Team -&amp;gt; Team Member Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Navigate to an assignment's Create Teams page and verify that the page displays real team data rather than fallback sample data. For Assignment &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, verify that Team 1 and Team 9 are shown with the correct members, and confirm that the correct members appear under the correct team for the selected assignment context.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Expertiza GitHub repository&lt;br /&gt;
* Expertiza project wiki&lt;br /&gt;
* RSpec documentation&lt;br /&gt;
* Vitest documentation&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167660</id>
		<title>CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167660"/>
		<updated>2026-03-31T02:53:17Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* View 3: Team -&amp;gt; Team Member Hierarchy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
'''Mentors:''' Ed Gehringer and Akhilsai Chittipolu&lt;br /&gt;
&lt;br /&gt;
This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== About Expertiza ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source Ruby on Rails platform for assignment management, team formation, topic signup, submissions, and peer review workflows. The system supports multiple user roles (students, TAs, instructors, admins) and complex assignment structures.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
The mentor requirement for E2608 was to implement hierarchical list rendering in a consistent pattern across major modules.&lt;br /&gt;
&lt;br /&gt;
Required hierarchy views:&lt;br /&gt;
&lt;br /&gt;
* Course -&amp;gt; Assignments&lt;br /&gt;
* Questionnaire Type -&amp;gt; Questionnaires&lt;br /&gt;
* Team -&amp;gt; Team Members&lt;br /&gt;
&lt;br /&gt;
The goal was to avoid one-off custom node components and instead apply a reusable hierarchical table pattern.&lt;br /&gt;
&lt;br /&gt;
== Project Description (E2608) ==&lt;br /&gt;
&lt;br /&gt;
Expertiza frequently displays hierarchical data:&lt;br /&gt;
&lt;br /&gt;
* Courses with nested assignments&lt;br /&gt;
* Questionnaire types with nested questionnaires&lt;br /&gt;
* Courses/assignments with nested teams and team members&lt;br /&gt;
&lt;br /&gt;
Historically, these hierarchies were represented with a Node superstructure where each entity had an associated Node and parent pointer. This introduced additional object management and coupling that was not strictly necessary for rendering parent-child lists.&lt;br /&gt;
&lt;br /&gt;
The project objective was to design and implement a reusable hierarchical display template where:&lt;br /&gt;
&lt;br /&gt;
* Backend performs direct database queries for parent and child data.&lt;br /&gt;
* Backend returns JSON payloads suitable for hierarchy rendering.&lt;br /&gt;
* Frontend applies a common expandable-list pattern while allowing view-specific presentation styles.&lt;br /&gt;
&lt;br /&gt;
In short, the project moves hierarchy rendering from Node-centric wiring to query-and-render patterns for maintainability and consistency.&lt;br /&gt;
&lt;br /&gt;
== Current Implementation (Before E2608) ==&lt;br /&gt;
&lt;br /&gt;
Before this work, hierarchical data existed in the domain model but was not consistently presented as a parent-child UI pattern across modules.&lt;br /&gt;
&lt;br /&gt;
Typical behavior before E2608:&lt;br /&gt;
&lt;br /&gt;
* Different pages used different data-loading styles, including separate API fetches for related entities.&lt;br /&gt;
* Some views depended on fallback/static sample structures when complete nested payloads were unavailable.&lt;br /&gt;
* Parent-child relationships were not always exposed in a way that made generic expandable tables straightforward.&lt;br /&gt;
* Hierarchical behavior varied by page rather than following one reusable template.&lt;br /&gt;
&lt;br /&gt;
== Drawbacks in Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
The pre-E2608 behavior created several practical issues:&lt;br /&gt;
&lt;br /&gt;
* Inconsistent user experience: hierarchy expansion behavior differed across pages.&lt;br /&gt;
* Additional client complexity: pages needed extra mapping/fetch orchestration to build nested displays.&lt;br /&gt;
* Higher coupling to page-specific logic instead of reusable table patterns.&lt;br /&gt;
* Harder validation against real backend hierarchy data in some flows.&lt;br /&gt;
* More chance of stale UI state when child lists were refetched separately.&lt;br /&gt;
&lt;br /&gt;
== Shared Team Architecture Decision ==&lt;br /&gt;
&lt;br /&gt;
Before implementation, the team agreed on a common hierarchy approach:&lt;br /&gt;
&lt;br /&gt;
* Use eager loading on the backend to fetch parent-child data in fewer queries.&lt;br /&gt;
* Return hierarchy-ready JSON (parents with embedded child collections) so frontend pages do minimal reshaping.&lt;br /&gt;
* Keep a consistent UX goal for expandable/collapsible hierarchy views, while allowing page-specific rendering style (table expansion or embedded dropdown lists).&lt;br /&gt;
&lt;br /&gt;
This shared approach keeps data retrieval efficient and makes hierarchy rendering consistent with the mentor's requested template style, without forcing a single UI widget across all pages.&lt;br /&gt;
&lt;br /&gt;
== Our Contribution ==&lt;br /&gt;
&lt;br /&gt;
We implemented a unified hierarchical-list strategy across three views and aligned backend payloads with frontend rendering needs.&lt;br /&gt;
&lt;br /&gt;
Summary of what we delivered:&lt;br /&gt;
&lt;br /&gt;
* Unified parent-child rendering approach for three major modules.&lt;br /&gt;
* Backend responses shaped to support hierarchy directly, with eager-loaded associations where applicable.&lt;br /&gt;
* Frontend pages updated to consume nested or hierarchy-aware data using view-appropriate UI patterns.&lt;br /&gt;
* Verification using both UI behavior and real database checks.&lt;br /&gt;
&lt;br /&gt;
== View 1: Course -&amp;gt; Assignment Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display assignments nested under their parent courses without CourseNode/AssignmentNode style custom hierarchy components.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Backend updated to return courses with associated assignments in one response.&lt;br /&gt;
* Frontend updated to consume nested assignment data from course payload.&lt;br /&gt;
* Frontend no longer depends on separate all-assignments fetch for this view.&lt;br /&gt;
* Minor delete-flow refinement: after successful assignment delete, assignment is removed from local frontend data instead of refetching assignments only.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Course rows can expand into assignment lists through the common hierarchy pattern.&lt;br /&gt;
&lt;br /&gt;
== View 2: Questionnaire Type -&amp;gt; Questionnaire Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Group questionnaires by questionnaire type and display questionnaires nested under each type.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Implemented hierarchical questionnaire list from the Admin view.&lt;br /&gt;
* Admin can create, edit, update, and delete questionnaires in these types:&lt;br /&gt;
** Review&lt;br /&gt;
** Metareview&lt;br /&gt;
** Author feedback&lt;br /&gt;
** Teammate Review&lt;br /&gt;
** Survey&lt;br /&gt;
** Assignment survey&lt;br /&gt;
** Global survey&lt;br /&gt;
** Course survey&lt;br /&gt;
** Bookmark rating&lt;br /&gt;
** Quiz&lt;br /&gt;
* In questionnaire listing, admin can expand a dropdown per type to see the embedded list of questionnaire instances for that category.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Questionnaire browsing follows the same parent-child model used in the other E2608 modules.&lt;br /&gt;
&lt;br /&gt;
== View 3: Team -&amp;gt; Team Member Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display team members nested under teams for a selected assignment context using real backend data.&lt;br /&gt;
&lt;br /&gt;
=== Backend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Teams filtering in index:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; filtering support.&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt; filtering support (&amp;lt;code&amp;gt;AssignmentTeam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MentoredTeam&amp;lt;/code&amp;gt;, etc.).&lt;br /&gt;
#* Added deterministic ordering by &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Added eager loading with users and team-participant associations.&lt;br /&gt;
# Team serialization:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; in team JSON payload for hierarchy-aware consumers.&lt;br /&gt;
# Backward-compatible params:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; acceptance in team params.&lt;br /&gt;
#* Preserved compatibility by mapping &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; when needed.&lt;br /&gt;
&lt;br /&gt;
=== Backend code snippet ===&lt;br /&gt;
&lt;br /&gt;
The following code snippet shows the core backend change that made the teams API hierarchy-aware:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
	@teams = Team.includes(:users, { teams_participants: :participant })&lt;br /&gt;
&lt;br /&gt;
	if params[:parent_id].present?&lt;br /&gt;
		@teams = @teams.where(parent_id: params[:parent_id])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if params[:types].present?&lt;br /&gt;
		requested_types = params[:types].is_a?(Array) ? params[:types] : params[:types].to_s.split(',')&lt;br /&gt;
		normalized_types = requested_types.map(&amp;amp;:strip).reject(&amp;amp;:blank?)&lt;br /&gt;
		@teams = @teams.where(type: normalized_types) if normalized_types.any?&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	@teams = @teams.order(:name, :id)&lt;br /&gt;
	render json: @teams, each_serializer: TeamSerializer&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frontend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Added dedicated Create Teams loader:&lt;br /&gt;
#* Loads teams using assignment context and allowed team types.&lt;br /&gt;
#* Loads assignment participants.&lt;br /&gt;
#* Maps API data into &amp;lt;code&amp;gt;initialTeams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialUnassigned&amp;lt;/code&amp;gt; structures required by the view.&lt;br /&gt;
# Route wiring:&lt;br /&gt;
#* Create Teams route switched to the new loader so it uses real backend data instead of fallback-only behavior.&lt;br /&gt;
&lt;br /&gt;
=== Real-data verification ===&lt;br /&gt;
&lt;br /&gt;
Verified against DB via Docker Rails runner for Assignment id &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Team 1 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** cameron_fahey / Prince Langosh VM&lt;br /&gt;
** rickie.hamill / Rep. Rosena Paucek&lt;br /&gt;
** elease / Myrl Durgan&lt;br /&gt;
* Team 9 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** jacinda / Joshua Raynor&lt;br /&gt;
** lydia.monahan / Edward Jacobi&lt;br /&gt;
** eddie / Halley Schinner VM&lt;br /&gt;
&lt;br /&gt;
This confirmed end-to-end data correctness for the team hierarchy view.&lt;br /&gt;
&lt;br /&gt;
== Verification and Testing ==&lt;br /&gt;
&lt;br /&gt;
The hosted deployment for our project is available at:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://152.7.177.90:3000/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Course -&amp;gt; Assignment Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in to the hosted system and navigate to the Courses page. Verify that a course row can be expanded to display the assignments that belong to that course. Also verify that after deleting an assignment, the assignment list updates correctly within the course hierarchy.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Questionnaire Type -&amp;gt; Questionnaire Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in as an administrator and navigate to the Questionnaires page. Verify that questionnaire types are shown as parent categories and that each type can be expanded to display the questionnaires in that category. Also verify that the admin workflow for creating, editing, updating, and deleting questionnaires works correctly for the supported questionnaire types.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Team -&amp;gt; Team Member Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Navigate to an assignment's Create Teams page and verify that the page displays real team data rather than fallback sample data. For Assignment &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, verify that Team 1 and Team 9 are shown with the correct members, and confirm that the correct members appear under the correct team for the selected assignment context.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Expertiza GitHub repository&lt;br /&gt;
* Expertiza project wiki&lt;br /&gt;
* RSpec documentation&lt;br /&gt;
* Vitest documentation&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167659</id>
		<title>CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167659"/>
		<updated>2026-03-31T02:48:55Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* Verification and Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
'''Mentors:''' Ed Gehringer and Akhilsai Chittipolu&lt;br /&gt;
&lt;br /&gt;
This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== About Expertiza ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source Ruby on Rails platform for assignment management, team formation, topic signup, submissions, and peer review workflows. The system supports multiple user roles (students, TAs, instructors, admins) and complex assignment structures.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
The mentor requirement for E2608 was to implement hierarchical list rendering in a consistent pattern across major modules.&lt;br /&gt;
&lt;br /&gt;
Required hierarchy views:&lt;br /&gt;
&lt;br /&gt;
* Course -&amp;gt; Assignments&lt;br /&gt;
* Questionnaire Type -&amp;gt; Questionnaires&lt;br /&gt;
* Team -&amp;gt; Team Members&lt;br /&gt;
&lt;br /&gt;
The goal was to avoid one-off custom node components and instead apply a reusable hierarchical table pattern.&lt;br /&gt;
&lt;br /&gt;
== Project Description (E2608) ==&lt;br /&gt;
&lt;br /&gt;
Expertiza frequently displays hierarchical data:&lt;br /&gt;
&lt;br /&gt;
* Courses with nested assignments&lt;br /&gt;
* Questionnaire types with nested questionnaires&lt;br /&gt;
* Courses/assignments with nested teams and team members&lt;br /&gt;
&lt;br /&gt;
Historically, these hierarchies were represented with a Node superstructure where each entity had an associated Node and parent pointer. This introduced additional object management and coupling that was not strictly necessary for rendering parent-child lists.&lt;br /&gt;
&lt;br /&gt;
The project objective was to design and implement a reusable hierarchical display template where:&lt;br /&gt;
&lt;br /&gt;
* Backend performs direct database queries for parent and child data.&lt;br /&gt;
* Backend returns JSON payloads suitable for hierarchy rendering.&lt;br /&gt;
* Frontend applies a common expandable-list pattern while allowing view-specific presentation styles.&lt;br /&gt;
&lt;br /&gt;
In short, the project moves hierarchy rendering from Node-centric wiring to query-and-render patterns for maintainability and consistency.&lt;br /&gt;
&lt;br /&gt;
== Current Implementation (Before E2608) ==&lt;br /&gt;
&lt;br /&gt;
Before this work, hierarchical data existed in the domain model but was not consistently presented as a parent-child UI pattern across modules.&lt;br /&gt;
&lt;br /&gt;
Typical behavior before E2608:&lt;br /&gt;
&lt;br /&gt;
* Different pages used different data-loading styles, including separate API fetches for related entities.&lt;br /&gt;
* Some views depended on fallback/static sample structures when complete nested payloads were unavailable.&lt;br /&gt;
* Parent-child relationships were not always exposed in a way that made generic expandable tables straightforward.&lt;br /&gt;
* Hierarchical behavior varied by page rather than following one reusable template.&lt;br /&gt;
&lt;br /&gt;
== Drawbacks in Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
The pre-E2608 behavior created several practical issues:&lt;br /&gt;
&lt;br /&gt;
* Inconsistent user experience: hierarchy expansion behavior differed across pages.&lt;br /&gt;
* Additional client complexity: pages needed extra mapping/fetch orchestration to build nested displays.&lt;br /&gt;
* Higher coupling to page-specific logic instead of reusable table patterns.&lt;br /&gt;
* Harder validation against real backend hierarchy data in some flows.&lt;br /&gt;
* More chance of stale UI state when child lists were refetched separately.&lt;br /&gt;
&lt;br /&gt;
== Shared Team Architecture Decision ==&lt;br /&gt;
&lt;br /&gt;
Before implementation, the team agreed on a common hierarchy approach:&lt;br /&gt;
&lt;br /&gt;
* Use eager loading on the backend to fetch parent-child data in fewer queries.&lt;br /&gt;
* Return hierarchy-ready JSON (parents with embedded child collections) so frontend pages do minimal reshaping.&lt;br /&gt;
* Keep a consistent UX goal for expandable/collapsible hierarchy views, while allowing page-specific rendering style (table expansion or embedded dropdown lists).&lt;br /&gt;
&lt;br /&gt;
This shared approach keeps data retrieval efficient and makes hierarchy rendering consistent with the mentor's requested template style, without forcing a single UI widget across all pages.&lt;br /&gt;
&lt;br /&gt;
== Our Contribution ==&lt;br /&gt;
&lt;br /&gt;
We implemented a unified hierarchical-list strategy across three views and aligned backend payloads with frontend rendering needs.&lt;br /&gt;
&lt;br /&gt;
Summary of what we delivered:&lt;br /&gt;
&lt;br /&gt;
* Unified parent-child rendering approach for three major modules.&lt;br /&gt;
* Backend responses shaped to support hierarchy directly, with eager-loaded associations where applicable.&lt;br /&gt;
* Frontend pages updated to consume nested or hierarchy-aware data using view-appropriate UI patterns.&lt;br /&gt;
* Verification using both UI behavior and real database checks.&lt;br /&gt;
&lt;br /&gt;
== View 1: Course -&amp;gt; Assignment Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display assignments nested under their parent courses without CourseNode/AssignmentNode style custom hierarchy components.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Backend updated to return courses with associated assignments in one response.&lt;br /&gt;
* Frontend updated to consume nested assignment data from course payload.&lt;br /&gt;
* Frontend no longer depends on separate all-assignments fetch for this view.&lt;br /&gt;
* Minor delete-flow refinement: after successful assignment delete, assignment is removed from local frontend data instead of refetching assignments only.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Course rows can expand into assignment lists through the common hierarchy pattern.&lt;br /&gt;
&lt;br /&gt;
== View 2: Questionnaire Type -&amp;gt; Questionnaire Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Group questionnaires by questionnaire type and display questionnaires nested under each type.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Implemented hierarchical questionnaire list from the Admin view.&lt;br /&gt;
* Admin can create, edit, update, and delete questionnaires in these types:&lt;br /&gt;
** Review&lt;br /&gt;
** Metareview&lt;br /&gt;
** Author feedback&lt;br /&gt;
** Teammate Review&lt;br /&gt;
** Survey&lt;br /&gt;
** Assignment survey&lt;br /&gt;
** Global survey&lt;br /&gt;
** Course survey&lt;br /&gt;
** Bookmark rating&lt;br /&gt;
** Quiz&lt;br /&gt;
* In questionnaire listing, admin can expand a dropdown per type to see the embedded list of questionnaire instances for that category.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Questionnaire browsing follows the same parent-child model used in the other E2608 modules.&lt;br /&gt;
&lt;br /&gt;
== View 3: Team -&amp;gt; Team Member Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display team members nested under teams for a selected assignment context using real backend data.&lt;br /&gt;
&lt;br /&gt;
=== Backend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Teams filtering in index:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; filtering support.&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt; filtering support (&amp;lt;code&amp;gt;AssignmentTeam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MentoredTeam&amp;lt;/code&amp;gt;, etc.).&lt;br /&gt;
#* Added deterministic ordering by &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Added eager loading with users and team-participant associations.&lt;br /&gt;
# Team serialization:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; in team JSON payload for hierarchy-aware consumers.&lt;br /&gt;
# Backward-compatible params:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; acceptance in team params.&lt;br /&gt;
#* Preserved compatibility by mapping &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; when needed.&lt;br /&gt;
&lt;br /&gt;
=== Frontend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Added dedicated Create Teams loader:&lt;br /&gt;
#* Loads teams using assignment context and allowed team types.&lt;br /&gt;
#* Loads assignment participants.&lt;br /&gt;
#* Maps API data into &amp;lt;code&amp;gt;initialTeams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialUnassigned&amp;lt;/code&amp;gt; structures required by the view.&lt;br /&gt;
# Route wiring:&lt;br /&gt;
#* Create Teams route switched to the new loader so it uses real backend data instead of fallback-only behavior.&lt;br /&gt;
&lt;br /&gt;
=== Real-data verification ===&lt;br /&gt;
&lt;br /&gt;
Verified against DB via Docker Rails runner for Assignment id &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Team 1 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** cameron_fahey / Prince Langosh VM&lt;br /&gt;
** rickie.hamill / Rep. Rosena Paucek&lt;br /&gt;
** elease / Myrl Durgan&lt;br /&gt;
* Team 9 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** jacinda / Joshua Raynor&lt;br /&gt;
** lydia.monahan / Edward Jacobi&lt;br /&gt;
** eddie / Halley Schinner VM&lt;br /&gt;
&lt;br /&gt;
This confirmed end-to-end data correctness for the team hierarchy view.&lt;br /&gt;
&lt;br /&gt;
== Verification and Testing ==&lt;br /&gt;
&lt;br /&gt;
The hosted deployment for our project is available at:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://152.7.177.90:3000/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Course -&amp;gt; Assignment Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in to the hosted system and navigate to the Courses page. Verify that a course row can be expanded to display the assignments that belong to that course. Also verify that after deleting an assignment, the assignment list updates correctly within the course hierarchy.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Questionnaire Type -&amp;gt; Questionnaire Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Log in as an administrator and navigate to the Questionnaires page. Verify that questionnaire types are shown as parent categories and that each type can be expanded to display the questionnaires in that category. Also verify that the admin workflow for creating, editing, updating, and deleting questionnaires works correctly for the supported questionnaire types.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing for Team -&amp;gt; Team Member Hierarchy ===&lt;br /&gt;
&lt;br /&gt;
Navigate to an assignment's Create Teams page and verify that the page displays real team data rather than fallback sample data. For Assignment &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, verify that Team 1 and Team 9 are shown with the correct members, and confirm that the correct members appear under the correct team for the selected assignment context.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Expertiza GitHub repository&lt;br /&gt;
* Expertiza project wiki&lt;br /&gt;
* RSpec documentation&lt;br /&gt;
* Vitest documentation&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167658</id>
		<title>CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167658"/>
		<updated>2026-03-31T02:40:46Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: /* CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
'''Mentors:''' Ed Gehringer and Akhilsai Chittipolu&lt;br /&gt;
&lt;br /&gt;
This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== About Expertiza ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source Ruby on Rails platform for assignment management, team formation, topic signup, submissions, and peer review workflows. The system supports multiple user roles (students, TAs, instructors, admins) and complex assignment structures.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
The mentor requirement for E2608 was to implement hierarchical list rendering in a consistent pattern across major modules.&lt;br /&gt;
&lt;br /&gt;
Required hierarchy views:&lt;br /&gt;
&lt;br /&gt;
* Course -&amp;gt; Assignments&lt;br /&gt;
* Questionnaire Type -&amp;gt; Questionnaires&lt;br /&gt;
* Team -&amp;gt; Team Members&lt;br /&gt;
&lt;br /&gt;
The goal was to avoid one-off custom node components and instead apply a reusable hierarchical table pattern.&lt;br /&gt;
&lt;br /&gt;
== Project Description (E2608) ==&lt;br /&gt;
&lt;br /&gt;
Expertiza frequently displays hierarchical data:&lt;br /&gt;
&lt;br /&gt;
* Courses with nested assignments&lt;br /&gt;
* Questionnaire types with nested questionnaires&lt;br /&gt;
* Courses/assignments with nested teams and team members&lt;br /&gt;
&lt;br /&gt;
Historically, these hierarchies were represented with a Node superstructure where each entity had an associated Node and parent pointer. This introduced additional object management and coupling that was not strictly necessary for rendering parent-child lists.&lt;br /&gt;
&lt;br /&gt;
The project objective was to design and implement a reusable hierarchical display template where:&lt;br /&gt;
&lt;br /&gt;
* Backend performs direct database queries for parent and child data.&lt;br /&gt;
* Backend returns JSON payloads suitable for hierarchy rendering.&lt;br /&gt;
* Frontend applies a common expandable-list pattern while allowing view-specific presentation styles.&lt;br /&gt;
&lt;br /&gt;
In short, the project moves hierarchy rendering from Node-centric wiring to query-and-render patterns for maintainability and consistency.&lt;br /&gt;
&lt;br /&gt;
== Current Implementation (Before E2608) ==&lt;br /&gt;
&lt;br /&gt;
Before this work, hierarchical data existed in the domain model but was not consistently presented as a parent-child UI pattern across modules.&lt;br /&gt;
&lt;br /&gt;
Typical behavior before E2608:&lt;br /&gt;
&lt;br /&gt;
* Different pages used different data-loading styles, including separate API fetches for related entities.&lt;br /&gt;
* Some views depended on fallback/static sample structures when complete nested payloads were unavailable.&lt;br /&gt;
* Parent-child relationships were not always exposed in a way that made generic expandable tables straightforward.&lt;br /&gt;
* Hierarchical behavior varied by page rather than following one reusable template.&lt;br /&gt;
&lt;br /&gt;
== Drawbacks in Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
The pre-E2608 behavior created several practical issues:&lt;br /&gt;
&lt;br /&gt;
* Inconsistent user experience: hierarchy expansion behavior differed across pages.&lt;br /&gt;
* Additional client complexity: pages needed extra mapping/fetch orchestration to build nested displays.&lt;br /&gt;
* Higher coupling to page-specific logic instead of reusable table patterns.&lt;br /&gt;
* Harder validation against real backend hierarchy data in some flows.&lt;br /&gt;
* More chance of stale UI state when child lists were refetched separately.&lt;br /&gt;
&lt;br /&gt;
== Shared Team Architecture Decision ==&lt;br /&gt;
&lt;br /&gt;
Before implementation, the team agreed on a common hierarchy approach:&lt;br /&gt;
&lt;br /&gt;
* Use eager loading on the backend to fetch parent-child data in fewer queries.&lt;br /&gt;
* Return hierarchy-ready JSON (parents with embedded child collections) so frontend pages do minimal reshaping.&lt;br /&gt;
* Keep a consistent UX goal for expandable/collapsible hierarchy views, while allowing page-specific rendering style (table expansion or embedded dropdown lists).&lt;br /&gt;
&lt;br /&gt;
This shared approach keeps data retrieval efficient and makes hierarchy rendering consistent with the mentor's requested template style, without forcing a single UI widget across all pages.&lt;br /&gt;
&lt;br /&gt;
== Our Contribution ==&lt;br /&gt;
&lt;br /&gt;
We implemented a unified hierarchical-list strategy across three views and aligned backend payloads with frontend rendering needs.&lt;br /&gt;
&lt;br /&gt;
Summary of what we delivered:&lt;br /&gt;
&lt;br /&gt;
* Unified parent-child rendering approach for three major modules.&lt;br /&gt;
* Backend responses shaped to support hierarchy directly, with eager-loaded associations where applicable.&lt;br /&gt;
* Frontend pages updated to consume nested or hierarchy-aware data using view-appropriate UI patterns.&lt;br /&gt;
* Verification using both UI behavior and real database checks.&lt;br /&gt;
&lt;br /&gt;
== View 1: Course -&amp;gt; Assignment Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display assignments nested under their parent courses without CourseNode/AssignmentNode style custom hierarchy components.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Backend updated to return courses with associated assignments in one response.&lt;br /&gt;
* Frontend updated to consume nested assignment data from course payload.&lt;br /&gt;
* Frontend no longer depends on separate all-assignments fetch for this view.&lt;br /&gt;
* Minor delete-flow refinement: after successful assignment delete, assignment is removed from local frontend data instead of refetching assignments only.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Course rows can expand into assignment lists through the common hierarchy pattern.&lt;br /&gt;
&lt;br /&gt;
== View 2: Questionnaire Type -&amp;gt; Questionnaire Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Group questionnaires by questionnaire type and display questionnaires nested under each type.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Implemented hierarchical questionnaire list from the Admin view.&lt;br /&gt;
* Admin can create, edit, update, and delete questionnaires in these types:&lt;br /&gt;
** Review&lt;br /&gt;
** Metareview&lt;br /&gt;
** Author feedback&lt;br /&gt;
** Teammate Review&lt;br /&gt;
** Survey&lt;br /&gt;
** Assignment survey&lt;br /&gt;
** Global survey&lt;br /&gt;
** Course survey&lt;br /&gt;
** Bookmark rating&lt;br /&gt;
** Quiz&lt;br /&gt;
* In questionnaire listing, admin can expand a dropdown per type to see the embedded list of questionnaire instances for that category.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Questionnaire browsing follows the same parent-child model used in the other E2608 modules.&lt;br /&gt;
&lt;br /&gt;
== View 3: Team -&amp;gt; Team Member Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display team members nested under teams for a selected assignment context using real backend data.&lt;br /&gt;
&lt;br /&gt;
=== Backend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Teams filtering in index:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; filtering support.&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt; filtering support (&amp;lt;code&amp;gt;AssignmentTeam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MentoredTeam&amp;lt;/code&amp;gt;, etc.).&lt;br /&gt;
#* Added deterministic ordering by &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Added eager loading with users and team-participant associations.&lt;br /&gt;
# Team serialization:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; in team JSON payload for hierarchy-aware consumers.&lt;br /&gt;
# Backward-compatible params:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; acceptance in team params.&lt;br /&gt;
#* Preserved compatibility by mapping &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; when needed.&lt;br /&gt;
&lt;br /&gt;
=== Frontend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Added dedicated Create Teams loader:&lt;br /&gt;
#* Loads teams using assignment context and allowed team types.&lt;br /&gt;
#* Loads assignment participants.&lt;br /&gt;
#* Maps API data into &amp;lt;code&amp;gt;initialTeams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialUnassigned&amp;lt;/code&amp;gt; structures required by the view.&lt;br /&gt;
# Route wiring:&lt;br /&gt;
#* Create Teams route switched to the new loader so it uses real backend data instead of fallback-only behavior.&lt;br /&gt;
&lt;br /&gt;
=== Real-data verification ===&lt;br /&gt;
&lt;br /&gt;
Verified against DB via Docker Rails runner for Assignment id &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Team 1 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** cameron_fahey / Prince Langosh VM&lt;br /&gt;
** rickie.hamill / Rep. Rosena Paucek&lt;br /&gt;
** elease / Myrl Durgan&lt;br /&gt;
* Team 9 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** jacinda / Joshua Raynor&lt;br /&gt;
** lydia.monahan / Edward Jacobi&lt;br /&gt;
** eddie / Halley Schinner VM&lt;br /&gt;
&lt;br /&gt;
This confirmed end-to-end data correctness for the team hierarchy view.&lt;br /&gt;
&lt;br /&gt;
== Verification and Testing ==&lt;br /&gt;
&lt;br /&gt;
=== Frontend ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Backend ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== UI validation flow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
# Validate each hierarchy page:&lt;br /&gt;
#* Courses page: course rows expand to assignments.&lt;br /&gt;
#* Questionnaires page: type rows expand to questionnaires.&lt;br /&gt;
#* Create Teams page: team rows expand or otherwise display the correct members for the selected assignment.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Expertiza GitHub repository&lt;br /&gt;
* Expertiza project wiki&lt;br /&gt;
* RSpec documentation&lt;br /&gt;
* Vitest documentation&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167657</id>
		<title>CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2026_-_E2608._Hierarchical_list_display&amp;diff=167657"/>
		<updated>2026-03-31T02:38:05Z</updated>

		<summary type="html">&lt;p&gt;Psubram3: Created page with &amp;quot;= CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display =  '''Mentors:''' Ed Gehringer and Akhilsai Chittipolu  This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.  __TOC__  == About Expertiza ==  Expertiza is an open-source Ruby on Rails platform for assignment management, team formation, topic signup, submissions, and peer review workflows. The system supports multiple user roles (students,...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= CSC/ECE 517 Spring 2026 - E2608. Hierarchical list display =&lt;br /&gt;
&lt;br /&gt;
'''Mentors:''' Ed Gehringer and Akhilsai Chittipolu&lt;br /&gt;
&lt;br /&gt;
This page documents our group implementation for E2608 (Hierarchical List Display) across Courses, Questionnaires, and Teams.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== About Expertiza ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source Ruby on Rails platform for assignment management, team formation, topic signup, submissions, and peer review workflows. The system supports multiple user roles (students, TAs, instructors, admins) and complex assignment structures.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
The mentor requirement for E2608 was to implement hierarchical list rendering in a consistent pattern across major modules.&lt;br /&gt;
&lt;br /&gt;
Required hierarchy views:&lt;br /&gt;
&lt;br /&gt;
* Course -&amp;gt; Assignments&lt;br /&gt;
* Questionnaire Type -&amp;gt; Questionnaires&lt;br /&gt;
* Team -&amp;gt; Team Members&lt;br /&gt;
&lt;br /&gt;
The goal was to avoid one-off custom node components and instead apply a reusable hierarchical table pattern.&lt;br /&gt;
&lt;br /&gt;
== Project Description (E2608) ==&lt;br /&gt;
&lt;br /&gt;
Expertiza frequently displays hierarchical data:&lt;br /&gt;
&lt;br /&gt;
* Courses with nested assignments&lt;br /&gt;
* Questionnaire types with nested questionnaires&lt;br /&gt;
* Courses/assignments with nested teams and team members&lt;br /&gt;
&lt;br /&gt;
Historically, these hierarchies were represented with a Node superstructure where each entity had an associated Node and parent pointer. This introduced additional object management and coupling that was not strictly necessary for rendering parent-child lists.&lt;br /&gt;
&lt;br /&gt;
The project objective was to design and implement a reusable hierarchical display template where:&lt;br /&gt;
&lt;br /&gt;
* Backend performs direct database queries for parent and child data.&lt;br /&gt;
* Backend returns JSON payloads suitable for hierarchy rendering.&lt;br /&gt;
* Frontend applies a common expandable-list pattern while allowing view-specific presentation styles.&lt;br /&gt;
&lt;br /&gt;
In short, the project moves hierarchy rendering from Node-centric wiring to query-and-render patterns for maintainability and consistency.&lt;br /&gt;
&lt;br /&gt;
== Current Implementation (Before E2608) ==&lt;br /&gt;
&lt;br /&gt;
Before this work, hierarchical data existed in the domain model but was not consistently presented as a parent-child UI pattern across modules.&lt;br /&gt;
&lt;br /&gt;
Typical behavior before E2608:&lt;br /&gt;
&lt;br /&gt;
* Different pages used different data-loading styles, including separate API fetches for related entities.&lt;br /&gt;
* Some views depended on fallback/static sample structures when complete nested payloads were unavailable.&lt;br /&gt;
* Parent-child relationships were not always exposed in a way that made generic expandable tables straightforward.&lt;br /&gt;
* Hierarchical behavior varied by page rather than following one reusable template.&lt;br /&gt;
&lt;br /&gt;
== Drawbacks in Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
The pre-E2608 behavior created several practical issues:&lt;br /&gt;
&lt;br /&gt;
* Inconsistent user experience: hierarchy expansion behavior differed across pages.&lt;br /&gt;
* Additional client complexity: pages needed extra mapping/fetch orchestration to build nested displays.&lt;br /&gt;
* Higher coupling to page-specific logic instead of reusable table patterns.&lt;br /&gt;
* Harder validation against real backend hierarchy data in some flows.&lt;br /&gt;
* More chance of stale UI state when child lists were refetched separately.&lt;br /&gt;
&lt;br /&gt;
== Shared Team Architecture Decision ==&lt;br /&gt;
&lt;br /&gt;
Before implementation, the team agreed on a common hierarchy approach:&lt;br /&gt;
&lt;br /&gt;
* Use eager loading on the backend to fetch parent-child data in fewer queries.&lt;br /&gt;
* Return hierarchy-ready JSON (parents with embedded child collections) so frontend pages do minimal reshaping.&lt;br /&gt;
* Keep a consistent UX goal for expandable/collapsible hierarchy views, while allowing page-specific rendering style (table expansion or embedded dropdown lists).&lt;br /&gt;
&lt;br /&gt;
This shared approach keeps data retrieval efficient and makes hierarchy rendering consistent with the mentor's requested template style, without forcing a single UI widget across all pages.&lt;br /&gt;
&lt;br /&gt;
== Our Contribution ==&lt;br /&gt;
&lt;br /&gt;
We implemented a unified hierarchical-list strategy across three views and aligned backend payloads with frontend rendering needs.&lt;br /&gt;
&lt;br /&gt;
Summary of what we delivered:&lt;br /&gt;
&lt;br /&gt;
* Unified parent-child rendering approach for three major modules.&lt;br /&gt;
* Backend responses shaped to support hierarchy directly, with eager-loaded associations where applicable.&lt;br /&gt;
* Frontend pages updated to consume nested or hierarchy-aware data using view-appropriate UI patterns.&lt;br /&gt;
* Verification using both UI behavior and real database checks.&lt;br /&gt;
&lt;br /&gt;
== View 1: Course -&amp;gt; Assignment Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display assignments nested under their parent courses without CourseNode/AssignmentNode style custom hierarchy components.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Backend updated to return courses with associated assignments in one response.&lt;br /&gt;
* Frontend updated to consume nested assignment data from course payload.&lt;br /&gt;
* Frontend no longer depends on separate all-assignments fetch for this view.&lt;br /&gt;
* Minor delete-flow refinement: after successful assignment delete, assignment is removed from local frontend data instead of refetching assignments only.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Course rows can expand into assignment lists through the common hierarchy pattern.&lt;br /&gt;
&lt;br /&gt;
== View 2: Questionnaire Type -&amp;gt; Questionnaire Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Group questionnaires by questionnaire type and display questionnaires nested under each type.&lt;br /&gt;
&lt;br /&gt;
=== Implemented work ===&lt;br /&gt;
&lt;br /&gt;
* Implemented hierarchical questionnaire list from the Admin view.&lt;br /&gt;
* Admin can create, edit, update, and delete questionnaires in these types:&lt;br /&gt;
** Review&lt;br /&gt;
** Metareview&lt;br /&gt;
** Author feedback&lt;br /&gt;
** Teammate Review&lt;br /&gt;
** Survey&lt;br /&gt;
** Assignment survey&lt;br /&gt;
** Global survey&lt;br /&gt;
** Course survey&lt;br /&gt;
** Bookmark rating&lt;br /&gt;
** Quiz&lt;br /&gt;
* In questionnaire listing, admin can expand a dropdown per type to see the embedded list of questionnaire instances for that category.&lt;br /&gt;
&lt;br /&gt;
=== Result ===&lt;br /&gt;
&lt;br /&gt;
Questionnaire browsing follows the same parent-child model used in the other E2608 modules.&lt;br /&gt;
&lt;br /&gt;
== View 3: Team -&amp;gt; Team Member Hierarchy ==&lt;br /&gt;
&lt;br /&gt;
=== Goal ===&lt;br /&gt;
&lt;br /&gt;
Display team members nested under teams for a selected assignment context using real backend data.&lt;br /&gt;
&lt;br /&gt;
=== Backend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Teams filtering in index:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; filtering support.&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;types&amp;lt;/code&amp;gt; filtering support (&amp;lt;code&amp;gt;AssignmentTeam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MentoredTeam&amp;lt;/code&amp;gt;, etc.).&lt;br /&gt;
#* Added deterministic ordering by &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Added eager loading with users and team-participant associations.&lt;br /&gt;
# Team serialization:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; in team JSON payload for hierarchy-aware consumers.&lt;br /&gt;
# Backward-compatible params:&lt;br /&gt;
#* Added &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; acceptance in team params.&lt;br /&gt;
#* Preserved compatibility by mapping &amp;lt;code&amp;gt;assignment_id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;parent_id&amp;lt;/code&amp;gt; when needed.&lt;br /&gt;
&lt;br /&gt;
=== Frontend implementation ===&lt;br /&gt;
&lt;br /&gt;
# Added dedicated Create Teams loader:&lt;br /&gt;
#* Loads teams using assignment context and allowed team types.&lt;br /&gt;
#* Loads assignment participants.&lt;br /&gt;
#* Maps API data into &amp;lt;code&amp;gt;initialTeams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialUnassigned&amp;lt;/code&amp;gt; structures required by the view.&lt;br /&gt;
# Route wiring:&lt;br /&gt;
#* Create Teams route switched to the new loader so it uses real backend data instead of fallback-only behavior.&lt;br /&gt;
&lt;br /&gt;
=== Real-data verification ===&lt;br /&gt;
&lt;br /&gt;
Verified against DB via Docker Rails runner for Assignment id &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Team 1 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** cameron_fahey / Prince Langosh VM&lt;br /&gt;
** rickie.hamill / Rep. Rosena Paucek&lt;br /&gt;
** elease / Myrl Durgan&lt;br /&gt;
* Team 9 (&amp;lt;code&amp;gt;parent_id=1&amp;lt;/code&amp;gt;):&lt;br /&gt;
** jacinda / Joshua Raynor&lt;br /&gt;
** lydia.monahan / Edward Jacobi&lt;br /&gt;
** eddie / Halley Schinner VM&lt;br /&gt;
&lt;br /&gt;
This confirmed end-to-end data correctness for the team hierarchy view.&lt;br /&gt;
&lt;br /&gt;
== Verification and Testing ==&lt;br /&gt;
&lt;br /&gt;
=== Frontend ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Backend ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== UI validation flow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
# Validate each hierarchy page:&lt;br /&gt;
#* Courses page: course rows expand to assignments.&lt;br /&gt;
#* Questionnaires page: type rows expand to questionnaires.&lt;br /&gt;
#* Create Teams page: team rows expand or otherwise display the correct members for the selected assignment.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* Expertiza GitHub repository&lt;br /&gt;
* Expertiza project wiki&lt;br /&gt;
* RSpec documentation&lt;br /&gt;
* Vitest documentation&lt;/div&gt;</summary>
		<author><name>Psubram3</name></author>
	</entry>
</feed>