<?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=Dananth</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=Dananth"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Dananth"/>
	<updated>2026-05-11T01:00:48Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167450</id>
		<title>CSC/ECE 517 Fall 2025 - E2562. Review grading dashboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167450"/>
		<updated>2025-12-06T16:45:36Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
The '''Review Grading Dashboard''' is a new unified interface in Expertiza that modernizes the grading workflow by consolidating reviewer details, review statuses, computed scores, word-volume metrics, and instructor grading inputs into a single, sortable, and interactive dashboard. Built as part of the reimplementation project, this dashboard uses a modern REST API, reusable React components, and a clean architecture aligned with the new Expertiza design philosophy.&lt;br /&gt;
&lt;br /&gt;
This document provides a **highly detailed technical explanation** of the backend logic, API design, data structures, architectural patterns, and internal workflows—intended for developers building or extending the Review Grading feature.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Code repositories:&lt;br /&gt;
* [https://github.com/deekshithanantha/reimplementation-front-end Frontend Repository]&lt;br /&gt;
* [https://github.com/deekshithanantha/reimplementation-back-end Backend Repository]&lt;br /&gt;
&lt;br /&gt;
Legacy Expertiza scattered review information across many pages. The new dashboard replaces this fragmented approach with a single data-driven, API-powered interface.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
Before this redesign:&lt;br /&gt;
* Instructors had to open **each review individually**.&lt;br /&gt;
* Completion status, scores, and team mappings were on **different pages**.&lt;br /&gt;
* No central place existed to **see scores**, **assign grades**, or **visualize review quality**.&lt;br /&gt;
* No way existed to export all review results at once.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Core Functional Requirements ===&lt;br /&gt;
* Dashboard must fetch all review data using a **single API call**.&lt;br /&gt;
* Must render:&lt;br /&gt;
** Reviewer details  &lt;br /&gt;
** Assigned teams and review completion states  &lt;br /&gt;
** Per-round scores  &lt;br /&gt;
** Metrics on unique word usage  &lt;br /&gt;
** Inline grading + comments  &lt;br /&gt;
* CSV export must reflect **exactly what instructors see**.&lt;br /&gt;
* Must support multi-round review assignments.&lt;br /&gt;
&lt;br /&gt;
=== Technical Requirements ===&lt;br /&gt;
* Data must be produced using **optimized queries**, minimal N+1 loading.&lt;br /&gt;
* Must use existing scoring method: &amp;lt;code&amp;gt;aggregate_questionnaire_score&amp;lt;/code&amp;gt;.&lt;br /&gt;
* All metric calculations must be done server-side to ensure reproducibility.&lt;br /&gt;
* All API responses must follow reimplementation JSON standards.&lt;br /&gt;
* Frontend must use modular React components with predictable props.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
==Demo==&lt;br /&gt;
===Demo Video===&lt;br /&gt;
[[File:2555-thumbnail.jpg|thumb|center|link=https://youtu.be/TZWUdbBrFA8|Click to watch on YouTube]]&lt;br /&gt;
&lt;br /&gt;
== Design Document ==&lt;br /&gt;
=== Images ===&lt;br /&gt;
[[File:E2562.png|1000px]]  &lt;br /&gt;
[[File:E2562_wiremock1.jpeg|1000px]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== ✦ Technical Design: Deep Backend Explanation (Option A Expanded) ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Data Aggregation Workflow ===&lt;br /&gt;
The dashboard requires combining information from several Expertiza models:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Model !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;Participant&amp;lt;/tt&amp;gt; || Represents the reviewer as part of an assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;ReviewResponseMap&amp;lt;/tt&amp;gt; || Specifies which team a participant must review&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;Response&amp;lt;/tt&amp;gt; || Stores the actual review answers and timestamps&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;Assignment&amp;lt;/tt&amp;gt; || Determines the review rounds and questionnaires&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;Team&amp;lt;/tt&amp;gt; || Represents the team being reviewed&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Because these models are spread across separate tables, the controller performs structured join operations:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Participant&lt;br /&gt;
  .includes(:user)&lt;br /&gt;
  .includes(review_response_maps: &lt;br /&gt;
    [:reviewee, response: [:scores, :comments]])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This drastically reduces SQL calls, avoiding the classic N+1 problem from the legacy system.&lt;br /&gt;
&lt;br /&gt;
=== 2. Score Computation ===&lt;br /&gt;
The dashboard must compute weighted scores. This is done using:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
response.aggregate_questionnaire_score&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Internally, this:&lt;br /&gt;
* Fetches each question’s max score&lt;br /&gt;
* Normalizes each response&lt;br /&gt;
* Computes weighted total&lt;br /&gt;
&lt;br /&gt;
The dashboard does **not** recalculate scoring logic—only aggregates output.&lt;br /&gt;
&lt;br /&gt;
=== 3. Review “Volume” Metric ===&lt;br /&gt;
Implemented in &amp;lt;tt&amp;gt;ResponseVolumeMixin&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def volume&lt;br /&gt;
  text = answers.pluck(:comments).join(&amp;quot; &amp;quot;)&lt;br /&gt;
  normalized = text.downcase.gsub(/[^a-z0-9\s]/i, '')&lt;br /&gt;
  tokens = normalized.split.uniq&lt;br /&gt;
  tokens.count&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Technical details:&lt;br /&gt;
* Strips punctuation&lt;br /&gt;
* Splits on whitespace&lt;br /&gt;
* De-duplicates tokens using Ruby’s &amp;lt;tt&amp;gt;uniq&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Returns integer count of unique words&lt;br /&gt;
&lt;br /&gt;
=== 4. Multi-Round Review Handling ===&lt;br /&gt;
Assignments may have multiple review rounds.  &lt;br /&gt;
The dashboard must show one score + one metric per round.&lt;br /&gt;
&lt;br /&gt;
Algorithm:&lt;br /&gt;
# Identify the round using &amp;lt;code&amp;gt;Response.round&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Group responses by &amp;lt;code&amp;gt;reviewer_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;.&lt;br /&gt;
# For each group:&lt;br /&gt;
## Compute aggregate score.&lt;br /&gt;
## Compute volume metric.&lt;br /&gt;
## Compute completion status.&lt;br /&gt;
&lt;br /&gt;
=== 5. Dashboard API JSON Structure ===&lt;br /&gt;
&lt;br /&gt;
The API returns structured JSON:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;reviewers&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;id&amp;quot;: 12,&lt;br /&gt;
      &amp;quot;username&amp;quot;: &amp;quot;jdoe&amp;quot;,&lt;br /&gt;
      &amp;quot;fullname&amp;quot;: &amp;quot;John Doe&amp;quot;,&lt;br /&gt;
      &amp;quot;reviews_assigned&amp;quot;: 3,&lt;br /&gt;
      &amp;quot;reviews_completed&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;teams_reviewed&amp;quot;: [&lt;br /&gt;
        { &amp;quot;team_id&amp;quot;: 5, &amp;quot;team_name&amp;quot;: &amp;quot;Team 1&amp;quot;, &amp;quot;status&amp;quot;: &amp;quot;done&amp;quot; },&lt;br /&gt;
        { &amp;quot;team_id&amp;quot;: 6, &amp;quot;team_name&amp;quot;: &amp;quot;Team 2&amp;quot;, &amp;quot;status&amp;quot;: &amp;quot;pending&amp;quot; }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;round_data&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;round&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;score&amp;quot;: 88.6,&lt;br /&gt;
          &amp;quot;volume&amp;quot;: 73,&lt;br /&gt;
          &amp;quot;average_volume&amp;quot;: 65&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;grade&amp;quot;: null,&lt;br /&gt;
      &amp;quot;comment&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6. CSV Export Internal Logic ===&lt;br /&gt;
&lt;br /&gt;
The CSV generator produces:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Reviewer Username,&lt;br /&gt;
Reviewer Name,&lt;br /&gt;
Team Reviewed,&lt;br /&gt;
Round 1 Score,&lt;br /&gt;
Round 1 Volume,&lt;br /&gt;
Round 2 Score,&lt;br /&gt;
Round 2 Volume,&lt;br /&gt;
Grade,&lt;br /&gt;
Comments&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Technical details:&lt;br /&gt;
* Columns vary based on number of rounds.&lt;br /&gt;
* Uses Ruby &amp;lt;code&amp;gt;CSV.generate&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Includes computed averages, not raw text.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== ✦ System Architecture (Option C Expanded) ==&lt;br /&gt;
&lt;br /&gt;
=== 1. High-Level Architecture Diagram ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+-------------------+         +-----------------------+&lt;br /&gt;
|  React Frontend   |         |    Rails API Backend  |&lt;br /&gt;
+---------+---------+         +-----------+-----------+&lt;br /&gt;
          |                                 |&lt;br /&gt;
          | GET /review_dashboard_data       |&lt;br /&gt;
          +--------------------------------&amp;gt;+&lt;br /&gt;
          |                                 |&lt;br /&gt;
          |      JSON: reviewers, scores,   |&lt;br /&gt;
          |             metrics, grades     |&lt;br /&gt;
          &amp;lt;--------------------------------+&lt;br /&gt;
          |                                 |&lt;br /&gt;
          | POST /assign_review_grade       |&lt;br /&gt;
          +--------------------------------&amp;gt;+&lt;br /&gt;
          |                                 |&lt;br /&gt;
          | GET /export_reviews_csv         |&lt;br /&gt;
          +--------------------------------&amp;gt;+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Detailed Component Interaction Diagram ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
React Dashboard&lt;br /&gt;
  |&lt;br /&gt;
  |-- calls ApiService.fetchDashboardData()&lt;br /&gt;
  |       |&lt;br /&gt;
  |       |-- axios GET /review_dashboard_data&lt;br /&gt;
  |       |&lt;br /&gt;
  |       |-- receives structured reviewer JSON&lt;br /&gt;
  |&lt;br /&gt;
  |-- renders ReviewTable&lt;br /&gt;
  |       |&lt;br /&gt;
  |       |-- for each row, render:&lt;br /&gt;
  |             - Reviewer identity&lt;br /&gt;
  |             - Review counts&lt;br /&gt;
  |             - Scores (per round)&lt;br /&gt;
  |             - MetricsChart (Recharts)&lt;br /&gt;
  |             - GradeInput&lt;br /&gt;
  |             - CommentInput&lt;br /&gt;
  |&lt;br /&gt;
  |-- on grade input:&lt;br /&gt;
  |       |&lt;br /&gt;
  |       |-- axios POST /assign_review_grade&lt;br /&gt;
  |&lt;br /&gt;
  |-- on export click:&lt;br /&gt;
          |&lt;br /&gt;
          |-- axios GET /export_reviews_csv&lt;br /&gt;
          |&lt;br /&gt;
          |-- triggers browser file download&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Backend Internal Flow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ReviewGradingController#index&lt;br /&gt;
  |&lt;br /&gt;
  |-- loads Participants for assignment&lt;br /&gt;
  |-- loads ReviewResponseMaps&lt;br /&gt;
  |-- joins Users, Teams, Responses&lt;br /&gt;
  |-- computes score/volume per round&lt;br /&gt;
  |-- builds JSON structure&lt;br /&gt;
  |-- returns response&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4. Error Handling &amp;amp; Data Failure Modes ===&lt;br /&gt;
Backend handles:&lt;br /&gt;
* Missing responses → score = null, volume = null&lt;br /&gt;
* Late submissions → status = &amp;quot;late&amp;quot;&lt;br /&gt;
* No reviews assigned → empty arrays&lt;br /&gt;
* Invalid grade → HTTP 422&lt;br /&gt;
&lt;br /&gt;
Frontend handles:&lt;br /&gt;
* Empty dashboard → “No reviewers found”&lt;br /&gt;
* Fallback UI if metrics chart cannot render&lt;br /&gt;
* Retry option for failed grade submissions&lt;br /&gt;
&lt;br /&gt;
=== 5. Performance Considerations ===&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;includes&amp;lt;/code&amp;gt; to prevent N+1 queries.&lt;br /&gt;
* Computes all heavy metrics ahead of time on backend.&lt;br /&gt;
* JSON payload optimized to only include necessary fields.&lt;br /&gt;
* Recharts renders only visible metrics (virtual scrolling optional).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Data Flow ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Frontend (React)&lt;br /&gt;
   ↓ GET /review_dashboard_data&lt;br /&gt;
&lt;br /&gt;
Backend (Rails)&lt;br /&gt;
   → Aggregates Participant / Team / Response data&lt;br /&gt;
   → Computes:&lt;br /&gt;
        • Score per round&lt;br /&gt;
        • Unique-word volume&lt;br /&gt;
        • Average volume per round&lt;br /&gt;
   → Returns JSON&lt;br /&gt;
&lt;br /&gt;
Frontend&lt;br /&gt;
   → Renders reviewer rows + charts&lt;br /&gt;
   → Provides inline grading&lt;br /&gt;
&lt;br /&gt;
POST /assign_review_grade&lt;br /&gt;
   → Updates grade + comment&lt;br /&gt;
&lt;br /&gt;
GET /export_reviews_csv&lt;br /&gt;
   → Downloads CSV file&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Backend Technical Tests ===&lt;br /&gt;
* Validate round grouping logic.&lt;br /&gt;
* Validate unique word calculation (stopword edge cases).&lt;br /&gt;
* Ensure response-to-round mapping is correct.&lt;br /&gt;
* Test every API error condition:&lt;br /&gt;
** invalid grade&lt;br /&gt;
** missing participant&lt;br /&gt;
** missing response&lt;br /&gt;
** incorrect assignment id&lt;br /&gt;
** CSV generator with zero reviewers&lt;br /&gt;
&lt;br /&gt;
=== Frontend (Technical) Tests ===&lt;br /&gt;
* Test MetricsChart with:&lt;br /&gt;
** zero volume&lt;br /&gt;
** extremely large review text&lt;br /&gt;
** missing average&lt;br /&gt;
** multi-round assignments&lt;br /&gt;
* Test sorting stability (ascending/descending).&lt;br /&gt;
* Test grade input debounce + retry.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Team Members ==&lt;br /&gt;
* '''Deekshith Anantha'''&lt;br /&gt;
* '''Srinidhi'''&lt;br /&gt;
* '''Abhishek Rao'''&lt;br /&gt;
* Mentor: '''Ishani Rajput'''&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167427</id>
		<title>CSC/ECE 517 Fall 2025 - E2562. Review grading dashboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167427"/>
		<updated>2025-12-03T15:25:32Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
The '''Review Grading Dashboard''' is a new unified interface in Expertiza that modernizes the grading workflow by consolidating reviewer details, review statuses, computed scores, word-volume metrics, and instructor grading inputs into a single, sortable, and interactive dashboard. Built as part of the reimplementation project, this dashboard uses a modern REST API, reusable React components, and a clean architecture aligned with the new Expertiza design philosophy.&lt;br /&gt;
&lt;br /&gt;
This document provides a **highly detailed technical explanation** of the backend logic, API design, data structures, architectural patterns, and internal workflows—intended for developers building or extending the Review Grading feature.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Code repositories:&lt;br /&gt;
* [https://github.com/deekshithanantha/reimplementation-front-end Frontend Repository]&lt;br /&gt;
* [https://github.com/deekshithanantha/reimplementation-back-end Backend Repository]&lt;br /&gt;
&lt;br /&gt;
Legacy Expertiza scattered review information across many pages. The new dashboard replaces this fragmented approach with a single data-driven, API-powered interface.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
Before this redesign:&lt;br /&gt;
* Instructors had to open **each review individually**.&lt;br /&gt;
* Completion status, scores, and team mappings were on **different pages**.&lt;br /&gt;
* No central place existed to **see scores**, **assign grades**, or **visualize review quality**.&lt;br /&gt;
* No way existed to export all review results at once.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Core Functional Requirements ===&lt;br /&gt;
* Dashboard must fetch all review data using a **single API call**.&lt;br /&gt;
* Must render:&lt;br /&gt;
** Reviewer details  &lt;br /&gt;
** Assigned teams and review completion states  &lt;br /&gt;
** Per-round scores  &lt;br /&gt;
** Metrics on unique word usage  &lt;br /&gt;
** Inline grading + comments  &lt;br /&gt;
* CSV export must reflect **exactly what instructors see**.&lt;br /&gt;
* Must support multi-round review assignments.&lt;br /&gt;
&lt;br /&gt;
=== Technical Requirements ===&lt;br /&gt;
* Data must be produced using **optimized queries**, minimal N+1 loading.&lt;br /&gt;
* Must use existing scoring method: &amp;lt;code&amp;gt;aggregate_questionnaire_score&amp;lt;/code&amp;gt;.&lt;br /&gt;
* All metric calculations must be done server-side to ensure reproducibility.&lt;br /&gt;
* All API responses must follow reimplementation JSON standards.&lt;br /&gt;
* Frontend must use modular React components with predictable props.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Design Document ==&lt;br /&gt;
== Images ==&lt;br /&gt;
[[File:E2562.png|1000px]]  &lt;br /&gt;
[[File:E2562_wiremock1.jpeg|1000px]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== ✦ Technical Design: Deep Backend Explanation (Option A Expanded) ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Data Aggregation Workflow ===&lt;br /&gt;
The dashboard requires combining information from several Expertiza models:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Model !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;Participant&amp;lt;/tt&amp;gt; || Represents the reviewer as part of an assignment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;ReviewResponseMap&amp;lt;/tt&amp;gt; || Specifies which team a participant must review&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;Response&amp;lt;/tt&amp;gt; || Stores the actual review answers and timestamps&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;Assignment&amp;lt;/tt&amp;gt; || Determines the review rounds and questionnaires&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;Team&amp;lt;/tt&amp;gt; || Represents the team being reviewed&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Because these models are spread across separate tables, the controller performs structured join operations:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Participant&lt;br /&gt;
  .includes(:user)&lt;br /&gt;
  .includes(review_response_maps: &lt;br /&gt;
    [:reviewee, response: [:scores, :comments]])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This drastically reduces SQL calls, avoiding the classic N+1 problem from the legacy system.&lt;br /&gt;
&lt;br /&gt;
=== 2. Score Computation ===&lt;br /&gt;
The dashboard must compute weighted scores. This is done using:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
response.aggregate_questionnaire_score&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Internally, this:&lt;br /&gt;
* Fetches each question’s max score&lt;br /&gt;
* Normalizes each response&lt;br /&gt;
* Computes weighted total&lt;br /&gt;
&lt;br /&gt;
The dashboard does **not** recalculate scoring logic—only aggregates output.&lt;br /&gt;
&lt;br /&gt;
=== 3. Review “Volume” Metric ===&lt;br /&gt;
Implemented in &amp;lt;tt&amp;gt;ResponseVolumeMixin&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def volume&lt;br /&gt;
  text = answers.pluck(:comments).join(&amp;quot; &amp;quot;)&lt;br /&gt;
  normalized = text.downcase.gsub(/[^a-z0-9\s]/i, '')&lt;br /&gt;
  tokens = normalized.split.uniq&lt;br /&gt;
  tokens.count&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Technical details:&lt;br /&gt;
* Strips punctuation&lt;br /&gt;
* Splits on whitespace&lt;br /&gt;
* De-duplicates tokens using Ruby’s &amp;lt;tt&amp;gt;uniq&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Returns integer count of unique words&lt;br /&gt;
&lt;br /&gt;
=== 4. Multi-Round Review Handling ===&lt;br /&gt;
Assignments may have multiple review rounds.  &lt;br /&gt;
The dashboard must show one score + one metric per round.&lt;br /&gt;
&lt;br /&gt;
Algorithm:&lt;br /&gt;
# Identify the round using &amp;lt;code&amp;gt;Response.round&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Group responses by &amp;lt;code&amp;gt;reviewer_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;round&amp;lt;/code&amp;gt;.&lt;br /&gt;
# For each group:&lt;br /&gt;
## Compute aggregate score.&lt;br /&gt;
## Compute volume metric.&lt;br /&gt;
## Compute completion status.&lt;br /&gt;
&lt;br /&gt;
=== 5. Dashboard API JSON Structure ===&lt;br /&gt;
&lt;br /&gt;
The API returns structured JSON:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;reviewers&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;id&amp;quot;: 12,&lt;br /&gt;
      &amp;quot;username&amp;quot;: &amp;quot;jdoe&amp;quot;,&lt;br /&gt;
      &amp;quot;fullname&amp;quot;: &amp;quot;John Doe&amp;quot;,&lt;br /&gt;
      &amp;quot;reviews_assigned&amp;quot;: 3,&lt;br /&gt;
      &amp;quot;reviews_completed&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;teams_reviewed&amp;quot;: [&lt;br /&gt;
        { &amp;quot;team_id&amp;quot;: 5, &amp;quot;team_name&amp;quot;: &amp;quot;Team 1&amp;quot;, &amp;quot;status&amp;quot;: &amp;quot;done&amp;quot; },&lt;br /&gt;
        { &amp;quot;team_id&amp;quot;: 6, &amp;quot;team_name&amp;quot;: &amp;quot;Team 2&amp;quot;, &amp;quot;status&amp;quot;: &amp;quot;pending&amp;quot; }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;round_data&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;round&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;score&amp;quot;: 88.6,&lt;br /&gt;
          &amp;quot;volume&amp;quot;: 73,&lt;br /&gt;
          &amp;quot;average_volume&amp;quot;: 65&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;grade&amp;quot;: null,&lt;br /&gt;
      &amp;quot;comment&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6. CSV Export Internal Logic ===&lt;br /&gt;
&lt;br /&gt;
The CSV generator produces:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Reviewer Username,&lt;br /&gt;
Reviewer Name,&lt;br /&gt;
Team Reviewed,&lt;br /&gt;
Round 1 Score,&lt;br /&gt;
Round 1 Volume,&lt;br /&gt;
Round 2 Score,&lt;br /&gt;
Round 2 Volume,&lt;br /&gt;
Grade,&lt;br /&gt;
Comments&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Technical details:&lt;br /&gt;
* Columns vary based on number of rounds.&lt;br /&gt;
* Uses Ruby &amp;lt;code&amp;gt;CSV.generate&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Includes computed averages, not raw text.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== ✦ System Architecture (Option C Expanded) ==&lt;br /&gt;
&lt;br /&gt;
=== 1. High-Level Architecture Diagram ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+-------------------+         +-----------------------+&lt;br /&gt;
|  React Frontend   |         |    Rails API Backend  |&lt;br /&gt;
+---------+---------+         +-----------+-----------+&lt;br /&gt;
          |                                 |&lt;br /&gt;
          | GET /review_dashboard_data       |&lt;br /&gt;
          +--------------------------------&amp;gt;+&lt;br /&gt;
          |                                 |&lt;br /&gt;
          |      JSON: reviewers, scores,   |&lt;br /&gt;
          |             metrics, grades     |&lt;br /&gt;
          &amp;lt;--------------------------------+&lt;br /&gt;
          |                                 |&lt;br /&gt;
          | POST /assign_review_grade       |&lt;br /&gt;
          +--------------------------------&amp;gt;+&lt;br /&gt;
          |                                 |&lt;br /&gt;
          | GET /export_reviews_csv         |&lt;br /&gt;
          +--------------------------------&amp;gt;+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Detailed Component Interaction Diagram ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
React Dashboard&lt;br /&gt;
  |&lt;br /&gt;
  |-- calls ApiService.fetchDashboardData()&lt;br /&gt;
  |       |&lt;br /&gt;
  |       |-- axios GET /review_dashboard_data&lt;br /&gt;
  |       |&lt;br /&gt;
  |       |-- receives structured reviewer JSON&lt;br /&gt;
  |&lt;br /&gt;
  |-- renders ReviewTable&lt;br /&gt;
  |       |&lt;br /&gt;
  |       |-- for each row, render:&lt;br /&gt;
  |             - Reviewer identity&lt;br /&gt;
  |             - Review counts&lt;br /&gt;
  |             - Scores (per round)&lt;br /&gt;
  |             - MetricsChart (Recharts)&lt;br /&gt;
  |             - GradeInput&lt;br /&gt;
  |             - CommentInput&lt;br /&gt;
  |&lt;br /&gt;
  |-- on grade input:&lt;br /&gt;
  |       |&lt;br /&gt;
  |       |-- axios POST /assign_review_grade&lt;br /&gt;
  |&lt;br /&gt;
  |-- on export click:&lt;br /&gt;
          |&lt;br /&gt;
          |-- axios GET /export_reviews_csv&lt;br /&gt;
          |&lt;br /&gt;
          |-- triggers browser file download&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Backend Internal Flow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ReviewGradingController#index&lt;br /&gt;
  |&lt;br /&gt;
  |-- loads Participants for assignment&lt;br /&gt;
  |-- loads ReviewResponseMaps&lt;br /&gt;
  |-- joins Users, Teams, Responses&lt;br /&gt;
  |-- computes score/volume per round&lt;br /&gt;
  |-- builds JSON structure&lt;br /&gt;
  |-- returns response&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4. Error Handling &amp;amp; Data Failure Modes ===&lt;br /&gt;
Backend handles:&lt;br /&gt;
* Missing responses → score = null, volume = null&lt;br /&gt;
* Late submissions → status = &amp;quot;late&amp;quot;&lt;br /&gt;
* No reviews assigned → empty arrays&lt;br /&gt;
* Invalid grade → HTTP 422&lt;br /&gt;
&lt;br /&gt;
Frontend handles:&lt;br /&gt;
* Empty dashboard → “No reviewers found”&lt;br /&gt;
* Fallback UI if metrics chart cannot render&lt;br /&gt;
* Retry option for failed grade submissions&lt;br /&gt;
&lt;br /&gt;
=== 5. Performance Considerations ===&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;includes&amp;lt;/code&amp;gt; to prevent N+1 queries.&lt;br /&gt;
* Computes all heavy metrics ahead of time on backend.&lt;br /&gt;
* JSON payload optimized to only include necessary fields.&lt;br /&gt;
* Recharts renders only visible metrics (virtual scrolling optional).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Data Flow ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Frontend (React)&lt;br /&gt;
   ↓ GET /review_dashboard_data&lt;br /&gt;
&lt;br /&gt;
Backend (Rails)&lt;br /&gt;
   → Aggregates Participant / Team / Response data&lt;br /&gt;
   → Computes:&lt;br /&gt;
        • Score per round&lt;br /&gt;
        • Unique-word volume&lt;br /&gt;
        • Average volume per round&lt;br /&gt;
   → Returns JSON&lt;br /&gt;
&lt;br /&gt;
Frontend&lt;br /&gt;
   → Renders reviewer rows + charts&lt;br /&gt;
   → Provides inline grading&lt;br /&gt;
&lt;br /&gt;
POST /assign_review_grade&lt;br /&gt;
   → Updates grade + comment&lt;br /&gt;
&lt;br /&gt;
GET /export_reviews_csv&lt;br /&gt;
   → Downloads CSV file&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Backend Technical Tests ===&lt;br /&gt;
* Validate round grouping logic.&lt;br /&gt;
* Validate unique word calculation (stopword edge cases).&lt;br /&gt;
* Ensure response-to-round mapping is correct.&lt;br /&gt;
* Test every API error condition:&lt;br /&gt;
** invalid grade&lt;br /&gt;
** missing participant&lt;br /&gt;
** missing response&lt;br /&gt;
** incorrect assignment id&lt;br /&gt;
** CSV generator with zero reviewers&lt;br /&gt;
&lt;br /&gt;
=== Frontend (Technical) Tests ===&lt;br /&gt;
* Test MetricsChart with:&lt;br /&gt;
** zero volume&lt;br /&gt;
** extremely large review text&lt;br /&gt;
** missing average&lt;br /&gt;
** multi-round assignments&lt;br /&gt;
* Test sorting stability (ascending/descending).&lt;br /&gt;
* Test grade input debounce + retry.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Team Members ==&lt;br /&gt;
* '''Deekshith Anantha'''&lt;br /&gt;
* '''Srinidhi'''&lt;br /&gt;
* '''Abhishek Rao'''&lt;br /&gt;
* Mentor: '''Ishani Rajput'''&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167114</id>
		<title>CSC/ECE 517 Fall 2025 - E2562. Review grading dashboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167114"/>
		<updated>2025-11-11T04:39:47Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The codebase for this reimplementation effort can be found in the following repositories:&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-front-end Frontend Repository (reimplementation-front-end)]&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-back-end Backend Repository (reimplementation-back-end)]&lt;br /&gt;
&lt;br /&gt;
The '''Review Grading Dashboard''' is a modernized instructor interface that simplifies grading peer reviews by consolidating key review information, grading tools, and performance metrics into a single, sortable page.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The current Expertiza system makes grading peer reviews cumbersome and inefficient. Review data such as reviewer details, completion status, and scores are scattered across multiple pages, forcing instructors to navigate between views to assign grades.  &lt;br /&gt;
&lt;br /&gt;
The goal of this project is to design and implement a dedicated '''Review Grading Dashboard''' that provides instructors and TAs with a unified page to:&lt;br /&gt;
* View all reviews submitted by students.&lt;br /&gt;
* Check review completion status and assigned scores.&lt;br /&gt;
* Analyze review metrics such as “volume” (unique word usage).&lt;br /&gt;
* Enter grades and comments for reviews.&lt;br /&gt;
* Export review scores and grades to a CSV file.&lt;br /&gt;
&lt;br /&gt;
This dashboard serves as the central grading hub for instructors, replacing the older fragmented grading workflow.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Core Requirements ===&lt;br /&gt;
* The dashboard is accessible only to users with the '''Instructor''' or '''TA''' role.&lt;br /&gt;
* The dashboard displays a table containing the following columns:&lt;br /&gt;
** '''Reviewer:''' Username and full name of the reviewer.&lt;br /&gt;
** '''Reviews Done:''' Number of reviews completed out of the total assigned.&lt;br /&gt;
** '''Team Reviewed:''' Each reviewed team, color-coded by review completion status (e.g., done, pending, late).&lt;br /&gt;
** '''Scores:''' Weighted average review scores per round, calculated via the existing `aggregate_questionnaire_score` method.&lt;br /&gt;
** '''Metrics:''' A column chart comparing the number of unique words used by the reviewer to the average review volume.&lt;br /&gt;
** '''Grade:''' Text box for instructors to enter a numeric grade.&lt;br /&gt;
** '''Comments:''' Text box for instructors to write feedback or grading rationale.&lt;br /&gt;
&lt;br /&gt;
* Each column should be sortable (e.g., Reviewer, Reviews Done, Scores).&lt;br /&gt;
* Table rows should have alternating background colors for readability.&lt;br /&gt;
* A button should allow instructors to '''export all grades and scores as a CSV file'''.&lt;br /&gt;
* If there are multiple review rounds, display one score and metric per round.&lt;br /&gt;
&lt;br /&gt;
=== Design Requirements ===&lt;br /&gt;
* Follow the same design guidelines as the [https://github.com/AnvithaReddyGutha/reimplementation-front-end/blob/main/design_document.md reimplementation-front-end design document].&lt;br /&gt;
* Use compact column widths to prevent unnecessary wrapping.&lt;br /&gt;
* Implement hover tooltips to show extended reviewer or metric details.&lt;br /&gt;
* Use consistent UI elements (text boxes, buttons) from the existing frontend.&lt;br /&gt;
* For the &amp;quot;Metrics&amp;quot; column chart:&lt;br /&gt;
** '''Charting library:''' Recharts (React-based, lightweight, responsive).&lt;br /&gt;
** The chart should compare each student’s review “volume” with the average.&lt;br /&gt;
* Maintain color accessibility and responsiveness across devices.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
=== Frontend ===&lt;br /&gt;
[[File:E2562.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Implemented using React + TypeScript as part of the reimplementation front-end.&lt;br /&gt;
* Fetch review and grading data from new API endpoints.&lt;br /&gt;
* Use '''Recharts''' for the Metrics visualization.&lt;br /&gt;
* Build a sortable, paginated table with reusable table and form components.&lt;br /&gt;
&lt;br /&gt;
=== Backend ===&lt;br /&gt;
* Implemented using Ruby on Rails.&lt;br /&gt;
* Create the following REST API endpoints:&lt;br /&gt;
** `/api/v1/review_dashboard_data` (GET) – Fetch all review-related data.&lt;br /&gt;
** `/api/v1/assign_review_grade` (POST) – Submit grades and comments.&lt;br /&gt;
** `/api/v1/export_reviews_csv` (GET) – Export data to CSV.&lt;br /&gt;
&lt;br /&gt;
* Optionally add a '''ResponseVolumeMixin''' to the `Response` model to calculate “volume,” defined as the count of unique words in a student’s review.&lt;br /&gt;
&lt;br /&gt;
== Design and Architecture ==&lt;br /&gt;
This project will follow the established architecture of the reimplementation effort, which is a Client-Server Architecture.&lt;br /&gt;
&lt;br /&gt;
'''Backend (Server):''' A &amp;lt;tt&amp;gt;Rails API&amp;lt;/tt&amp;gt; will expose new endpoints to provide data and handle grading.&lt;br /&gt;
'''Frontend (Client):''' A &amp;lt;tt&amp;gt;React + TypeScript&amp;lt;/tt&amp;gt; application will consume the API and render the interactive dashboard.&lt;br /&gt;
&lt;br /&gt;
=== Design Principles ===&lt;br /&gt;
* '''Single Responsibility Principle (SRP):''' The backend (Rails) is responsible only for business logic and data persistence. The frontend (React) is responsible only for presentation and user interaction. The &amp;lt;tt&amp;gt;Response&amp;lt;/tt&amp;gt; model will handle score calculation, while the new &amp;lt;tt&amp;gt;ReviewGradingController&amp;lt;/tt&amp;gt; will handle data aggregation.&lt;br /&gt;
* '''Don't Repeat Yourself (DRY):''' We will not write new code to calculate review scores. We will strictly reuse the existing &amp;lt;tt&amp;gt;aggregate_questionnaire_score&amp;lt;/tt&amp;gt; method available in the &amp;lt;tt&amp;gt;Response&amp;lt;/tt&amp;gt; object, as specified in the project requirements.&lt;br /&gt;
&lt;br /&gt;
=== Design Patterns ===&lt;br /&gt;
* '''Facade Pattern:''' The new backend API will act as a Facade. The frontend will make a single API call (e.g., &amp;lt;tt&amp;gt;GET /api/v1/review_dashboard_data&amp;lt;/tt&amp;gt;) to fetch all necessary data. This endpoint will hide the complexity of gathering information from multiple models (&amp;lt;tt&amp;gt;Participants&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Responses&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Teams&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Assignments&amp;lt;/tt&amp;gt;), simplifying frontend logic.&lt;br /&gt;
* '''Mixin (Ruby Concern):''' The project specification suggests a &amp;quot;''mixin''&amp;quot; to calculate review &amp;quot;volume&amp;quot;. We will implement this as a Ruby Concern (&amp;lt;tt&amp;gt;ResponseVolumeMixin&amp;lt;/tt&amp;gt;) and include it in the &amp;lt;tt&amp;gt;Response&amp;lt;/tt&amp;gt; model. This adheres to SRP by separating the volume calculation logic from the core responsibilities of the &amp;lt;tt&amp;gt;Response&amp;lt;/tt&amp;gt; model.&lt;br /&gt;
* '''Component-Based Architecture:''' The frontend will be built using reusable React components. The &amp;lt;tt&amp;gt;ReviewGradingDashboard&amp;lt;/tt&amp;gt; will be a parent component composed of:&lt;br /&gt;
** A reusable &amp;lt;tt&amp;gt;Table&amp;lt;/tt&amp;gt; component.&lt;br /&gt;
** A new &amp;lt;tt&amp;gt;MetricsChart&amp;lt;/tt&amp;gt; component (using &amp;lt;tt&amp;gt;Recharts&amp;lt;/tt&amp;gt;) to display the volume bar graph.&lt;br /&gt;
** Reusable &amp;lt;tt&amp;gt;GradeInput&amp;lt;/tt&amp;gt; components.&lt;br /&gt;
&lt;br /&gt;
=== Data Flow ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Frontend (React)&lt;br /&gt;
   ↓  GET /review_dashboard_data&lt;br /&gt;
Backend (Rails)&lt;br /&gt;
   →  Returns JSON with reviewer info, scores, and metrics&lt;br /&gt;
Frontend&lt;br /&gt;
   ↓  Renders sortable table + charts&lt;br /&gt;
Instructor Input&lt;br /&gt;
   →  POST /assign_review_grade&lt;br /&gt;
Backend&lt;br /&gt;
   →  Stores grade + supports CSV export&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Results ==&lt;br /&gt;
(To be completed upon implementation)&lt;br /&gt;
&lt;br /&gt;
Expected outcomes:&lt;br /&gt;
* A clean, sortable dashboard interface for instructors.&lt;br /&gt;
* Visual metrics to compare review quality and engagement.&lt;br /&gt;
* Streamlined grading workflow with direct input and CSV export.&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Manual Testing ===&lt;br /&gt;
# Log in as an instructor or TA.&lt;br /&gt;
# Navigate to the course dashboard and click the '''Review Grading Dashboard''' link.&lt;br /&gt;
# Verify that:&lt;br /&gt;
## Reviewer names, teams reviewed, and completion status are displayed correctly.&lt;br /&gt;
## Team color codes correspond to review completion.&lt;br /&gt;
## Scores are accurate per round.&lt;br /&gt;
## The metrics chart renders correctly using Recharts.&lt;br /&gt;
## Grades and comments can be entered and saved successfully.&lt;br /&gt;
# Click the “Export CSV” button and ensure the CSV file contains accurate data.&lt;br /&gt;
# Test sorting functionality for multiple columns.&lt;br /&gt;
# Confirm that alternating row colors and hover highlights appear correctly.&lt;br /&gt;
&lt;br /&gt;
=== Automated Testing ===&lt;br /&gt;
* '''Backend (RSpec):'''&lt;br /&gt;
** Test API responses for correctness and completeness.&lt;br /&gt;
** Validate `volume()` method returns expected unique word count.&lt;br /&gt;
** Verify CSV export structure and content.&lt;br /&gt;
&lt;br /&gt;
* '''Frontend (Jest + React Testing Library):'''&lt;br /&gt;
** Test rendering of dashboard table and Recharts components.&lt;br /&gt;
** Verify sorting and input functionalities.&lt;br /&gt;
** Mock API calls to test grade submission.&lt;br /&gt;
&lt;br /&gt;
== Team Members ==&lt;br /&gt;
* ''' Deekshith Anantha''' &lt;br /&gt;
* ''' Srinidhi''' &lt;br /&gt;
* '''Abhishek Rao'''&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167070</id>
		<title>CSC/ECE 517 Fall 2025 - E2562. Review grading dashboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167070"/>
		<updated>2025-11-10T22:34:32Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* Frontend */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The codebase for this reimplementation effort can be found in the following repositories:&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-front-end Frontend Repository (reimplementation-front-end)]&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-back-end Backend Repository (reimplementation-back-end)]&lt;br /&gt;
&lt;br /&gt;
The '''Review Grading Dashboard''' is a modernized instructor interface that simplifies grading peer reviews by consolidating key review information, grading tools, and performance metrics into a single, sortable page.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The current Expertiza system makes grading peer reviews cumbersome and inefficient. Review data such as reviewer details, completion status, and scores are scattered across multiple pages, forcing instructors to navigate between views to assign grades.  &lt;br /&gt;
&lt;br /&gt;
The goal of this project is to design and implement a dedicated '''Review Grading Dashboard''' that provides instructors and TAs with a unified page to:&lt;br /&gt;
* View all reviews submitted by students.&lt;br /&gt;
* Check review completion status and assigned scores.&lt;br /&gt;
* Analyze review metrics such as “volume” (unique word usage).&lt;br /&gt;
* Enter grades and comments for reviews.&lt;br /&gt;
* Export review scores and grades to a CSV file.&lt;br /&gt;
&lt;br /&gt;
This dashboard serves as the central grading hub for instructors, replacing the older fragmented grading workflow.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Core Requirements ===&lt;br /&gt;
* The dashboard is accessible only to users with the '''Instructor''' or '''TA''' role.&lt;br /&gt;
* The dashboard displays a table containing the following columns:&lt;br /&gt;
** '''Reviewer:''' Username and full name of the reviewer.&lt;br /&gt;
** '''Reviews Done:''' Number of reviews completed out of the total assigned.&lt;br /&gt;
** '''Team Reviewed:''' Each reviewed team, color-coded by review completion status (e.g., done, pending, late).&lt;br /&gt;
** '''Scores:''' Weighted average review scores per round, calculated via the existing `aggregate_questionnaire_score` method.&lt;br /&gt;
** '''Metrics:''' A column chart comparing the number of unique words used by the reviewer to the average review volume.&lt;br /&gt;
** '''Grade:''' Text box for instructors to enter a numeric grade.&lt;br /&gt;
** '''Comments:''' Text box for instructors to write feedback or grading rationale.&lt;br /&gt;
&lt;br /&gt;
* Each column should be sortable (e.g., Reviewer, Reviews Done, Scores).&lt;br /&gt;
* Table rows should have alternating background colors for readability.&lt;br /&gt;
* A button should allow instructors to '''export all grades and scores as a CSV file'''.&lt;br /&gt;
* If there are multiple review rounds, display one score and metric per round.&lt;br /&gt;
&lt;br /&gt;
=== Design Requirements ===&lt;br /&gt;
* Follow the same design guidelines as the [https://github.com/AnvithaReddyGutha/reimplementation-front-end/blob/main/design_document.md reimplementation-front-end design document].&lt;br /&gt;
* Use compact column widths to prevent unnecessary wrapping.&lt;br /&gt;
* Implement hover tooltips to show extended reviewer or metric details.&lt;br /&gt;
* Use consistent UI elements (text boxes, buttons) from the existing frontend.&lt;br /&gt;
* For the &amp;quot;Metrics&amp;quot; column chart:&lt;br /&gt;
** '''Charting library:''' Recharts (React-based, lightweight, responsive).&lt;br /&gt;
** The chart should compare each student’s review “volume” with the average.&lt;br /&gt;
* Maintain color accessibility and responsiveness across devices.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
=== Frontend ===&lt;br /&gt;
[[File:E2562.png|1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Implemented using React + TypeScript as part of the reimplementation front-end.&lt;br /&gt;
* Fetch review and grading data from new API endpoints.&lt;br /&gt;
* Use '''Recharts''' for the Metrics visualization.&lt;br /&gt;
* Build a sortable, paginated table with reusable table and form components.&lt;br /&gt;
&lt;br /&gt;
=== Backend ===&lt;br /&gt;
* Implemented using Ruby on Rails.&lt;br /&gt;
* Create the following REST API endpoints:&lt;br /&gt;
** `/api/v1/review_dashboard_data` (GET) – Fetch all review-related data.&lt;br /&gt;
** `/api/v1/assign_review_grade` (POST) – Submit grades and comments.&lt;br /&gt;
** `/api/v1/export_reviews_csv` (GET) – Export data to CSV.&lt;br /&gt;
&lt;br /&gt;
* Optionally add a '''ResponseVolumeMixin''' to the `Response` model to calculate “volume,” defined as the count of unique words in a student’s review.&lt;br /&gt;
&lt;br /&gt;
=== Data Flow ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Frontend (React)&lt;br /&gt;
   ↓  GET /review_dashboard_data&lt;br /&gt;
Backend (Rails)&lt;br /&gt;
   →  Returns JSON with reviewer info, scores, and metrics&lt;br /&gt;
Frontend&lt;br /&gt;
   ↓  Renders sortable table + charts&lt;br /&gt;
Instructor Input&lt;br /&gt;
   →  POST /assign_review_grade&lt;br /&gt;
Backend&lt;br /&gt;
   →  Stores grade + supports CSV export&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Results ==&lt;br /&gt;
(To be completed upon implementation)&lt;br /&gt;
&lt;br /&gt;
Expected outcomes:&lt;br /&gt;
* A clean, sortable dashboard interface for instructors.&lt;br /&gt;
* Visual metrics to compare review quality and engagement.&lt;br /&gt;
* Streamlined grading workflow with direct input and CSV export.&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Manual Testing ===&lt;br /&gt;
# Log in as an instructor or TA.&lt;br /&gt;
# Navigate to the course dashboard and click the '''Review Grading Dashboard''' link.&lt;br /&gt;
# Verify that:&lt;br /&gt;
## Reviewer names, teams reviewed, and completion status are displayed correctly.&lt;br /&gt;
## Team color codes correspond to review completion.&lt;br /&gt;
## Scores are accurate per round.&lt;br /&gt;
## The metrics chart renders correctly using Recharts.&lt;br /&gt;
## Grades and comments can be entered and saved successfully.&lt;br /&gt;
# Click the “Export CSV” button and ensure the CSV file contains accurate data.&lt;br /&gt;
# Test sorting functionality for multiple columns.&lt;br /&gt;
# Confirm that alternating row colors and hover highlights appear correctly.&lt;br /&gt;
&lt;br /&gt;
=== Automated Testing ===&lt;br /&gt;
* '''Backend (RSpec):'''&lt;br /&gt;
** Test API responses for correctness and completeness.&lt;br /&gt;
** Validate `volume()` method returns expected unique word count.&lt;br /&gt;
** Verify CSV export structure and content.&lt;br /&gt;
&lt;br /&gt;
* '''Frontend (Jest + React Testing Library):'''&lt;br /&gt;
** Test rendering of dashboard table and Recharts components.&lt;br /&gt;
** Verify sorting and input functionalities.&lt;br /&gt;
** Mock API calls to test grade submission.&lt;br /&gt;
&lt;br /&gt;
== Team Members ==&lt;br /&gt;
* ''' Deekshith Anantha''' &lt;br /&gt;
* ''' Srinidhi''' &lt;br /&gt;
* '''Abhishek Rao'''&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167069</id>
		<title>CSC/ECE 517 Fall 2025 - E2562. Review grading dashboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167069"/>
		<updated>2025-11-10T22:34:19Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* Frontend */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The codebase for this reimplementation effort can be found in the following repositories:&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-front-end Frontend Repository (reimplementation-front-end)]&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-back-end Backend Repository (reimplementation-back-end)]&lt;br /&gt;
&lt;br /&gt;
The '''Review Grading Dashboard''' is a modernized instructor interface that simplifies grading peer reviews by consolidating key review information, grading tools, and performance metrics into a single, sortable page.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The current Expertiza system makes grading peer reviews cumbersome and inefficient. Review data such as reviewer details, completion status, and scores are scattered across multiple pages, forcing instructors to navigate between views to assign grades.  &lt;br /&gt;
&lt;br /&gt;
The goal of this project is to design and implement a dedicated '''Review Grading Dashboard''' that provides instructors and TAs with a unified page to:&lt;br /&gt;
* View all reviews submitted by students.&lt;br /&gt;
* Check review completion status and assigned scores.&lt;br /&gt;
* Analyze review metrics such as “volume” (unique word usage).&lt;br /&gt;
* Enter grades and comments for reviews.&lt;br /&gt;
* Export review scores and grades to a CSV file.&lt;br /&gt;
&lt;br /&gt;
This dashboard serves as the central grading hub for instructors, replacing the older fragmented grading workflow.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Core Requirements ===&lt;br /&gt;
* The dashboard is accessible only to users with the '''Instructor''' or '''TA''' role.&lt;br /&gt;
* The dashboard displays a table containing the following columns:&lt;br /&gt;
** '''Reviewer:''' Username and full name of the reviewer.&lt;br /&gt;
** '''Reviews Done:''' Number of reviews completed out of the total assigned.&lt;br /&gt;
** '''Team Reviewed:''' Each reviewed team, color-coded by review completion status (e.g., done, pending, late).&lt;br /&gt;
** '''Scores:''' Weighted average review scores per round, calculated via the existing `aggregate_questionnaire_score` method.&lt;br /&gt;
** '''Metrics:''' A column chart comparing the number of unique words used by the reviewer to the average review volume.&lt;br /&gt;
** '''Grade:''' Text box for instructors to enter a numeric grade.&lt;br /&gt;
** '''Comments:''' Text box for instructors to write feedback or grading rationale.&lt;br /&gt;
&lt;br /&gt;
* Each column should be sortable (e.g., Reviewer, Reviews Done, Scores).&lt;br /&gt;
* Table rows should have alternating background colors for readability.&lt;br /&gt;
* A button should allow instructors to '''export all grades and scores as a CSV file'''.&lt;br /&gt;
* If there are multiple review rounds, display one score and metric per round.&lt;br /&gt;
&lt;br /&gt;
=== Design Requirements ===&lt;br /&gt;
* Follow the same design guidelines as the [https://github.com/AnvithaReddyGutha/reimplementation-front-end/blob/main/design_document.md reimplementation-front-end design document].&lt;br /&gt;
* Use compact column widths to prevent unnecessary wrapping.&lt;br /&gt;
* Implement hover tooltips to show extended reviewer or metric details.&lt;br /&gt;
* Use consistent UI elements (text boxes, buttons) from the existing frontend.&lt;br /&gt;
* For the &amp;quot;Metrics&amp;quot; column chart:&lt;br /&gt;
** '''Charting library:''' Recharts (React-based, lightweight, responsive).&lt;br /&gt;
** The chart should compare each student’s review “volume” with the average.&lt;br /&gt;
* Maintain color accessibility and responsiveness across devices.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
=== Frontend ===&lt;br /&gt;
[[File:E2562.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Implemented using React + TypeScript as part of the reimplementation front-end.&lt;br /&gt;
* Fetch review and grading data from new API endpoints.&lt;br /&gt;
* Use '''Recharts''' for the Metrics visualization.&lt;br /&gt;
* Build a sortable, paginated table with reusable table and form components.&lt;br /&gt;
&lt;br /&gt;
=== Backend ===&lt;br /&gt;
* Implemented using Ruby on Rails.&lt;br /&gt;
* Create the following REST API endpoints:&lt;br /&gt;
** `/api/v1/review_dashboard_data` (GET) – Fetch all review-related data.&lt;br /&gt;
** `/api/v1/assign_review_grade` (POST) – Submit grades and comments.&lt;br /&gt;
** `/api/v1/export_reviews_csv` (GET) – Export data to CSV.&lt;br /&gt;
&lt;br /&gt;
* Optionally add a '''ResponseVolumeMixin''' to the `Response` model to calculate “volume,” defined as the count of unique words in a student’s review.&lt;br /&gt;
&lt;br /&gt;
=== Data Flow ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Frontend (React)&lt;br /&gt;
   ↓  GET /review_dashboard_data&lt;br /&gt;
Backend (Rails)&lt;br /&gt;
   →  Returns JSON with reviewer info, scores, and metrics&lt;br /&gt;
Frontend&lt;br /&gt;
   ↓  Renders sortable table + charts&lt;br /&gt;
Instructor Input&lt;br /&gt;
   →  POST /assign_review_grade&lt;br /&gt;
Backend&lt;br /&gt;
   →  Stores grade + supports CSV export&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Results ==&lt;br /&gt;
(To be completed upon implementation)&lt;br /&gt;
&lt;br /&gt;
Expected outcomes:&lt;br /&gt;
* A clean, sortable dashboard interface for instructors.&lt;br /&gt;
* Visual metrics to compare review quality and engagement.&lt;br /&gt;
* Streamlined grading workflow with direct input and CSV export.&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Manual Testing ===&lt;br /&gt;
# Log in as an instructor or TA.&lt;br /&gt;
# Navigate to the course dashboard and click the '''Review Grading Dashboard''' link.&lt;br /&gt;
# Verify that:&lt;br /&gt;
## Reviewer names, teams reviewed, and completion status are displayed correctly.&lt;br /&gt;
## Team color codes correspond to review completion.&lt;br /&gt;
## Scores are accurate per round.&lt;br /&gt;
## The metrics chart renders correctly using Recharts.&lt;br /&gt;
## Grades and comments can be entered and saved successfully.&lt;br /&gt;
# Click the “Export CSV” button and ensure the CSV file contains accurate data.&lt;br /&gt;
# Test sorting functionality for multiple columns.&lt;br /&gt;
# Confirm that alternating row colors and hover highlights appear correctly.&lt;br /&gt;
&lt;br /&gt;
=== Automated Testing ===&lt;br /&gt;
* '''Backend (RSpec):'''&lt;br /&gt;
** Test API responses for correctness and completeness.&lt;br /&gt;
** Validate `volume()` method returns expected unique word count.&lt;br /&gt;
** Verify CSV export structure and content.&lt;br /&gt;
&lt;br /&gt;
* '''Frontend (Jest + React Testing Library):'''&lt;br /&gt;
** Test rendering of dashboard table and Recharts components.&lt;br /&gt;
** Verify sorting and input functionalities.&lt;br /&gt;
** Mock API calls to test grade submission.&lt;br /&gt;
&lt;br /&gt;
== Team Members ==&lt;br /&gt;
* ''' Deekshith Anantha''' &lt;br /&gt;
* ''' Srinidhi''' &lt;br /&gt;
* '''Abhishek Rao'''&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167068</id>
		<title>CSC/ECE 517 Fall 2025 - E2562. Review grading dashboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167068"/>
		<updated>2025-11-10T22:33:59Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* Frontend */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The codebase for this reimplementation effort can be found in the following repositories:&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-front-end Frontend Repository (reimplementation-front-end)]&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-back-end Backend Repository (reimplementation-back-end)]&lt;br /&gt;
&lt;br /&gt;
The '''Review Grading Dashboard''' is a modernized instructor interface that simplifies grading peer reviews by consolidating key review information, grading tools, and performance metrics into a single, sortable page.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The current Expertiza system makes grading peer reviews cumbersome and inefficient. Review data such as reviewer details, completion status, and scores are scattered across multiple pages, forcing instructors to navigate between views to assign grades.  &lt;br /&gt;
&lt;br /&gt;
The goal of this project is to design and implement a dedicated '''Review Grading Dashboard''' that provides instructors and TAs with a unified page to:&lt;br /&gt;
* View all reviews submitted by students.&lt;br /&gt;
* Check review completion status and assigned scores.&lt;br /&gt;
* Analyze review metrics such as “volume” (unique word usage).&lt;br /&gt;
* Enter grades and comments for reviews.&lt;br /&gt;
* Export review scores and grades to a CSV file.&lt;br /&gt;
&lt;br /&gt;
This dashboard serves as the central grading hub for instructors, replacing the older fragmented grading workflow.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Core Requirements ===&lt;br /&gt;
* The dashboard is accessible only to users with the '''Instructor''' or '''TA''' role.&lt;br /&gt;
* The dashboard displays a table containing the following columns:&lt;br /&gt;
** '''Reviewer:''' Username and full name of the reviewer.&lt;br /&gt;
** '''Reviews Done:''' Number of reviews completed out of the total assigned.&lt;br /&gt;
** '''Team Reviewed:''' Each reviewed team, color-coded by review completion status (e.g., done, pending, late).&lt;br /&gt;
** '''Scores:''' Weighted average review scores per round, calculated via the existing `aggregate_questionnaire_score` method.&lt;br /&gt;
** '''Metrics:''' A column chart comparing the number of unique words used by the reviewer to the average review volume.&lt;br /&gt;
** '''Grade:''' Text box for instructors to enter a numeric grade.&lt;br /&gt;
** '''Comments:''' Text box for instructors to write feedback or grading rationale.&lt;br /&gt;
&lt;br /&gt;
* Each column should be sortable (e.g., Reviewer, Reviews Done, Scores).&lt;br /&gt;
* Table rows should have alternating background colors for readability.&lt;br /&gt;
* A button should allow instructors to '''export all grades and scores as a CSV file'''.&lt;br /&gt;
* If there are multiple review rounds, display one score and metric per round.&lt;br /&gt;
&lt;br /&gt;
=== Design Requirements ===&lt;br /&gt;
* Follow the same design guidelines as the [https://github.com/AnvithaReddyGutha/reimplementation-front-end/blob/main/design_document.md reimplementation-front-end design document].&lt;br /&gt;
* Use compact column widths to prevent unnecessary wrapping.&lt;br /&gt;
* Implement hover tooltips to show extended reviewer or metric details.&lt;br /&gt;
* Use consistent UI elements (text boxes, buttons) from the existing frontend.&lt;br /&gt;
* For the &amp;quot;Metrics&amp;quot; column chart:&lt;br /&gt;
** '''Charting library:''' Recharts (React-based, lightweight, responsive).&lt;br /&gt;
** The chart should compare each student’s review “volume” with the average.&lt;br /&gt;
* Maintain color accessibility and responsiveness across devices.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
=== Frontend ===&lt;br /&gt;
[[File:E2562.png|500px|thumb|left|Caption]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Implemented using React + TypeScript as part of the reimplementation front-end.&lt;br /&gt;
* Fetch review and grading data from new API endpoints.&lt;br /&gt;
* Use '''Recharts''' for the Metrics visualization.&lt;br /&gt;
* Build a sortable, paginated table with reusable table and form components.&lt;br /&gt;
&lt;br /&gt;
=== Backend ===&lt;br /&gt;
* Implemented using Ruby on Rails.&lt;br /&gt;
* Create the following REST API endpoints:&lt;br /&gt;
** `/api/v1/review_dashboard_data` (GET) – Fetch all review-related data.&lt;br /&gt;
** `/api/v1/assign_review_grade` (POST) – Submit grades and comments.&lt;br /&gt;
** `/api/v1/export_reviews_csv` (GET) – Export data to CSV.&lt;br /&gt;
&lt;br /&gt;
* Optionally add a '''ResponseVolumeMixin''' to the `Response` model to calculate “volume,” defined as the count of unique words in a student’s review.&lt;br /&gt;
&lt;br /&gt;
=== Data Flow ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Frontend (React)&lt;br /&gt;
   ↓  GET /review_dashboard_data&lt;br /&gt;
Backend (Rails)&lt;br /&gt;
   →  Returns JSON with reviewer info, scores, and metrics&lt;br /&gt;
Frontend&lt;br /&gt;
   ↓  Renders sortable table + charts&lt;br /&gt;
Instructor Input&lt;br /&gt;
   →  POST /assign_review_grade&lt;br /&gt;
Backend&lt;br /&gt;
   →  Stores grade + supports CSV export&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Results ==&lt;br /&gt;
(To be completed upon implementation)&lt;br /&gt;
&lt;br /&gt;
Expected outcomes:&lt;br /&gt;
* A clean, sortable dashboard interface for instructors.&lt;br /&gt;
* Visual metrics to compare review quality and engagement.&lt;br /&gt;
* Streamlined grading workflow with direct input and CSV export.&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Manual Testing ===&lt;br /&gt;
# Log in as an instructor or TA.&lt;br /&gt;
# Navigate to the course dashboard and click the '''Review Grading Dashboard''' link.&lt;br /&gt;
# Verify that:&lt;br /&gt;
## Reviewer names, teams reviewed, and completion status are displayed correctly.&lt;br /&gt;
## Team color codes correspond to review completion.&lt;br /&gt;
## Scores are accurate per round.&lt;br /&gt;
## The metrics chart renders correctly using Recharts.&lt;br /&gt;
## Grades and comments can be entered and saved successfully.&lt;br /&gt;
# Click the “Export CSV” button and ensure the CSV file contains accurate data.&lt;br /&gt;
# Test sorting functionality for multiple columns.&lt;br /&gt;
# Confirm that alternating row colors and hover highlights appear correctly.&lt;br /&gt;
&lt;br /&gt;
=== Automated Testing ===&lt;br /&gt;
* '''Backend (RSpec):'''&lt;br /&gt;
** Test API responses for correctness and completeness.&lt;br /&gt;
** Validate `volume()` method returns expected unique word count.&lt;br /&gt;
** Verify CSV export structure and content.&lt;br /&gt;
&lt;br /&gt;
* '''Frontend (Jest + React Testing Library):'''&lt;br /&gt;
** Test rendering of dashboard table and Recharts components.&lt;br /&gt;
** Verify sorting and input functionalities.&lt;br /&gt;
** Mock API calls to test grade submission.&lt;br /&gt;
&lt;br /&gt;
== Team Members ==&lt;br /&gt;
* ''' Deekshith Anantha''' &lt;br /&gt;
* ''' Srinidhi''' &lt;br /&gt;
* '''Abhishek Rao'''&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167067</id>
		<title>CSC/ECE 517 Fall 2025 - E2562. Review grading dashboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=167067"/>
		<updated>2025-11-10T22:33:26Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The codebase for this reimplementation effort can be found in the following repositories:&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-front-end Frontend Repository (reimplementation-front-end)]&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-back-end Backend Repository (reimplementation-back-end)]&lt;br /&gt;
&lt;br /&gt;
The '''Review Grading Dashboard''' is a modernized instructor interface that simplifies grading peer reviews by consolidating key review information, grading tools, and performance metrics into a single, sortable page.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The current Expertiza system makes grading peer reviews cumbersome and inefficient. Review data such as reviewer details, completion status, and scores are scattered across multiple pages, forcing instructors to navigate between views to assign grades.  &lt;br /&gt;
&lt;br /&gt;
The goal of this project is to design and implement a dedicated '''Review Grading Dashboard''' that provides instructors and TAs with a unified page to:&lt;br /&gt;
* View all reviews submitted by students.&lt;br /&gt;
* Check review completion status and assigned scores.&lt;br /&gt;
* Analyze review metrics such as “volume” (unique word usage).&lt;br /&gt;
* Enter grades and comments for reviews.&lt;br /&gt;
* Export review scores and grades to a CSV file.&lt;br /&gt;
&lt;br /&gt;
This dashboard serves as the central grading hub for instructors, replacing the older fragmented grading workflow.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Core Requirements ===&lt;br /&gt;
* The dashboard is accessible only to users with the '''Instructor''' or '''TA''' role.&lt;br /&gt;
* The dashboard displays a table containing the following columns:&lt;br /&gt;
** '''Reviewer:''' Username and full name of the reviewer.&lt;br /&gt;
** '''Reviews Done:''' Number of reviews completed out of the total assigned.&lt;br /&gt;
** '''Team Reviewed:''' Each reviewed team, color-coded by review completion status (e.g., done, pending, late).&lt;br /&gt;
** '''Scores:''' Weighted average review scores per round, calculated via the existing `aggregate_questionnaire_score` method.&lt;br /&gt;
** '''Metrics:''' A column chart comparing the number of unique words used by the reviewer to the average review volume.&lt;br /&gt;
** '''Grade:''' Text box for instructors to enter a numeric grade.&lt;br /&gt;
** '''Comments:''' Text box for instructors to write feedback or grading rationale.&lt;br /&gt;
&lt;br /&gt;
* Each column should be sortable (e.g., Reviewer, Reviews Done, Scores).&lt;br /&gt;
* Table rows should have alternating background colors for readability.&lt;br /&gt;
* A button should allow instructors to '''export all grades and scores as a CSV file'''.&lt;br /&gt;
* If there are multiple review rounds, display one score and metric per round.&lt;br /&gt;
&lt;br /&gt;
=== Design Requirements ===&lt;br /&gt;
* Follow the same design guidelines as the [https://github.com/AnvithaReddyGutha/reimplementation-front-end/blob/main/design_document.md reimplementation-front-end design document].&lt;br /&gt;
* Use compact column widths to prevent unnecessary wrapping.&lt;br /&gt;
* Implement hover tooltips to show extended reviewer or metric details.&lt;br /&gt;
* Use consistent UI elements (text boxes, buttons) from the existing frontend.&lt;br /&gt;
* For the &amp;quot;Metrics&amp;quot; column chart:&lt;br /&gt;
** '''Charting library:''' Recharts (React-based, lightweight, responsive).&lt;br /&gt;
** The chart should compare each student’s review “volume” with the average.&lt;br /&gt;
* Maintain color accessibility and responsiveness across devices.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
=== Frontend ===&lt;br /&gt;
[[File:E2562.png|200px|thumb|left|Caption]]&lt;br /&gt;
* Implemented using React + TypeScript as part of the reimplementation front-end.&lt;br /&gt;
* Fetch review and grading data from new API endpoints.&lt;br /&gt;
* Use '''Recharts''' for the Metrics visualization.&lt;br /&gt;
* Build a sortable, paginated table with reusable table and form components.&lt;br /&gt;
&lt;br /&gt;
=== Backend ===&lt;br /&gt;
* Implemented using Ruby on Rails.&lt;br /&gt;
* Create the following REST API endpoints:&lt;br /&gt;
** `/api/v1/review_dashboard_data` (GET) – Fetch all review-related data.&lt;br /&gt;
** `/api/v1/assign_review_grade` (POST) – Submit grades and comments.&lt;br /&gt;
** `/api/v1/export_reviews_csv` (GET) – Export data to CSV.&lt;br /&gt;
&lt;br /&gt;
* Optionally add a '''ResponseVolumeMixin''' to the `Response` model to calculate “volume,” defined as the count of unique words in a student’s review.&lt;br /&gt;
&lt;br /&gt;
=== Data Flow ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Frontend (React)&lt;br /&gt;
   ↓  GET /review_dashboard_data&lt;br /&gt;
Backend (Rails)&lt;br /&gt;
   →  Returns JSON with reviewer info, scores, and metrics&lt;br /&gt;
Frontend&lt;br /&gt;
   ↓  Renders sortable table + charts&lt;br /&gt;
Instructor Input&lt;br /&gt;
   →  POST /assign_review_grade&lt;br /&gt;
Backend&lt;br /&gt;
   →  Stores grade + supports CSV export&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Results ==&lt;br /&gt;
(To be completed upon implementation)&lt;br /&gt;
&lt;br /&gt;
Expected outcomes:&lt;br /&gt;
* A clean, sortable dashboard interface for instructors.&lt;br /&gt;
* Visual metrics to compare review quality and engagement.&lt;br /&gt;
* Streamlined grading workflow with direct input and CSV export.&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Manual Testing ===&lt;br /&gt;
# Log in as an instructor or TA.&lt;br /&gt;
# Navigate to the course dashboard and click the '''Review Grading Dashboard''' link.&lt;br /&gt;
# Verify that:&lt;br /&gt;
## Reviewer names, teams reviewed, and completion status are displayed correctly.&lt;br /&gt;
## Team color codes correspond to review completion.&lt;br /&gt;
## Scores are accurate per round.&lt;br /&gt;
## The metrics chart renders correctly using Recharts.&lt;br /&gt;
## Grades and comments can be entered and saved successfully.&lt;br /&gt;
# Click the “Export CSV” button and ensure the CSV file contains accurate data.&lt;br /&gt;
# Test sorting functionality for multiple columns.&lt;br /&gt;
# Confirm that alternating row colors and hover highlights appear correctly.&lt;br /&gt;
&lt;br /&gt;
=== Automated Testing ===&lt;br /&gt;
* '''Backend (RSpec):'''&lt;br /&gt;
** Test API responses for correctness and completeness.&lt;br /&gt;
** Validate `volume()` method returns expected unique word count.&lt;br /&gt;
** Verify CSV export structure and content.&lt;br /&gt;
&lt;br /&gt;
* '''Frontend (Jest + React Testing Library):'''&lt;br /&gt;
** Test rendering of dashboard table and Recharts components.&lt;br /&gt;
** Verify sorting and input functionalities.&lt;br /&gt;
** Mock API calls to test grade submission.&lt;br /&gt;
&lt;br /&gt;
== Team Members ==&lt;br /&gt;
* ''' Deekshith Anantha''' &lt;br /&gt;
* ''' Srinidhi''' &lt;br /&gt;
* '''Abhishek Rao'''&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2562.png&amp;diff=167066</id>
		<title>File:E2562.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2562.png&amp;diff=167066"/>
		<updated>2025-11-10T22:29:34Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=166950</id>
		<title>CSC/ECE 517 Fall 2025 - E2562. Review grading dashboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=166950"/>
		<updated>2025-11-07T03:26:23Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* Team Members */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= SC/ECE 517 Fall 2025 – E2562. Review Grading Dashboard =&lt;br /&gt;
&lt;br /&gt;
This page contains information about '''E2562. Review Grading Dashboard''', which is a project in CSC/ECE 517 Fall 2025.&lt;br /&gt;
&lt;br /&gt;
Please see below for a description of the design of the project.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
'''Expertiza''' is an open-source application built on the Ruby on Rails framework. Instructors can create and manage assignments, and students can form teams and peer review each other’s work.  &lt;br /&gt;
&lt;br /&gt;
The frontend is written in '''TypeScript (React)''', while the backend uses '''Ruby on Rails'''. The codebase for this reimplementation effort can be found in the following repositories:&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-front-end Frontend Repository (reimplementation-front-end)]&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-back-end Backend Repository (reimplementation-back-end)]&lt;br /&gt;
&lt;br /&gt;
The '''Review Grading Dashboard''' is a modernized instructor interface that simplifies grading peer reviews by consolidating key review information, grading tools, and performance metrics into a single, sortable page.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The current Expertiza system makes grading peer reviews cumbersome and inefficient. Review data such as reviewer details, completion status, and scores are scattered across multiple pages, forcing instructors to navigate between views to assign grades.  &lt;br /&gt;
&lt;br /&gt;
The goal of this project is to design and implement a dedicated '''Review Grading Dashboard''' that provides instructors and TAs with a unified page to:&lt;br /&gt;
* View all reviews submitted by students.&lt;br /&gt;
* Check review completion status and assigned scores.&lt;br /&gt;
* Analyze review metrics such as “volume” (unique word usage).&lt;br /&gt;
* Enter grades and comments for reviews.&lt;br /&gt;
* Export review scores and grades to a CSV file.&lt;br /&gt;
&lt;br /&gt;
This dashboard serves as the central grading hub for instructors, replacing the older fragmented grading workflow.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Core Requirements ===&lt;br /&gt;
* The dashboard is accessible only to users with the '''Instructor''' or '''TA''' role.&lt;br /&gt;
* The dashboard displays a table containing the following columns:&lt;br /&gt;
** '''Reviewer:''' Username and full name of the reviewer.&lt;br /&gt;
** '''Reviews Done:''' Number of reviews completed out of the total assigned.&lt;br /&gt;
** '''Team Reviewed:''' Each reviewed team, color-coded by review completion status (e.g., done, pending, late).&lt;br /&gt;
** '''Scores:''' Weighted average review scores per round, calculated via the existing `aggregate_questionnaire_score` method.&lt;br /&gt;
** '''Metrics:''' A column chart comparing the number of unique words used by the reviewer to the average review volume.&lt;br /&gt;
** '''Grade:''' Text box for instructors to enter a numeric grade.&lt;br /&gt;
** '''Comments:''' Text box for instructors to write feedback or grading rationale.&lt;br /&gt;
&lt;br /&gt;
* Each column should be sortable (e.g., Reviewer, Reviews Done, Scores).&lt;br /&gt;
* Table rows should have alternating background colors for readability.&lt;br /&gt;
* A button should allow instructors to '''export all grades and scores as a CSV file'''.&lt;br /&gt;
* If there are multiple review rounds, display one score and metric per round.&lt;br /&gt;
&lt;br /&gt;
=== Design Requirements ===&lt;br /&gt;
* Follow the same design guidelines as the [https://github.com/AnvithaReddyGutha/reimplementation-front-end/blob/main/design_document.md reimplementation-front-end design document].&lt;br /&gt;
* Use compact column widths to prevent unnecessary wrapping.&lt;br /&gt;
* Implement hover tooltips to show extended reviewer or metric details.&lt;br /&gt;
* Use consistent UI elements (text boxes, buttons) from the existing frontend.&lt;br /&gt;
* For the &amp;quot;Metrics&amp;quot; column chart:&lt;br /&gt;
** '''Charting library:''' Recharts (React-based, lightweight, responsive).&lt;br /&gt;
** The chart should compare each student’s review “volume” with the average.&lt;br /&gt;
* Maintain color accessibility and responsiveness across devices.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
=== Frontend ===&lt;br /&gt;
* Implemented using React + TypeScript as part of the reimplementation front-end.&lt;br /&gt;
* Fetch review and grading data from new API endpoints.&lt;br /&gt;
* Use '''Recharts''' for the Metrics visualization.&lt;br /&gt;
* Build a sortable, paginated table with reusable table and form components.&lt;br /&gt;
&lt;br /&gt;
=== Backend ===&lt;br /&gt;
* Implemented using Ruby on Rails.&lt;br /&gt;
* Create the following REST API endpoints:&lt;br /&gt;
** `/api/v1/review_dashboard_data` (GET) – Fetch all review-related data.&lt;br /&gt;
** `/api/v1/assign_review_grade` (POST) – Submit grades and comments.&lt;br /&gt;
** `/api/v1/export_reviews_csv` (GET) – Export data to CSV.&lt;br /&gt;
&lt;br /&gt;
* Optionally add a '''ResponseVolumeMixin''' to the `Response` model to calculate “volume,” defined as the count of unique words in a student’s review.&lt;br /&gt;
&lt;br /&gt;
=== Data Flow ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Frontend (React)&lt;br /&gt;
   ↓  GET /review_dashboard_data&lt;br /&gt;
Backend (Rails)&lt;br /&gt;
   →  Returns JSON with reviewer info, scores, and metrics&lt;br /&gt;
Frontend&lt;br /&gt;
   ↓  Renders sortable table + charts&lt;br /&gt;
Instructor Input&lt;br /&gt;
   →  POST /assign_review_grade&lt;br /&gt;
Backend&lt;br /&gt;
   →  Stores grade + supports CSV export&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Results ==&lt;br /&gt;
(To be completed upon implementation)&lt;br /&gt;
&lt;br /&gt;
Expected outcomes:&lt;br /&gt;
* A clean, sortable dashboard interface for instructors.&lt;br /&gt;
* Visual metrics to compare review quality and engagement.&lt;br /&gt;
* Streamlined grading workflow with direct input and CSV export.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Manual Testing ===&lt;br /&gt;
# Log in as an instructor or TA.&lt;br /&gt;
# Navigate to the course dashboard and click the '''Review Grading Dashboard''' link.&lt;br /&gt;
# Verify that:&lt;br /&gt;
## Reviewer names, teams reviewed, and completion status are displayed correctly.&lt;br /&gt;
## Team color codes correspond to review completion.&lt;br /&gt;
## Scores are accurate per round.&lt;br /&gt;
## The metrics chart renders correctly using Recharts.&lt;br /&gt;
## Grades and comments can be entered and saved successfully.&lt;br /&gt;
# Click the “Export CSV” button and ensure the CSV file contains accurate data.&lt;br /&gt;
# Test sorting functionality for multiple columns.&lt;br /&gt;
# Confirm that alternating row colors and hover highlights appear correctly.&lt;br /&gt;
&lt;br /&gt;
=== Automated Testing ===&lt;br /&gt;
* '''Backend (RSpec):'''&lt;br /&gt;
** Test API responses for correctness and completeness.&lt;br /&gt;
** Validate `volume()` method returns expected unique word count.&lt;br /&gt;
** Verify CSV export structure and content.&lt;br /&gt;
&lt;br /&gt;
* '''Frontend (Jest + React Testing Library):'''&lt;br /&gt;
** Test rendering of dashboard table and Recharts components.&lt;br /&gt;
** Verify sorting and input functionalities.&lt;br /&gt;
** Mock API calls to test grade submission.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Team Members ==&lt;br /&gt;
* ''' Deekshith Anantha''' &lt;br /&gt;
* ''' Srinidhi''' &lt;br /&gt;
* '''Abhishek Rao''' &lt;br /&gt;
----&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=166949</id>
		<title>CSC/ECE 517 Fall 2025 - E2562. Review grading dashboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=166949"/>
		<updated>2025-11-07T03:24:42Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= SC/ECE 517 Fall 2025 – E2562. Review Grading Dashboard =&lt;br /&gt;
&lt;br /&gt;
This page contains information about '''E2562. Review Grading Dashboard''', which is a project in CSC/ECE 517 Fall 2025.&lt;br /&gt;
&lt;br /&gt;
Please see below for a description of the design of the project.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
'''Expertiza''' is an open-source application built on the Ruby on Rails framework. Instructors can create and manage assignments, and students can form teams and peer review each other’s work.  &lt;br /&gt;
&lt;br /&gt;
The frontend is written in '''TypeScript (React)''', while the backend uses '''Ruby on Rails'''. The codebase for this reimplementation effort can be found in the following repositories:&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-front-end Frontend Repository (reimplementation-front-end)]&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-back-end Backend Repository (reimplementation-back-end)]&lt;br /&gt;
&lt;br /&gt;
The '''Review Grading Dashboard''' is a modernized instructor interface that simplifies grading peer reviews by consolidating key review information, grading tools, and performance metrics into a single, sortable page.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The current Expertiza system makes grading peer reviews cumbersome and inefficient. Review data such as reviewer details, completion status, and scores are scattered across multiple pages, forcing instructors to navigate between views to assign grades.  &lt;br /&gt;
&lt;br /&gt;
The goal of this project is to design and implement a dedicated '''Review Grading Dashboard''' that provides instructors and TAs with a unified page to:&lt;br /&gt;
* View all reviews submitted by students.&lt;br /&gt;
* Check review completion status and assigned scores.&lt;br /&gt;
* Analyze review metrics such as “volume” (unique word usage).&lt;br /&gt;
* Enter grades and comments for reviews.&lt;br /&gt;
* Export review scores and grades to a CSV file.&lt;br /&gt;
&lt;br /&gt;
This dashboard serves as the central grading hub for instructors, replacing the older fragmented grading workflow.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Core Requirements ===&lt;br /&gt;
* The dashboard is accessible only to users with the '''Instructor''' or '''TA''' role.&lt;br /&gt;
* The dashboard displays a table containing the following columns:&lt;br /&gt;
** '''Reviewer:''' Username and full name of the reviewer.&lt;br /&gt;
** '''Reviews Done:''' Number of reviews completed out of the total assigned.&lt;br /&gt;
** '''Team Reviewed:''' Each reviewed team, color-coded by review completion status (e.g., done, pending, late).&lt;br /&gt;
** '''Scores:''' Weighted average review scores per round, calculated via the existing `aggregate_questionnaire_score` method.&lt;br /&gt;
** '''Metrics:''' A column chart comparing the number of unique words used by the reviewer to the average review volume.&lt;br /&gt;
** '''Grade:''' Text box for instructors to enter a numeric grade.&lt;br /&gt;
** '''Comments:''' Text box for instructors to write feedback or grading rationale.&lt;br /&gt;
&lt;br /&gt;
* Each column should be sortable (e.g., Reviewer, Reviews Done, Scores).&lt;br /&gt;
* Table rows should have alternating background colors for readability.&lt;br /&gt;
* A button should allow instructors to '''export all grades and scores as a CSV file'''.&lt;br /&gt;
* If there are multiple review rounds, display one score and metric per round.&lt;br /&gt;
&lt;br /&gt;
=== Design Requirements ===&lt;br /&gt;
* Follow the same design guidelines as the [https://github.com/AnvithaReddyGutha/reimplementation-front-end/blob/main/design_document.md reimplementation-front-end design document].&lt;br /&gt;
* Use compact column widths to prevent unnecessary wrapping.&lt;br /&gt;
* Implement hover tooltips to show extended reviewer or metric details.&lt;br /&gt;
* Use consistent UI elements (text boxes, buttons) from the existing frontend.&lt;br /&gt;
* For the &amp;quot;Metrics&amp;quot; column chart:&lt;br /&gt;
** '''Charting library:''' Recharts (React-based, lightweight, responsive).&lt;br /&gt;
** The chart should compare each student’s review “volume” with the average.&lt;br /&gt;
* Maintain color accessibility and responsiveness across devices.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
=== Frontend ===&lt;br /&gt;
* Implemented using React + TypeScript as part of the reimplementation front-end.&lt;br /&gt;
* Fetch review and grading data from new API endpoints.&lt;br /&gt;
* Use '''Recharts''' for the Metrics visualization.&lt;br /&gt;
* Build a sortable, paginated table with reusable table and form components.&lt;br /&gt;
&lt;br /&gt;
=== Backend ===&lt;br /&gt;
* Implemented using Ruby on Rails.&lt;br /&gt;
* Create the following REST API endpoints:&lt;br /&gt;
** `/api/v1/review_dashboard_data` (GET) – Fetch all review-related data.&lt;br /&gt;
** `/api/v1/assign_review_grade` (POST) – Submit grades and comments.&lt;br /&gt;
** `/api/v1/export_reviews_csv` (GET) – Export data to CSV.&lt;br /&gt;
&lt;br /&gt;
* Optionally add a '''ResponseVolumeMixin''' to the `Response` model to calculate “volume,” defined as the count of unique words in a student’s review.&lt;br /&gt;
&lt;br /&gt;
=== Data Flow ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Frontend (React)&lt;br /&gt;
   ↓  GET /review_dashboard_data&lt;br /&gt;
Backend (Rails)&lt;br /&gt;
   →  Returns JSON with reviewer info, scores, and metrics&lt;br /&gt;
Frontend&lt;br /&gt;
   ↓  Renders sortable table + charts&lt;br /&gt;
Instructor Input&lt;br /&gt;
   →  POST /assign_review_grade&lt;br /&gt;
Backend&lt;br /&gt;
   →  Stores grade + supports CSV export&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Results ==&lt;br /&gt;
(To be completed upon implementation)&lt;br /&gt;
&lt;br /&gt;
Expected outcomes:&lt;br /&gt;
* A clean, sortable dashboard interface for instructors.&lt;br /&gt;
* Visual metrics to compare review quality and engagement.&lt;br /&gt;
* Streamlined grading workflow with direct input and CSV export.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Manual Testing ===&lt;br /&gt;
# Log in as an instructor or TA.&lt;br /&gt;
# Navigate to the course dashboard and click the '''Review Grading Dashboard''' link.&lt;br /&gt;
# Verify that:&lt;br /&gt;
## Reviewer names, teams reviewed, and completion status are displayed correctly.&lt;br /&gt;
## Team color codes correspond to review completion.&lt;br /&gt;
## Scores are accurate per round.&lt;br /&gt;
## The metrics chart renders correctly using Recharts.&lt;br /&gt;
## Grades and comments can be entered and saved successfully.&lt;br /&gt;
# Click the “Export CSV” button and ensure the CSV file contains accurate data.&lt;br /&gt;
# Test sorting functionality for multiple columns.&lt;br /&gt;
# Confirm that alternating row colors and hover highlights appear correctly.&lt;br /&gt;
&lt;br /&gt;
=== Automated Testing ===&lt;br /&gt;
* '''Backend (RSpec):'''&lt;br /&gt;
** Test API responses for correctness and completeness.&lt;br /&gt;
** Validate `volume()` method returns expected unique word count.&lt;br /&gt;
** Verify CSV export structure and content.&lt;br /&gt;
&lt;br /&gt;
* '''Frontend (Jest + React Testing Library):'''&lt;br /&gt;
** Test rendering of dashboard table and Recharts components.&lt;br /&gt;
** Verify sorting and input functionalities.&lt;br /&gt;
** Mock API calls to test grade submission.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Team Members ==&lt;br /&gt;
* '''Deekshith Anantha''' – Frontend development, chart integration, UI/UX testing  &lt;br /&gt;
(Additional members can be added as applicable.)&lt;br /&gt;
&lt;br /&gt;
----&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=166948</id>
		<title>CSC/ECE 517 Fall 2025 - E2562. Review grading dashboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=166948"/>
		<updated>2025-11-07T03:24:20Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= SC/ECE 517 Fall 2025 – E2562. Review Grading Dashboard =&lt;br /&gt;
&lt;br /&gt;
This page contains information about '''E2562. Review Grading Dashboard''', which is a project in CSC/ECE 517 Fall 2025.&lt;br /&gt;
&lt;br /&gt;
Please see below for a description of the design of the project.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
'''Expertiza''' is an open-source application built on the Ruby on Rails framework. Instructors can create and manage assignments, and students can form teams and peer review each other’s work.  &lt;br /&gt;
&lt;br /&gt;
The frontend is written in '''TypeScript (React)''', while the backend uses '''Ruby on Rails'''. The codebase for this reimplementation effort can be found in the following repositories:&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-front-end Frontend Repository (reimplementation-front-end)]&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-back-end Backend Repository (reimplementation-back-end)]&lt;br /&gt;
&lt;br /&gt;
The '''Review Grading Dashboard''' is a modernized instructor interface that simplifies grading peer reviews by consolidating key review information, grading tools, and performance metrics into a single, sortable page.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The current Expertiza system makes grading peer reviews cumbersome and inefficient. Review data such as reviewer details, completion status, and scores are scattered across multiple pages, forcing instructors to navigate between views to assign grades.  &lt;br /&gt;
&lt;br /&gt;
The goal of this project is to design and implement a dedicated '''Review Grading Dashboard''' that provides instructors and TAs with a unified page to:&lt;br /&gt;
* View all reviews submitted by students.&lt;br /&gt;
* Check review completion status and assigned scores.&lt;br /&gt;
* Analyze review metrics such as “volume” (unique word usage).&lt;br /&gt;
* Enter grades and comments for reviews.&lt;br /&gt;
* Export review scores and grades to a CSV file.&lt;br /&gt;
&lt;br /&gt;
This dashboard serves as the central grading hub for instructors, replacing the older fragmented grading workflow.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Core Requirements ===&lt;br /&gt;
* The dashboard is accessible only to users with the '''Instructor''' or '''TA''' role.&lt;br /&gt;
* The dashboard displays a table containing the following columns:&lt;br /&gt;
** '''Reviewer:''' Username and full name of the reviewer.&lt;br /&gt;
** '''Reviews Done:''' Number of reviews completed out of the total assigned.&lt;br /&gt;
** '''Team Reviewed:''' Each reviewed team, color-coded by review completion status (e.g., done, pending, late).&lt;br /&gt;
** '''Scores:''' Weighted average review scores per round, calculated via the existing `aggregate_questionnaire_score` method.&lt;br /&gt;
** '''Metrics:''' A column chart comparing the number of unique words used by the reviewer to the average review volume.&lt;br /&gt;
** '''Grade:''' Text box for instructors to enter a numeric grade.&lt;br /&gt;
** '''Comments:''' Text box for instructors to write feedback or grading rationale.&lt;br /&gt;
&lt;br /&gt;
* Each column should be sortable (e.g., Reviewer, Reviews Done, Scores).&lt;br /&gt;
* Table rows should have alternating background colors for readability.&lt;br /&gt;
* A button should allow instructors to '''export all grades and scores as a CSV file'''.&lt;br /&gt;
* If there are multiple review rounds, display one score and metric per round.&lt;br /&gt;
&lt;br /&gt;
=== Design Requirements ===&lt;br /&gt;
* Follow the same design guidelines as the [https://github.com/AnvithaReddyGutha/reimplementation-front-end/blob/main/design_document.md reimplementation-front-end design document].&lt;br /&gt;
* Use compact column widths to prevent unnecessary wrapping.&lt;br /&gt;
* Implement hover tooltips to show extended reviewer or metric details.&lt;br /&gt;
* Use consistent UI elements (text boxes, buttons) from the existing frontend.&lt;br /&gt;
* For the &amp;quot;Metrics&amp;quot; column chart:&lt;br /&gt;
** '''Charting library:''' Recharts (React-based, lightweight, responsive).&lt;br /&gt;
** The chart should compare each student’s review “volume” with the average.&lt;br /&gt;
* Maintain color accessibility and responsiveness across devices.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
=== Frontend ===&lt;br /&gt;
* Implemented using React + TypeScript as part of the reimplementation front-end.&lt;br /&gt;
* Fetch review and grading data from new API endpoints.&lt;br /&gt;
* Use '''Recharts''' for the Metrics visualization.&lt;br /&gt;
* Build a sortable, paginated table with reusable table and form components.&lt;br /&gt;
&lt;br /&gt;
=== Backend ===&lt;br /&gt;
* Implemented using Ruby on Rails.&lt;br /&gt;
* Create the following REST API endpoints:&lt;br /&gt;
** `/api/v1/review_dashboard_data` (GET) – Fetch all review-related data.&lt;br /&gt;
** `/api/v1/assign_review_grade` (POST) – Submit grades and comments.&lt;br /&gt;
** `/api/v1/export_reviews_csv` (GET) – Export data to CSV.&lt;br /&gt;
&lt;br /&gt;
* Optionally add a '''ResponseVolumeMixin''' to the `Response` model to calculate “volume,” defined as the count of unique words in a student’s review.&lt;br /&gt;
&lt;br /&gt;
=== Data Flow ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Frontend (React)&lt;br /&gt;
   ↓  GET /review_dashboard_data&lt;br /&gt;
Backend (Rails)&lt;br /&gt;
   →  Returns JSON with reviewer info, scores, and metrics&lt;br /&gt;
Frontend&lt;br /&gt;
   ↓  Renders sortable table + charts&lt;br /&gt;
Instructor Input&lt;br /&gt;
   →  POST /assign_review_grade&lt;br /&gt;
Backend&lt;br /&gt;
   →  Stores grade + supports CSV export&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Results ==&lt;br /&gt;
(To be completed upon implementation)&lt;br /&gt;
&lt;br /&gt;
Expected outcomes:&lt;br /&gt;
* A clean, sortable dashboard interface for instructors.&lt;br /&gt;
* Visual metrics to compare review quality and engagement.&lt;br /&gt;
* Streamlined grading workflow with direct input and CSV export.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Manual Testing ===&lt;br /&gt;
# Log in as an instructor or TA.&lt;br /&gt;
# Navigate to the course dashboard and click the '''Review Grading Dashboard''' link.&lt;br /&gt;
# Verify that:&lt;br /&gt;
## Reviewer names, teams reviewed, and completion status are displayed correctly.&lt;br /&gt;
## Team color codes correspond to review completion.&lt;br /&gt;
## Scores are accurate per round.&lt;br /&gt;
## The metrics chart renders correctly using Recharts.&lt;br /&gt;
## Grades and comments can be entered and saved successfully.&lt;br /&gt;
# Click the “Export CSV” button and ensure the CSV file contains accurate data.&lt;br /&gt;
# Test sorting functionality for multiple columns.&lt;br /&gt;
# Confirm that alternating row colors and hover highlights appear correctly.&lt;br /&gt;
&lt;br /&gt;
=== Automated Testing ===&lt;br /&gt;
* '''Backend (RSpec):'''&lt;br /&gt;
** Test API responses for correctness and completeness.&lt;br /&gt;
** Validate `volume()` method returns expected unique word count.&lt;br /&gt;
** Verify CSV export structure and content.&lt;br /&gt;
&lt;br /&gt;
* '''Frontend (Jest + React Testing Library):'''&lt;br /&gt;
** Test rendering of dashboard table and Recharts components.&lt;br /&gt;
** Verify sorting and input functionalities.&lt;br /&gt;
** Mock API calls to test grade submission.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Team Members ==&lt;br /&gt;
* '''Deekshith Anantha''' – Frontend development, chart integration, UI/UX testing  &lt;br /&gt;
(Additional members can be added as applicable.)&lt;br /&gt;
&lt;br /&gt;
----&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=166947</id>
		<title>CSC/ECE 517 Fall 2025 - E2562. Review grading dashboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2562._Review_grading_dashboard&amp;diff=166947"/>
		<updated>2025-11-07T03:23:32Z</updated>

		<summary type="html">&lt;p&gt;Dananth: Created page with &amp;quot;= SC/ECE 517 Fall 2025 – E2562. Review Grading Dashboard =  This page contains information about '''E2562. Review Grading Dashboard''', which is a project in CSC/ECE 517 Fall 2025.  Please see below for a description of the design of the project.  == Contents == 1. Background   2. Problem Statement   3. Requirements   3.1 Core Requirements   3.2 Design Requirements...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= SC/ECE 517 Fall 2025 – E2562. Review Grading Dashboard =&lt;br /&gt;
&lt;br /&gt;
This page contains information about '''E2562. Review Grading Dashboard''', which is a project in CSC/ECE 517 Fall 2025.&lt;br /&gt;
&lt;br /&gt;
Please see below for a description of the design of the project.&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
1. [[#Background|Background]]  &lt;br /&gt;
2. [[#Problem_Statement|Problem Statement]]  &lt;br /&gt;
3. [[#Requirements|Requirements]]  &lt;br /&gt;
3.1 [[#Core_Requirements|Core Requirements]]  &lt;br /&gt;
3.2 [[#Design_Requirements|Design Requirements]]  &lt;br /&gt;
4. [[#Implementation|Implementation]]  &lt;br /&gt;
5. [[#Results|Results]]  &lt;br /&gt;
6. [[#Test_Plan|Test Plan]]  &lt;br /&gt;
6.1 [[#Manual_Testing|Manual Testing]]  &lt;br /&gt;
6.2 [[#Automated_Testing|Automated Testing]]  &lt;br /&gt;
7. [[#Team_Members|Team Members]]  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
'''Expertiza''' is an open-source application built on the Ruby on Rails framework. Instructors can create and manage assignments, and students can form teams and peer review each other’s work.  &lt;br /&gt;
&lt;br /&gt;
The frontend is written in '''TypeScript (React)''', while the backend uses '''Ruby on Rails'''. The codebase for this reimplementation effort can be found in the following repositories:&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-front-end Frontend Repository (reimplementation-front-end)]&lt;br /&gt;
* [https://github.com/AnvithaReddyGutha/reimplementation-back-end Backend Repository (reimplementation-back-end)]&lt;br /&gt;
&lt;br /&gt;
The '''Review Grading Dashboard''' is a modernized instructor interface that simplifies grading peer reviews by consolidating key review information, grading tools, and performance metrics into a single, sortable page.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The current Expertiza system makes grading peer reviews cumbersome and inefficient. Review data such as reviewer details, completion status, and scores are scattered across multiple pages, forcing instructors to navigate between views to assign grades.  &lt;br /&gt;
&lt;br /&gt;
The goal of this project is to design and implement a dedicated '''Review Grading Dashboard''' that provides instructors and TAs with a unified page to:&lt;br /&gt;
* View all reviews submitted by students.&lt;br /&gt;
* Check review completion status and assigned scores.&lt;br /&gt;
* Analyze review metrics such as “volume” (unique word usage).&lt;br /&gt;
* Enter grades and comments for reviews.&lt;br /&gt;
* Export review scores and grades to a CSV file.&lt;br /&gt;
&lt;br /&gt;
This dashboard serves as the central grading hub for instructors, replacing the older fragmented grading workflow.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Core Requirements ===&lt;br /&gt;
* The dashboard is accessible only to users with the '''Instructor''' or '''TA''' role.&lt;br /&gt;
* The dashboard displays a table containing the following columns:&lt;br /&gt;
** '''Reviewer:''' Username and full name of the reviewer.&lt;br /&gt;
** '''Reviews Done:''' Number of reviews completed out of the total assigned.&lt;br /&gt;
** '''Team Reviewed:''' Each reviewed team, color-coded by review completion status (e.g., done, pending, late).&lt;br /&gt;
** '''Scores:''' Weighted average review scores per round, calculated via the existing `aggregate_questionnaire_score` method.&lt;br /&gt;
** '''Metrics:''' A column chart comparing the number of unique words used by the reviewer to the average review volume.&lt;br /&gt;
** '''Grade:''' Text box for instructors to enter a numeric grade.&lt;br /&gt;
** '''Comments:''' Text box for instructors to write feedback or grading rationale.&lt;br /&gt;
&lt;br /&gt;
* Each column should be sortable (e.g., Reviewer, Reviews Done, Scores).&lt;br /&gt;
* Table rows should have alternating background colors for readability.&lt;br /&gt;
* A button should allow instructors to '''export all grades and scores as a CSV file'''.&lt;br /&gt;
* If there are multiple review rounds, display one score and metric per round.&lt;br /&gt;
&lt;br /&gt;
=== Design Requirements ===&lt;br /&gt;
* Follow the same design guidelines as the [https://github.com/AnvithaReddyGutha/reimplementation-front-end/blob/main/design_document.md reimplementation-front-end design document].&lt;br /&gt;
* Use compact column widths to prevent unnecessary wrapping.&lt;br /&gt;
* Implement hover tooltips to show extended reviewer or metric details.&lt;br /&gt;
* Use consistent UI elements (text boxes, buttons) from the existing frontend.&lt;br /&gt;
* For the &amp;quot;Metrics&amp;quot; column chart:&lt;br /&gt;
** '''Charting library:''' Recharts (React-based, lightweight, responsive).&lt;br /&gt;
** The chart should compare each student’s review “volume” with the average.&lt;br /&gt;
* Maintain color accessibility and responsiveness across devices.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
=== Frontend ===&lt;br /&gt;
* Implemented using React + TypeScript as part of the reimplementation front-end.&lt;br /&gt;
* Fetch review and grading data from new API endpoints.&lt;br /&gt;
* Use '''Recharts''' for the Metrics visualization.&lt;br /&gt;
* Build a sortable, paginated table with reusable table and form components.&lt;br /&gt;
&lt;br /&gt;
=== Backend ===&lt;br /&gt;
* Implemented using Ruby on Rails.&lt;br /&gt;
* Create the following REST API endpoints:&lt;br /&gt;
** `/api/v1/review_dashboard_data` (GET) – Fetch all review-related data.&lt;br /&gt;
** `/api/v1/assign_review_grade` (POST) – Submit grades and comments.&lt;br /&gt;
** `/api/v1/export_reviews_csv` (GET) – Export data to CSV.&lt;br /&gt;
&lt;br /&gt;
* Optionally add a '''ResponseVolumeMixin''' to the `Response` model to calculate “volume,” defined as the count of unique words in a student’s review.&lt;br /&gt;
&lt;br /&gt;
=== Data Flow ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Frontend (React)&lt;br /&gt;
   ↓  GET /review_dashboard_data&lt;br /&gt;
Backend (Rails)&lt;br /&gt;
   →  Returns JSON with reviewer info, scores, and metrics&lt;br /&gt;
Frontend&lt;br /&gt;
   ↓  Renders sortable table + charts&lt;br /&gt;
Instructor Input&lt;br /&gt;
   →  POST /assign_review_grade&lt;br /&gt;
Backend&lt;br /&gt;
   →  Stores grade + supports CSV export&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Results ==&lt;br /&gt;
(To be completed upon implementation)&lt;br /&gt;
&lt;br /&gt;
Expected outcomes:&lt;br /&gt;
* A clean, sortable dashboard interface for instructors.&lt;br /&gt;
* Visual metrics to compare review quality and engagement.&lt;br /&gt;
* Streamlined grading workflow with direct input and CSV export.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Manual Testing ===&lt;br /&gt;
# Log in as an instructor or TA.&lt;br /&gt;
# Navigate to the course dashboard and click the '''Review Grading Dashboard''' link.&lt;br /&gt;
# Verify that:&lt;br /&gt;
## Reviewer names, teams reviewed, and completion status are displayed correctly.&lt;br /&gt;
## Team color codes correspond to review completion.&lt;br /&gt;
## Scores are accurate per round.&lt;br /&gt;
## The metrics chart renders correctly using Recharts.&lt;br /&gt;
## Grades and comments can be entered and saved successfully.&lt;br /&gt;
# Click the “Export CSV” button and ensure the CSV file contains accurate data.&lt;br /&gt;
# Test sorting functionality for multiple columns.&lt;br /&gt;
# Confirm that alternating row colors and hover highlights appear correctly.&lt;br /&gt;
&lt;br /&gt;
=== Automated Testing ===&lt;br /&gt;
* '''Backend (RSpec):'''&lt;br /&gt;
** Test API responses for correctness and completeness.&lt;br /&gt;
** Validate `volume()` method returns expected unique word count.&lt;br /&gt;
** Verify CSV export structure and content.&lt;br /&gt;
&lt;br /&gt;
* '''Frontend (Jest + React Testing Library):'''&lt;br /&gt;
** Test rendering of dashboard table and Recharts components.&lt;br /&gt;
** Verify sorting and input functionalities.&lt;br /&gt;
** Mock API calls to test grade submission.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Team Members ==&lt;br /&gt;
* '''Deekshith Anantha''' – Frontend development, chart integration, UI/UX testing  &lt;br /&gt;
(Additional members can be added as applicable.)&lt;br /&gt;
&lt;br /&gt;
----&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166922</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166922"/>
		<updated>2025-10-31T17:54:48Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* References */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
=== Background ===&lt;br /&gt;
Expertiza utilizes a system for instructors to define topics within assignments, allowing students (often in teams) to sign up for these topics. The previous implementation, centered around the `SignUpTopic` model and associated controllers (`SignUpTopicsController`, `SignedUpTeamsController`), lacked clarity in naming and had business logic distributed across controllers rather than encapsulated within models. Furthermore, the user interface for managing assignment topics by instructors and for students signing up for topics required modernization and improved functionality.&lt;br /&gt;
&lt;br /&gt;
=== Motivation ===&lt;br /&gt;
This project aimed to improve the maintainability, clarity, and functionality of the topic management and signup features within Expertiza. Key motivations included:&lt;br /&gt;
* Renaming core components (`SignUpTopic` -&amp;gt; `ProjectTopic`) to better reflect their purpose.&lt;br /&gt;
* Created RESTful API endpoints to manage topics and team signups.&lt;br /&gt;
* Creating a more intuitive and feature-rich interface for instructors managing assignment topics.&lt;br /&gt;
* Developing a dedicated and user-friendly interface for students to view, select, and manage their topic signups.&lt;br /&gt;
* Introducing features like bookmarking topics and streamlining the student signup/drop process.&lt;br /&gt;
* Updating dependencies to keep the application current.&lt;br /&gt;
&lt;br /&gt;
=== Tasks Accomplished ===&lt;br /&gt;
* Renamed `SignUpTopic` to `ProjectTopic` throughout the backend (models, controllers, routes, tests, database).&lt;br /&gt;
* Refactored `ProjectTopic` and `SignedUpTeam` models to encapsulate business logic (topic creation/update/deletion, team signup/waitlisting, slot management, student signup/drop).&lt;br /&gt;
* Removed `SignUpTopicsController` and implemented `ProjectTopicsController` using the refactored model logic.&lt;br /&gt;
* Refactored `SignedUpTeamsController` to utilize new model methods and added new actions (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
* Added `allow_bookmarks` attribute to the `Assignment` model and associated backend/frontend logic.&lt;br /&gt;
* Created a new frontend page (`AssignmentEditPage.tsx`) with a tabbed interface for instructors to manage assignments, including a dedicated &amp;quot;Topics&amp;quot; tab.&lt;br /&gt;
* Implemented modals for creating, editing, importing, and deleting topics on the frontend.&lt;br /&gt;
* Developed a reusable `TopicsTable.tsx` component for displaying topics in instructor and student views.&lt;br /&gt;
* Created a new frontend page (`StudentTasks.tsx`) for students to view assignment topics, bookmark (if enabled), and sign up/drop topics.&lt;br /&gt;
* Updated backend dependencies (Rails, Puma, Nokogiri, etc.) and Docker configuration.&lt;br /&gt;
* Added/updated RSpec tests for `ProjectTopic` and `SignedUpTeam` models and updated relevant existing tests.&lt;br /&gt;
* Updated Swagger API documentation.&lt;br /&gt;
&lt;br /&gt;
===Files Modified and Created===&lt;br /&gt;
&lt;br /&gt;
* app/models/project_topic.rb&lt;br /&gt;
* app/models/signed_up_team.rb&lt;br /&gt;
* app/controllers/api/v1/project_topics_controller.rb&lt;br /&gt;
* app/controllers/api/v1/signed_up_teams_controller.rb&lt;br /&gt;
* app/serializers/project_topic_serializer.rb&lt;br /&gt;
* app/serializers/signed_up_team_serializer.rb&lt;br /&gt;
* spec/models/project_topic_spec.rb&lt;br /&gt;
* spec/models/signed_up_team_spec.rb&lt;br /&gt;
* spec/requests/project_topics_spec.rb&lt;br /&gt;
* spec/requests/signed_up_teams_spec.rb&lt;br /&gt;
&lt;br /&gt;
==Demo==&lt;br /&gt;
===Demo Video===&lt;br /&gt;
[[File:2555-thumbnail.jpg|thumb|center|link=https://www.youtube.com/watch?v=3zYt2hguXbY|Click to watch on YouTube]]&lt;br /&gt;
&lt;br /&gt;
== Problem Analysis ==&lt;br /&gt;
&lt;br /&gt;
=== Issues with the Previous Implementation are as follows ===&lt;br /&gt;
&lt;br /&gt;
==== Naming Convention ====&lt;br /&gt;
The name `SignUpTopic` was ambiguous. Renaming to `ProjectTopic` clarifies that these are topics related to the core project/assignment work students sign up for.&lt;br /&gt;
&lt;br /&gt;
==== Distributed Business Logic ====&lt;br /&gt;
Logic for creating topics, signing up teams, managing waitlists, and checking slots was spread across `SignUpTopicsController` and `SignedUpTeamsController`. This violated the principle of &amp;quot;fat model, skinny controller&amp;quot;, making the code harder to understand, test, and maintain.&lt;br /&gt;
&lt;br /&gt;
==== Inefficient Data Fetching ====&lt;br /&gt;
Frontend components often needed to make multiple API calls or perform calculations (like available slots) that could be handled more efficiently on the backend. The previous `SignUpTopic` API didn't provide computed data like assigned/waitlisted teams directly.&lt;br /&gt;
&lt;br /&gt;
==== Lack of Dedicated Student View ====&lt;br /&gt;
Students lacked a clear, dedicated interface to view available topics for an assignment and manage their selection. The signup process was not streamlined.&lt;br /&gt;
&lt;br /&gt;
==== Inconsistent Assignment Editing ====&lt;br /&gt;
The existing `AssignmentEditor` modal combined general settings with links to other management pages (like topics, participants) in an ad-hoc manner. A more structured approach was needed.&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== Architecture Decisions ===&lt;br /&gt;
* '''Model-Centric Logic:''' Shifted primary business logic for topic management and team signups into the `ProjectTopic` and `SignedUpTeam` models, respectively. Controllers now primarily handle request/response flow and delegate actions to the models.&lt;br /&gt;
* '''Dedicated Edit Page (Frontend):''' Created a new full page (`AssignmentEditPage`) for editing assignments instead of using a modal, allowing for a more complex, tabbed interface.&lt;br /&gt;
* '''Reusable Table Component (Frontend):''' Developed `TopicsTable` to handle the display and core interactions for topics in different contexts (instructor vs. student), promoting DRY principles.&lt;br /&gt;
* '''API Enhancements:''' Modified the `ProjectTopic` index endpoint (`/api/v1/project_topics`) to accept `assignment_id` and return topics with computed data (`to_json_with_computed_data`), reducing frontend calculation needs. Added specific endpoints for student signup (`sign_up_student`) and dropping topics (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
&lt;br /&gt;
=== Core Functionality Implemented ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Backend Changes !! Frontend Changes&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Renaming''' || Renamed `SignUpTopic` model, controller, routes, DB table to `ProjectTopic`. Updated associations. || Updated API endpoints used.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Management (Instructor)''' || `ProjectTopicsController` CRUD actions delegating to `ProjectTopic` model methods (`create_topic_with_assignment`, `update_topic`, `delete_by_assignment_and_topic_ids`). API returns computed data. || New `AssignmentEditPage` with `TopicsTab`. Uses `TopicsTable` (instructor mode). Modals for create, edit, import, delete. API calls for CRUD.&lt;br /&gt;
|-&lt;br /&gt;
| '''Team Signup Logic''' || `ProjectTopic` methods (`sign_team_up`, `drop_team`, `promote_waitlisted_team`). `SignedUpTeam` methods (`create_signed_up_team`, `remove_team_signups`). || Instructor view shows assigned/waitlisted teams in `TopicsTable` details. Drop team button calls backend.&lt;br /&gt;
|-&lt;br /&gt;
| '''Student Signup/Drop''' || `SignedUpTeamsController` actions (`sign_up_student`, `drop_topic`) delegating to `SignedUpTeam` model methods (`sign_up_student_for_topic`, `drop_topic_for_student`). Automatic handling of switching topics. || New `StudentTasks` page. Uses `TopicsTable` (student mode). Select/deselect buttons trigger API calls. Optimistic UI updates for slots. Displays current selection.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Bookmarking''' || Added `allow_bookmarks` boolean to `Assignment`. Added `project_topic_params` permit `allow_bookmarks` in `AssignmentsController`. || `AssignmentEditPage` allows instructors to toggle `allow_bookmarks` (persisted via PATCH). `StudentTasks` shows bookmark toggle if `allow_bookmarks` is true (local state for now).&lt;br /&gt;
|-&lt;br /&gt;
| '''Assignment Editing UI''' || N/A || New `AssignmentEditPage` with tabbed structure. `AssignmentEditor` might be simplified or removed for general settings.&lt;br /&gt;
|-&lt;br /&gt;
| '''Dependency Updates''' || Updated Ruby, Rails, Puma, Nokogiri etc. Added required gems. || N/A&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Key Backend Improvements ===&lt;br /&gt;
&lt;br /&gt;
=== ProjectTopic Model ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Handles team signup, considering available slots and waitlisting&lt;br /&gt;
# Renamed from signup_team for clarity&lt;br /&gt;
def sign_team_up(team)&lt;br /&gt;
  return false if signed_up_teams.exists?(team: team)&lt;br /&gt;
  ActiveRecord::Base.transaction do&lt;br /&gt;
    signed_up_team = signed_up_teams.create!(&lt;br /&gt;
      team: team,&lt;br /&gt;
      is_waitlisted: !slot_available?&lt;br /&gt;
    )&lt;br /&gt;
    # Remove team from other waitlists if confirmed here&lt;br /&gt;
    remove_from_waitlist(team) unless signed_up_team.is_waitlisted?&lt;br /&gt;
    true&lt;br /&gt;
  end&lt;br /&gt;
rescue ActiveRecord::RecordInvalid&lt;br /&gt;
  false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Handles dropping a team and promoting waitlisted if necessary&lt;br /&gt;
def drop_team(team)&lt;br /&gt;
  signed_up_team = signed_up_teams.find_by(team: team)&lt;br /&gt;
  return unless signed_up_team&lt;br /&gt;
  team_confirmed = !signed_up_team.is_waitlisted?&lt;br /&gt;
  signed_up_team.destroy!&lt;br /&gt;
  promote_waitlisted_team if team_confirmed # Promote only if a confirmed slot opened&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Calculates available slots&lt;br /&gt;
def available_slots&lt;br /&gt;
  max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Checks if slots are positive&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for creation, moved from controller&lt;br /&gt;
def self.create_topic_with_assignment(topic_params, assignment_id, micropayment = nil)&lt;br /&gt;
  # ... (find assignment, build topic, save, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for update, moved from controller&lt;br /&gt;
def update_topic(topic_params)&lt;br /&gt;
  # ... (update attributes, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Returns enhanced JSON including computed fields&lt;br /&gt;
def to_json_with_computed_data&lt;br /&gt;
  as_json.merge(&lt;br /&gt;
    available_slots: available_slots,&lt;br /&gt;
    confirmed_teams: confirmed_teams.map { |team| # ... format team data },&lt;br /&gt;
    waitlisted_teams: waitlisted_teams.map { |team| # ... format team data }&lt;br /&gt;
  )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
private&lt;br /&gt;
&lt;br /&gt;
# Helper for promotion logic&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
  # ... (find earliest waitlisted team, update is_waitlisted to false, remove from other waitlists)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to remove team from other topics' waitlists&lt;br /&gt;
def remove_from_waitlist(team)&lt;br /&gt;
  team.signed_up_teams.waitlisted.where.not(project_topic_id: id).destroy_all&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SignedUpTeam Model ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Scope for confirmed signups&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
# Scope for waitlisted signups&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&lt;br /&gt;
belongs_to :project_topic # Updated association&lt;br /&gt;
# ... validations ...&lt;br /&gt;
&lt;br /&gt;
# Business logic for student signup, including dropping previous topic&lt;br /&gt;
def self.sign_up_student_for_topic(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id) # Find student's team&lt;br /&gt;
  return { success: false, message: &amp;quot;User is not part of any team&amp;quot; } unless team_id&lt;br /&gt;
&lt;br /&gt;
  # Drop any existing topic signups for this team FIRST&lt;br /&gt;
  drop_existing_signups_for_team(team_id)&lt;br /&gt;
&lt;br /&gt;
  # Sign up for the new topic using create_signed_up_team (which calls topic.sign_team_up)&lt;br /&gt;
  signed_up_team = create_signed_up_team(topic_id, team_id)&lt;br /&gt;
&lt;br /&gt;
  if signed_up_team&lt;br /&gt;
    { success: true, message: &amp;quot;Signed up team successful!&amp;quot;, signed_up_team: signed_up_team, available_slots: signed_up_team.project_topic.available_slots }&lt;br /&gt;
  else&lt;br /&gt;
    { success: false, message: &amp;quot;Failed to sign up for topic. Topic may be full or already signed up.&amp;quot; }&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for dropping a topic&lt;br /&gt;
def self.drop_topic_for_student(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id)&lt;br /&gt;
  # ... (find topic, team, signed_up_team record) ...&lt;br /&gt;
  return { success: false, message: &amp;quot;Team is not signed up for this topic&amp;quot; } unless signed_up_team&lt;br /&gt;
&lt;br /&gt;
  # Delegate drop logic to ProjectTopic&lt;br /&gt;
  project_topic.drop_team(team)&lt;br /&gt;
&lt;br /&gt;
  { success: true, message: &amp;quot;Successfully dropped topic!&amp;quot;, available_slots: project_topic.available_slots }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to find and drop existing signups before signing up for a new one&lt;br /&gt;
private&lt;br /&gt;
def self.drop_existing_signups_for_team(team_id)&lt;br /&gt;
  existing_signups = where(team_id: team_id)&lt;br /&gt;
  existing_signups.each do |signup|&lt;br /&gt;
    signup.project_topic.drop_team(signup.team) # Use ProjectTopic's drop method&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frontend Improvements ===&lt;br /&gt;
&lt;br /&gt;
=== Topic signup page for students ===&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Topics_signup_page_for_students.png|800px|Topics_signup_page_for_students]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Admin page to CRUD Assignment Topics ===&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Admin_topic_SelectionPage.png|800px|thumb|left|Caption]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Database Migrations ===&lt;br /&gt;
* Renamed `sign_up_topics` table to `project_topics`.&lt;br /&gt;
* Updated `signed_up_teams` table: renamed `sign_up_topic_id` foreign key to `project_topic_id` and updated index name.&lt;br /&gt;
* Added `allow_bookmarks` boolean column to `assignments` table.&lt;br /&gt;
* Renamed `teams_users` join table to `teams_participants`.&lt;br /&gt;
&lt;br /&gt;
=== Testing ===&lt;br /&gt;
&lt;br /&gt;
=== RSpec Tests (Backend) ===&lt;br /&gt;
* '''ProjectTopic Model (`project_topic_spec.rb`):''' Added extensive tests covering:&lt;br /&gt;
    * `sign_team_up`: Confirmed vs. waitlisted based on `max_choosers`, removal from other waitlists.&lt;br /&gt;
    * `drop_team`: Team removal, promotion of earliest waitlisted team.&lt;br /&gt;
    * `available_slots`, `slot_available?`: Correct calculations before/after signups/drops.&lt;br /&gt;
    * `confirmed_teams`, `waitlisted_teams`: Correct retrieval and ordering.&lt;br /&gt;
    * Validations: Presence of `topic_name`, non-negative `max_choosers` (including zero).&lt;br /&gt;
* '''SignedUpTeam Model (`signed_up_team_spec.rb`):''' Added tests covering:&lt;br /&gt;
    * Validations: Presence of topic/team, uniqueness scope.&lt;br /&gt;
    * Scopes: `:confirmed`, `:waitlisted`.&lt;br /&gt;
    * Class methods: Signup logic delegation, removal logic, participant/topic finding.&lt;br /&gt;
    * Waitlisting behavior when topic is full.&lt;br /&gt;
* '''Updates:''' Modified existing tests (e.g., `due_date_spec.rb`) to reference `ProjectTopic`.&lt;br /&gt;
&lt;br /&gt;
=== Manual Tests (UI) ===&lt;br /&gt;
* '''Instructor Flow:''' Verified assignment editing via `/assignments/edit/:id`, topic creation/editing/deletion/import via modals, toggling `allow_bookmarks`, dropping teams from topics.&lt;br /&gt;
* '''Student Flow:''' Verified topic viewing via `/student_tasks/:assignmentId`, selecting/deselecting topics (including automatic drop of previous), bookmarking (when enabled), correct display of slots and waitlists, disabled selection for full topics.&lt;br /&gt;
&lt;br /&gt;
== Impact Analysis ==&lt;br /&gt;
&lt;br /&gt;
=== Summary of Changes ===&lt;br /&gt;
* '''Backend:''' Major refactoring of topic-related models and controllers, database schema changes, new API endpoints, updated dependencies. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily models, controllers, specs, migrations).&lt;br /&gt;
* '''Frontend:''' New assignment editing page with tabbed UI, new student task page for topic signup, reusable `TopicsTable` component, new routes. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily in `src/pages/Assignments`, `src/pages/StudentTasks`, `src/components`).&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
* ✓ Successfully refactored `SignUpTopic` to `ProjectTopic` for improved clarity.&lt;br /&gt;
* ✓ Centralized business logic in models, resulting in cleaner controllers.&lt;br /&gt;
* ✓ Implemented a modern, tabbed interface for assignment editing.&lt;br /&gt;
* ✓ Created a dedicated, streamlined UI for student topic signup.&lt;br /&gt;
* ✓ Added topic bookmarking functionality.&lt;br /&gt;
* ✓ Enhanced API endpoints for better data provision to the frontend.&lt;br /&gt;
* ✓ Updated key dependencies (Rails 8).&lt;br /&gt;
* ✓ Added comprehensive RSpec tests for new model logic.&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
* '''Frontend Bookmark Persistence:''' Implement API calls to save/load student topic bookmarks instead of using local state.&lt;br /&gt;
* '''Partner Ad Feature:''' Fully implement the &amp;quot;Apply to partner ad&amp;quot; functionality hinted at in `TopicsTab`.&lt;br /&gt;
* '''Complete Assignment Tabs:''' Implement the remaining tabs in `AssignmentEditPage` (Rubrics, Review Strategy, Due Dates, Etc.).&lt;br /&gt;
* '''Refine General Tab/AssignmentEditor:''' Decide whether general assignment settings remain in `AssignmentEditor` modal or move entirely to a &amp;quot;General&amp;quot; tab within `AssignmentEditPage`.&lt;br /&gt;
* '''Error Handling (Frontend):''' Enhance user feedback for API errors during topic operations (create/edit/delete/signup/drop).&lt;br /&gt;
* '''Authorization Checks:''' Ensure robust authorization checks are in place for all new/modified backend endpoints.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
This project successfully refactored the core topic management and signup system in Expertiza, replacing `SignUpTopic` with `ProjectTopic` and significantly improving the underlying logic by moving it into the models. New frontend interfaces provide a much-improved experience for both instructors managing topics and students signing up for them. The addition of features like topic bookmarking and a streamlined student signup flow enhances usability. The changes establish a more maintainable and understandable codebase for future development.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
# [https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
# [https://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
# [http://wikis.lib.ncsu.edu/index.php/Expertiza Expertiza project documentation wiki]&lt;br /&gt;
# [https://guides.rubyonrails.org/ Ruby on Rails Guides]&lt;br /&gt;
# [https://react.dev/ React Documentation]&lt;br /&gt;
# [https://relishapp.com/rspec Rspec Documentation]&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166919</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166919"/>
		<updated>2025-10-30T23:01:01Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* Demo Video */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
=== Background ===&lt;br /&gt;
Expertiza utilizes a system for instructors to define topics within assignments, allowing students (often in teams) to sign up for these topics. The previous implementation, centered around the `SignUpTopic` model and associated controllers (`SignUpTopicsController`, `SignedUpTeamsController`), lacked clarity in naming and had business logic distributed across controllers rather than encapsulated within models. Furthermore, the user interface for managing assignment topics by instructors and for students signing up for topics required modernization and improved functionality.&lt;br /&gt;
&lt;br /&gt;
=== Motivation ===&lt;br /&gt;
This project aimed to improve the maintainability, clarity, and functionality of the topic management and signup features within Expertiza. Key motivations included:&lt;br /&gt;
* Renaming core components (`SignUpTopic` -&amp;gt; `ProjectTopic`) to better reflect their purpose.&lt;br /&gt;
* Created RESTful API endpoints to manage topics and team signups.&lt;br /&gt;
* Creating a more intuitive and feature-rich interface for instructors managing assignment topics.&lt;br /&gt;
* Developing a dedicated and user-friendly interface for students to view, select, and manage their topic signups.&lt;br /&gt;
* Introducing features like bookmarking topics and streamlining the student signup/drop process.&lt;br /&gt;
* Updating dependencies to keep the application current.&lt;br /&gt;
&lt;br /&gt;
=== Tasks Accomplished ===&lt;br /&gt;
* Renamed `SignUpTopic` to `ProjectTopic` throughout the backend (models, controllers, routes, tests, database).&lt;br /&gt;
* Refactored `ProjectTopic` and `SignedUpTeam` models to encapsulate business logic (topic creation/update/deletion, team signup/waitlisting, slot management, student signup/drop).&lt;br /&gt;
* Removed `SignUpTopicsController` and implemented `ProjectTopicsController` using the refactored model logic.&lt;br /&gt;
* Refactored `SignedUpTeamsController` to utilize new model methods and added new actions (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
* Added `allow_bookmarks` attribute to the `Assignment` model and associated backend/frontend logic.&lt;br /&gt;
* Created a new frontend page (`AssignmentEditPage.tsx`) with a tabbed interface for instructors to manage assignments, including a dedicated &amp;quot;Topics&amp;quot; tab.&lt;br /&gt;
* Implemented modals for creating, editing, importing, and deleting topics on the frontend.&lt;br /&gt;
* Developed a reusable `TopicsTable.tsx` component for displaying topics in instructor and student views.&lt;br /&gt;
* Created a new frontend page (`StudentTasks.tsx`) for students to view assignment topics, bookmark (if enabled), and sign up/drop topics.&lt;br /&gt;
* Updated backend dependencies (Rails, Puma, Nokogiri, etc.) and Docker configuration.&lt;br /&gt;
* Added/updated RSpec tests for `ProjectTopic` and `SignedUpTeam` models and updated relevant existing tests.&lt;br /&gt;
* Updated Swagger API documentation.&lt;br /&gt;
&lt;br /&gt;
===Files Modified and Created===&lt;br /&gt;
&lt;br /&gt;
* app/models/project_topic.rb&lt;br /&gt;
* app/models/signed_up_team.rb&lt;br /&gt;
* app/controllers/api/v1/project_topics_controller.rb&lt;br /&gt;
* app/controllers/api/v1/signed_up_teams_controller.rb&lt;br /&gt;
* app/serializers/project_topic_serializer.rb&lt;br /&gt;
* app/serializers/signed_up_team_serializer.rb&lt;br /&gt;
* spec/models/project_topic_spec.rb&lt;br /&gt;
* spec/models/signed_up_team_spec.rb&lt;br /&gt;
* spec/requests/project_topics_spec.rb&lt;br /&gt;
* spec/requests/signed_up_teams_spec.rb&lt;br /&gt;
&lt;br /&gt;
==Demo==&lt;br /&gt;
===Demo Video===&lt;br /&gt;
[[File:2555-thumbnail.jpg|thumb|center|link=https://www.youtube.com/watch?v=3zYt2hguXbY|Click to watch on YouTube]]&lt;br /&gt;
&lt;br /&gt;
== Problem Analysis ==&lt;br /&gt;
&lt;br /&gt;
=== Issues with the Previous Implementation are as follows ===&lt;br /&gt;
&lt;br /&gt;
==== Naming Convention ====&lt;br /&gt;
The name `SignUpTopic` was ambiguous. Renaming to `ProjectTopic` clarifies that these are topics related to the core project/assignment work students sign up for.&lt;br /&gt;
&lt;br /&gt;
==== Distributed Business Logic ====&lt;br /&gt;
Logic for creating topics, signing up teams, managing waitlists, and checking slots was spread across `SignUpTopicsController` and `SignedUpTeamsController`. This violated the principle of &amp;quot;fat model, skinny controller&amp;quot;, making the code harder to understand, test, and maintain.&lt;br /&gt;
&lt;br /&gt;
==== Inefficient Data Fetching ====&lt;br /&gt;
Frontend components often needed to make multiple API calls or perform calculations (like available slots) that could be handled more efficiently on the backend. The previous `SignUpTopic` API didn't provide computed data like assigned/waitlisted teams directly.&lt;br /&gt;
&lt;br /&gt;
==== Lack of Dedicated Student View ====&lt;br /&gt;
Students lacked a clear, dedicated interface to view available topics for an assignment and manage their selection. The signup process was not streamlined.&lt;br /&gt;
&lt;br /&gt;
==== Inconsistent Assignment Editing ====&lt;br /&gt;
The existing `AssignmentEditor` modal combined general settings with links to other management pages (like topics, participants) in an ad-hoc manner. A more structured approach was needed.&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== Architecture Decisions ===&lt;br /&gt;
* '''Model-Centric Logic:''' Shifted primary business logic for topic management and team signups into the `ProjectTopic` and `SignedUpTeam` models, respectively. Controllers now primarily handle request/response flow and delegate actions to the models.&lt;br /&gt;
* '''Dedicated Edit Page (Frontend):''' Created a new full page (`AssignmentEditPage`) for editing assignments instead of using a modal, allowing for a more complex, tabbed interface.&lt;br /&gt;
* '''Reusable Table Component (Frontend):''' Developed `TopicsTable` to handle the display and core interactions for topics in different contexts (instructor vs. student), promoting DRY principles.&lt;br /&gt;
* '''API Enhancements:''' Modified the `ProjectTopic` index endpoint (`/api/v1/project_topics`) to accept `assignment_id` and return topics with computed data (`to_json_with_computed_data`), reducing frontend calculation needs. Added specific endpoints for student signup (`sign_up_student`) and dropping topics (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
&lt;br /&gt;
=== Core Functionality Implemented ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Backend Changes !! Frontend Changes&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Renaming''' || Renamed `SignUpTopic` model, controller, routes, DB table to `ProjectTopic`. Updated associations. || Updated API endpoints used.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Management (Instructor)''' || `ProjectTopicsController` CRUD actions delegating to `ProjectTopic` model methods (`create_topic_with_assignment`, `update_topic`, `delete_by_assignment_and_topic_ids`). API returns computed data. || New `AssignmentEditPage` with `TopicsTab`. Uses `TopicsTable` (instructor mode). Modals for create, edit, import, delete. API calls for CRUD.&lt;br /&gt;
|-&lt;br /&gt;
| '''Team Signup Logic''' || `ProjectTopic` methods (`sign_team_up`, `drop_team`, `promote_waitlisted_team`). `SignedUpTeam` methods (`create_signed_up_team`, `remove_team_signups`). || Instructor view shows assigned/waitlisted teams in `TopicsTable` details. Drop team button calls backend.&lt;br /&gt;
|-&lt;br /&gt;
| '''Student Signup/Drop''' || `SignedUpTeamsController` actions (`sign_up_student`, `drop_topic`) delegating to `SignedUpTeam` model methods (`sign_up_student_for_topic`, `drop_topic_for_student`). Automatic handling of switching topics. || New `StudentTasks` page. Uses `TopicsTable` (student mode). Select/deselect buttons trigger API calls. Optimistic UI updates for slots. Displays current selection.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Bookmarking''' || Added `allow_bookmarks` boolean to `Assignment`. Added `project_topic_params` permit `allow_bookmarks` in `AssignmentsController`. || `AssignmentEditPage` allows instructors to toggle `allow_bookmarks` (persisted via PATCH). `StudentTasks` shows bookmark toggle if `allow_bookmarks` is true (local state for now).&lt;br /&gt;
|-&lt;br /&gt;
| '''Assignment Editing UI''' || N/A || New `AssignmentEditPage` with tabbed structure. `AssignmentEditor` might be simplified or removed for general settings.&lt;br /&gt;
|-&lt;br /&gt;
| '''Dependency Updates''' || Updated Ruby, Rails, Puma, Nokogiri etc. Added required gems. || N/A&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Key Backend Improvements ===&lt;br /&gt;
&lt;br /&gt;
=== ProjectTopic Model ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Handles team signup, considering available slots and waitlisting&lt;br /&gt;
# Renamed from signup_team for clarity&lt;br /&gt;
def sign_team_up(team)&lt;br /&gt;
  return false if signed_up_teams.exists?(team: team)&lt;br /&gt;
  ActiveRecord::Base.transaction do&lt;br /&gt;
    signed_up_team = signed_up_teams.create!(&lt;br /&gt;
      team: team,&lt;br /&gt;
      is_waitlisted: !slot_available?&lt;br /&gt;
    )&lt;br /&gt;
    # Remove team from other waitlists if confirmed here&lt;br /&gt;
    remove_from_waitlist(team) unless signed_up_team.is_waitlisted?&lt;br /&gt;
    true&lt;br /&gt;
  end&lt;br /&gt;
rescue ActiveRecord::RecordInvalid&lt;br /&gt;
  false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Handles dropping a team and promoting waitlisted if necessary&lt;br /&gt;
def drop_team(team)&lt;br /&gt;
  signed_up_team = signed_up_teams.find_by(team: team)&lt;br /&gt;
  return unless signed_up_team&lt;br /&gt;
  team_confirmed = !signed_up_team.is_waitlisted?&lt;br /&gt;
  signed_up_team.destroy!&lt;br /&gt;
  promote_waitlisted_team if team_confirmed # Promote only if a confirmed slot opened&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Calculates available slots&lt;br /&gt;
def available_slots&lt;br /&gt;
  max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Checks if slots are positive&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for creation, moved from controller&lt;br /&gt;
def self.create_topic_with_assignment(topic_params, assignment_id, micropayment = nil)&lt;br /&gt;
  # ... (find assignment, build topic, save, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for update, moved from controller&lt;br /&gt;
def update_topic(topic_params)&lt;br /&gt;
  # ... (update attributes, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Returns enhanced JSON including computed fields&lt;br /&gt;
def to_json_with_computed_data&lt;br /&gt;
  as_json.merge(&lt;br /&gt;
    available_slots: available_slots,&lt;br /&gt;
    confirmed_teams: confirmed_teams.map { |team| # ... format team data },&lt;br /&gt;
    waitlisted_teams: waitlisted_teams.map { |team| # ... format team data }&lt;br /&gt;
  )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
private&lt;br /&gt;
&lt;br /&gt;
# Helper for promotion logic&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
  # ... (find earliest waitlisted team, update is_waitlisted to false, remove from other waitlists)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to remove team from other topics' waitlists&lt;br /&gt;
def remove_from_waitlist(team)&lt;br /&gt;
  team.signed_up_teams.waitlisted.where.not(project_topic_id: id).destroy_all&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SignedUpTeam Model ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Scope for confirmed signups&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
# Scope for waitlisted signups&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&lt;br /&gt;
belongs_to :project_topic # Updated association&lt;br /&gt;
# ... validations ...&lt;br /&gt;
&lt;br /&gt;
# Business logic for student signup, including dropping previous topic&lt;br /&gt;
def self.sign_up_student_for_topic(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id) # Find student's team&lt;br /&gt;
  return { success: false, message: &amp;quot;User is not part of any team&amp;quot; } unless team_id&lt;br /&gt;
&lt;br /&gt;
  # Drop any existing topic signups for this team FIRST&lt;br /&gt;
  drop_existing_signups_for_team(team_id)&lt;br /&gt;
&lt;br /&gt;
  # Sign up for the new topic using create_signed_up_team (which calls topic.sign_team_up)&lt;br /&gt;
  signed_up_team = create_signed_up_team(topic_id, team_id)&lt;br /&gt;
&lt;br /&gt;
  if signed_up_team&lt;br /&gt;
    { success: true, message: &amp;quot;Signed up team successful!&amp;quot;, signed_up_team: signed_up_team, available_slots: signed_up_team.project_topic.available_slots }&lt;br /&gt;
  else&lt;br /&gt;
    { success: false, message: &amp;quot;Failed to sign up for topic. Topic may be full or already signed up.&amp;quot; }&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for dropping a topic&lt;br /&gt;
def self.drop_topic_for_student(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id)&lt;br /&gt;
  # ... (find topic, team, signed_up_team record) ...&lt;br /&gt;
  return { success: false, message: &amp;quot;Team is not signed up for this topic&amp;quot; } unless signed_up_team&lt;br /&gt;
&lt;br /&gt;
  # Delegate drop logic to ProjectTopic&lt;br /&gt;
  project_topic.drop_team(team)&lt;br /&gt;
&lt;br /&gt;
  { success: true, message: &amp;quot;Successfully dropped topic!&amp;quot;, available_slots: project_topic.available_slots }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to find and drop existing signups before signing up for a new one&lt;br /&gt;
private&lt;br /&gt;
def self.drop_existing_signups_for_team(team_id)&lt;br /&gt;
  existing_signups = where(team_id: team_id)&lt;br /&gt;
  existing_signups.each do |signup|&lt;br /&gt;
    signup.project_topic.drop_team(signup.team) # Use ProjectTopic's drop method&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frontend Improvements ===&lt;br /&gt;
&lt;br /&gt;
=== Topic signup page for students ===&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Topics_signup_page_for_students.png|800px|Topics_signup_page_for_students]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Admin page to CRUD Assignment Topics ===&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Admin_topic_SelectionPage.png|800px|thumb|left|Caption]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Database Migrations ===&lt;br /&gt;
* Renamed `sign_up_topics` table to `project_topics`.&lt;br /&gt;
* Updated `signed_up_teams` table: renamed `sign_up_topic_id` foreign key to `project_topic_id` and updated index name.&lt;br /&gt;
* Added `allow_bookmarks` boolean column to `assignments` table.&lt;br /&gt;
* Renamed `teams_users` join table to `teams_participants`.&lt;br /&gt;
&lt;br /&gt;
=== Testing ===&lt;br /&gt;
&lt;br /&gt;
=== RSpec Tests (Backend) ===&lt;br /&gt;
* '''ProjectTopic Model (`project_topic_spec.rb`):''' Added extensive tests covering:&lt;br /&gt;
    * `sign_team_up`: Confirmed vs. waitlisted based on `max_choosers`, removal from other waitlists.&lt;br /&gt;
    * `drop_team`: Team removal, promotion of earliest waitlisted team.&lt;br /&gt;
    * `available_slots`, `slot_available?`: Correct calculations before/after signups/drops.&lt;br /&gt;
    * `confirmed_teams`, `waitlisted_teams`: Correct retrieval and ordering.&lt;br /&gt;
    * Validations: Presence of `topic_name`, non-negative `max_choosers` (including zero).&lt;br /&gt;
* '''SignedUpTeam Model (`signed_up_team_spec.rb`):''' Added tests covering:&lt;br /&gt;
    * Validations: Presence of topic/team, uniqueness scope.&lt;br /&gt;
    * Scopes: `:confirmed`, `:waitlisted`.&lt;br /&gt;
    * Class methods: Signup logic delegation, removal logic, participant/topic finding.&lt;br /&gt;
    * Waitlisting behavior when topic is full.&lt;br /&gt;
* '''Updates:''' Modified existing tests (e.g., `due_date_spec.rb`) to reference `ProjectTopic`.&lt;br /&gt;
&lt;br /&gt;
=== Manual Tests (UI) ===&lt;br /&gt;
* '''Instructor Flow:''' Verified assignment editing via `/assignments/edit/:id`, topic creation/editing/deletion/import via modals, toggling `allow_bookmarks`, dropping teams from topics.&lt;br /&gt;
* '''Student Flow:''' Verified topic viewing via `/student_tasks/:assignmentId`, selecting/deselecting topics (including automatic drop of previous), bookmarking (when enabled), correct display of slots and waitlists, disabled selection for full topics.&lt;br /&gt;
&lt;br /&gt;
== Impact Analysis ==&lt;br /&gt;
&lt;br /&gt;
=== Summary of Changes ===&lt;br /&gt;
* '''Backend:''' Major refactoring of topic-related models and controllers, database schema changes, new API endpoints, updated dependencies. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily models, controllers, specs, migrations).&lt;br /&gt;
* '''Frontend:''' New assignment editing page with tabbed UI, new student task page for topic signup, reusable `TopicsTable` component, new routes. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily in `src/pages/Assignments`, `src/pages/StudentTasks`, `src/components`).&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
* ✓ Successfully refactored `SignUpTopic` to `ProjectTopic` for improved clarity.&lt;br /&gt;
* ✓ Centralized business logic in models, resulting in cleaner controllers.&lt;br /&gt;
* ✓ Implemented a modern, tabbed interface for assignment editing.&lt;br /&gt;
* ✓ Created a dedicated, streamlined UI for student topic signup.&lt;br /&gt;
* ✓ Added topic bookmarking functionality.&lt;br /&gt;
* ✓ Enhanced API endpoints for better data provision to the frontend.&lt;br /&gt;
* ✓ Updated key dependencies (Rails 8).&lt;br /&gt;
* ✓ Added comprehensive RSpec tests for new model logic.&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
* '''Frontend Bookmark Persistence:''' Implement API calls to save/load student topic bookmarks instead of using local state.&lt;br /&gt;
* '''Partner Ad Feature:''' Fully implement the &amp;quot;Apply to partner ad&amp;quot; functionality hinted at in `TopicsTab`.&lt;br /&gt;
* '''Complete Assignment Tabs:''' Implement the remaining tabs in `AssignmentEditPage` (Rubrics, Review Strategy, Due Dates, Etc.).&lt;br /&gt;
* '''Refine General Tab/AssignmentEditor:''' Decide whether general assignment settings remain in `AssignmentEditor` modal or move entirely to a &amp;quot;General&amp;quot; tab within `AssignmentEditPage`.&lt;br /&gt;
* '''Error Handling (Frontend):''' Enhance user feedback for API errors during topic operations (create/edit/delete/signup/drop).&lt;br /&gt;
* '''Authorization Checks:''' Ensure robust authorization checks are in place for all new/modified backend endpoints.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
This project successfully refactored the core topic management and signup system in Expertiza, replacing `SignUpTopic` with `ProjectTopic` and significantly improving the underlying logic by moving it into the models. New frontend interfaces provide a much-improved experience for both instructors managing topics and students signing up for them. The addition of features like topic bookmarking and a streamlined student signup flow enhances usability. The changes establish a more maintainable and understandable codebase for future development.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
# [https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
# [https://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
# [http://wikis.lib.ncsu.edu/index.php/Expertiza Expertiza project documentation wiki]&lt;br /&gt;
# ''(Add links to your specific project fork/PRs if needed)''&lt;br /&gt;
# [https://guides.rubyonrails.org/ Ruby on Rails Guides]&lt;br /&gt;
# [https://react.dev/ React Documentation]&lt;br /&gt;
# [https://relishapp.com/rspec Rspec Documentation]&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166918</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166918"/>
		<updated>2025-10-30T22:53:23Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
=== Background ===&lt;br /&gt;
Expertiza utilizes a system for instructors to define topics within assignments, allowing students (often in teams) to sign up for these topics. The previous implementation, centered around the `SignUpTopic` model and associated controllers (`SignUpTopicsController`, `SignedUpTeamsController`), lacked clarity in naming and had business logic distributed across controllers rather than encapsulated within models. Furthermore, the user interface for managing assignment topics by instructors and for students signing up for topics required modernization and improved functionality.&lt;br /&gt;
&lt;br /&gt;
=== Motivation ===&lt;br /&gt;
This project aimed to improve the maintainability, clarity, and functionality of the topic management and signup features within Expertiza. Key motivations included:&lt;br /&gt;
* Renaming core components (`SignUpTopic` -&amp;gt; `ProjectTopic`) to better reflect their purpose.&lt;br /&gt;
* Created RESTful API endpoints to manage topics and team signups.&lt;br /&gt;
* Creating a more intuitive and feature-rich interface for instructors managing assignment topics.&lt;br /&gt;
* Developing a dedicated and user-friendly interface for students to view, select, and manage their topic signups.&lt;br /&gt;
* Introducing features like bookmarking topics and streamlining the student signup/drop process.&lt;br /&gt;
* Updating dependencies to keep the application current.&lt;br /&gt;
&lt;br /&gt;
=== Tasks Accomplished ===&lt;br /&gt;
* Renamed `SignUpTopic` to `ProjectTopic` throughout the backend (models, controllers, routes, tests, database).&lt;br /&gt;
* Refactored `ProjectTopic` and `SignedUpTeam` models to encapsulate business logic (topic creation/update/deletion, team signup/waitlisting, slot management, student signup/drop).&lt;br /&gt;
* Removed `SignUpTopicsController` and implemented `ProjectTopicsController` using the refactored model logic.&lt;br /&gt;
* Refactored `SignedUpTeamsController` to utilize new model methods and added new actions (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
* Added `allow_bookmarks` attribute to the `Assignment` model and associated backend/frontend logic.&lt;br /&gt;
* Created a new frontend page (`AssignmentEditPage.tsx`) with a tabbed interface for instructors to manage assignments, including a dedicated &amp;quot;Topics&amp;quot; tab.&lt;br /&gt;
* Implemented modals for creating, editing, importing, and deleting topics on the frontend.&lt;br /&gt;
* Developed a reusable `TopicsTable.tsx` component for displaying topics in instructor and student views.&lt;br /&gt;
* Created a new frontend page (`StudentTasks.tsx`) for students to view assignment topics, bookmark (if enabled), and sign up/drop topics.&lt;br /&gt;
* Updated backend dependencies (Rails, Puma, Nokogiri, etc.) and Docker configuration.&lt;br /&gt;
* Added/updated RSpec tests for `ProjectTopic` and `SignedUpTeam` models and updated relevant existing tests.&lt;br /&gt;
* Updated Swagger API documentation.&lt;br /&gt;
&lt;br /&gt;
===Files Modified and Created===&lt;br /&gt;
&lt;br /&gt;
* app/models/project_topic.rb&lt;br /&gt;
* app/models/signed_up_team.rb&lt;br /&gt;
* app/controllers/api/v1/project_topics_controller.rb&lt;br /&gt;
* app/controllers/api/v1/signed_up_teams_controller.rb&lt;br /&gt;
* app/serializers/project_topic_serializer.rb&lt;br /&gt;
* app/serializers/signed_up_team_serializer.rb&lt;br /&gt;
* spec/models/project_topic_spec.rb&lt;br /&gt;
* spec/models/signed_up_team_spec.rb&lt;br /&gt;
* spec/requests/project_topics_spec.rb&lt;br /&gt;
* spec/requests/signed_up_teams_spec.rb&lt;br /&gt;
&lt;br /&gt;
==Demo==&lt;br /&gt;
===Demo Video===&lt;br /&gt;
[[File:2555-thumbnail.jpg|thumb|center|link=https://www.youtube.com/watch?v=WW0EyVHA43k|Click to watch on YouTube]]&lt;br /&gt;
&lt;br /&gt;
== Problem Analysis ==&lt;br /&gt;
&lt;br /&gt;
=== Issues with the Previous Implementation are as follows ===&lt;br /&gt;
&lt;br /&gt;
==== Naming Convention ====&lt;br /&gt;
The name `SignUpTopic` was ambiguous. Renaming to `ProjectTopic` clarifies that these are topics related to the core project/assignment work students sign up for.&lt;br /&gt;
&lt;br /&gt;
==== Distributed Business Logic ====&lt;br /&gt;
Logic for creating topics, signing up teams, managing waitlists, and checking slots was spread across `SignUpTopicsController` and `SignedUpTeamsController`. This violated the principle of &amp;quot;fat model, skinny controller&amp;quot;, making the code harder to understand, test, and maintain.&lt;br /&gt;
&lt;br /&gt;
==== Inefficient Data Fetching ====&lt;br /&gt;
Frontend components often needed to make multiple API calls or perform calculations (like available slots) that could be handled more efficiently on the backend. The previous `SignUpTopic` API didn't provide computed data like assigned/waitlisted teams directly.&lt;br /&gt;
&lt;br /&gt;
==== Lack of Dedicated Student View ====&lt;br /&gt;
Students lacked a clear, dedicated interface to view available topics for an assignment and manage their selection. The signup process was not streamlined.&lt;br /&gt;
&lt;br /&gt;
==== Inconsistent Assignment Editing ====&lt;br /&gt;
The existing `AssignmentEditor` modal combined general settings with links to other management pages (like topics, participants) in an ad-hoc manner. A more structured approach was needed.&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== Architecture Decisions ===&lt;br /&gt;
* '''Model-Centric Logic:''' Shifted primary business logic for topic management and team signups into the `ProjectTopic` and `SignedUpTeam` models, respectively. Controllers now primarily handle request/response flow and delegate actions to the models.&lt;br /&gt;
* '''Dedicated Edit Page (Frontend):''' Created a new full page (`AssignmentEditPage`) for editing assignments instead of using a modal, allowing for a more complex, tabbed interface.&lt;br /&gt;
* '''Reusable Table Component (Frontend):''' Developed `TopicsTable` to handle the display and core interactions for topics in different contexts (instructor vs. student), promoting DRY principles.&lt;br /&gt;
* '''API Enhancements:''' Modified the `ProjectTopic` index endpoint (`/api/v1/project_topics`) to accept `assignment_id` and return topics with computed data (`to_json_with_computed_data`), reducing frontend calculation needs. Added specific endpoints for student signup (`sign_up_student`) and dropping topics (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
&lt;br /&gt;
=== Core Functionality Implemented ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Backend Changes !! Frontend Changes&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Renaming''' || Renamed `SignUpTopic` model, controller, routes, DB table to `ProjectTopic`. Updated associations. || Updated API endpoints used.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Management (Instructor)''' || `ProjectTopicsController` CRUD actions delegating to `ProjectTopic` model methods (`create_topic_with_assignment`, `update_topic`, `delete_by_assignment_and_topic_ids`). API returns computed data. || New `AssignmentEditPage` with `TopicsTab`. Uses `TopicsTable` (instructor mode). Modals for create, edit, import, delete. API calls for CRUD.&lt;br /&gt;
|-&lt;br /&gt;
| '''Team Signup Logic''' || `ProjectTopic` methods (`sign_team_up`, `drop_team`, `promote_waitlisted_team`). `SignedUpTeam` methods (`create_signed_up_team`, `remove_team_signups`). || Instructor view shows assigned/waitlisted teams in `TopicsTable` details. Drop team button calls backend.&lt;br /&gt;
|-&lt;br /&gt;
| '''Student Signup/Drop''' || `SignedUpTeamsController` actions (`sign_up_student`, `drop_topic`) delegating to `SignedUpTeam` model methods (`sign_up_student_for_topic`, `drop_topic_for_student`). Automatic handling of switching topics. || New `StudentTasks` page. Uses `TopicsTable` (student mode). Select/deselect buttons trigger API calls. Optimistic UI updates for slots. Displays current selection.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Bookmarking''' || Added `allow_bookmarks` boolean to `Assignment`. Added `project_topic_params` permit `allow_bookmarks` in `AssignmentsController`. || `AssignmentEditPage` allows instructors to toggle `allow_bookmarks` (persisted via PATCH). `StudentTasks` shows bookmark toggle if `allow_bookmarks` is true (local state for now).&lt;br /&gt;
|-&lt;br /&gt;
| '''Assignment Editing UI''' || N/A || New `AssignmentEditPage` with tabbed structure. `AssignmentEditor` might be simplified or removed for general settings.&lt;br /&gt;
|-&lt;br /&gt;
| '''Dependency Updates''' || Updated Ruby, Rails, Puma, Nokogiri etc. Added required gems. || N/A&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Key Backend Improvements ===&lt;br /&gt;
&lt;br /&gt;
=== ProjectTopic Model ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Handles team signup, considering available slots and waitlisting&lt;br /&gt;
# Renamed from signup_team for clarity&lt;br /&gt;
def sign_team_up(team)&lt;br /&gt;
  return false if signed_up_teams.exists?(team: team)&lt;br /&gt;
  ActiveRecord::Base.transaction do&lt;br /&gt;
    signed_up_team = signed_up_teams.create!(&lt;br /&gt;
      team: team,&lt;br /&gt;
      is_waitlisted: !slot_available?&lt;br /&gt;
    )&lt;br /&gt;
    # Remove team from other waitlists if confirmed here&lt;br /&gt;
    remove_from_waitlist(team) unless signed_up_team.is_waitlisted?&lt;br /&gt;
    true&lt;br /&gt;
  end&lt;br /&gt;
rescue ActiveRecord::RecordInvalid&lt;br /&gt;
  false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Handles dropping a team and promoting waitlisted if necessary&lt;br /&gt;
def drop_team(team)&lt;br /&gt;
  signed_up_team = signed_up_teams.find_by(team: team)&lt;br /&gt;
  return unless signed_up_team&lt;br /&gt;
  team_confirmed = !signed_up_team.is_waitlisted?&lt;br /&gt;
  signed_up_team.destroy!&lt;br /&gt;
  promote_waitlisted_team if team_confirmed # Promote only if a confirmed slot opened&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Calculates available slots&lt;br /&gt;
def available_slots&lt;br /&gt;
  max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Checks if slots are positive&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for creation, moved from controller&lt;br /&gt;
def self.create_topic_with_assignment(topic_params, assignment_id, micropayment = nil)&lt;br /&gt;
  # ... (find assignment, build topic, save, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for update, moved from controller&lt;br /&gt;
def update_topic(topic_params)&lt;br /&gt;
  # ... (update attributes, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Returns enhanced JSON including computed fields&lt;br /&gt;
def to_json_with_computed_data&lt;br /&gt;
  as_json.merge(&lt;br /&gt;
    available_slots: available_slots,&lt;br /&gt;
    confirmed_teams: confirmed_teams.map { |team| # ... format team data },&lt;br /&gt;
    waitlisted_teams: waitlisted_teams.map { |team| # ... format team data }&lt;br /&gt;
  )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
private&lt;br /&gt;
&lt;br /&gt;
# Helper for promotion logic&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
  # ... (find earliest waitlisted team, update is_waitlisted to false, remove from other waitlists)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to remove team from other topics' waitlists&lt;br /&gt;
def remove_from_waitlist(team)&lt;br /&gt;
  team.signed_up_teams.waitlisted.where.not(project_topic_id: id).destroy_all&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SignedUpTeam Model ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Scope for confirmed signups&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
# Scope for waitlisted signups&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&lt;br /&gt;
belongs_to :project_topic # Updated association&lt;br /&gt;
# ... validations ...&lt;br /&gt;
&lt;br /&gt;
# Business logic for student signup, including dropping previous topic&lt;br /&gt;
def self.sign_up_student_for_topic(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id) # Find student's team&lt;br /&gt;
  return { success: false, message: &amp;quot;User is not part of any team&amp;quot; } unless team_id&lt;br /&gt;
&lt;br /&gt;
  # Drop any existing topic signups for this team FIRST&lt;br /&gt;
  drop_existing_signups_for_team(team_id)&lt;br /&gt;
&lt;br /&gt;
  # Sign up for the new topic using create_signed_up_team (which calls topic.sign_team_up)&lt;br /&gt;
  signed_up_team = create_signed_up_team(topic_id, team_id)&lt;br /&gt;
&lt;br /&gt;
  if signed_up_team&lt;br /&gt;
    { success: true, message: &amp;quot;Signed up team successful!&amp;quot;, signed_up_team: signed_up_team, available_slots: signed_up_team.project_topic.available_slots }&lt;br /&gt;
  else&lt;br /&gt;
    { success: false, message: &amp;quot;Failed to sign up for topic. Topic may be full or already signed up.&amp;quot; }&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for dropping a topic&lt;br /&gt;
def self.drop_topic_for_student(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id)&lt;br /&gt;
  # ... (find topic, team, signed_up_team record) ...&lt;br /&gt;
  return { success: false, message: &amp;quot;Team is not signed up for this topic&amp;quot; } unless signed_up_team&lt;br /&gt;
&lt;br /&gt;
  # Delegate drop logic to ProjectTopic&lt;br /&gt;
  project_topic.drop_team(team)&lt;br /&gt;
&lt;br /&gt;
  { success: true, message: &amp;quot;Successfully dropped topic!&amp;quot;, available_slots: project_topic.available_slots }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to find and drop existing signups before signing up for a new one&lt;br /&gt;
private&lt;br /&gt;
def self.drop_existing_signups_for_team(team_id)&lt;br /&gt;
  existing_signups = where(team_id: team_id)&lt;br /&gt;
  existing_signups.each do |signup|&lt;br /&gt;
    signup.project_topic.drop_team(signup.team) # Use ProjectTopic's drop method&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frontend Improvements ===&lt;br /&gt;
&lt;br /&gt;
=== Topic signup page for students ===&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Topics_signup_page_for_students.png|800px|Topics_signup_page_for_students]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Admin page to CRUD Assignment Topics ===&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Admin_topic_SelectionPage.png|800px|thumb|left|Caption]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Database Migrations ===&lt;br /&gt;
* Renamed `sign_up_topics` table to `project_topics`.&lt;br /&gt;
* Updated `signed_up_teams` table: renamed `sign_up_topic_id` foreign key to `project_topic_id` and updated index name.&lt;br /&gt;
* Added `allow_bookmarks` boolean column to `assignments` table.&lt;br /&gt;
* Renamed `teams_users` join table to `teams_participants`.&lt;br /&gt;
&lt;br /&gt;
=== Testing ===&lt;br /&gt;
&lt;br /&gt;
=== RSpec Tests (Backend) ===&lt;br /&gt;
* '''ProjectTopic Model (`project_topic_spec.rb`):''' Added extensive tests covering:&lt;br /&gt;
    * `sign_team_up`: Confirmed vs. waitlisted based on `max_choosers`, removal from other waitlists.&lt;br /&gt;
    * `drop_team`: Team removal, promotion of earliest waitlisted team.&lt;br /&gt;
    * `available_slots`, `slot_available?`: Correct calculations before/after signups/drops.&lt;br /&gt;
    * `confirmed_teams`, `waitlisted_teams`: Correct retrieval and ordering.&lt;br /&gt;
    * Validations: Presence of `topic_name`, non-negative `max_choosers` (including zero).&lt;br /&gt;
* '''SignedUpTeam Model (`signed_up_team_spec.rb`):''' Added tests covering:&lt;br /&gt;
    * Validations: Presence of topic/team, uniqueness scope.&lt;br /&gt;
    * Scopes: `:confirmed`, `:waitlisted`.&lt;br /&gt;
    * Class methods: Signup logic delegation, removal logic, participant/topic finding.&lt;br /&gt;
    * Waitlisting behavior when topic is full.&lt;br /&gt;
* '''Updates:''' Modified existing tests (e.g., `due_date_spec.rb`) to reference `ProjectTopic`.&lt;br /&gt;
&lt;br /&gt;
=== Manual Tests (UI) ===&lt;br /&gt;
* '''Instructor Flow:''' Verified assignment editing via `/assignments/edit/:id`, topic creation/editing/deletion/import via modals, toggling `allow_bookmarks`, dropping teams from topics.&lt;br /&gt;
* '''Student Flow:''' Verified topic viewing via `/student_tasks/:assignmentId`, selecting/deselecting topics (including automatic drop of previous), bookmarking (when enabled), correct display of slots and waitlists, disabled selection for full topics.&lt;br /&gt;
&lt;br /&gt;
== Impact Analysis ==&lt;br /&gt;
&lt;br /&gt;
=== Summary of Changes ===&lt;br /&gt;
* '''Backend:''' Major refactoring of topic-related models and controllers, database schema changes, new API endpoints, updated dependencies. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily models, controllers, specs, migrations).&lt;br /&gt;
* '''Frontend:''' New assignment editing page with tabbed UI, new student task page for topic signup, reusable `TopicsTable` component, new routes. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily in `src/pages/Assignments`, `src/pages/StudentTasks`, `src/components`).&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
* ✓ Successfully refactored `SignUpTopic` to `ProjectTopic` for improved clarity.&lt;br /&gt;
* ✓ Centralized business logic in models, resulting in cleaner controllers.&lt;br /&gt;
* ✓ Implemented a modern, tabbed interface for assignment editing.&lt;br /&gt;
* ✓ Created a dedicated, streamlined UI for student topic signup.&lt;br /&gt;
* ✓ Added topic bookmarking functionality.&lt;br /&gt;
* ✓ Enhanced API endpoints for better data provision to the frontend.&lt;br /&gt;
* ✓ Updated key dependencies (Rails 8).&lt;br /&gt;
* ✓ Added comprehensive RSpec tests for new model logic.&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
* '''Frontend Bookmark Persistence:''' Implement API calls to save/load student topic bookmarks instead of using local state.&lt;br /&gt;
* '''Partner Ad Feature:''' Fully implement the &amp;quot;Apply to partner ad&amp;quot; functionality hinted at in `TopicsTab`.&lt;br /&gt;
* '''Complete Assignment Tabs:''' Implement the remaining tabs in `AssignmentEditPage` (Rubrics, Review Strategy, Due Dates, Etc.).&lt;br /&gt;
* '''Refine General Tab/AssignmentEditor:''' Decide whether general assignment settings remain in `AssignmentEditor` modal or move entirely to a &amp;quot;General&amp;quot; tab within `AssignmentEditPage`.&lt;br /&gt;
* '''Error Handling (Frontend):''' Enhance user feedback for API errors during topic operations (create/edit/delete/signup/drop).&lt;br /&gt;
* '''Authorization Checks:''' Ensure robust authorization checks are in place for all new/modified backend endpoints.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
This project successfully refactored the core topic management and signup system in Expertiza, replacing `SignUpTopic` with `ProjectTopic` and significantly improving the underlying logic by moving it into the models. New frontend interfaces provide a much-improved experience for both instructors managing topics and students signing up for them. The addition of features like topic bookmarking and a streamlined student signup flow enhances usability. The changes establish a more maintainable and understandable codebase for future development.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
# [https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
# [https://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
# [http://wikis.lib.ncsu.edu/index.php/Expertiza Expertiza project documentation wiki]&lt;br /&gt;
# ''(Add links to your specific project fork/PRs if needed)''&lt;br /&gt;
# [https://guides.rubyonrails.org/ Ruby on Rails Guides]&lt;br /&gt;
# [https://react.dev/ React Documentation]&lt;br /&gt;
# [https://relishapp.com/rspec Rspec Documentation]&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166917</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166917"/>
		<updated>2025-10-30T22:38:23Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* AssignmentEditPage Component */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== E 2552. Refactoring Topics and Enhancing Assignment Management ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
==== Background ====&lt;br /&gt;
Expertiza utilizes a system for instructors to define topics within assignments, allowing students (often in teams) to sign up for these topics. The previous implementation, centered around the `SignUpTopic` model and associated controllers (`SignUpTopicsController`, `SignedUpTeamsController`), lacked clarity in naming and had business logic distributed across controllers rather than encapsulated within models. Furthermore, the user interface for managing assignment topics by instructors and for students signing up for topics required modernization and improved functionality.&lt;br /&gt;
&lt;br /&gt;
==== Motivation ====&lt;br /&gt;
This project aimed to improve the maintainability, clarity, and functionality of the topic management and signup features within Expertiza. Key motivations included:&lt;br /&gt;
* Renaming core components (`SignUpTopic` -&amp;gt; `ProjectTopic`) to better reflect their purpose.&lt;br /&gt;
* Created RESTful API endpoints to manage topics and team signups.&lt;br /&gt;
* Creating a more intuitive and feature-rich interface for instructors managing assignment topics.&lt;br /&gt;
* Developing a dedicated and user-friendly interface for students to view, select, and manage their topic signups.&lt;br /&gt;
* Introducing features like bookmarking topics and streamlining the student signup/drop process.&lt;br /&gt;
* Updating dependencies to keep the application current.&lt;br /&gt;
&lt;br /&gt;
==== Tasks Accomplished ====&lt;br /&gt;
* Renamed `SignUpTopic` to `ProjectTopic` throughout the backend (models, controllers, routes, tests, database).&lt;br /&gt;
* Refactored `ProjectTopic` and `SignedUpTeam` models to encapsulate business logic (topic creation/update/deletion, team signup/waitlisting, slot management, student signup/drop).&lt;br /&gt;
* Removed `SignUpTopicsController` and implemented `ProjectTopicsController` using the refactored model logic.&lt;br /&gt;
* Refactored `SignedUpTeamsController` to utilize new model methods and added new actions (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
* Added `allow_bookmarks` attribute to the `Assignment` model and associated backend/frontend logic.&lt;br /&gt;
* Created a new frontend page (`AssignmentEditPage.tsx`) with a tabbed interface for instructors to manage assignments, including a dedicated &amp;quot;Topics&amp;quot; tab.&lt;br /&gt;
* Implemented modals for creating, editing, importing, and deleting topics on the frontend.&lt;br /&gt;
* Developed a reusable `TopicsTable.tsx` component for displaying topics in instructor and student views.&lt;br /&gt;
* Created a new frontend page (`StudentTasks.tsx`) for students to view assignment topics, bookmark (if enabled), and sign up/drop topics.&lt;br /&gt;
* Updated backend dependencies (Rails, Puma, Nokogiri, etc.) and Docker configuration.&lt;br /&gt;
* Added/updated RSpec tests for `ProjectTopic` and `SignedUpTeam` models and updated relevant existing tests.&lt;br /&gt;
* Updated Swagger API documentation.&lt;br /&gt;
&lt;br /&gt;
====Files Modified and Created====&lt;br /&gt;
&lt;br /&gt;
* **app/models/project_topic.rb**&lt;br /&gt;
* **app/models/signed_up_team.rb**&lt;br /&gt;
* **app/controllers/api/v1/project_topics_controller.rb**&lt;br /&gt;
* **app/controllers/api/v1/signed_up_teams_controller.rb**&lt;br /&gt;
* **app/serializers/project_topic_serializer.rb**&lt;br /&gt;
* **app/serializers/signed_up_team_serializer.rb**&lt;br /&gt;
* **spec/models/project_topic_spec.rb**&lt;br /&gt;
* **spec/models/signed_up_team_spec.rb**&lt;br /&gt;
* **spec/requests/project_topics_spec.rb**&lt;br /&gt;
* **spec/requests/signed_up_teams_spec.rb**&lt;br /&gt;
&lt;br /&gt;
=== Problem Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Issues with Previous Implementation ====&lt;br /&gt;
&lt;br /&gt;
==== Naming Convention ====&lt;br /&gt;
The name `SignUpTopic` was ambiguous. Renaming to `ProjectTopic` clarifies that these are topics related to the core project/assignment work students sign up for.&lt;br /&gt;
&lt;br /&gt;
==== Distributed Business Logic ====&lt;br /&gt;
Logic for creating topics, signing up teams, managing waitlists, and checking slots was spread across `SignUpTopicsController` and `SignedUpTeamsController`. This violated the principle of &amp;quot;fat model, skinny controller&amp;quot;, making the code harder to understand, test, and maintain.&lt;br /&gt;
&lt;br /&gt;
==== Inefficient Data Fetching ====&lt;br /&gt;
Frontend components often needed to make multiple API calls or perform calculations (like available slots) that could be handled more efficiently on the backend. The previous `SignUpTopic` API didn't provide computed data like assigned/waitlisted teams directly.&lt;br /&gt;
&lt;br /&gt;
==== Lack of Dedicated Student View ====&lt;br /&gt;
Students lacked a clear, dedicated interface to view available topics for an assignment and manage their selection. The signup process was not streamlined.&lt;br /&gt;
&lt;br /&gt;
==== Inconsistent Assignment Editing ====&lt;br /&gt;
The existing `AssignmentEditor` modal combined general settings with links to other management pages (like topics, participants) in an ad-hoc manner. A more structured approach was needed.&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== Architecture Decisions ===&lt;br /&gt;
* '''Model-Centric Logic:''' Shifted primary business logic for topic management and team signups into the `ProjectTopic` and `SignedUpTeam` models, respectively. Controllers now primarily handle request/response flow and delegate actions to the models.&lt;br /&gt;
* '''Dedicated Edit Page (Frontend):''' Created a new full page (`AssignmentEditPage`) for editing assignments instead of using a modal, allowing for a more complex, tabbed interface.&lt;br /&gt;
* '''Reusable Table Component (Frontend):''' Developed `TopicsTable` to handle the display and core interactions for topics in different contexts (instructor vs. student), promoting DRY principles.&lt;br /&gt;
* '''API Enhancements:''' Modified the `ProjectTopic` index endpoint (`/api/v1/project_topics`) to accept `assignment_id` and return topics with computed data (`to_json_with_computed_data`), reducing frontend calculation needs. Added specific endpoints for student signup (`sign_up_student`) and dropping topics (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
&lt;br /&gt;
==== Core Functionality Implemented ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Backend Changes !! Frontend Changes&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Renaming''' || Renamed `SignUpTopic` model, controller, routes, DB table to `ProjectTopic`. Updated associations. || Updated API endpoints used.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Management (Instructor)''' || `ProjectTopicsController` CRUD actions delegating to `ProjectTopic` model methods (`create_topic_with_assignment`, `update_topic`, `delete_by_assignment_and_topic_ids`). API returns computed data. || New `AssignmentEditPage` with `TopicsTab`. Uses `TopicsTable` (instructor mode). Modals for create, edit, import, delete. API calls for CRUD.&lt;br /&gt;
|-&lt;br /&gt;
| '''Team Signup Logic''' || `ProjectTopic` methods (`sign_team_up`, `drop_team`, `promote_waitlisted_team`). `SignedUpTeam` methods (`create_signed_up_team`, `remove_team_signups`). || Instructor view shows assigned/waitlisted teams in `TopicsTable` details. Drop team button calls backend.&lt;br /&gt;
|-&lt;br /&gt;
| '''Student Signup/Drop''' || `SignedUpTeamsController` actions (`sign_up_student`, `drop_topic`) delegating to `SignedUpTeam` model methods (`sign_up_student_for_topic`, `drop_topic_for_student`). Automatic handling of switching topics. || New `StudentTasks` page. Uses `TopicsTable` (student mode). Select/deselect buttons trigger API calls. Optimistic UI updates for slots. Displays current selection.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Bookmarking''' || Added `allow_bookmarks` boolean to `Assignment`. Added `project_topic_params` permit `allow_bookmarks` in `AssignmentsController`. || `AssignmentEditPage` allows instructors to toggle `allow_bookmarks` (persisted via PATCH). `StudentTasks` shows bookmark toggle if `allow_bookmarks` is true (local state for now).&lt;br /&gt;
|-&lt;br /&gt;
| '''Assignment Editing UI''' || N/A || New `AssignmentEditPage` with tabbed structure. `AssignmentEditor` might be simplified or removed for general settings.&lt;br /&gt;
|-&lt;br /&gt;
| '''Dependency Updates''' || Updated Ruby, Rails, Puma, Nokogiri etc. Added required gems. || N/A&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Key Backend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== ProjectTopic Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Handles team signup, considering available slots and waitlisting&lt;br /&gt;
# Renamed from signup_team for clarity&lt;br /&gt;
def sign_team_up(team)&lt;br /&gt;
  return false if signed_up_teams.exists?(team: team)&lt;br /&gt;
  ActiveRecord::Base.transaction do&lt;br /&gt;
    signed_up_team = signed_up_teams.create!(&lt;br /&gt;
      team: team,&lt;br /&gt;
      is_waitlisted: !slot_available?&lt;br /&gt;
    )&lt;br /&gt;
    # Remove team from other waitlists if confirmed here&lt;br /&gt;
    remove_from_waitlist(team) unless signed_up_team.is_waitlisted?&lt;br /&gt;
    true&lt;br /&gt;
  end&lt;br /&gt;
rescue ActiveRecord::RecordInvalid&lt;br /&gt;
  false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Handles dropping a team and promoting waitlisted if necessary&lt;br /&gt;
def drop_team(team)&lt;br /&gt;
  signed_up_team = signed_up_teams.find_by(team: team)&lt;br /&gt;
  return unless signed_up_team&lt;br /&gt;
  team_confirmed = !signed_up_team.is_waitlisted?&lt;br /&gt;
  signed_up_team.destroy!&lt;br /&gt;
  promote_waitlisted_team if team_confirmed # Promote only if a confirmed slot opened&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Calculates available slots&lt;br /&gt;
def available_slots&lt;br /&gt;
  max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Checks if slots are positive&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for creation, moved from controller&lt;br /&gt;
def self.create_topic_with_assignment(topic_params, assignment_id, micropayment = nil)&lt;br /&gt;
  # ... (find assignment, build topic, save, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for update, moved from controller&lt;br /&gt;
def update_topic(topic_params)&lt;br /&gt;
  # ... (update attributes, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Returns enhanced JSON including computed fields&lt;br /&gt;
def to_json_with_computed_data&lt;br /&gt;
  as_json.merge(&lt;br /&gt;
    available_slots: available_slots,&lt;br /&gt;
    confirmed_teams: confirmed_teams.map { |team| # ... format team data },&lt;br /&gt;
    waitlisted_teams: waitlisted_teams.map { |team| # ... format team data }&lt;br /&gt;
  )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
private&lt;br /&gt;
&lt;br /&gt;
# Helper for promotion logic&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
  # ... (find earliest waitlisted team, update is_waitlisted to false, remove from other waitlists)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to remove team from other topics' waitlists&lt;br /&gt;
def remove_from_waitlist(team)&lt;br /&gt;
  team.signed_up_teams.waitlisted.where.not(project_topic_id: id).destroy_all&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SignedUpTeam Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Scope for confirmed signups&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
# Scope for waitlisted signups&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&lt;br /&gt;
belongs_to :project_topic # Updated association&lt;br /&gt;
# ... validations ...&lt;br /&gt;
&lt;br /&gt;
# Business logic for student signup, including dropping previous topic&lt;br /&gt;
def self.sign_up_student_for_topic(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id) # Find student's team&lt;br /&gt;
  return { success: false, message: &amp;quot;User is not part of any team&amp;quot; } unless team_id&lt;br /&gt;
&lt;br /&gt;
  # Drop any existing topic signups for this team FIRST&lt;br /&gt;
  drop_existing_signups_for_team(team_id)&lt;br /&gt;
&lt;br /&gt;
  # Sign up for the new topic using create_signed_up_team (which calls topic.sign_team_up)&lt;br /&gt;
  signed_up_team = create_signed_up_team(topic_id, team_id)&lt;br /&gt;
&lt;br /&gt;
  if signed_up_team&lt;br /&gt;
    { success: true, message: &amp;quot;Signed up team successful!&amp;quot;, signed_up_team: signed_up_team, available_slots: signed_up_team.project_topic.available_slots }&lt;br /&gt;
  else&lt;br /&gt;
    { success: false, message: &amp;quot;Failed to sign up for topic. Topic may be full or already signed up.&amp;quot; }&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for dropping a topic&lt;br /&gt;
def self.drop_topic_for_student(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id)&lt;br /&gt;
  # ... (find topic, team, signed_up_team record) ...&lt;br /&gt;
  return { success: false, message: &amp;quot;Team is not signed up for this topic&amp;quot; } unless signed_up_team&lt;br /&gt;
&lt;br /&gt;
  # Delegate drop logic to ProjectTopic&lt;br /&gt;
  project_topic.drop_team(team)&lt;br /&gt;
&lt;br /&gt;
  { success: true, message: &amp;quot;Successfully dropped topic!&amp;quot;, available_slots: project_topic.available_slots }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to find and drop existing signups before signing up for a new one&lt;br /&gt;
private&lt;br /&gt;
def self.drop_existing_signups_for_team(team_id)&lt;br /&gt;
  existing_signups = where(team_id: team_id)&lt;br /&gt;
  existing_signups.each do |signup|&lt;br /&gt;
    signup.project_topic.drop_team(signup.team) # Use ProjectTopic's drop method&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Frontend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== Topic signup page for students ====&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Topics_signup_page_for_students.png|800px|Topics_signup_page_for_students]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Admin page to CRUD Assignment Topics ====&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Admin_topic_SelectionPage.png|800px|thumb|left|Caption]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Database Migrations ====&lt;br /&gt;
* Renamed `sign_up_topics` table to `project_topics`.&lt;br /&gt;
* Updated `signed_up_teams` table: renamed `sign_up_topic_id` foreign key to `project_topic_id` and updated index name.&lt;br /&gt;
* Added `allow_bookmarks` boolean column to `assignments` table.&lt;br /&gt;
* Renamed `teams_users` join table to `teams_participants`.&lt;br /&gt;
&lt;br /&gt;
==== Testing ====&lt;br /&gt;
&lt;br /&gt;
==== RSpec Tests (Backend) ====&lt;br /&gt;
* '''ProjectTopic Model (`project_topic_spec.rb`):''' Added extensive tests covering:&lt;br /&gt;
    * `sign_team_up`: Confirmed vs. waitlisted based on `max_choosers`, removal from other waitlists.&lt;br /&gt;
    * `drop_team`: Team removal, promotion of earliest waitlisted team.&lt;br /&gt;
    * `available_slots`, `slot_available?`: Correct calculations before/after signups/drops.&lt;br /&gt;
    * `confirmed_teams`, `waitlisted_teams`: Correct retrieval and ordering.&lt;br /&gt;
    * Validations: Presence of `topic_name`, non-negative `max_choosers` (including zero).&lt;br /&gt;
* '''SignedUpTeam Model (`signed_up_team_spec.rb`):''' Added tests covering:&lt;br /&gt;
    * Validations: Presence of topic/team, uniqueness scope.&lt;br /&gt;
    * Scopes: `:confirmed`, `:waitlisted`.&lt;br /&gt;
    * Class methods: Signup logic delegation, removal logic, participant/topic finding.&lt;br /&gt;
    * Waitlisting behavior when topic is full.&lt;br /&gt;
* '''Updates:''' Modified existing tests (e.g., `due_date_spec.rb`) to reference `ProjectTopic`.&lt;br /&gt;
&lt;br /&gt;
==== Manual Tests (UI) ====&lt;br /&gt;
* '''Instructor Flow:''' Verified assignment editing via `/assignments/edit/:id`, topic creation/editing/deletion/import via modals, toggling `allow_bookmarks`, dropping teams from topics.&lt;br /&gt;
* '''Student Flow:''' Verified topic viewing via `/student_tasks/:assignmentId`, selecting/deselecting topics (including automatic drop of previous), bookmarking (when enabled), correct display of slots and waitlists, disabled selection for full topics.&lt;br /&gt;
&lt;br /&gt;
=== Impact Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Summary of Changes ====&lt;br /&gt;
* '''Backend:''' Major refactoring of topic-related models and controllers, database schema changes, new API endpoints, updated dependencies. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily models, controllers, specs, migrations).&lt;br /&gt;
* '''Frontend:''' New assignment editing page with tabbed UI, new student task page for topic signup, reusable `TopicsTable` component, new routes. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily in `src/pages/Assignments`, `src/pages/StudentTasks`, `src/components`).&lt;br /&gt;
&lt;br /&gt;
==== Achievements ====&lt;br /&gt;
* ✓ Successfully refactored `SignUpTopic` to `ProjectTopic` for improved clarity.&lt;br /&gt;
* ✓ Centralized business logic in models, resulting in cleaner controllers.&lt;br /&gt;
* ✓ Implemented a modern, tabbed interface for assignment editing.&lt;br /&gt;
* ✓ Created a dedicated, streamlined UI for student topic signup.&lt;br /&gt;
* ✓ Added topic bookmarking functionality.&lt;br /&gt;
* ✓ Enhanced API endpoints for better data provision to the frontend.&lt;br /&gt;
* ✓ Updated key dependencies (Rails 8).&lt;br /&gt;
* ✓ Added comprehensive RSpec tests for new model logic.&lt;br /&gt;
&lt;br /&gt;
=== Future Work ===&lt;br /&gt;
* '''Frontend Bookmark Persistence:''' Implement API calls to save/load student topic bookmarks instead of using local state.&lt;br /&gt;
* '''Partner Ad Feature:''' Fully implement the &amp;quot;Apply to partner ad&amp;quot; functionality hinted at in `TopicsTab`.&lt;br /&gt;
* '''Complete Assignment Tabs:''' Implement the remaining tabs in `AssignmentEditPage` (Rubrics, Review Strategy, Due Dates, Etc.).&lt;br /&gt;
* '''Refine General Tab/AssignmentEditor:''' Decide whether general assignment settings remain in `AssignmentEditor` modal or move entirely to a &amp;quot;General&amp;quot; tab within `AssignmentEditPage`.&lt;br /&gt;
* '''Error Handling (Frontend):''' Enhance user feedback for API errors during topic operations (create/edit/delete/signup/drop).&lt;br /&gt;
* '''Authorization Checks:''' Ensure robust authorization checks are in place for all new/modified backend endpoints.&lt;br /&gt;
&lt;br /&gt;
=== Conclusion ===&lt;br /&gt;
This project successfully refactored the core topic management and signup system in Expertiza, replacing `SignUpTopic` with `ProjectTopic` and significantly improving the underlying logic by moving it into the models. New frontend interfaces provide a much-improved experience for both instructors managing topics and students signing up for them. The addition of features like topic bookmarking and a streamlined student signup flow enhances usability. The changes establish a more maintainable and understandable codebase for future development.&lt;br /&gt;
&lt;br /&gt;
=== References ===&lt;br /&gt;
# [https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
# [https://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
# [http://wikis.lib.ncsu.edu/index.php/Expertiza Expertiza project documentation wiki]&lt;br /&gt;
# ''(Add links to your specific project fork/PRs if needed)''&lt;br /&gt;
# [https://guides.rubyonrails.org/ Ruby on Rails Guides]&lt;br /&gt;
# [https://react.dev/ React Documentation]&lt;br /&gt;
# [https://relishapp.com/rspec Rspec Documentation]&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166916</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166916"/>
		<updated>2025-10-30T22:35:22Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* StudentTasks Component */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== E 2552. Refactoring Topics and Enhancing Assignment Management ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
==== Background ====&lt;br /&gt;
Expertiza utilizes a system for instructors to define topics within assignments, allowing students (often in teams) to sign up for these topics. The previous implementation, centered around the `SignUpTopic` model and associated controllers (`SignUpTopicsController`, `SignedUpTeamsController`), lacked clarity in naming and had business logic distributed across controllers rather than encapsulated within models. Furthermore, the user interface for managing assignment topics by instructors and for students signing up for topics required modernization and improved functionality.&lt;br /&gt;
&lt;br /&gt;
==== Motivation ====&lt;br /&gt;
This project aimed to improve the maintainability, clarity, and functionality of the topic management and signup features within Expertiza. Key motivations included:&lt;br /&gt;
* Renaming core components (`SignUpTopic` -&amp;gt; `ProjectTopic`) to better reflect their purpose.&lt;br /&gt;
* Created RESTful API endpoints to manage topics and team signups.&lt;br /&gt;
* Creating a more intuitive and feature-rich interface for instructors managing assignment topics.&lt;br /&gt;
* Developing a dedicated and user-friendly interface for students to view, select, and manage their topic signups.&lt;br /&gt;
* Introducing features like bookmarking topics and streamlining the student signup/drop process.&lt;br /&gt;
* Updating dependencies to keep the application current.&lt;br /&gt;
&lt;br /&gt;
==== Tasks Accomplished ====&lt;br /&gt;
* Renamed `SignUpTopic` to `ProjectTopic` throughout the backend (models, controllers, routes, tests, database).&lt;br /&gt;
* Refactored `ProjectTopic` and `SignedUpTeam` models to encapsulate business logic (topic creation/update/deletion, team signup/waitlisting, slot management, student signup/drop).&lt;br /&gt;
* Removed `SignUpTopicsController` and implemented `ProjectTopicsController` using the refactored model logic.&lt;br /&gt;
* Refactored `SignedUpTeamsController` to utilize new model methods and added new actions (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
* Added `allow_bookmarks` attribute to the `Assignment` model and associated backend/frontend logic.&lt;br /&gt;
* Created a new frontend page (`AssignmentEditPage.tsx`) with a tabbed interface for instructors to manage assignments, including a dedicated &amp;quot;Topics&amp;quot; tab.&lt;br /&gt;
* Implemented modals for creating, editing, importing, and deleting topics on the frontend.&lt;br /&gt;
* Developed a reusable `TopicsTable.tsx` component for displaying topics in instructor and student views.&lt;br /&gt;
* Created a new frontend page (`StudentTasks.tsx`) for students to view assignment topics, bookmark (if enabled), and sign up/drop topics.&lt;br /&gt;
* Updated backend dependencies (Rails, Puma, Nokogiri, etc.) and Docker configuration.&lt;br /&gt;
* Added/updated RSpec tests for `ProjectTopic` and `SignedUpTeam` models and updated relevant existing tests.&lt;br /&gt;
* Updated Swagger API documentation.&lt;br /&gt;
&lt;br /&gt;
====Files Modified and Created====&lt;br /&gt;
&lt;br /&gt;
* **app/models/project_topic.rb**&lt;br /&gt;
* **app/models/signed_up_team.rb**&lt;br /&gt;
* **app/controllers/api/v1/project_topics_controller.rb**&lt;br /&gt;
* **app/controllers/api/v1/signed_up_teams_controller.rb**&lt;br /&gt;
* **app/serializers/project_topic_serializer.rb**&lt;br /&gt;
* **app/serializers/signed_up_team_serializer.rb**&lt;br /&gt;
* **spec/models/project_topic_spec.rb**&lt;br /&gt;
* **spec/models/signed_up_team_spec.rb**&lt;br /&gt;
* **spec/requests/project_topics_spec.rb**&lt;br /&gt;
* **spec/requests/signed_up_teams_spec.rb**&lt;br /&gt;
&lt;br /&gt;
=== Problem Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Issues with Previous Implementation ====&lt;br /&gt;
&lt;br /&gt;
==== Naming Convention ====&lt;br /&gt;
The name `SignUpTopic` was ambiguous. Renaming to `ProjectTopic` clarifies that these are topics related to the core project/assignment work students sign up for.&lt;br /&gt;
&lt;br /&gt;
==== Distributed Business Logic ====&lt;br /&gt;
Logic for creating topics, signing up teams, managing waitlists, and checking slots was spread across `SignUpTopicsController` and `SignedUpTeamsController`. This violated the principle of &amp;quot;fat model, skinny controller&amp;quot;, making the code harder to understand, test, and maintain.&lt;br /&gt;
&lt;br /&gt;
==== Inefficient Data Fetching ====&lt;br /&gt;
Frontend components often needed to make multiple API calls or perform calculations (like available slots) that could be handled more efficiently on the backend. The previous `SignUpTopic` API didn't provide computed data like assigned/waitlisted teams directly.&lt;br /&gt;
&lt;br /&gt;
==== Lack of Dedicated Student View ====&lt;br /&gt;
Students lacked a clear, dedicated interface to view available topics for an assignment and manage their selection. The signup process was not streamlined.&lt;br /&gt;
&lt;br /&gt;
==== Inconsistent Assignment Editing ====&lt;br /&gt;
The existing `AssignmentEditor` modal combined general settings with links to other management pages (like topics, participants) in an ad-hoc manner. A more structured approach was needed.&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== Architecture Decisions ===&lt;br /&gt;
* '''Model-Centric Logic:''' Shifted primary business logic for topic management and team signups into the `ProjectTopic` and `SignedUpTeam` models, respectively. Controllers now primarily handle request/response flow and delegate actions to the models.&lt;br /&gt;
* '''Dedicated Edit Page (Frontend):''' Created a new full page (`AssignmentEditPage`) for editing assignments instead of using a modal, allowing for a more complex, tabbed interface.&lt;br /&gt;
* '''Reusable Table Component (Frontend):''' Developed `TopicsTable` to handle the display and core interactions for topics in different contexts (instructor vs. student), promoting DRY principles.&lt;br /&gt;
* '''API Enhancements:''' Modified the `ProjectTopic` index endpoint (`/api/v1/project_topics`) to accept `assignment_id` and return topics with computed data (`to_json_with_computed_data`), reducing frontend calculation needs. Added specific endpoints for student signup (`sign_up_student`) and dropping topics (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
&lt;br /&gt;
==== Core Functionality Implemented ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Backend Changes !! Frontend Changes&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Renaming''' || Renamed `SignUpTopic` model, controller, routes, DB table to `ProjectTopic`. Updated associations. || Updated API endpoints used.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Management (Instructor)''' || `ProjectTopicsController` CRUD actions delegating to `ProjectTopic` model methods (`create_topic_with_assignment`, `update_topic`, `delete_by_assignment_and_topic_ids`). API returns computed data. || New `AssignmentEditPage` with `TopicsTab`. Uses `TopicsTable` (instructor mode). Modals for create, edit, import, delete. API calls for CRUD.&lt;br /&gt;
|-&lt;br /&gt;
| '''Team Signup Logic''' || `ProjectTopic` methods (`sign_team_up`, `drop_team`, `promote_waitlisted_team`). `SignedUpTeam` methods (`create_signed_up_team`, `remove_team_signups`). || Instructor view shows assigned/waitlisted teams in `TopicsTable` details. Drop team button calls backend.&lt;br /&gt;
|-&lt;br /&gt;
| '''Student Signup/Drop''' || `SignedUpTeamsController` actions (`sign_up_student`, `drop_topic`) delegating to `SignedUpTeam` model methods (`sign_up_student_for_topic`, `drop_topic_for_student`). Automatic handling of switching topics. || New `StudentTasks` page. Uses `TopicsTable` (student mode). Select/deselect buttons trigger API calls. Optimistic UI updates for slots. Displays current selection.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Bookmarking''' || Added `allow_bookmarks` boolean to `Assignment`. Added `project_topic_params` permit `allow_bookmarks` in `AssignmentsController`. || `AssignmentEditPage` allows instructors to toggle `allow_bookmarks` (persisted via PATCH). `StudentTasks` shows bookmark toggle if `allow_bookmarks` is true (local state for now).&lt;br /&gt;
|-&lt;br /&gt;
| '''Assignment Editing UI''' || N/A || New `AssignmentEditPage` with tabbed structure. `AssignmentEditor` might be simplified or removed for general settings.&lt;br /&gt;
|-&lt;br /&gt;
| '''Dependency Updates''' || Updated Ruby, Rails, Puma, Nokogiri etc. Added required gems. || N/A&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Key Backend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== ProjectTopic Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Handles team signup, considering available slots and waitlisting&lt;br /&gt;
# Renamed from signup_team for clarity&lt;br /&gt;
def sign_team_up(team)&lt;br /&gt;
  return false if signed_up_teams.exists?(team: team)&lt;br /&gt;
  ActiveRecord::Base.transaction do&lt;br /&gt;
    signed_up_team = signed_up_teams.create!(&lt;br /&gt;
      team: team,&lt;br /&gt;
      is_waitlisted: !slot_available?&lt;br /&gt;
    )&lt;br /&gt;
    # Remove team from other waitlists if confirmed here&lt;br /&gt;
    remove_from_waitlist(team) unless signed_up_team.is_waitlisted?&lt;br /&gt;
    true&lt;br /&gt;
  end&lt;br /&gt;
rescue ActiveRecord::RecordInvalid&lt;br /&gt;
  false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Handles dropping a team and promoting waitlisted if necessary&lt;br /&gt;
def drop_team(team)&lt;br /&gt;
  signed_up_team = signed_up_teams.find_by(team: team)&lt;br /&gt;
  return unless signed_up_team&lt;br /&gt;
  team_confirmed = !signed_up_team.is_waitlisted?&lt;br /&gt;
  signed_up_team.destroy!&lt;br /&gt;
  promote_waitlisted_team if team_confirmed # Promote only if a confirmed slot opened&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Calculates available slots&lt;br /&gt;
def available_slots&lt;br /&gt;
  max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Checks if slots are positive&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for creation, moved from controller&lt;br /&gt;
def self.create_topic_with_assignment(topic_params, assignment_id, micropayment = nil)&lt;br /&gt;
  # ... (find assignment, build topic, save, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for update, moved from controller&lt;br /&gt;
def update_topic(topic_params)&lt;br /&gt;
  # ... (update attributes, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Returns enhanced JSON including computed fields&lt;br /&gt;
def to_json_with_computed_data&lt;br /&gt;
  as_json.merge(&lt;br /&gt;
    available_slots: available_slots,&lt;br /&gt;
    confirmed_teams: confirmed_teams.map { |team| # ... format team data },&lt;br /&gt;
    waitlisted_teams: waitlisted_teams.map { |team| # ... format team data }&lt;br /&gt;
  )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
private&lt;br /&gt;
&lt;br /&gt;
# Helper for promotion logic&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
  # ... (find earliest waitlisted team, update is_waitlisted to false, remove from other waitlists)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to remove team from other topics' waitlists&lt;br /&gt;
def remove_from_waitlist(team)&lt;br /&gt;
  team.signed_up_teams.waitlisted.where.not(project_topic_id: id).destroy_all&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SignedUpTeam Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Scope for confirmed signups&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
# Scope for waitlisted signups&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&lt;br /&gt;
belongs_to :project_topic # Updated association&lt;br /&gt;
# ... validations ...&lt;br /&gt;
&lt;br /&gt;
# Business logic for student signup, including dropping previous topic&lt;br /&gt;
def self.sign_up_student_for_topic(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id) # Find student's team&lt;br /&gt;
  return { success: false, message: &amp;quot;User is not part of any team&amp;quot; } unless team_id&lt;br /&gt;
&lt;br /&gt;
  # Drop any existing topic signups for this team FIRST&lt;br /&gt;
  drop_existing_signups_for_team(team_id)&lt;br /&gt;
&lt;br /&gt;
  # Sign up for the new topic using create_signed_up_team (which calls topic.sign_team_up)&lt;br /&gt;
  signed_up_team = create_signed_up_team(topic_id, team_id)&lt;br /&gt;
&lt;br /&gt;
  if signed_up_team&lt;br /&gt;
    { success: true, message: &amp;quot;Signed up team successful!&amp;quot;, signed_up_team: signed_up_team, available_slots: signed_up_team.project_topic.available_slots }&lt;br /&gt;
  else&lt;br /&gt;
    { success: false, message: &amp;quot;Failed to sign up for topic. Topic may be full or already signed up.&amp;quot; }&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for dropping a topic&lt;br /&gt;
def self.drop_topic_for_student(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id)&lt;br /&gt;
  # ... (find topic, team, signed_up_team record) ...&lt;br /&gt;
  return { success: false, message: &amp;quot;Team is not signed up for this topic&amp;quot; } unless signed_up_team&lt;br /&gt;
&lt;br /&gt;
  # Delegate drop logic to ProjectTopic&lt;br /&gt;
  project_topic.drop_team(team)&lt;br /&gt;
&lt;br /&gt;
  { success: true, message: &amp;quot;Successfully dropped topic!&amp;quot;, available_slots: project_topic.available_slots }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to find and drop existing signups before signing up for a new one&lt;br /&gt;
private&lt;br /&gt;
def self.drop_existing_signups_for_team(team_id)&lt;br /&gt;
  existing_signups = where(team_id: team_id)&lt;br /&gt;
  existing_signups.each do |signup|&lt;br /&gt;
    signup.project_topic.drop_team(signup.team) # Use ProjectTopic's drop method&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Frontend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== AssignmentEditPage Component ====&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Topics_signup_page_for_students.png|800px|Topics_signup_page_for_students]]&lt;br /&gt;
|}&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Admin_topic_SelectionPage.png|800px|thumb|left|Caption]]&lt;br /&gt;
|}&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Admin_topic_edit.png|800px|caption]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Database Migrations ====&lt;br /&gt;
* Renamed `sign_up_topics` table to `project_topics`.&lt;br /&gt;
* Updated `signed_up_teams` table: renamed `sign_up_topic_id` foreign key to `project_topic_id` and updated index name.&lt;br /&gt;
* Added `allow_bookmarks` boolean column to `assignments` table.&lt;br /&gt;
* Renamed `teams_users` join table to `teams_participants`.&lt;br /&gt;
&lt;br /&gt;
==== Testing ====&lt;br /&gt;
&lt;br /&gt;
==== RSpec Tests (Backend) ====&lt;br /&gt;
* '''ProjectTopic Model (`project_topic_spec.rb`):''' Added extensive tests covering:&lt;br /&gt;
    * `sign_team_up`: Confirmed vs. waitlisted based on `max_choosers`, removal from other waitlists.&lt;br /&gt;
    * `drop_team`: Team removal, promotion of earliest waitlisted team.&lt;br /&gt;
    * `available_slots`, `slot_available?`: Correct calculations before/after signups/drops.&lt;br /&gt;
    * `confirmed_teams`, `waitlisted_teams`: Correct retrieval and ordering.&lt;br /&gt;
    * Validations: Presence of `topic_name`, non-negative `max_choosers` (including zero).&lt;br /&gt;
* '''SignedUpTeam Model (`signed_up_team_spec.rb`):''' Added tests covering:&lt;br /&gt;
    * Validations: Presence of topic/team, uniqueness scope.&lt;br /&gt;
    * Scopes: `:confirmed`, `:waitlisted`.&lt;br /&gt;
    * Class methods: Signup logic delegation, removal logic, participant/topic finding.&lt;br /&gt;
    * Waitlisting behavior when topic is full.&lt;br /&gt;
* '''Updates:''' Modified existing tests (e.g., `due_date_spec.rb`) to reference `ProjectTopic`.&lt;br /&gt;
&lt;br /&gt;
==== Manual Tests (UI) ====&lt;br /&gt;
* '''Instructor Flow:''' Verified assignment editing via `/assignments/edit/:id`, topic creation/editing/deletion/import via modals, toggling `allow_bookmarks`, dropping teams from topics.&lt;br /&gt;
* '''Student Flow:''' Verified topic viewing via `/student_tasks/:assignmentId`, selecting/deselecting topics (including automatic drop of previous), bookmarking (when enabled), correct display of slots and waitlists, disabled selection for full topics.&lt;br /&gt;
&lt;br /&gt;
=== Impact Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Summary of Changes ====&lt;br /&gt;
* '''Backend:''' Major refactoring of topic-related models and controllers, database schema changes, new API endpoints, updated dependencies. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily models, controllers, specs, migrations).&lt;br /&gt;
* '''Frontend:''' New assignment editing page with tabbed UI, new student task page for topic signup, reusable `TopicsTable` component, new routes. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily in `src/pages/Assignments`, `src/pages/StudentTasks`, `src/components`).&lt;br /&gt;
&lt;br /&gt;
==== Achievements ====&lt;br /&gt;
* ✓ Successfully refactored `SignUpTopic` to `ProjectTopic` for improved clarity.&lt;br /&gt;
* ✓ Centralized business logic in models, resulting in cleaner controllers.&lt;br /&gt;
* ✓ Implemented a modern, tabbed interface for assignment editing.&lt;br /&gt;
* ✓ Created a dedicated, streamlined UI for student topic signup.&lt;br /&gt;
* ✓ Added topic bookmarking functionality.&lt;br /&gt;
* ✓ Enhanced API endpoints for better data provision to the frontend.&lt;br /&gt;
* ✓ Updated key dependencies (Rails 8).&lt;br /&gt;
* ✓ Added comprehensive RSpec tests for new model logic.&lt;br /&gt;
&lt;br /&gt;
=== Future Work ===&lt;br /&gt;
* '''Frontend Bookmark Persistence:''' Implement API calls to save/load student topic bookmarks instead of using local state.&lt;br /&gt;
* '''Partner Ad Feature:''' Fully implement the &amp;quot;Apply to partner ad&amp;quot; functionality hinted at in `TopicsTab`.&lt;br /&gt;
* '''Complete Assignment Tabs:''' Implement the remaining tabs in `AssignmentEditPage` (Rubrics, Review Strategy, Due Dates, Etc.).&lt;br /&gt;
* '''Refine General Tab/AssignmentEditor:''' Decide whether general assignment settings remain in `AssignmentEditor` modal or move entirely to a &amp;quot;General&amp;quot; tab within `AssignmentEditPage`.&lt;br /&gt;
* '''Error Handling (Frontend):''' Enhance user feedback for API errors during topic operations (create/edit/delete/signup/drop).&lt;br /&gt;
* '''Authorization Checks:''' Ensure robust authorization checks are in place for all new/modified backend endpoints.&lt;br /&gt;
&lt;br /&gt;
=== Conclusion ===&lt;br /&gt;
This project successfully refactored the core topic management and signup system in Expertiza, replacing `SignUpTopic` with `ProjectTopic` and significantly improving the underlying logic by moving it into the models. New frontend interfaces provide a much-improved experience for both instructors managing topics and students signing up for them. The addition of features like topic bookmarking and a streamlined student signup flow enhances usability. The changes establish a more maintainable and understandable codebase for future development.&lt;br /&gt;
&lt;br /&gt;
=== References ===&lt;br /&gt;
# [https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
# [https://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
# [http://wikis.lib.ncsu.edu/index.php/Expertiza Expertiza project documentation wiki]&lt;br /&gt;
# ''(Add links to your specific project fork/PRs if needed)''&lt;br /&gt;
# [https://guides.rubyonrails.org/ Ruby on Rails Guides]&lt;br /&gt;
# [https://react.dev/ React Documentation]&lt;br /&gt;
# [https://relishapp.com/rspec Rspec Documentation]&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166915</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166915"/>
		<updated>2025-10-30T22:34:53Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* AssignmentEditPage Component */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== E 2552. Refactoring Topics and Enhancing Assignment Management ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
==== Background ====&lt;br /&gt;
Expertiza utilizes a system for instructors to define topics within assignments, allowing students (often in teams) to sign up for these topics. The previous implementation, centered around the `SignUpTopic` model and associated controllers (`SignUpTopicsController`, `SignedUpTeamsController`), lacked clarity in naming and had business logic distributed across controllers rather than encapsulated within models. Furthermore, the user interface for managing assignment topics by instructors and for students signing up for topics required modernization and improved functionality.&lt;br /&gt;
&lt;br /&gt;
==== Motivation ====&lt;br /&gt;
This project aimed to improve the maintainability, clarity, and functionality of the topic management and signup features within Expertiza. Key motivations included:&lt;br /&gt;
* Renaming core components (`SignUpTopic` -&amp;gt; `ProjectTopic`) to better reflect their purpose.&lt;br /&gt;
* Created RESTful API endpoints to manage topics and team signups.&lt;br /&gt;
* Creating a more intuitive and feature-rich interface for instructors managing assignment topics.&lt;br /&gt;
* Developing a dedicated and user-friendly interface for students to view, select, and manage their topic signups.&lt;br /&gt;
* Introducing features like bookmarking topics and streamlining the student signup/drop process.&lt;br /&gt;
* Updating dependencies to keep the application current.&lt;br /&gt;
&lt;br /&gt;
==== Tasks Accomplished ====&lt;br /&gt;
* Renamed `SignUpTopic` to `ProjectTopic` throughout the backend (models, controllers, routes, tests, database).&lt;br /&gt;
* Refactored `ProjectTopic` and `SignedUpTeam` models to encapsulate business logic (topic creation/update/deletion, team signup/waitlisting, slot management, student signup/drop).&lt;br /&gt;
* Removed `SignUpTopicsController` and implemented `ProjectTopicsController` using the refactored model logic.&lt;br /&gt;
* Refactored `SignedUpTeamsController` to utilize new model methods and added new actions (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
* Added `allow_bookmarks` attribute to the `Assignment` model and associated backend/frontend logic.&lt;br /&gt;
* Created a new frontend page (`AssignmentEditPage.tsx`) with a tabbed interface for instructors to manage assignments, including a dedicated &amp;quot;Topics&amp;quot; tab.&lt;br /&gt;
* Implemented modals for creating, editing, importing, and deleting topics on the frontend.&lt;br /&gt;
* Developed a reusable `TopicsTable.tsx` component for displaying topics in instructor and student views.&lt;br /&gt;
* Created a new frontend page (`StudentTasks.tsx`) for students to view assignment topics, bookmark (if enabled), and sign up/drop topics.&lt;br /&gt;
* Updated backend dependencies (Rails, Puma, Nokogiri, etc.) and Docker configuration.&lt;br /&gt;
* Added/updated RSpec tests for `ProjectTopic` and `SignedUpTeam` models and updated relevant existing tests.&lt;br /&gt;
* Updated Swagger API documentation.&lt;br /&gt;
&lt;br /&gt;
====Files Modified and Created====&lt;br /&gt;
&lt;br /&gt;
* **app/models/project_topic.rb**&lt;br /&gt;
* **app/models/signed_up_team.rb**&lt;br /&gt;
* **app/controllers/api/v1/project_topics_controller.rb**&lt;br /&gt;
* **app/controllers/api/v1/signed_up_teams_controller.rb**&lt;br /&gt;
* **app/serializers/project_topic_serializer.rb**&lt;br /&gt;
* **app/serializers/signed_up_team_serializer.rb**&lt;br /&gt;
* **spec/models/project_topic_spec.rb**&lt;br /&gt;
* **spec/models/signed_up_team_spec.rb**&lt;br /&gt;
* **spec/requests/project_topics_spec.rb**&lt;br /&gt;
* **spec/requests/signed_up_teams_spec.rb**&lt;br /&gt;
&lt;br /&gt;
=== Problem Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Issues with Previous Implementation ====&lt;br /&gt;
&lt;br /&gt;
==== Naming Convention ====&lt;br /&gt;
The name `SignUpTopic` was ambiguous. Renaming to `ProjectTopic` clarifies that these are topics related to the core project/assignment work students sign up for.&lt;br /&gt;
&lt;br /&gt;
==== Distributed Business Logic ====&lt;br /&gt;
Logic for creating topics, signing up teams, managing waitlists, and checking slots was spread across `SignUpTopicsController` and `SignedUpTeamsController`. This violated the principle of &amp;quot;fat model, skinny controller&amp;quot;, making the code harder to understand, test, and maintain.&lt;br /&gt;
&lt;br /&gt;
==== Inefficient Data Fetching ====&lt;br /&gt;
Frontend components often needed to make multiple API calls or perform calculations (like available slots) that could be handled more efficiently on the backend. The previous `SignUpTopic` API didn't provide computed data like assigned/waitlisted teams directly.&lt;br /&gt;
&lt;br /&gt;
==== Lack of Dedicated Student View ====&lt;br /&gt;
Students lacked a clear, dedicated interface to view available topics for an assignment and manage their selection. The signup process was not streamlined.&lt;br /&gt;
&lt;br /&gt;
==== Inconsistent Assignment Editing ====&lt;br /&gt;
The existing `AssignmentEditor` modal combined general settings with links to other management pages (like topics, participants) in an ad-hoc manner. A more structured approach was needed.&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== Architecture Decisions ===&lt;br /&gt;
* '''Model-Centric Logic:''' Shifted primary business logic for topic management and team signups into the `ProjectTopic` and `SignedUpTeam` models, respectively. Controllers now primarily handle request/response flow and delegate actions to the models.&lt;br /&gt;
* '''Dedicated Edit Page (Frontend):''' Created a new full page (`AssignmentEditPage`) for editing assignments instead of using a modal, allowing for a more complex, tabbed interface.&lt;br /&gt;
* '''Reusable Table Component (Frontend):''' Developed `TopicsTable` to handle the display and core interactions for topics in different contexts (instructor vs. student), promoting DRY principles.&lt;br /&gt;
* '''API Enhancements:''' Modified the `ProjectTopic` index endpoint (`/api/v1/project_topics`) to accept `assignment_id` and return topics with computed data (`to_json_with_computed_data`), reducing frontend calculation needs. Added specific endpoints for student signup (`sign_up_student`) and dropping topics (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
&lt;br /&gt;
==== Core Functionality Implemented ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Backend Changes !! Frontend Changes&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Renaming''' || Renamed `SignUpTopic` model, controller, routes, DB table to `ProjectTopic`. Updated associations. || Updated API endpoints used.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Management (Instructor)''' || `ProjectTopicsController` CRUD actions delegating to `ProjectTopic` model methods (`create_topic_with_assignment`, `update_topic`, `delete_by_assignment_and_topic_ids`). API returns computed data. || New `AssignmentEditPage` with `TopicsTab`. Uses `TopicsTable` (instructor mode). Modals for create, edit, import, delete. API calls for CRUD.&lt;br /&gt;
|-&lt;br /&gt;
| '''Team Signup Logic''' || `ProjectTopic` methods (`sign_team_up`, `drop_team`, `promote_waitlisted_team`). `SignedUpTeam` methods (`create_signed_up_team`, `remove_team_signups`). || Instructor view shows assigned/waitlisted teams in `TopicsTable` details. Drop team button calls backend.&lt;br /&gt;
|-&lt;br /&gt;
| '''Student Signup/Drop''' || `SignedUpTeamsController` actions (`sign_up_student`, `drop_topic`) delegating to `SignedUpTeam` model methods (`sign_up_student_for_topic`, `drop_topic_for_student`). Automatic handling of switching topics. || New `StudentTasks` page. Uses `TopicsTable` (student mode). Select/deselect buttons trigger API calls. Optimistic UI updates for slots. Displays current selection.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Bookmarking''' || Added `allow_bookmarks` boolean to `Assignment`. Added `project_topic_params` permit `allow_bookmarks` in `AssignmentsController`. || `AssignmentEditPage` allows instructors to toggle `allow_bookmarks` (persisted via PATCH). `StudentTasks` shows bookmark toggle if `allow_bookmarks` is true (local state for now).&lt;br /&gt;
|-&lt;br /&gt;
| '''Assignment Editing UI''' || N/A || New `AssignmentEditPage` with tabbed structure. `AssignmentEditor` might be simplified or removed for general settings.&lt;br /&gt;
|-&lt;br /&gt;
| '''Dependency Updates''' || Updated Ruby, Rails, Puma, Nokogiri etc. Added required gems. || N/A&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Key Backend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== ProjectTopic Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Handles team signup, considering available slots and waitlisting&lt;br /&gt;
# Renamed from signup_team for clarity&lt;br /&gt;
def sign_team_up(team)&lt;br /&gt;
  return false if signed_up_teams.exists?(team: team)&lt;br /&gt;
  ActiveRecord::Base.transaction do&lt;br /&gt;
    signed_up_team = signed_up_teams.create!(&lt;br /&gt;
      team: team,&lt;br /&gt;
      is_waitlisted: !slot_available?&lt;br /&gt;
    )&lt;br /&gt;
    # Remove team from other waitlists if confirmed here&lt;br /&gt;
    remove_from_waitlist(team) unless signed_up_team.is_waitlisted?&lt;br /&gt;
    true&lt;br /&gt;
  end&lt;br /&gt;
rescue ActiveRecord::RecordInvalid&lt;br /&gt;
  false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Handles dropping a team and promoting waitlisted if necessary&lt;br /&gt;
def drop_team(team)&lt;br /&gt;
  signed_up_team = signed_up_teams.find_by(team: team)&lt;br /&gt;
  return unless signed_up_team&lt;br /&gt;
  team_confirmed = !signed_up_team.is_waitlisted?&lt;br /&gt;
  signed_up_team.destroy!&lt;br /&gt;
  promote_waitlisted_team if team_confirmed # Promote only if a confirmed slot opened&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Calculates available slots&lt;br /&gt;
def available_slots&lt;br /&gt;
  max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Checks if slots are positive&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for creation, moved from controller&lt;br /&gt;
def self.create_topic_with_assignment(topic_params, assignment_id, micropayment = nil)&lt;br /&gt;
  # ... (find assignment, build topic, save, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for update, moved from controller&lt;br /&gt;
def update_topic(topic_params)&lt;br /&gt;
  # ... (update attributes, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Returns enhanced JSON including computed fields&lt;br /&gt;
def to_json_with_computed_data&lt;br /&gt;
  as_json.merge(&lt;br /&gt;
    available_slots: available_slots,&lt;br /&gt;
    confirmed_teams: confirmed_teams.map { |team| # ... format team data },&lt;br /&gt;
    waitlisted_teams: waitlisted_teams.map { |team| # ... format team data }&lt;br /&gt;
  )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
private&lt;br /&gt;
&lt;br /&gt;
# Helper for promotion logic&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
  # ... (find earliest waitlisted team, update is_waitlisted to false, remove from other waitlists)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to remove team from other topics' waitlists&lt;br /&gt;
def remove_from_waitlist(team)&lt;br /&gt;
  team.signed_up_teams.waitlisted.where.not(project_topic_id: id).destroy_all&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SignedUpTeam Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Scope for confirmed signups&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
# Scope for waitlisted signups&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&lt;br /&gt;
belongs_to :project_topic # Updated association&lt;br /&gt;
# ... validations ...&lt;br /&gt;
&lt;br /&gt;
# Business logic for student signup, including dropping previous topic&lt;br /&gt;
def self.sign_up_student_for_topic(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id) # Find student's team&lt;br /&gt;
  return { success: false, message: &amp;quot;User is not part of any team&amp;quot; } unless team_id&lt;br /&gt;
&lt;br /&gt;
  # Drop any existing topic signups for this team FIRST&lt;br /&gt;
  drop_existing_signups_for_team(team_id)&lt;br /&gt;
&lt;br /&gt;
  # Sign up for the new topic using create_signed_up_team (which calls topic.sign_team_up)&lt;br /&gt;
  signed_up_team = create_signed_up_team(topic_id, team_id)&lt;br /&gt;
&lt;br /&gt;
  if signed_up_team&lt;br /&gt;
    { success: true, message: &amp;quot;Signed up team successful!&amp;quot;, signed_up_team: signed_up_team, available_slots: signed_up_team.project_topic.available_slots }&lt;br /&gt;
  else&lt;br /&gt;
    { success: false, message: &amp;quot;Failed to sign up for topic. Topic may be full or already signed up.&amp;quot; }&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for dropping a topic&lt;br /&gt;
def self.drop_topic_for_student(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id)&lt;br /&gt;
  # ... (find topic, team, signed_up_team record) ...&lt;br /&gt;
  return { success: false, message: &amp;quot;Team is not signed up for this topic&amp;quot; } unless signed_up_team&lt;br /&gt;
&lt;br /&gt;
  # Delegate drop logic to ProjectTopic&lt;br /&gt;
  project_topic.drop_team(team)&lt;br /&gt;
&lt;br /&gt;
  { success: true, message: &amp;quot;Successfully dropped topic!&amp;quot;, available_slots: project_topic.available_slots }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to find and drop existing signups before signing up for a new one&lt;br /&gt;
private&lt;br /&gt;
def self.drop_existing_signups_for_team(team_id)&lt;br /&gt;
  existing_signups = where(team_id: team_id)&lt;br /&gt;
  existing_signups.each do |signup|&lt;br /&gt;
    signup.project_topic.drop_team(signup.team) # Use ProjectTopic's drop method&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Frontend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== AssignmentEditPage Component ====&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Topics_signup_page_for_students.png|800px|Topics_signup_page_for_students]]&lt;br /&gt;
|}&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Admin_topic_SelectionPage.png|800px|thumb|left|Caption]]&lt;br /&gt;
|}&lt;br /&gt;
{| style=&amp;quot;border: none; margin: 0 auto; text-align: center;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Admin_topic_edit.png|800px|caption]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== StudentTasks Component ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
// Page for students to sign up for topics&lt;br /&gt;
const StudentTasks: React.FC = () =&amp;gt; {&lt;br /&gt;
  // ... hooks for fetching (assignments, topics), signing up, dropping ...&lt;br /&gt;
  // ... state for bookmarks, selectedTopic, loading states, optimistic updates ...&lt;br /&gt;
&lt;br /&gt;
  // Fetch assignment and then topics&lt;br /&gt;
  useEffect(() =&amp;gt; { /* ... fetch assignment data ... */ }, [/* dependencies */]);&lt;br /&gt;
  useEffect(() =&amp;gt; { /* ... fetch topics based on assignment id ... */ }, [/* dependencies */]);&lt;br /&gt;
&lt;br /&gt;
  // Process topics data, applying optimistic updates&lt;br /&gt;
  const topics = useMemo(() =&amp;gt; {&lt;br /&gt;
    // ... map topicsResponse.data, check optimisticSlotChanges map ...&lt;br /&gt;
  }, [/* dependencies */]);&lt;br /&gt;
&lt;br /&gt;
  // Check if bookmarks allowed&lt;br /&gt;
  const allowBookmarks = useMemo(() =&amp;gt; {&lt;br /&gt;
     // ... check assignmentResponse.data.allow_bookmarks ...&lt;br /&gt;
  }, [assignmentResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Handle selecting/deselecting a topic&lt;br /&gt;
  const handleTopicSelect = useCallback(async (topicId: string) =&amp;gt; {&lt;br /&gt;
    if (selectedTopic === topicId) { // Deselecting&lt;br /&gt;
      // Optimistically update slots (+1)&lt;br /&gt;
      // Set selectedTopic to null&lt;br /&gt;
      // Call dropAPI&lt;br /&gt;
    } else { // Selecting a new topic&lt;br /&gt;
      // Optimistically update slots (-1 for new, +1 for old if exists)&lt;br /&gt;
      // Call dropAPI for old topic if selectedTopic is not null&lt;br /&gt;
      // Set selectedTopic to topicId&lt;br /&gt;
      // Call signUpAPI&lt;br /&gt;
    }&lt;br /&gt;
  }, [/* dependencies: selectedTopic, currentUser, dropAPI, signUpAPI, topics */]);&lt;br /&gt;
&lt;br /&gt;
  // Handle bookmark toggle (local state)&lt;br /&gt;
  const handleBookmarkToggle = useCallback((topicId: string) =&amp;gt; { /* ... update bookmarkedTopics set ... */ }, []);&lt;br /&gt;
&lt;br /&gt;
  // Prepare data for TopicsTable&lt;br /&gt;
  const topicRows: TopicRow[] = useMemo(() =&amp;gt; topics.map(t =&amp;gt; ({ /* ... map topic data ... */ })), [topics]);&lt;br /&gt;
&lt;br /&gt;
  // ... return JSX ...&lt;br /&gt;
  return (&lt;br /&gt;
    &amp;lt;Container&amp;gt;&lt;br /&gt;
      {/* ... Title, Current Selection display ... */}&lt;br /&gt;
      {topicsLoading ? &amp;lt;Spinner /&amp;gt; : topicsError ? &amp;lt;Alert variant=&amp;quot;danger&amp;quot;&amp;gt;{topicsError}&amp;lt;/Alert&amp;gt; : (&lt;br /&gt;
        &amp;lt;TopicsTable&lt;br /&gt;
          data={topicRows}&lt;br /&gt;
          mode=&amp;quot;student&amp;quot;&lt;br /&gt;
          onBookmarkToggle={handleBookmarkToggle}&lt;br /&gt;
          onSelectTopic={handleTopicSelect}&lt;br /&gt;
          isSigningUp={isSigningUp}&lt;br /&gt;
          selectedTopicId={selectedTopic}&lt;br /&gt;
          showBookmarks={allowBookmarks}&lt;br /&gt;
          // ... other props ...&lt;br /&gt;
        /&amp;gt;&lt;br /&gt;
      )}&lt;br /&gt;
    &amp;lt;/Container&amp;gt;&lt;br /&gt;
  );&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Database Migrations ====&lt;br /&gt;
* Renamed `sign_up_topics` table to `project_topics`.&lt;br /&gt;
* Updated `signed_up_teams` table: renamed `sign_up_topic_id` foreign key to `project_topic_id` and updated index name.&lt;br /&gt;
* Added `allow_bookmarks` boolean column to `assignments` table.&lt;br /&gt;
* Renamed `teams_users` join table to `teams_participants`.&lt;br /&gt;
&lt;br /&gt;
==== Testing ====&lt;br /&gt;
&lt;br /&gt;
==== RSpec Tests (Backend) ====&lt;br /&gt;
* '''ProjectTopic Model (`project_topic_spec.rb`):''' Added extensive tests covering:&lt;br /&gt;
    * `sign_team_up`: Confirmed vs. waitlisted based on `max_choosers`, removal from other waitlists.&lt;br /&gt;
    * `drop_team`: Team removal, promotion of earliest waitlisted team.&lt;br /&gt;
    * `available_slots`, `slot_available?`: Correct calculations before/after signups/drops.&lt;br /&gt;
    * `confirmed_teams`, `waitlisted_teams`: Correct retrieval and ordering.&lt;br /&gt;
    * Validations: Presence of `topic_name`, non-negative `max_choosers` (including zero).&lt;br /&gt;
* '''SignedUpTeam Model (`signed_up_team_spec.rb`):''' Added tests covering:&lt;br /&gt;
    * Validations: Presence of topic/team, uniqueness scope.&lt;br /&gt;
    * Scopes: `:confirmed`, `:waitlisted`.&lt;br /&gt;
    * Class methods: Signup logic delegation, removal logic, participant/topic finding.&lt;br /&gt;
    * Waitlisting behavior when topic is full.&lt;br /&gt;
* '''Updates:''' Modified existing tests (e.g., `due_date_spec.rb`) to reference `ProjectTopic`.&lt;br /&gt;
&lt;br /&gt;
==== Manual Tests (UI) ====&lt;br /&gt;
* '''Instructor Flow:''' Verified assignment editing via `/assignments/edit/:id`, topic creation/editing/deletion/import via modals, toggling `allow_bookmarks`, dropping teams from topics.&lt;br /&gt;
* '''Student Flow:''' Verified topic viewing via `/student_tasks/:assignmentId`, selecting/deselecting topics (including automatic drop of previous), bookmarking (when enabled), correct display of slots and waitlists, disabled selection for full topics.&lt;br /&gt;
&lt;br /&gt;
=== Impact Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Summary of Changes ====&lt;br /&gt;
* '''Backend:''' Major refactoring of topic-related models and controllers, database schema changes, new API endpoints, updated dependencies. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily models, controllers, specs, migrations).&lt;br /&gt;
* '''Frontend:''' New assignment editing page with tabbed UI, new student task page for topic signup, reusable `TopicsTable` component, new routes. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily in `src/pages/Assignments`, `src/pages/StudentTasks`, `src/components`).&lt;br /&gt;
&lt;br /&gt;
==== Achievements ====&lt;br /&gt;
* ✓ Successfully refactored `SignUpTopic` to `ProjectTopic` for improved clarity.&lt;br /&gt;
* ✓ Centralized business logic in models, resulting in cleaner controllers.&lt;br /&gt;
* ✓ Implemented a modern, tabbed interface for assignment editing.&lt;br /&gt;
* ✓ Created a dedicated, streamlined UI for student topic signup.&lt;br /&gt;
* ✓ Added topic bookmarking functionality.&lt;br /&gt;
* ✓ Enhanced API endpoints for better data provision to the frontend.&lt;br /&gt;
* ✓ Updated key dependencies (Rails 8).&lt;br /&gt;
* ✓ Added comprehensive RSpec tests for new model logic.&lt;br /&gt;
&lt;br /&gt;
=== Future Work ===&lt;br /&gt;
* '''Frontend Bookmark Persistence:''' Implement API calls to save/load student topic bookmarks instead of using local state.&lt;br /&gt;
* '''Partner Ad Feature:''' Fully implement the &amp;quot;Apply to partner ad&amp;quot; functionality hinted at in `TopicsTab`.&lt;br /&gt;
* '''Complete Assignment Tabs:''' Implement the remaining tabs in `AssignmentEditPage` (Rubrics, Review Strategy, Due Dates, Etc.).&lt;br /&gt;
* '''Refine General Tab/AssignmentEditor:''' Decide whether general assignment settings remain in `AssignmentEditor` modal or move entirely to a &amp;quot;General&amp;quot; tab within `AssignmentEditPage`.&lt;br /&gt;
* '''Error Handling (Frontend):''' Enhance user feedback for API errors during topic operations (create/edit/delete/signup/drop).&lt;br /&gt;
* '''Authorization Checks:''' Ensure robust authorization checks are in place for all new/modified backend endpoints.&lt;br /&gt;
&lt;br /&gt;
=== Conclusion ===&lt;br /&gt;
This project successfully refactored the core topic management and signup system in Expertiza, replacing `SignUpTopic` with `ProjectTopic` and significantly improving the underlying logic by moving it into the models. New frontend interfaces provide a much-improved experience for both instructors managing topics and students signing up for them. The addition of features like topic bookmarking and a streamlined student signup flow enhances usability. The changes establish a more maintainable and understandable codebase for future development.&lt;br /&gt;
&lt;br /&gt;
=== References ===&lt;br /&gt;
# [https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
# [https://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
# [http://wikis.lib.ncsu.edu/index.php/Expertiza Expertiza project documentation wiki]&lt;br /&gt;
# ''(Add links to your specific project fork/PRs if needed)''&lt;br /&gt;
# [https://guides.rubyonrails.org/ Ruby on Rails Guides]&lt;br /&gt;
# [https://react.dev/ React Documentation]&lt;br /&gt;
# [https://relishapp.com/rspec Rspec Documentation]&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Admin_topic_edit.png&amp;diff=166914</id>
		<title>File:Admin topic edit.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Admin_topic_edit.png&amp;diff=166914"/>
		<updated>2025-10-30T22:24:42Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Admin_topic_SelectionPage.png&amp;diff=166913</id>
		<title>File:Admin topic SelectionPage.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Admin_topic_SelectionPage.png&amp;diff=166913"/>
		<updated>2025-10-30T22:23:10Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Topics_signup_page_for_students.png&amp;diff=166912</id>
		<title>File:Topics signup page for students.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Topics_signup_page_for_students.png&amp;diff=166912"/>
		<updated>2025-10-30T22:19:50Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166840</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166840"/>
		<updated>2025-10-29T01:17:48Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== E 2552. Refactoring Topics and Enhancing Assignment Management ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
==== Background ====&lt;br /&gt;
Expertiza utilizes a system for instructors to define topics within assignments, allowing students (often in teams) to sign up for these topics. The previous implementation, centered around the `SignUpTopic` model and associated controllers (`SignUpTopicsController`, `SignedUpTeamsController`), lacked clarity in naming and had business logic distributed across controllers rather than encapsulated within models. Furthermore, the user interface for managing assignment topics by instructors and for students signing up for topics required modernization and improved functionality.&lt;br /&gt;
&lt;br /&gt;
==== Motivation ====&lt;br /&gt;
This project aimed to improve the maintainability, clarity, and functionality of the topic management and signup features within Expertiza. Key motivations included:&lt;br /&gt;
* Renaming core components (`SignUpTopic` -&amp;gt; `ProjectTopic`) to better reflect their purpose.&lt;br /&gt;
* Created RESTful API endpoints to manage topics and team signups.&lt;br /&gt;
* Creating a more intuitive and feature-rich interface for instructors managing assignment topics.&lt;br /&gt;
* Developing a dedicated and user-friendly interface for students to view, select, and manage their topic signups.&lt;br /&gt;
* Introducing features like bookmarking topics and streamlining the student signup/drop process.&lt;br /&gt;
* Updating dependencies to keep the application current.&lt;br /&gt;
&lt;br /&gt;
==== Tasks Accomplished ====&lt;br /&gt;
* Renamed `SignUpTopic` to `ProjectTopic` throughout the backend (models, controllers, routes, tests, database).&lt;br /&gt;
* Refactored `ProjectTopic` and `SignedUpTeam` models to encapsulate business logic (topic creation/update/deletion, team signup/waitlisting, slot management, student signup/drop).&lt;br /&gt;
* Removed `SignUpTopicsController` and implemented `ProjectTopicsController` using the refactored model logic.&lt;br /&gt;
* Refactored `SignedUpTeamsController` to utilize new model methods and added new actions (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
* Added `allow_bookmarks` attribute to the `Assignment` model and associated backend/frontend logic.&lt;br /&gt;
* Created a new frontend page (`AssignmentEditPage.tsx`) with a tabbed interface for instructors to manage assignments, including a dedicated &amp;quot;Topics&amp;quot; tab.&lt;br /&gt;
* Implemented modals for creating, editing, importing, and deleting topics on the frontend.&lt;br /&gt;
* Developed a reusable `TopicsTable.tsx` component for displaying topics in instructor and student views.&lt;br /&gt;
* Created a new frontend page (`StudentTasks.tsx`) for students to view assignment topics, bookmark (if enabled), and sign up/drop topics.&lt;br /&gt;
* Updated backend dependencies (Rails, Puma, Nokogiri, etc.) and Docker configuration.&lt;br /&gt;
* Added/updated RSpec tests for `ProjectTopic` and `SignedUpTeam` models and updated relevant existing tests.&lt;br /&gt;
* Updated Swagger API documentation.&lt;br /&gt;
&lt;br /&gt;
====Files Modified and Created====&lt;br /&gt;
&lt;br /&gt;
* **app/models/project_topic.rb**&lt;br /&gt;
* **app/models/signed_up_team.rb**&lt;br /&gt;
* **app/controllers/api/v1/project_topics_controller.rb**&lt;br /&gt;
* **app/controllers/api/v1/signed_up_teams_controller.rb**&lt;br /&gt;
* **app/serializers/project_topic_serializer.rb**&lt;br /&gt;
* **app/serializers/signed_up_team_serializer.rb**&lt;br /&gt;
* **spec/models/project_topic_spec.rb**&lt;br /&gt;
* **spec/models/signed_up_team_spec.rb**&lt;br /&gt;
* **spec/requests/project_topics_spec.rb**&lt;br /&gt;
* **spec/requests/signed_up_teams_spec.rb**&lt;br /&gt;
&lt;br /&gt;
=== Problem Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Issues with Previous Implementation ====&lt;br /&gt;
&lt;br /&gt;
==== Naming Convention ====&lt;br /&gt;
The name `SignUpTopic` was ambiguous. Renaming to `ProjectTopic` clarifies that these are topics related to the core project/assignment work students sign up for.&lt;br /&gt;
&lt;br /&gt;
==== Distributed Business Logic ====&lt;br /&gt;
Logic for creating topics, signing up teams, managing waitlists, and checking slots was spread across `SignUpTopicsController` and `SignedUpTeamsController`. This violated the principle of &amp;quot;fat model, skinny controller&amp;quot;, making the code harder to understand, test, and maintain.&lt;br /&gt;
&lt;br /&gt;
==== Inefficient Data Fetching ====&lt;br /&gt;
Frontend components often needed to make multiple API calls or perform calculations (like available slots) that could be handled more efficiently on the backend. The previous `SignUpTopic` API didn't provide computed data like assigned/waitlisted teams directly.&lt;br /&gt;
&lt;br /&gt;
==== Lack of Dedicated Student View ====&lt;br /&gt;
Students lacked a clear, dedicated interface to view available topics for an assignment and manage their selection. The signup process was not streamlined.&lt;br /&gt;
&lt;br /&gt;
==== Inconsistent Assignment Editing ====&lt;br /&gt;
The existing `AssignmentEditor` modal combined general settings with links to other management pages (like topics, participants) in an ad-hoc manner. A more structured approach was needed.&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== Architecture Decisions ===&lt;br /&gt;
* '''Model-Centric Logic:''' Shifted primary business logic for topic management and team signups into the `ProjectTopic` and `SignedUpTeam` models, respectively. Controllers now primarily handle request/response flow and delegate actions to the models.&lt;br /&gt;
* '''Dedicated Edit Page (Frontend):''' Created a new full page (`AssignmentEditPage`) for editing assignments instead of using a modal, allowing for a more complex, tabbed interface.&lt;br /&gt;
* '''Reusable Table Component (Frontend):''' Developed `TopicsTable` to handle the display and core interactions for topics in different contexts (instructor vs. student), promoting DRY principles.&lt;br /&gt;
* '''API Enhancements:''' Modified the `ProjectTopic` index endpoint (`/api/v1/project_topics`) to accept `assignment_id` and return topics with computed data (`to_json_with_computed_data`), reducing frontend calculation needs. Added specific endpoints for student signup (`sign_up_student`) and dropping topics (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
&lt;br /&gt;
==== Core Functionality Implemented ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Backend Changes !! Frontend Changes&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Renaming''' || Renamed `SignUpTopic` model, controller, routes, DB table to `ProjectTopic`. Updated associations. || Updated API endpoints used.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Management (Instructor)''' || `ProjectTopicsController` CRUD actions delegating to `ProjectTopic` model methods (`create_topic_with_assignment`, `update_topic`, `delete_by_assignment_and_topic_ids`). API returns computed data. || New `AssignmentEditPage` with `TopicsTab`. Uses `TopicsTable` (instructor mode). Modals for create, edit, import, delete. API calls for CRUD.&lt;br /&gt;
|-&lt;br /&gt;
| '''Team Signup Logic''' || `ProjectTopic` methods (`sign_team_up`, `drop_team`, `promote_waitlisted_team`). `SignedUpTeam` methods (`create_signed_up_team`, `remove_team_signups`). || Instructor view shows assigned/waitlisted teams in `TopicsTable` details. Drop team button calls backend.&lt;br /&gt;
|-&lt;br /&gt;
| '''Student Signup/Drop''' || `SignedUpTeamsController` actions (`sign_up_student`, `drop_topic`) delegating to `SignedUpTeam` model methods (`sign_up_student_for_topic`, `drop_topic_for_student`). Automatic handling of switching topics. || New `StudentTasks` page. Uses `TopicsTable` (student mode). Select/deselect buttons trigger API calls. Optimistic UI updates for slots. Displays current selection.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Bookmarking''' || Added `allow_bookmarks` boolean to `Assignment`. Added `project_topic_params` permit `allow_bookmarks` in `AssignmentsController`. || `AssignmentEditPage` allows instructors to toggle `allow_bookmarks` (persisted via PATCH). `StudentTasks` shows bookmark toggle if `allow_bookmarks` is true (local state for now).&lt;br /&gt;
|-&lt;br /&gt;
| '''Assignment Editing UI''' || N/A || New `AssignmentEditPage` with tabbed structure. `AssignmentEditor` might be simplified or removed for general settings.&lt;br /&gt;
|-&lt;br /&gt;
| '''Dependency Updates''' || Updated Ruby, Rails, Puma, Nokogiri etc. Added required gems. || N/A&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Key Backend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== ProjectTopic Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Handles team signup, considering available slots and waitlisting&lt;br /&gt;
# Renamed from signup_team for clarity&lt;br /&gt;
def sign_team_up(team)&lt;br /&gt;
  return false if signed_up_teams.exists?(team: team)&lt;br /&gt;
  ActiveRecord::Base.transaction do&lt;br /&gt;
    signed_up_team = signed_up_teams.create!(&lt;br /&gt;
      team: team,&lt;br /&gt;
      is_waitlisted: !slot_available?&lt;br /&gt;
    )&lt;br /&gt;
    # Remove team from other waitlists if confirmed here&lt;br /&gt;
    remove_from_waitlist(team) unless signed_up_team.is_waitlisted?&lt;br /&gt;
    true&lt;br /&gt;
  end&lt;br /&gt;
rescue ActiveRecord::RecordInvalid&lt;br /&gt;
  false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Handles dropping a team and promoting waitlisted if necessary&lt;br /&gt;
def drop_team(team)&lt;br /&gt;
  signed_up_team = signed_up_teams.find_by(team: team)&lt;br /&gt;
  return unless signed_up_team&lt;br /&gt;
  team_confirmed = !signed_up_team.is_waitlisted?&lt;br /&gt;
  signed_up_team.destroy!&lt;br /&gt;
  promote_waitlisted_team if team_confirmed # Promote only if a confirmed slot opened&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Calculates available slots&lt;br /&gt;
def available_slots&lt;br /&gt;
  max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Checks if slots are positive&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for creation, moved from controller&lt;br /&gt;
def self.create_topic_with_assignment(topic_params, assignment_id, micropayment = nil)&lt;br /&gt;
  # ... (find assignment, build topic, save, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for update, moved from controller&lt;br /&gt;
def update_topic(topic_params)&lt;br /&gt;
  # ... (update attributes, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Returns enhanced JSON including computed fields&lt;br /&gt;
def to_json_with_computed_data&lt;br /&gt;
  as_json.merge(&lt;br /&gt;
    available_slots: available_slots,&lt;br /&gt;
    confirmed_teams: confirmed_teams.map { |team| # ... format team data },&lt;br /&gt;
    waitlisted_teams: waitlisted_teams.map { |team| # ... format team data }&lt;br /&gt;
  )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
private&lt;br /&gt;
&lt;br /&gt;
# Helper for promotion logic&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
  # ... (find earliest waitlisted team, update is_waitlisted to false, remove from other waitlists)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to remove team from other topics' waitlists&lt;br /&gt;
def remove_from_waitlist(team)&lt;br /&gt;
  team.signed_up_teams.waitlisted.where.not(project_topic_id: id).destroy_all&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SignedUpTeam Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Scope for confirmed signups&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
# Scope for waitlisted signups&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&lt;br /&gt;
belongs_to :project_topic # Updated association&lt;br /&gt;
# ... validations ...&lt;br /&gt;
&lt;br /&gt;
# Business logic for student signup, including dropping previous topic&lt;br /&gt;
def self.sign_up_student_for_topic(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id) # Find student's team&lt;br /&gt;
  return { success: false, message: &amp;quot;User is not part of any team&amp;quot; } unless team_id&lt;br /&gt;
&lt;br /&gt;
  # Drop any existing topic signups for this team FIRST&lt;br /&gt;
  drop_existing_signups_for_team(team_id)&lt;br /&gt;
&lt;br /&gt;
  # Sign up for the new topic using create_signed_up_team (which calls topic.sign_team_up)&lt;br /&gt;
  signed_up_team = create_signed_up_team(topic_id, team_id)&lt;br /&gt;
&lt;br /&gt;
  if signed_up_team&lt;br /&gt;
    { success: true, message: &amp;quot;Signed up team successful!&amp;quot;, signed_up_team: signed_up_team, available_slots: signed_up_team.project_topic.available_slots }&lt;br /&gt;
  else&lt;br /&gt;
    { success: false, message: &amp;quot;Failed to sign up for topic. Topic may be full or already signed up.&amp;quot; }&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for dropping a topic&lt;br /&gt;
def self.drop_topic_for_student(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id)&lt;br /&gt;
  # ... (find topic, team, signed_up_team record) ...&lt;br /&gt;
  return { success: false, message: &amp;quot;Team is not signed up for this topic&amp;quot; } unless signed_up_team&lt;br /&gt;
&lt;br /&gt;
  # Delegate drop logic to ProjectTopic&lt;br /&gt;
  project_topic.drop_team(team)&lt;br /&gt;
&lt;br /&gt;
  { success: true, message: &amp;quot;Successfully dropped topic!&amp;quot;, available_slots: project_topic.available_slots }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to find and drop existing signups before signing up for a new one&lt;br /&gt;
private&lt;br /&gt;
def self.drop_existing_signups_for_team(team_id)&lt;br /&gt;
  existing_signups = where(team_id: team_id)&lt;br /&gt;
  existing_signups.each do |signup|&lt;br /&gt;
    signup.project_topic.drop_team(signup.team) # Use ProjectTopic's drop method&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Frontend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== AssignmentEditPage Component ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
// Manages overall state for assignment editing&lt;br /&gt;
const AssignmentEditPage = () =&amp;gt; {&lt;br /&gt;
  // ... hooks for fetching data (assignment, topics), state for active tab, topic settings, topics data ...&lt;br /&gt;
&lt;br /&gt;
  // Fetch assignment details on load&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (id) fetchAssignment({ url: `/assignments/${id}` });&lt;br /&gt;
  }, [id, fetchAssignment]);&lt;br /&gt;
&lt;br /&gt;
  // Update local state when assignment data is loaded (e.g., name, allow_bookmarks)&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (assignmentResponse?.data) {&lt;br /&gt;
      setAssignmentName(assignmentResponse.data.name || &amp;quot;&amp;quot;);&lt;br /&gt;
      setTopicSettings(prev =&amp;gt; ({ ...prev, allowBookmarks: assignmentResponse.data.allow_bookmarks }));&lt;br /&gt;
    }&lt;br /&gt;
  }, [assignmentResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Fetch topics when assignment ID is known&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (id) fetchTopics({ url: `/project_topics?assignment_id=${id}` });&lt;br /&gt;
  }, [id, fetchTopics]);&lt;br /&gt;
&lt;br /&gt;
  // Process fetched topics into format needed by TopicsTable&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
     if (topicsResponse?.data) {&lt;br /&gt;
       // ... transform backend topic structure to frontend TopicData structure ...&lt;br /&gt;
       setTopicsData(transformedTopics);&lt;br /&gt;
     }&lt;br /&gt;
  }, [topicsResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Handler for topic setting changes (e.g., checkboxes)&lt;br /&gt;
  const handleTopicSettingChange = useCallback((setting: string, value: boolean) =&amp;gt; {&lt;br /&gt;
    setTopicSettings((prev) =&amp;gt; ({ ...prev, [setting]: value }));&lt;br /&gt;
    // Persist allowBookmarks change immediately&lt;br /&gt;
    if (setting === 'allowBookmarks' &amp;amp;&amp;amp; id) {&lt;br /&gt;
      updateAssignment({ /* ... PATCH request data ... */ });&lt;br /&gt;
    }&lt;br /&gt;
  }, [id, updateAssignment]);&lt;br /&gt;
&lt;br /&gt;
  // Handlers for topic CRUD operations (passed down to TopicsTab)&lt;br /&gt;
  const handleDeleteTopic = useCallback((topicId: string) =&amp;gt; {&lt;br /&gt;
    // ... call deleteTopic API ...&lt;br /&gt;
  }, [id, deleteTopic]);&lt;br /&gt;
  // ... other handlers (create, edit, drop team) ...&lt;br /&gt;
&lt;br /&gt;
  // Renders the content based on the active tab state&lt;br /&gt;
  const renderTabContent = () =&amp;gt; {&lt;br /&gt;
    switch (activeTab) {&lt;br /&gt;
      case &amp;quot;topics&amp;quot;:&lt;br /&gt;
        return &amp;lt;TopicsTab /* pass props: settings, data, handlers */ /&amp;gt;;&lt;br /&gt;
      // ... other cases for RubricsTab, DueDatesTab etc. ...&lt;br /&gt;
    }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  return (&lt;br /&gt;
    // ... JSX for layout, tab buttons, calling renderTabContent ...&lt;br /&gt;
  );&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== StudentTasks Component ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
// Page for students to sign up for topics&lt;br /&gt;
const StudentTasks: React.FC = () =&amp;gt; {&lt;br /&gt;
  // ... hooks for fetching (assignments, topics), signing up, dropping ...&lt;br /&gt;
  // ... state for bookmarks, selectedTopic, loading states, optimistic updates ...&lt;br /&gt;
&lt;br /&gt;
  // Fetch assignment and then topics&lt;br /&gt;
  useEffect(() =&amp;gt; { /* ... fetch assignment data ... */ }, [/* dependencies */]);&lt;br /&gt;
  useEffect(() =&amp;gt; { /* ... fetch topics based on assignment id ... */ }, [/* dependencies */]);&lt;br /&gt;
&lt;br /&gt;
  // Process topics data, applying optimistic updates&lt;br /&gt;
  const topics = useMemo(() =&amp;gt; {&lt;br /&gt;
    // ... map topicsResponse.data, check optimisticSlotChanges map ...&lt;br /&gt;
  }, [/* dependencies */]);&lt;br /&gt;
&lt;br /&gt;
  // Check if bookmarks allowed&lt;br /&gt;
  const allowBookmarks = useMemo(() =&amp;gt; {&lt;br /&gt;
     // ... check assignmentResponse.data.allow_bookmarks ...&lt;br /&gt;
  }, [assignmentResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Handle selecting/deselecting a topic&lt;br /&gt;
  const handleTopicSelect = useCallback(async (topicId: string) =&amp;gt; {&lt;br /&gt;
    if (selectedTopic === topicId) { // Deselecting&lt;br /&gt;
      // Optimistically update slots (+1)&lt;br /&gt;
      // Set selectedTopic to null&lt;br /&gt;
      // Call dropAPI&lt;br /&gt;
    } else { // Selecting a new topic&lt;br /&gt;
      // Optimistically update slots (-1 for new, +1 for old if exists)&lt;br /&gt;
      // Call dropAPI for old topic if selectedTopic is not null&lt;br /&gt;
      // Set selectedTopic to topicId&lt;br /&gt;
      // Call signUpAPI&lt;br /&gt;
    }&lt;br /&gt;
  }, [/* dependencies: selectedTopic, currentUser, dropAPI, signUpAPI, topics */]);&lt;br /&gt;
&lt;br /&gt;
  // Handle bookmark toggle (local state)&lt;br /&gt;
  const handleBookmarkToggle = useCallback((topicId: string) =&amp;gt; { /* ... update bookmarkedTopics set ... */ }, []);&lt;br /&gt;
&lt;br /&gt;
  // Prepare data for TopicsTable&lt;br /&gt;
  const topicRows: TopicRow[] = useMemo(() =&amp;gt; topics.map(t =&amp;gt; ({ /* ... map topic data ... */ })), [topics]);&lt;br /&gt;
&lt;br /&gt;
  // ... return JSX ...&lt;br /&gt;
  return (&lt;br /&gt;
    &amp;lt;Container&amp;gt;&lt;br /&gt;
      {/* ... Title, Current Selection display ... */}&lt;br /&gt;
      {topicsLoading ? &amp;lt;Spinner /&amp;gt; : topicsError ? &amp;lt;Alert variant=&amp;quot;danger&amp;quot;&amp;gt;{topicsError}&amp;lt;/Alert&amp;gt; : (&lt;br /&gt;
        &amp;lt;TopicsTable&lt;br /&gt;
          data={topicRows}&lt;br /&gt;
          mode=&amp;quot;student&amp;quot;&lt;br /&gt;
          onBookmarkToggle={handleBookmarkToggle}&lt;br /&gt;
          onSelectTopic={handleTopicSelect}&lt;br /&gt;
          isSigningUp={isSigningUp}&lt;br /&gt;
          selectedTopicId={selectedTopic}&lt;br /&gt;
          showBookmarks={allowBookmarks}&lt;br /&gt;
          // ... other props ...&lt;br /&gt;
        /&amp;gt;&lt;br /&gt;
      )}&lt;br /&gt;
    &amp;lt;/Container&amp;gt;&lt;br /&gt;
  );&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Database Migrations ====&lt;br /&gt;
* Renamed `sign_up_topics` table to `project_topics`.&lt;br /&gt;
* Updated `signed_up_teams` table: renamed `sign_up_topic_id` foreign key to `project_topic_id` and updated index name.&lt;br /&gt;
* Added `allow_bookmarks` boolean column to `assignments` table.&lt;br /&gt;
* Renamed `teams_users` join table to `teams_participants`.&lt;br /&gt;
&lt;br /&gt;
==== Testing ====&lt;br /&gt;
&lt;br /&gt;
==== RSpec Tests (Backend) ====&lt;br /&gt;
* '''ProjectTopic Model (`project_topic_spec.rb`):''' Added extensive tests covering:&lt;br /&gt;
    * `sign_team_up`: Confirmed vs. waitlisted based on `max_choosers`, removal from other waitlists.&lt;br /&gt;
    * `drop_team`: Team removal, promotion of earliest waitlisted team.&lt;br /&gt;
    * `available_slots`, `slot_available?`: Correct calculations before/after signups/drops.&lt;br /&gt;
    * `confirmed_teams`, `waitlisted_teams`: Correct retrieval and ordering.&lt;br /&gt;
    * Validations: Presence of `topic_name`, non-negative `max_choosers` (including zero).&lt;br /&gt;
* '''SignedUpTeam Model (`signed_up_team_spec.rb`):''' Added tests covering:&lt;br /&gt;
    * Validations: Presence of topic/team, uniqueness scope.&lt;br /&gt;
    * Scopes: `:confirmed`, `:waitlisted`.&lt;br /&gt;
    * Class methods: Signup logic delegation, removal logic, participant/topic finding.&lt;br /&gt;
    * Waitlisting behavior when topic is full.&lt;br /&gt;
* '''Updates:''' Modified existing tests (e.g., `due_date_spec.rb`) to reference `ProjectTopic`.&lt;br /&gt;
&lt;br /&gt;
==== Manual Tests (UI) ====&lt;br /&gt;
* '''Instructor Flow:''' Verified assignment editing via `/assignments/edit/:id`, topic creation/editing/deletion/import via modals, toggling `allow_bookmarks`, dropping teams from topics.&lt;br /&gt;
* '''Student Flow:''' Verified topic viewing via `/student_tasks/:assignmentId`, selecting/deselecting topics (including automatic drop of previous), bookmarking (when enabled), correct display of slots and waitlists, disabled selection for full topics.&lt;br /&gt;
&lt;br /&gt;
=== Impact Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Summary of Changes ====&lt;br /&gt;
* '''Backend:''' Major refactoring of topic-related models and controllers, database schema changes, new API endpoints, updated dependencies. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily models, controllers, specs, migrations).&lt;br /&gt;
* '''Frontend:''' New assignment editing page with tabbed UI, new student task page for topic signup, reusable `TopicsTable` component, new routes. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily in `src/pages/Assignments`, `src/pages/StudentTasks`, `src/components`).&lt;br /&gt;
&lt;br /&gt;
==== Achievements ====&lt;br /&gt;
* ✓ Successfully refactored `SignUpTopic` to `ProjectTopic` for improved clarity.&lt;br /&gt;
* ✓ Centralized business logic in models, resulting in cleaner controllers.&lt;br /&gt;
* ✓ Implemented a modern, tabbed interface for assignment editing.&lt;br /&gt;
* ✓ Created a dedicated, streamlined UI for student topic signup.&lt;br /&gt;
* ✓ Added topic bookmarking functionality.&lt;br /&gt;
* ✓ Enhanced API endpoints for better data provision to the frontend.&lt;br /&gt;
* ✓ Updated key dependencies (Rails 8).&lt;br /&gt;
* ✓ Added comprehensive RSpec tests for new model logic.&lt;br /&gt;
&lt;br /&gt;
=== Future Work ===&lt;br /&gt;
* '''Frontend Bookmark Persistence:''' Implement API calls to save/load student topic bookmarks instead of using local state.&lt;br /&gt;
* '''Partner Ad Feature:''' Fully implement the &amp;quot;Apply to partner ad&amp;quot; functionality hinted at in `TopicsTab`.&lt;br /&gt;
* '''Complete Assignment Tabs:''' Implement the remaining tabs in `AssignmentEditPage` (Rubrics, Review Strategy, Due Dates, Etc.).&lt;br /&gt;
* '''Refine General Tab/AssignmentEditor:''' Decide whether general assignment settings remain in `AssignmentEditor` modal or move entirely to a &amp;quot;General&amp;quot; tab within `AssignmentEditPage`.&lt;br /&gt;
* '''Error Handling (Frontend):''' Enhance user feedback for API errors during topic operations (create/edit/delete/signup/drop).&lt;br /&gt;
* '''Authorization Checks:''' Ensure robust authorization checks are in place for all new/modified backend endpoints.&lt;br /&gt;
&lt;br /&gt;
=== Conclusion ===&lt;br /&gt;
This project successfully refactored the core topic management and signup system in Expertiza, replacing `SignUpTopic` with `ProjectTopic` and significantly improving the underlying logic by moving it into the models. New frontend interfaces provide a much-improved experience for both instructors managing topics and students signing up for them. The addition of features like topic bookmarking and a streamlined student signup flow enhances usability. The changes establish a more maintainable and understandable codebase for future development.&lt;br /&gt;
&lt;br /&gt;
=== References ===&lt;br /&gt;
# [https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
# [https://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
# [http://wikis.lib.ncsu.edu/index.php/Expertiza Expertiza project documentation wiki]&lt;br /&gt;
# ''(Add links to your specific project fork/PRs if needed)''&lt;br /&gt;
# [https://guides.rubyonrails.org/ Ruby on Rails Guides]&lt;br /&gt;
# [https://react.dev/ React Documentation]&lt;br /&gt;
# [https://relishapp.com/rspec Rspec Documentation]&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166838</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166838"/>
		<updated>2025-10-29T01:17:20Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== E XXXX. Refactoring Topics and Enhancing Assignment Management ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
==== Background ====&lt;br /&gt;
Expertiza utilizes a system for instructors to define topics within assignments, allowing students (often in teams) to sign up for these topics. The previous implementation, centered around the `SignUpTopic` model and associated controllers (`SignUpTopicsController`, `SignedUpTeamsController`), lacked clarity in naming and had business logic distributed across controllers rather than encapsulated within models. Furthermore, the user interface for managing assignment topics by instructors and for students signing up for topics required modernization and improved functionality.&lt;br /&gt;
&lt;br /&gt;
==== Motivation ====&lt;br /&gt;
This project aimed to improve the maintainability, clarity, and functionality of the topic management and signup features within Expertiza. Key motivations included:&lt;br /&gt;
* Renaming core components (`SignUpTopic` -&amp;gt; `ProjectTopic`) to better reflect their purpose.&lt;br /&gt;
* Created RESTful API endpoints to manage topics and team signups.&lt;br /&gt;
* Creating a more intuitive and feature-rich interface for instructors managing assignment topics.&lt;br /&gt;
* Developing a dedicated and user-friendly interface for students to view, select, and manage their topic signups.&lt;br /&gt;
* Introducing features like bookmarking topics and streamlining the student signup/drop process.&lt;br /&gt;
* Updating dependencies to keep the application current.&lt;br /&gt;
&lt;br /&gt;
==== Tasks Accomplished ====&lt;br /&gt;
* Renamed `SignUpTopic` to `ProjectTopic` throughout the backend (models, controllers, routes, tests, database).&lt;br /&gt;
* Refactored `ProjectTopic` and `SignedUpTeam` models to encapsulate business logic (topic creation/update/deletion, team signup/waitlisting, slot management, student signup/drop).&lt;br /&gt;
* Removed `SignUpTopicsController` and implemented `ProjectTopicsController` using the refactored model logic.&lt;br /&gt;
* Refactored `SignedUpTeamsController` to utilize new model methods and added new actions (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
* Added `allow_bookmarks` attribute to the `Assignment` model and associated backend/frontend logic.&lt;br /&gt;
* Created a new frontend page (`AssignmentEditPage.tsx`) with a tabbed interface for instructors to manage assignments, including a dedicated &amp;quot;Topics&amp;quot; tab.&lt;br /&gt;
* Implemented modals for creating, editing, importing, and deleting topics on the frontend.&lt;br /&gt;
* Developed a reusable `TopicsTable.tsx` component for displaying topics in instructor and student views.&lt;br /&gt;
* Created a new frontend page (`StudentTasks.tsx`) for students to view assignment topics, bookmark (if enabled), and sign up/drop topics.&lt;br /&gt;
* Updated backend dependencies (Rails, Puma, Nokogiri, etc.) and Docker configuration.&lt;br /&gt;
* Added/updated RSpec tests for `ProjectTopic` and `SignedUpTeam` models and updated relevant existing tests.&lt;br /&gt;
* Updated Swagger API documentation.&lt;br /&gt;
&lt;br /&gt;
====Files Modified and Created====&lt;br /&gt;
&lt;br /&gt;
* **app/models/project_topic.rb**&lt;br /&gt;
* **app/models/signed_up_team.rb**&lt;br /&gt;
* **app/controllers/api/v1/project_topics_controller.rb**&lt;br /&gt;
* **app/controllers/api/v1/signed_up_teams_controller.rb**&lt;br /&gt;
* **app/serializers/project_topic_serializer.rb**&lt;br /&gt;
* **app/serializers/signed_up_team_serializer.rb**&lt;br /&gt;
* **spec/models/project_topic_spec.rb**&lt;br /&gt;
* **spec/models/signed_up_team_spec.rb**&lt;br /&gt;
* **spec/requests/project_topics_spec.rb**&lt;br /&gt;
* **spec/requests/signed_up_teams_spec.rb**&lt;br /&gt;
&lt;br /&gt;
=== Problem Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Issues with Previous Implementation ====&lt;br /&gt;
&lt;br /&gt;
==== Naming Convention ====&lt;br /&gt;
The name `SignUpTopic` was ambiguous. Renaming to `ProjectTopic` clarifies that these are topics related to the core project/assignment work students sign up for.&lt;br /&gt;
&lt;br /&gt;
==== Distributed Business Logic ====&lt;br /&gt;
Logic for creating topics, signing up teams, managing waitlists, and checking slots was spread across `SignUpTopicsController` and `SignedUpTeamsController`. This violated the principle of &amp;quot;fat model, skinny controller&amp;quot;, making the code harder to understand, test, and maintain.&lt;br /&gt;
&lt;br /&gt;
==== Inefficient Data Fetching ====&lt;br /&gt;
Frontend components often needed to make multiple API calls or perform calculations (like available slots) that could be handled more efficiently on the backend. The previous `SignUpTopic` API didn't provide computed data like assigned/waitlisted teams directly.&lt;br /&gt;
&lt;br /&gt;
==== Lack of Dedicated Student View ====&lt;br /&gt;
Students lacked a clear, dedicated interface to view available topics for an assignment and manage their selection. The signup process was not streamlined.&lt;br /&gt;
&lt;br /&gt;
==== Inconsistent Assignment Editing ====&lt;br /&gt;
The existing `AssignmentEditor` modal combined general settings with links to other management pages (like topics, participants) in an ad-hoc manner. A more structured approach was needed.&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== Architecture Decisions ===&lt;br /&gt;
* '''Model-Centric Logic:''' Shifted primary business logic for topic management and team signups into the `ProjectTopic` and `SignedUpTeam` models, respectively. Controllers now primarily handle request/response flow and delegate actions to the models.&lt;br /&gt;
* '''Dedicated Edit Page (Frontend):''' Created a new full page (`AssignmentEditPage`) for editing assignments instead of using a modal, allowing for a more complex, tabbed interface.&lt;br /&gt;
* '''Reusable Table Component (Frontend):''' Developed `TopicsTable` to handle the display and core interactions for topics in different contexts (instructor vs. student), promoting DRY principles.&lt;br /&gt;
* '''API Enhancements:''' Modified the `ProjectTopic` index endpoint (`/api/v1/project_topics`) to accept `assignment_id` and return topics with computed data (`to_json_with_computed_data`), reducing frontend calculation needs. Added specific endpoints for student signup (`sign_up_student`) and dropping topics (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
&lt;br /&gt;
==== Core Functionality Implemented ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Backend Changes !! Frontend Changes&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Renaming''' || Renamed `SignUpTopic` model, controller, routes, DB table to `ProjectTopic`. Updated associations. || Updated API endpoints used.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Management (Instructor)''' || `ProjectTopicsController` CRUD actions delegating to `ProjectTopic` model methods (`create_topic_with_assignment`, `update_topic`, `delete_by_assignment_and_topic_ids`). API returns computed data. || New `AssignmentEditPage` with `TopicsTab`. Uses `TopicsTable` (instructor mode). Modals for create, edit, import, delete. API calls for CRUD.&lt;br /&gt;
|-&lt;br /&gt;
| '''Team Signup Logic''' || `ProjectTopic` methods (`sign_team_up`, `drop_team`, `promote_waitlisted_team`). `SignedUpTeam` methods (`create_signed_up_team`, `remove_team_signups`). || Instructor view shows assigned/waitlisted teams in `TopicsTable` details. Drop team button calls backend.&lt;br /&gt;
|-&lt;br /&gt;
| '''Student Signup/Drop''' || `SignedUpTeamsController` actions (`sign_up_student`, `drop_topic`) delegating to `SignedUpTeam` model methods (`sign_up_student_for_topic`, `drop_topic_for_student`). Automatic handling of switching topics. || New `StudentTasks` page. Uses `TopicsTable` (student mode). Select/deselect buttons trigger API calls. Optimistic UI updates for slots. Displays current selection.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Bookmarking''' || Added `allow_bookmarks` boolean to `Assignment`. Added `project_topic_params` permit `allow_bookmarks` in `AssignmentsController`. || `AssignmentEditPage` allows instructors to toggle `allow_bookmarks` (persisted via PATCH). `StudentTasks` shows bookmark toggle if `allow_bookmarks` is true (local state for now).&lt;br /&gt;
|-&lt;br /&gt;
| '''Assignment Editing UI''' || N/A || New `AssignmentEditPage` with tabbed structure. `AssignmentEditor` might be simplified or removed for general settings.&lt;br /&gt;
|-&lt;br /&gt;
| '''Dependency Updates''' || Updated Ruby, Rails, Puma, Nokogiri etc. Added required gems. || N/A&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Key Backend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== ProjectTopic Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Handles team signup, considering available slots and waitlisting&lt;br /&gt;
# Renamed from signup_team for clarity&lt;br /&gt;
def sign_team_up(team)&lt;br /&gt;
  return false if signed_up_teams.exists?(team: team)&lt;br /&gt;
  ActiveRecord::Base.transaction do&lt;br /&gt;
    signed_up_team = signed_up_teams.create!(&lt;br /&gt;
      team: team,&lt;br /&gt;
      is_waitlisted: !slot_available?&lt;br /&gt;
    )&lt;br /&gt;
    # Remove team from other waitlists if confirmed here&lt;br /&gt;
    remove_from_waitlist(team) unless signed_up_team.is_waitlisted?&lt;br /&gt;
    true&lt;br /&gt;
  end&lt;br /&gt;
rescue ActiveRecord::RecordInvalid&lt;br /&gt;
  false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Handles dropping a team and promoting waitlisted if necessary&lt;br /&gt;
def drop_team(team)&lt;br /&gt;
  signed_up_team = signed_up_teams.find_by(team: team)&lt;br /&gt;
  return unless signed_up_team&lt;br /&gt;
  team_confirmed = !signed_up_team.is_waitlisted?&lt;br /&gt;
  signed_up_team.destroy!&lt;br /&gt;
  promote_waitlisted_team if team_confirmed # Promote only if a confirmed slot opened&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Calculates available slots&lt;br /&gt;
def available_slots&lt;br /&gt;
  max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Checks if slots are positive&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for creation, moved from controller&lt;br /&gt;
def self.create_topic_with_assignment(topic_params, assignment_id, micropayment = nil)&lt;br /&gt;
  # ... (find assignment, build topic, save, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for update, moved from controller&lt;br /&gt;
def update_topic(topic_params)&lt;br /&gt;
  # ... (update attributes, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Returns enhanced JSON including computed fields&lt;br /&gt;
def to_json_with_computed_data&lt;br /&gt;
  as_json.merge(&lt;br /&gt;
    available_slots: available_slots,&lt;br /&gt;
    confirmed_teams: confirmed_teams.map { |team| # ... format team data },&lt;br /&gt;
    waitlisted_teams: waitlisted_teams.map { |team| # ... format team data }&lt;br /&gt;
  )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
private&lt;br /&gt;
&lt;br /&gt;
# Helper for promotion logic&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
  # ... (find earliest waitlisted team, update is_waitlisted to false, remove from other waitlists)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to remove team from other topics' waitlists&lt;br /&gt;
def remove_from_waitlist(team)&lt;br /&gt;
  team.signed_up_teams.waitlisted.where.not(project_topic_id: id).destroy_all&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SignedUpTeam Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Scope for confirmed signups&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
# Scope for waitlisted signups&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&lt;br /&gt;
belongs_to :project_topic # Updated association&lt;br /&gt;
# ... validations ...&lt;br /&gt;
&lt;br /&gt;
# Business logic for student signup, including dropping previous topic&lt;br /&gt;
def self.sign_up_student_for_topic(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id) # Find student's team&lt;br /&gt;
  return { success: false, message: &amp;quot;User is not part of any team&amp;quot; } unless team_id&lt;br /&gt;
&lt;br /&gt;
  # Drop any existing topic signups for this team FIRST&lt;br /&gt;
  drop_existing_signups_for_team(team_id)&lt;br /&gt;
&lt;br /&gt;
  # Sign up for the new topic using create_signed_up_team (which calls topic.sign_team_up)&lt;br /&gt;
  signed_up_team = create_signed_up_team(topic_id, team_id)&lt;br /&gt;
&lt;br /&gt;
  if signed_up_team&lt;br /&gt;
    { success: true, message: &amp;quot;Signed up team successful!&amp;quot;, signed_up_team: signed_up_team, available_slots: signed_up_team.project_topic.available_slots }&lt;br /&gt;
  else&lt;br /&gt;
    { success: false, message: &amp;quot;Failed to sign up for topic. Topic may be full or already signed up.&amp;quot; }&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for dropping a topic&lt;br /&gt;
def self.drop_topic_for_student(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id)&lt;br /&gt;
  # ... (find topic, team, signed_up_team record) ...&lt;br /&gt;
  return { success: false, message: &amp;quot;Team is not signed up for this topic&amp;quot; } unless signed_up_team&lt;br /&gt;
&lt;br /&gt;
  # Delegate drop logic to ProjectTopic&lt;br /&gt;
  project_topic.drop_team(team)&lt;br /&gt;
&lt;br /&gt;
  { success: true, message: &amp;quot;Successfully dropped topic!&amp;quot;, available_slots: project_topic.available_slots }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to find and drop existing signups before signing up for a new one&lt;br /&gt;
private&lt;br /&gt;
def self.drop_existing_signups_for_team(team_id)&lt;br /&gt;
  existing_signups = where(team_id: team_id)&lt;br /&gt;
  existing_signups.each do |signup|&lt;br /&gt;
    signup.project_topic.drop_team(signup.team) # Use ProjectTopic's drop method&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Frontend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== AssignmentEditPage Component ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
// Manages overall state for assignment editing&lt;br /&gt;
const AssignmentEditPage = () =&amp;gt; {&lt;br /&gt;
  // ... hooks for fetching data (assignment, topics), state for active tab, topic settings, topics data ...&lt;br /&gt;
&lt;br /&gt;
  // Fetch assignment details on load&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (id) fetchAssignment({ url: `/assignments/${id}` });&lt;br /&gt;
  }, [id, fetchAssignment]);&lt;br /&gt;
&lt;br /&gt;
  // Update local state when assignment data is loaded (e.g., name, allow_bookmarks)&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (assignmentResponse?.data) {&lt;br /&gt;
      setAssignmentName(assignmentResponse.data.name || &amp;quot;&amp;quot;);&lt;br /&gt;
      setTopicSettings(prev =&amp;gt; ({ ...prev, allowBookmarks: assignmentResponse.data.allow_bookmarks }));&lt;br /&gt;
    }&lt;br /&gt;
  }, [assignmentResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Fetch topics when assignment ID is known&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (id) fetchTopics({ url: `/project_topics?assignment_id=${id}` });&lt;br /&gt;
  }, [id, fetchTopics]);&lt;br /&gt;
&lt;br /&gt;
  // Process fetched topics into format needed by TopicsTable&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
     if (topicsResponse?.data) {&lt;br /&gt;
       // ... transform backend topic structure to frontend TopicData structure ...&lt;br /&gt;
       setTopicsData(transformedTopics);&lt;br /&gt;
     }&lt;br /&gt;
  }, [topicsResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Handler for topic setting changes (e.g., checkboxes)&lt;br /&gt;
  const handleTopicSettingChange = useCallback((setting: string, value: boolean) =&amp;gt; {&lt;br /&gt;
    setTopicSettings((prev) =&amp;gt; ({ ...prev, [setting]: value }));&lt;br /&gt;
    // Persist allowBookmarks change immediately&lt;br /&gt;
    if (setting === 'allowBookmarks' &amp;amp;&amp;amp; id) {&lt;br /&gt;
      updateAssignment({ /* ... PATCH request data ... */ });&lt;br /&gt;
    }&lt;br /&gt;
  }, [id, updateAssignment]);&lt;br /&gt;
&lt;br /&gt;
  // Handlers for topic CRUD operations (passed down to TopicsTab)&lt;br /&gt;
  const handleDeleteTopic = useCallback((topicId: string) =&amp;gt; {&lt;br /&gt;
    // ... call deleteTopic API ...&lt;br /&gt;
  }, [id, deleteTopic]);&lt;br /&gt;
  // ... other handlers (create, edit, drop team) ...&lt;br /&gt;
&lt;br /&gt;
  // Renders the content based on the active tab state&lt;br /&gt;
  const renderTabContent = () =&amp;gt; {&lt;br /&gt;
    switch (activeTab) {&lt;br /&gt;
      case &amp;quot;topics&amp;quot;:&lt;br /&gt;
        return &amp;lt;TopicsTab /* pass props: settings, data, handlers */ /&amp;gt;;&lt;br /&gt;
      // ... other cases for RubricsTab, DueDatesTab etc. ...&lt;br /&gt;
    }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  return (&lt;br /&gt;
    // ... JSX for layout, tab buttons, calling renderTabContent ...&lt;br /&gt;
  );&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== StudentTasks Component ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
// Page for students to sign up for topics&lt;br /&gt;
const StudentTasks: React.FC = () =&amp;gt; {&lt;br /&gt;
  // ... hooks for fetching (assignments, topics), signing up, dropping ...&lt;br /&gt;
  // ... state for bookmarks, selectedTopic, loading states, optimistic updates ...&lt;br /&gt;
&lt;br /&gt;
  // Fetch assignment and then topics&lt;br /&gt;
  useEffect(() =&amp;gt; { /* ... fetch assignment data ... */ }, [/* dependencies */]);&lt;br /&gt;
  useEffect(() =&amp;gt; { /* ... fetch topics based on assignment id ... */ }, [/* dependencies */]);&lt;br /&gt;
&lt;br /&gt;
  // Process topics data, applying optimistic updates&lt;br /&gt;
  const topics = useMemo(() =&amp;gt; {&lt;br /&gt;
    // ... map topicsResponse.data, check optimisticSlotChanges map ...&lt;br /&gt;
  }, [/* dependencies */]);&lt;br /&gt;
&lt;br /&gt;
  // Check if bookmarks allowed&lt;br /&gt;
  const allowBookmarks = useMemo(() =&amp;gt; {&lt;br /&gt;
     // ... check assignmentResponse.data.allow_bookmarks ...&lt;br /&gt;
  }, [assignmentResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Handle selecting/deselecting a topic&lt;br /&gt;
  const handleTopicSelect = useCallback(async (topicId: string) =&amp;gt; {&lt;br /&gt;
    if (selectedTopic === topicId) { // Deselecting&lt;br /&gt;
      // Optimistically update slots (+1)&lt;br /&gt;
      // Set selectedTopic to null&lt;br /&gt;
      // Call dropAPI&lt;br /&gt;
    } else { // Selecting a new topic&lt;br /&gt;
      // Optimistically update slots (-1 for new, +1 for old if exists)&lt;br /&gt;
      // Call dropAPI for old topic if selectedTopic is not null&lt;br /&gt;
      // Set selectedTopic to topicId&lt;br /&gt;
      // Call signUpAPI&lt;br /&gt;
    }&lt;br /&gt;
  }, [/* dependencies: selectedTopic, currentUser, dropAPI, signUpAPI, topics */]);&lt;br /&gt;
&lt;br /&gt;
  // Handle bookmark toggle (local state)&lt;br /&gt;
  const handleBookmarkToggle = useCallback((topicId: string) =&amp;gt; { /* ... update bookmarkedTopics set ... */ }, []);&lt;br /&gt;
&lt;br /&gt;
  // Prepare data for TopicsTable&lt;br /&gt;
  const topicRows: TopicRow[] = useMemo(() =&amp;gt; topics.map(t =&amp;gt; ({ /* ... map topic data ... */ })), [topics]);&lt;br /&gt;
&lt;br /&gt;
  // ... return JSX ...&lt;br /&gt;
  return (&lt;br /&gt;
    &amp;lt;Container&amp;gt;&lt;br /&gt;
      {/* ... Title, Current Selection display ... */}&lt;br /&gt;
      {topicsLoading ? &amp;lt;Spinner /&amp;gt; : topicsError ? &amp;lt;Alert variant=&amp;quot;danger&amp;quot;&amp;gt;{topicsError}&amp;lt;/Alert&amp;gt; : (&lt;br /&gt;
        &amp;lt;TopicsTable&lt;br /&gt;
          data={topicRows}&lt;br /&gt;
          mode=&amp;quot;student&amp;quot;&lt;br /&gt;
          onBookmarkToggle={handleBookmarkToggle}&lt;br /&gt;
          onSelectTopic={handleTopicSelect}&lt;br /&gt;
          isSigningUp={isSigningUp}&lt;br /&gt;
          selectedTopicId={selectedTopic}&lt;br /&gt;
          showBookmarks={allowBookmarks}&lt;br /&gt;
          // ... other props ...&lt;br /&gt;
        /&amp;gt;&lt;br /&gt;
      )}&lt;br /&gt;
    &amp;lt;/Container&amp;gt;&lt;br /&gt;
  );&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Database Migrations ====&lt;br /&gt;
* Renamed `sign_up_topics` table to `project_topics`.&lt;br /&gt;
* Updated `signed_up_teams` table: renamed `sign_up_topic_id` foreign key to `project_topic_id` and updated index name.&lt;br /&gt;
* Added `allow_bookmarks` boolean column to `assignments` table.&lt;br /&gt;
* Renamed `teams_users` join table to `teams_participants`.&lt;br /&gt;
&lt;br /&gt;
==== Testing ====&lt;br /&gt;
&lt;br /&gt;
==== RSpec Tests (Backend) ====&lt;br /&gt;
* '''ProjectTopic Model (`project_topic_spec.rb`):''' Added extensive tests covering:&lt;br /&gt;
    * `sign_team_up`: Confirmed vs. waitlisted based on `max_choosers`, removal from other waitlists.&lt;br /&gt;
    * `drop_team`: Team removal, promotion of earliest waitlisted team.&lt;br /&gt;
    * `available_slots`, `slot_available?`: Correct calculations before/after signups/drops.&lt;br /&gt;
    * `confirmed_teams`, `waitlisted_teams`: Correct retrieval and ordering.&lt;br /&gt;
    * Validations: Presence of `topic_name`, non-negative `max_choosers` (including zero).&lt;br /&gt;
* '''SignedUpTeam Model (`signed_up_team_spec.rb`):''' Added tests covering:&lt;br /&gt;
    * Validations: Presence of topic/team, uniqueness scope.&lt;br /&gt;
    * Scopes: `:confirmed`, `:waitlisted`.&lt;br /&gt;
    * Class methods: Signup logic delegation, removal logic, participant/topic finding.&lt;br /&gt;
    * Waitlisting behavior when topic is full.&lt;br /&gt;
* '''Updates:''' Modified existing tests (e.g., `due_date_spec.rb`) to reference `ProjectTopic`.&lt;br /&gt;
&lt;br /&gt;
==== Manual Tests (UI) ====&lt;br /&gt;
* '''Instructor Flow:''' Verified assignment editing via `/assignments/edit/:id`, topic creation/editing/deletion/import via modals, toggling `allow_bookmarks`, dropping teams from topics.&lt;br /&gt;
* '''Student Flow:''' Verified topic viewing via `/student_tasks/:assignmentId`, selecting/deselecting topics (including automatic drop of previous), bookmarking (when enabled), correct display of slots and waitlists, disabled selection for full topics.&lt;br /&gt;
&lt;br /&gt;
=== Impact Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Summary of Changes ====&lt;br /&gt;
* '''Backend:''' Major refactoring of topic-related models and controllers, database schema changes, new API endpoints, updated dependencies. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily models, controllers, specs, migrations).&lt;br /&gt;
* '''Frontend:''' New assignment editing page with tabbed UI, new student task page for topic signup, reusable `TopicsTable` component, new routes. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily in `src/pages/Assignments`, `src/pages/StudentTasks`, `src/components`).&lt;br /&gt;
&lt;br /&gt;
==== Achievements ====&lt;br /&gt;
* ✓ Successfully refactored `SignUpTopic` to `ProjectTopic` for improved clarity.&lt;br /&gt;
* ✓ Centralized business logic in models, resulting in cleaner controllers.&lt;br /&gt;
* ✓ Implemented a modern, tabbed interface for assignment editing.&lt;br /&gt;
* ✓ Created a dedicated, streamlined UI for student topic signup.&lt;br /&gt;
* ✓ Added topic bookmarking functionality.&lt;br /&gt;
* ✓ Enhanced API endpoints for better data provision to the frontend.&lt;br /&gt;
* ✓ Updated key dependencies (Rails 8).&lt;br /&gt;
* ✓ Added comprehensive RSpec tests for new model logic.&lt;br /&gt;
&lt;br /&gt;
=== Future Work ===&lt;br /&gt;
* '''Frontend Bookmark Persistence:''' Implement API calls to save/load student topic bookmarks instead of using local state.&lt;br /&gt;
* '''Partner Ad Feature:''' Fully implement the &amp;quot;Apply to partner ad&amp;quot; functionality hinted at in `TopicsTab`.&lt;br /&gt;
* '''Complete Assignment Tabs:''' Implement the remaining tabs in `AssignmentEditPage` (Rubrics, Review Strategy, Due Dates, Etc.).&lt;br /&gt;
* '''Refine General Tab/AssignmentEditor:''' Decide whether general assignment settings remain in `AssignmentEditor` modal or move entirely to a &amp;quot;General&amp;quot; tab within `AssignmentEditPage`.&lt;br /&gt;
* '''Error Handling (Frontend):''' Enhance user feedback for API errors during topic operations (create/edit/delete/signup/drop).&lt;br /&gt;
* '''Authorization Checks:''' Ensure robust authorization checks are in place for all new/modified backend endpoints.&lt;br /&gt;
&lt;br /&gt;
=== Conclusion ===&lt;br /&gt;
This project successfully refactored the core topic management and signup system in Expertiza, replacing `SignUpTopic` with `ProjectTopic` and significantly improving the underlying logic by moving it into the models. New frontend interfaces provide a much-improved experience for both instructors managing topics and students signing up for them. The addition of features like topic bookmarking and a streamlined student signup flow enhances usability. The changes establish a more maintainable and understandable codebase for future development.&lt;br /&gt;
&lt;br /&gt;
=== References ===&lt;br /&gt;
# [https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
# [https://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
# [http://wikis.lib.ncsu.edu/index.php/Expertiza Expertiza project documentation wiki]&lt;br /&gt;
# ''(Add links to your specific project fork/PRs if needed)''&lt;br /&gt;
# [https://guides.rubyonrails.org/ Ruby on Rails Guides]&lt;br /&gt;
# [https://react.dev/ React Documentation]&lt;br /&gt;
# [https://relishapp.com/rspec Rspec Documentation]&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166835</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166835"/>
		<updated>2025-10-29T01:09:59Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==E2552. Reimplementation of ProjectTopic and SignedUpTeam==&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza-based OSS project completed as part of the reimplementation effort for Fall 2025.&lt;br /&gt;
&lt;br /&gt;
**TOC**&lt;br /&gt;
&lt;br /&gt;
===About Expertiza===&lt;br /&gt;
&lt;br /&gt;
[[http://expertiza.ncsu.edu/](http://expertiza.ncsu.edu/) Expertiza] is an open-source educational web application developed on the [[http://rubyonrails.org/](http://rubyonrails.org/) Ruby on Rails] framework. It enables instructors to create assignments, manage teams, and facilitate peer reviews. Students can sign up for topics, form teams, submit work, and review peers’ submissions. The new reimplementation of Expertiza separates the back end and front end — with a Rails API providing REST endpoints and a React/TypeScript front end consuming those APIs.&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
&lt;br /&gt;
In the existing Expertiza system, the topic signup mechanism was implemented using legacy classes such as `SignUpTopic` and `SignedUpTeam`. This implementation was tightly coupled to the MVC structure, contained redundant logic, lacked proper validation, and offered limited flexibility for team-based topic management.&lt;br /&gt;
&lt;br /&gt;
The goal of this project (E2552) was to **reimplement ProjectTopic and SignedUpTeam** in the modern Expertiza architecture, aligning with RESTful API principles and React-driven UI. The backend was built on Rails API, and the frontend was developed in React with TypeScript.&lt;br /&gt;
&lt;br /&gt;
The following tasks were accomplished:&lt;br /&gt;
&lt;br /&gt;
* Reimplemented `ProjectTopic` and `SignedUpTeam` models with ActiveRecord relationships and validations.&lt;br /&gt;
* Created RESTful API endpoints to manage topics and team signups.&lt;br /&gt;
* Implemented controllers with robust error handling, transaction safety, and parameter validation.&lt;br /&gt;
* Added RSpec test coverage for all new controllers, models, and routes.&lt;br /&gt;
* Built the corresponding React front-end components for viewing, signing up for, and managing topics.&lt;br /&gt;
&lt;br /&gt;
===Backend Implementation===&lt;br /&gt;
&lt;br /&gt;
====Files Modified and Created====&lt;br /&gt;
&lt;br /&gt;
* **app/models/project_topic.rb**&lt;br /&gt;
* **app/models/signed_up_team.rb**&lt;br /&gt;
* **app/controllers/api/v1/project_topics_controller.rb**&lt;br /&gt;
* **app/controllers/api/v1/signed_up_teams_controller.rb**&lt;br /&gt;
* **app/serializers/project_topic_serializer.rb**&lt;br /&gt;
* **app/serializers/signed_up_team_serializer.rb**&lt;br /&gt;
* **spec/models/project_topic_spec.rb**&lt;br /&gt;
* **spec/models/signed_up_team_spec.rb**&lt;br /&gt;
* **spec/requests/project_topics_spec.rb**&lt;br /&gt;
* **spec/requests/signed_up_teams_spec.rb**&lt;br /&gt;
&lt;br /&gt;
====Key Features Implemented====&lt;br /&gt;
&lt;br /&gt;
* **ProjectTopic model**&lt;br /&gt;
&lt;br /&gt;
  * Represents a topic that students or teams can sign up for.&lt;br /&gt;
  * Includes fields such as `topic_identifier`, `topic_name`, `max_choosers`, `category`, `description`, and `link`.&lt;br /&gt;
  * Associations:&lt;br /&gt;
&lt;br /&gt;
    * `has_many :signed_up_teams`&lt;br /&gt;
    * `has_many :teams, through: :signed_up_teams`&lt;br /&gt;
  * Validations ensure that topic name, identifier, and slot count are always present and valid.&lt;br /&gt;
  * Scopes added to filter available and full topics.&lt;br /&gt;
&lt;br /&gt;
* **SignedUpTeam model**&lt;br /&gt;
&lt;br /&gt;
  * Connects a team with a project topic.&lt;br /&gt;
  * Contains foreign keys `team_id` and `project_topic_id`.&lt;br /&gt;
  * Includes methods for checking waitlist status and slot availability.&lt;br /&gt;
  * Adds validation to prevent over-signing beyond max_choosers.&lt;br /&gt;
  * Includes transaction-based signup to ensure atomic slot allocation.&lt;br /&gt;
&lt;br /&gt;
* **Controllers**&lt;br /&gt;
&lt;br /&gt;
  * Implemented RESTful endpoints:&lt;br /&gt;
&lt;br /&gt;
    * `GET /api/v1/project_topics` — List all topics for a given assignment.&lt;br /&gt;
    * `POST /api/v1/project_topics` — Create a new project topic.&lt;br /&gt;
    * `PATCH /api/v1/project_topics/:id` — Update topic details.&lt;br /&gt;
    * `DELETE /api/v1/project_topics/:id` — Remove a topic.&lt;br /&gt;
    * `POST /api/v1/signed_up_teams` — Sign a team up for a topic.&lt;br /&gt;
    * `DELETE /api/v1/signed_up_teams/:id` — Remove a team from a topic.&lt;br /&gt;
  * Implemented strong parameters for input validation.&lt;br /&gt;
  * Added custom error messages for invalid signups and slot constraints.&lt;br /&gt;
  * Ensured all database operations run in transactions for consistency.&lt;br /&gt;
&lt;br /&gt;
* **Serializers**&lt;br /&gt;
&lt;br /&gt;
  * Added serializers for both models to return clean JSON for frontend consumption.&lt;br /&gt;
  * Serialized attributes include topic metadata, associated teams, and available slots.&lt;br /&gt;
&lt;br /&gt;
* **RSpec Testing**&lt;br /&gt;
&lt;br /&gt;
  * Added unit tests for all models and request specs for controllers.&lt;br /&gt;
  * Tests verify successful CRUD operations, validation errors, and edge cases (like signing up when no slots are available).&lt;br /&gt;
&lt;br /&gt;
====Example Snippet====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# POST /api/v1/signed_up_teams&lt;br /&gt;
def create&lt;br /&gt;
  team_id = params[:team_id]&lt;br /&gt;
  topic = ProjectTopic.find(params[:project_topic_id])&lt;br /&gt;
&lt;br /&gt;
  if topic.available_slots? &lt;br /&gt;
    SignedUpTeam.transaction do&lt;br /&gt;
      SignedUpTeam.create!(team_id: team_id, project_topic_id: topic.id)&lt;br /&gt;
    end&lt;br /&gt;
    render json: { message: 'Team successfully signed up!' }, status: :created&lt;br /&gt;
  else&lt;br /&gt;
    render json: { error: 'No slots available for this topic.' }, status: :unprocessable_entity&lt;br /&gt;
  end&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;
====Files Modified and Created====&lt;br /&gt;
&lt;br /&gt;
* **src/pages/ProjectTopics.tsx**&lt;br /&gt;
* **src/components/TopicTable.tsx**&lt;br /&gt;
* **src/components/TopicRow.tsx**&lt;br /&gt;
* **src/api/projectTopics.ts**&lt;br /&gt;
* **src/api/signedUpTeams.ts**&lt;br /&gt;
&lt;br /&gt;
====Key Features====&lt;br /&gt;
&lt;br /&gt;
* Implemented the Project Topic view in React/TypeScript to display topics fetched from the backend.&lt;br /&gt;
* Added a reusable **TopicTable** component to list all topics, including columns for:&lt;br /&gt;
&lt;br /&gt;
  * Topic ID&lt;br /&gt;
  * Topic name (linked if a URL is provided)&lt;br /&gt;
  * Max choosers and available slots&lt;br /&gt;
  * Waitlist count&lt;br /&gt;
* Implemented signup and withdrawal buttons that trigger API requests to the backend.&lt;br /&gt;
* Added loading and error states for better UX.&lt;br /&gt;
* Integrated the API layer with Axios for RESTful communication.&lt;br /&gt;
* Used React hooks (`useState`, `useEffect`) to manage data and side effects.&lt;br /&gt;
* Ensured responsiveness and accessibility according to Expertiza design standards.&lt;br /&gt;
&lt;br /&gt;
====UI Features====&lt;br /&gt;
&lt;br /&gt;
* Instructors can:&lt;br /&gt;
&lt;br /&gt;
  * Create, edit, and delete topics.&lt;br /&gt;
  * View signed-up and waitlisted teams.&lt;br /&gt;
* Students can:&lt;br /&gt;
&lt;br /&gt;
  * View available topics.&lt;br /&gt;
  * Sign up for a topic or withdraw from one.&lt;br /&gt;
  * See waitlist status and slot availability.&lt;br /&gt;
* Added conditional rendering for available slots and disabled signup if a topic is full.&lt;br /&gt;
&lt;br /&gt;
===Testing===&lt;br /&gt;
&lt;br /&gt;
====Backend Testing====&lt;br /&gt;
&lt;br /&gt;
* Implemented RSpec tests covering:&lt;br /&gt;
&lt;br /&gt;
  * Model validations and associations.&lt;br /&gt;
  * API request success/failure responses.&lt;br /&gt;
  * Transaction rollback on failed signups.&lt;br /&gt;
* All tests passed successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ rspec spec&lt;br /&gt;
Finished in 4.82 seconds&lt;br /&gt;
52 examples, 0 failures&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Frontend Testing====&lt;br /&gt;
&lt;br /&gt;
* Verified API integration manually using local backend.&lt;br /&gt;
* Used Jest and React Testing Library for component testing.&lt;br /&gt;
* Ensured UI correctly reflects backend responses for:&lt;br /&gt;
&lt;br /&gt;
  * Available slots&lt;br /&gt;
  * Waitlist updates&lt;br /&gt;
  * Topic creation and deletion&lt;br /&gt;
&lt;br /&gt;
===Impact and Improvements===&lt;br /&gt;
&lt;br /&gt;
* The new implementation decouples topic and team logic from the legacy system.&lt;br /&gt;
* Enforces data integrity using validations and transaction safety.&lt;br /&gt;
* Adds clear separation of concerns between backend logic and UI presentation.&lt;br /&gt;
* Provides a scalable, maintainable structure for future Expertiza features such as bookmarks and partner advertisements.&lt;br /&gt;
&lt;br /&gt;
===Future Work===&lt;br /&gt;
&lt;br /&gt;
* Add pagination and filtering for large topic lists.&lt;br /&gt;
* Implement bookmarking feature and partner advertisements.&lt;br /&gt;
* Introduce instructor analytics dashboard for topic statistics.&lt;br /&gt;
* Integrate full end-to-end Cypress tests once frontend is deployed.&lt;br /&gt;
&lt;br /&gt;
===References===&lt;br /&gt;
#[[https://github.com/expertiza/reimplementation-back-end](https://github.com/expertiza/reimplementation-back-end) Expertiza Reimplementation Backend Repository]&lt;br /&gt;
#[[https://github.com/expertiza/reimplementation-front-end](https://github.com/expertiza/reimplementation-front-end) Expertiza Reimplementation Frontend Repository]&lt;br /&gt;
#[[https://wiki.expertiza.ncsu.edu/index.php/Expertiza](https://wiki.expertiza.ncsu.edu/index.php/Expertiza) Expertiza Wiki]&lt;br /&gt;
#[[http://rspec.info](http://rspec.info) RSpec Documentation]&lt;br /&gt;
#[[http://wikis.lib.ncsu.edu/index.php/Documentation_on_Database_Tables](http://wikis.lib.ncsu.edu/index.php/Documentation_on_Database_Tables) Expertiza Database Tables Documentation]&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166833</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166833"/>
		<updated>2025-10-29T00:59:53Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* Key Backend Improvements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== E 2552. Refactoring Topics and Enhancing Assignment Management ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
Expertiza is an educational web application created and maintained by the joint efforts of the students and the faculty at NCSU. It’s an open source project developed on Ruby on Rails platform and its code is available on Github. It allows students to review each other’s work and improve their work upon this feedback. The current effort involves reimplementing the application with a Ruby on Rails API backend and a React/Typescript frontend&lt;br /&gt;
&lt;br /&gt;
==== Background ====&lt;br /&gt;
Expertiza utilizes a system for instructors to define topics within assignments, allowing students (often in teams) to sign up for these topics. The previous implementation, centered around the `SignUpTopic` model and associated controllers (`SignUpTopicsController`, `SignedUpTeamsController`), lacked clarity in naming and had business logic distributed across controllers rather than encapsulated within models. Furthermore, the user interface for managing assignment topics by instructors and for students signing up for topics required modernization and improved functionality.&lt;br /&gt;
&lt;br /&gt;
==== Motivation ====&lt;br /&gt;
This project aimed to improve the maintainability, clarity, and functionality of the topic management and signup features within Expertiza. Key motivations included:&lt;br /&gt;
* Renaming core components (`SignUpTopic` -&amp;gt; `ProjectTopic`) to better reflect their purpose.&lt;br /&gt;
* Centralizing business logic within models for better separation of concerns and testability.&lt;br /&gt;
* Creating a more intuitive and feature-rich interface for instructors managing assignment topics.&lt;br /&gt;
* Developing a dedicated and user-friendly interface for students to view, select, and manage their topic signups.&lt;br /&gt;
* Introducing features like bookmarking topics and streamlining the student signup/drop process.&lt;br /&gt;
* Updating dependencies to keep the application current.&lt;br /&gt;
&lt;br /&gt;
==== Tasks Accomplished ====&lt;br /&gt;
* Renamed `SignUpTopic` to `ProjectTopic` throughout the backend (models, controllers, routes, tests, database).&lt;br /&gt;
* Refactored `ProjectTopic` and `SignedUpTeam` models to encapsulate business logic (topic creation/update/deletion, team signup/waitlisting, slot management, student signup/drop).&lt;br /&gt;
* Removed `SignUpTopicsController` and implemented `ProjectTopicsController` using the refactored model logic.&lt;br /&gt;
* Refactored `SignedUpTeamsController` to utilize new model methods and added new actions (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
* Added `allow_bookmarks` attribute to the `Assignment` model and associated backend/frontend logic.&lt;br /&gt;
* Created a new frontend page (`AssignmentEditPage.tsx`) with a tabbed interface for instructors to manage assignments, including a dedicated &amp;quot;Topics&amp;quot; tab.&lt;br /&gt;
* Implemented modals for creating, editing, importing, and deleting topics on the frontend.&lt;br /&gt;
* Developed a reusable `TopicsTable.tsx` component for displaying topics in instructor and student views.&lt;br /&gt;
* Created a new frontend page (`StudentTasks.tsx`) for students to view assignment topics, bookmark (if enabled), and sign up/drop topics.&lt;br /&gt;
* Updated backend dependencies (Rails, Puma, Nokogiri, etc.) and Docker configuration.&lt;br /&gt;
* Added/updated RSpec tests for `ProjectTopic` and `SignedUpTeam` models and updated relevant existing tests.&lt;br /&gt;
* Updated Swagger API documentation.&lt;br /&gt;
&lt;br /&gt;
==== Files ====&lt;br /&gt;
'''New Backend Files Created:'''&lt;br /&gt;
* `app/controllers/project_topics_controller.rb`&lt;br /&gt;
* `app/models/project_topic.rb`&lt;br /&gt;
* `db/migrate/20250319015434_rename_sign_up_topics_to_project_topics.rb`&lt;br /&gt;
* `db/migrate/20250321222753_rename_sign_up_topic_to_project_topic_in_signed_up_teams.rb`&lt;br /&gt;
* `db/migrate/20251028200538_add_allow_bookmarks_to_assignments.rb`&lt;br /&gt;
* `spec/factories/project_topics.rb`&lt;br /&gt;
* `spec/models/project_topic_spec.rb`&lt;br /&gt;
* `spec/models/signed_up_team_spec.rb`&lt;br /&gt;
* `spec/routing/project_topics_routing_spec.rb`&lt;br /&gt;
&lt;br /&gt;
'''Modified Backend Files:'''&lt;br /&gt;
* `.ruby-version`, `Gemfile`, `Gemfile.lock`&lt;br /&gt;
* `app/controllers/assignments_controller.rb`&lt;br /&gt;
* `app/controllers/signed_up_teams_controller.rb`&lt;br /&gt;
* `app/models/assignment.rb`&lt;br /&gt;
* `app/models/bookmark.rb`&lt;br /&gt;
* `app/models/signed_up_team.rb`&lt;br /&gt;
* `app/models/user.rb`&lt;br /&gt;
* `config/routes.rb`&lt;br /&gt;
* `db/migrate/20231129050431_create_sign_up_topics.rb` (Renamed table)&lt;br /&gt;
* `db/schema.rb`&lt;br /&gt;
* `db/seeds.rb`&lt;br /&gt;
* `docker-compose.yml`&lt;br /&gt;
* `spec/factories/assignments.rb`&lt;br /&gt;
* `spec/models/due_date_spec.rb`&lt;br /&gt;
* `spec/rails_helper.rb`&lt;br /&gt;
* `swagger/v1/swagger.yaml`&lt;br /&gt;
&lt;br /&gt;
'''Deleted Backend Files:'''&lt;br /&gt;
* `app/controllers/sign_up_topics_controller.rb`&lt;br /&gt;
* `app/models/sign_up_topic.rb`&lt;br /&gt;
* `spec/routing/sign_up_topics_routing_spec.rb`&lt;br /&gt;
&lt;br /&gt;
'''New Frontend Files Created:'''&lt;br /&gt;
* `public/assets/icons/Check-icon.png`&lt;br /&gt;
* `src/pages/Assignments/AssignmentEditPage.tsx`&lt;br /&gt;
* `src/pages/Assignments/components/TopicsTable.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/DueDatesTab.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/EtcTab.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/GeneralTab.tsx` (Note: This might be redundant if general editing stays in AssignmentEditor)&lt;br /&gt;
* `src/pages/Assignments/tabs/ReviewStrategyTab.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/RubricsTab.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/TopicsTab.tsx`&lt;br /&gt;
* `src/pages/StudentTasks/StudentTasks.tsx`&lt;br /&gt;
&lt;br /&gt;
'''Modified Frontend Files:'''&lt;br /&gt;
* `src/App.tsx` (Routing changes)&lt;br /&gt;
* `src/components/Table/Table.tsx` (Added selected row styling)&lt;br /&gt;
* `src/hooks/useAPI.ts` (Minor adjustment to isLoading)&lt;br /&gt;
* `src/layout/Header.tsx` (Conditional assignments link for students)&lt;br /&gt;
* `src/pages/Assignments/Assignment.tsx` (Adjusted to accommodate new edit page link)&lt;br /&gt;
* `src/pages/Assignments/AssignmentEditor.tsx` (Potentially simplified if general settings move to GeneralTab)&lt;br /&gt;
&lt;br /&gt;
=== Problem Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Issues with Previous Implementation ====&lt;br /&gt;
&lt;br /&gt;
==== Naming Convention ====&lt;br /&gt;
The name `SignUpTopic` was ambiguous. Renaming to `ProjectTopic` clarifies that these are topics related to the core project/assignment work students sign up for.&lt;br /&gt;
&lt;br /&gt;
==== Distributed Business Logic ====&lt;br /&gt;
Logic for creating topics, signing up teams, managing waitlists, and checking slots was spread across `SignUpTopicsController` and `SignedUpTeamsController`. This violated the principle of &amp;quot;fat model, skinny controller&amp;quot;, making the code harder to understand, test, and maintain.&lt;br /&gt;
&lt;br /&gt;
==== Inefficient Data Fetching ====&lt;br /&gt;
Frontend components often needed to make multiple API calls or perform calculations (like available slots) that could be handled more efficiently on the backend. The previous `SignUpTopic` API didn't provide computed data like assigned/waitlisted teams directly.&lt;br /&gt;
&lt;br /&gt;
==== Lack of Dedicated Student View ====&lt;br /&gt;
Students lacked a clear, dedicated interface to view available topics for an assignment and manage their selection. The signup process was not streamlined.&lt;br /&gt;
&lt;br /&gt;
==== Inconsistent Assignment Editing ====&lt;br /&gt;
The existing `AssignmentEditor` modal combined general settings with links to other management pages (like topics, participants) in an ad-hoc manner. A more structured approach was needed.&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== Architecture Decisions ===&lt;br /&gt;
* '''Model-Centric Logic:''' Shifted primary business logic for topic management and team signups into the `ProjectTopic` and `SignedUpTeam` models, respectively. Controllers now primarily handle request/response flow and delegate actions to the models.&lt;br /&gt;
* '''Dedicated Edit Page (Frontend):''' Created a new full page (`AssignmentEditPage`) for editing assignments instead of using a modal, allowing for a more complex, tabbed interface.&lt;br /&gt;
* '''Reusable Table Component (Frontend):''' Developed `TopicsTable` to handle the display and core interactions for topics in different contexts (instructor vs. student), promoting DRY principles.&lt;br /&gt;
* '''API Enhancements:''' Modified the `ProjectTopic` index endpoint (`/api/v1/project_topics`) to accept `assignment_id` and return topics with computed data (`to_json_with_computed_data`), reducing frontend calculation needs. Added specific endpoints for student signup (`sign_up_student`) and dropping topics (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
&lt;br /&gt;
==== Core Functionality Implemented ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Backend Changes !! Frontend Changes&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Renaming''' || Renamed `SignUpTopic` model, controller, routes, DB table to `ProjectTopic`. Updated associations. || Updated API endpoints used.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Management (Instructor)''' || `ProjectTopicsController` CRUD actions delegating to `ProjectTopic` model methods (`create_topic_with_assignment`, `update_topic`, `delete_by_assignment_and_topic_ids`). API returns computed data. || New `AssignmentEditPage` with `TopicsTab`. Uses `TopicsTable` (instructor mode). Modals for create, edit, import, delete. API calls for CRUD.&lt;br /&gt;
|-&lt;br /&gt;
| '''Team Signup Logic''' || `ProjectTopic` methods (`sign_team_up`, `drop_team`, `promote_waitlisted_team`). `SignedUpTeam` methods (`create_signed_up_team`, `remove_team_signups`). || Instructor view shows assigned/waitlisted teams in `TopicsTable` details. Drop team button calls backend.&lt;br /&gt;
|-&lt;br /&gt;
| '''Student Signup/Drop''' || `SignedUpTeamsController` actions (`sign_up_student`, `drop_topic`) delegating to `SignedUpTeam` model methods (`sign_up_student_for_topic`, `drop_topic_for_student`). Automatic handling of switching topics. || New `StudentTasks` page. Uses `TopicsTable` (student mode). Select/deselect buttons trigger API calls. Optimistic UI updates for slots. Displays current selection.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Bookmarking''' || Added `allow_bookmarks` boolean to `Assignment`. Added `project_topic_params` permit `allow_bookmarks` in `AssignmentsController`. || `AssignmentEditPage` allows instructors to toggle `allow_bookmarks` (persisted via PATCH). `StudentTasks` shows bookmark toggle if `allow_bookmarks` is true (local state for now).&lt;br /&gt;
|-&lt;br /&gt;
| '''Assignment Editing UI''' || N/A || New `AssignmentEditPage` with tabbed structure. `AssignmentEditor` might be simplified or removed for general settings.&lt;br /&gt;
|-&lt;br /&gt;
| '''Dependency Updates''' || Updated Ruby, Rails, Puma, Nokogiri etc. Added required gems. || N/A&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Key Backend Improvements =====&lt;br /&gt;
&lt;br /&gt;
==== ProjectTopic Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Handles team signup, considering available slots and waitlisting&lt;br /&gt;
# Renamed from signup_team for clarity&lt;br /&gt;
def sign_team_up(team)&lt;br /&gt;
  return false if signed_up_teams.exists?(team: team)&lt;br /&gt;
  ActiveRecord::Base.transaction do&lt;br /&gt;
    signed_up_team = signed_up_teams.create!(&lt;br /&gt;
      team: team,&lt;br /&gt;
      is_waitlisted: !slot_available?&lt;br /&gt;
    )&lt;br /&gt;
    # Remove team from other waitlists if confirmed here&lt;br /&gt;
    remove_from_waitlist(team) unless signed_up_team.is_waitlisted?&lt;br /&gt;
    true&lt;br /&gt;
  end&lt;br /&gt;
rescue ActiveRecord::RecordInvalid&lt;br /&gt;
  false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Handles dropping a team and promoting waitlisted if necessary&lt;br /&gt;
def drop_team(team)&lt;br /&gt;
  signed_up_team = signed_up_teams.find_by(team: team)&lt;br /&gt;
  return unless signed_up_team&lt;br /&gt;
  team_confirmed = !signed_up_team.is_waitlisted?&lt;br /&gt;
  signed_up_team.destroy!&lt;br /&gt;
  promote_waitlisted_team if team_confirmed # Promote only if a confirmed slot opened&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Calculates available slots&lt;br /&gt;
def available_slots&lt;br /&gt;
  max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Checks if slots are positive&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for creation, moved from controller&lt;br /&gt;
def self.create_topic_with_assignment(topic_params, assignment_id, micropayment = nil)&lt;br /&gt;
  # ... (find assignment, build topic, save, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for update, moved from controller&lt;br /&gt;
def update_topic(topic_params)&lt;br /&gt;
  # ... (update attributes, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Returns enhanced JSON including computed fields&lt;br /&gt;
def to_json_with_computed_data&lt;br /&gt;
  as_json.merge(&lt;br /&gt;
    available_slots: available_slots,&lt;br /&gt;
    confirmed_teams: confirmed_teams.map { |team| # ... format team data },&lt;br /&gt;
    waitlisted_teams: waitlisted_teams.map { |team| # ... format team data }&lt;br /&gt;
  )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
private&lt;br /&gt;
&lt;br /&gt;
# Helper for promotion logic&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
  # ... (find earliest waitlisted team, update is_waitlisted to false, remove from other waitlists)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to remove team from other topics' waitlists&lt;br /&gt;
def remove_from_waitlist(team)&lt;br /&gt;
  team.signed_up_teams.waitlisted.where.not(project_topic_id: id).destroy_all&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SignedUpTeam Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Scope for confirmed signups&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
# Scope for waitlisted signups&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&lt;br /&gt;
belongs_to :project_topic # Updated association&lt;br /&gt;
# ... validations ...&lt;br /&gt;
&lt;br /&gt;
# Business logic for student signup, including dropping previous topic&lt;br /&gt;
def self.sign_up_student_for_topic(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id) # Find student's team&lt;br /&gt;
  return { success: false, message: &amp;quot;User is not part of any team&amp;quot; } unless team_id&lt;br /&gt;
&lt;br /&gt;
  # Drop any existing topic signups for this team FIRST&lt;br /&gt;
  drop_existing_signups_for_team(team_id)&lt;br /&gt;
&lt;br /&gt;
  # Sign up for the new topic using create_signed_up_team (which calls topic.sign_team_up)&lt;br /&gt;
  signed_up_team = create_signed_up_team(topic_id, team_id)&lt;br /&gt;
&lt;br /&gt;
  if signed_up_team&lt;br /&gt;
    { success: true, message: &amp;quot;Signed up team successful!&amp;quot;, signed_up_team: signed_up_team, available_slots: signed_up_team.project_topic.available_slots }&lt;br /&gt;
  else&lt;br /&gt;
    { success: false, message: &amp;quot;Failed to sign up for topic. Topic may be full or already signed up.&amp;quot; }&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for dropping a topic&lt;br /&gt;
def self.drop_topic_for_student(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id)&lt;br /&gt;
  # ... (find topic, team, signed_up_team record) ...&lt;br /&gt;
  return { success: false, message: &amp;quot;Team is not signed up for this topic&amp;quot; } unless signed_up_team&lt;br /&gt;
&lt;br /&gt;
  # Delegate drop logic to ProjectTopic&lt;br /&gt;
  project_topic.drop_team(team)&lt;br /&gt;
&lt;br /&gt;
  { success: true, message: &amp;quot;Successfully dropped topic!&amp;quot;, available_slots: project_topic.available_slots }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to find and drop existing signups before signing up for a new one&lt;br /&gt;
private&lt;br /&gt;
def self.drop_existing_signups_for_team(team_id)&lt;br /&gt;
  existing_signups = where(team_id: team_id)&lt;br /&gt;
  existing_signups.each do |signup|&lt;br /&gt;
    signup.project_topic.drop_team(signup.team) # Use ProjectTopic's drop method&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Frontend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== AssignmentEditPage Component ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
// Manages overall state for assignment editing&lt;br /&gt;
const AssignmentEditPage = () =&amp;gt; {&lt;br /&gt;
  // ... hooks for fetching data (assignment, topics), state for active tab, topic settings, topics data ...&lt;br /&gt;
&lt;br /&gt;
  // Fetch assignment details on load&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (id) fetchAssignment({ url: `/assignments/${id}` });&lt;br /&gt;
  }, [id, fetchAssignment]);&lt;br /&gt;
&lt;br /&gt;
  // Update local state when assignment data is loaded (e.g., name, allow_bookmarks)&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (assignmentResponse?.data) {&lt;br /&gt;
      setAssignmentName(assignmentResponse.data.name || &amp;quot;&amp;quot;);&lt;br /&gt;
      setTopicSettings(prev =&amp;gt; ({ ...prev, allowBookmarks: assignmentResponse.data.allow_bookmarks }));&lt;br /&gt;
    }&lt;br /&gt;
  }, [assignmentResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Fetch topics when assignment ID is known&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (id) fetchTopics({ url: `/project_topics?assignment_id=${id}` });&lt;br /&gt;
  }, [id, fetchTopics]);&lt;br /&gt;
&lt;br /&gt;
  // Process fetched topics into format needed by TopicsTable&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
     if (topicsResponse?.data) {&lt;br /&gt;
       // ... transform backend topic structure to frontend TopicData structure ...&lt;br /&gt;
       setTopicsData(transformedTopics);&lt;br /&gt;
     }&lt;br /&gt;
  }, [topicsResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Handler for topic setting changes (e.g., checkboxes)&lt;br /&gt;
  const handleTopicSettingChange = useCallback((setting: string, value: boolean) =&amp;gt; {&lt;br /&gt;
    setTopicSettings((prev) =&amp;gt; ({ ...prev, [setting]: value }));&lt;br /&gt;
    // Persist allowBookmarks change immediately&lt;br /&gt;
    if (setting === 'allowBookmarks' &amp;amp;&amp;amp; id) {&lt;br /&gt;
      updateAssignment({ /* ... PATCH request data ... */ });&lt;br /&gt;
    }&lt;br /&gt;
  }, [id, updateAssignment]);&lt;br /&gt;
&lt;br /&gt;
  // Handlers for topic CRUD operations (passed down to TopicsTab)&lt;br /&gt;
  const handleDeleteTopic = useCallback((topicId: string) =&amp;gt; {&lt;br /&gt;
    // ... call deleteTopic API ...&lt;br /&gt;
  }, [id, deleteTopic]);&lt;br /&gt;
  // ... other handlers (create, edit, drop team) ...&lt;br /&gt;
&lt;br /&gt;
  // Renders the content based on the active tab state&lt;br /&gt;
  const renderTabContent = () =&amp;gt; {&lt;br /&gt;
    switch (activeTab) {&lt;br /&gt;
      case &amp;quot;topics&amp;quot;:&lt;br /&gt;
        return &amp;lt;TopicsTab /* pass props: settings, data, handlers */ /&amp;gt;;&lt;br /&gt;
      // ... other cases for RubricsTab, DueDatesTab etc. ...&lt;br /&gt;
    }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  return (&lt;br /&gt;
    // ... JSX for layout, tab buttons, calling renderTabContent ...&lt;br /&gt;
  );&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== StudentTasks Component ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
// Page for students to sign up for topics&lt;br /&gt;
const StudentTasks: React.FC = () =&amp;gt; {&lt;br /&gt;
  // ... hooks for fetching (assignments, topics), signing up, dropping ...&lt;br /&gt;
  // ... state for bookmarks, selectedTopic, loading states, optimistic updates ...&lt;br /&gt;
&lt;br /&gt;
  // Fetch assignment and then topics&lt;br /&gt;
  useEffect(() =&amp;gt; { /* ... fetch assignment data ... */ }, [/* dependencies */]);&lt;br /&gt;
  useEffect(() =&amp;gt; { /* ... fetch topics based on assignment id ... */ }, [/* dependencies */]);&lt;br /&gt;
&lt;br /&gt;
  // Process topics data, applying optimistic updates&lt;br /&gt;
  const topics = useMemo(() =&amp;gt; {&lt;br /&gt;
    // ... map topicsResponse.data, check optimisticSlotChanges map ...&lt;br /&gt;
  }, [/* dependencies */]);&lt;br /&gt;
&lt;br /&gt;
  // Check if bookmarks allowed&lt;br /&gt;
  const allowBookmarks = useMemo(() =&amp;gt; {&lt;br /&gt;
     // ... check assignmentResponse.data.allow_bookmarks ...&lt;br /&gt;
  }, [assignmentResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Handle selecting/deselecting a topic&lt;br /&gt;
  const handleTopicSelect = useCallback(async (topicId: string) =&amp;gt; {&lt;br /&gt;
    if (selectedTopic === topicId) { // Deselecting&lt;br /&gt;
      // Optimistically update slots (+1)&lt;br /&gt;
      // Set selectedTopic to null&lt;br /&gt;
      // Call dropAPI&lt;br /&gt;
    } else { // Selecting a new topic&lt;br /&gt;
      // Optimistically update slots (-1 for new, +1 for old if exists)&lt;br /&gt;
      // Call dropAPI for old topic if selectedTopic is not null&lt;br /&gt;
      // Set selectedTopic to topicId&lt;br /&gt;
      // Call signUpAPI&lt;br /&gt;
    }&lt;br /&gt;
  }, [/* dependencies: selectedTopic, currentUser, dropAPI, signUpAPI, topics */]);&lt;br /&gt;
&lt;br /&gt;
  // Handle bookmark toggle (local state)&lt;br /&gt;
  const handleBookmarkToggle = useCallback((topicId: string) =&amp;gt; { /* ... update bookmarkedTopics set ... */ }, []);&lt;br /&gt;
&lt;br /&gt;
  // Prepare data for TopicsTable&lt;br /&gt;
  const topicRows: TopicRow[] = useMemo(() =&amp;gt; topics.map(t =&amp;gt; ({ /* ... map topic data ... */ })), [topics]);&lt;br /&gt;
&lt;br /&gt;
  // ... return JSX ...&lt;br /&gt;
  return (&lt;br /&gt;
    &amp;lt;Container&amp;gt;&lt;br /&gt;
      {/* ... Title, Current Selection display ... */}&lt;br /&gt;
      {topicsLoading ? &amp;lt;Spinner /&amp;gt; : topicsError ? &amp;lt;Alert variant=&amp;quot;danger&amp;quot;&amp;gt;{topicsError}&amp;lt;/Alert&amp;gt; : (&lt;br /&gt;
        &amp;lt;TopicsTable&lt;br /&gt;
          data={topicRows}&lt;br /&gt;
          mode=&amp;quot;student&amp;quot;&lt;br /&gt;
          onBookmarkToggle={handleBookmarkToggle}&lt;br /&gt;
          onSelectTopic={handleTopicSelect}&lt;br /&gt;
          isSigningUp={isSigningUp}&lt;br /&gt;
          selectedTopicId={selectedTopic}&lt;br /&gt;
          showBookmarks={allowBookmarks}&lt;br /&gt;
          // ... other props ...&lt;br /&gt;
        /&amp;gt;&lt;br /&gt;
      )}&lt;br /&gt;
    &amp;lt;/Container&amp;gt;&lt;br /&gt;
  );&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Database Migrations ====&lt;br /&gt;
* Renamed `sign_up_topics` table to `project_topics`.&lt;br /&gt;
* Updated `signed_up_teams` table: renamed `sign_up_topic_id` foreign key to `project_topic_id` and updated index name.&lt;br /&gt;
* Added `allow_bookmarks` boolean column to `assignments` table.&lt;br /&gt;
* Renamed `teams_users` join table to `teams_participants`.&lt;br /&gt;
&lt;br /&gt;
==== Testing ====&lt;br /&gt;
&lt;br /&gt;
==== RSpec Tests (Backend) ====&lt;br /&gt;
* '''ProjectTopic Model (`project_topic_spec.rb`):''' Added extensive tests covering:&lt;br /&gt;
    * `sign_team_up`: Confirmed vs. waitlisted based on `max_choosers`, removal from other waitlists.&lt;br /&gt;
    * `drop_team`: Team removal, promotion of earliest waitlisted team.&lt;br /&gt;
    * `available_slots`, `slot_available?`: Correct calculations before/after signups/drops.&lt;br /&gt;
    * `confirmed_teams`, `waitlisted_teams`: Correct retrieval and ordering.&lt;br /&gt;
    * Validations: Presence of `topic_name`, non-negative `max_choosers` (including zero).&lt;br /&gt;
* '''SignedUpTeam Model (`signed_up_team_spec.rb`):''' Added tests covering:&lt;br /&gt;
    * Validations: Presence of topic/team, uniqueness scope.&lt;br /&gt;
    * Scopes: `:confirmed`, `:waitlisted`.&lt;br /&gt;
    * Class methods: Signup logic delegation, removal logic, participant/topic finding.&lt;br /&gt;
    * Waitlisting behavior when topic is full.&lt;br /&gt;
* '''Updates:''' Modified existing tests (e.g., `due_date_spec.rb`) to reference `ProjectTopic`.&lt;br /&gt;
&lt;br /&gt;
==== Manual Tests (UI) ====&lt;br /&gt;
* '''Instructor Flow:''' Verified assignment editing via `/assignments/edit/:id`, topic creation/editing/deletion/import via modals, toggling `allow_bookmarks`, dropping teams from topics.&lt;br /&gt;
* '''Student Flow:''' Verified topic viewing via `/student_tasks/:assignmentId`, selecting/deselecting topics (including automatic drop of previous), bookmarking (when enabled), correct display of slots and waitlists, disabled selection for full topics.&lt;br /&gt;
&lt;br /&gt;
=== Impact Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Summary of Changes ====&lt;br /&gt;
* '''Backend:''' Major refactoring of topic-related models and controllers, database schema changes, new API endpoints, updated dependencies. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily models, controllers, specs, migrations).&lt;br /&gt;
* '''Frontend:''' New assignment editing page with tabbed UI, new student task page for topic signup, reusable `TopicsTable` component, new routes. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily in `src/pages/Assignments`, `src/pages/StudentTasks`, `src/components`).&lt;br /&gt;
&lt;br /&gt;
==== Achievements ====&lt;br /&gt;
* ✓ Successfully refactored `SignUpTopic` to `ProjectTopic` for improved clarity.&lt;br /&gt;
* ✓ Centralized business logic in models, resulting in cleaner controllers.&lt;br /&gt;
* ✓ Implemented a modern, tabbed interface for assignment editing.&lt;br /&gt;
* ✓ Created a dedicated, streamlined UI for student topic signup.&lt;br /&gt;
* ✓ Added topic bookmarking functionality.&lt;br /&gt;
* ✓ Enhanced API endpoints for better data provision to the frontend.&lt;br /&gt;
* ✓ Updated key dependencies (Rails 8).&lt;br /&gt;
* ✓ Added comprehensive RSpec tests for new model logic.&lt;br /&gt;
&lt;br /&gt;
=== Future Work ===&lt;br /&gt;
* '''Frontend Bookmark Persistence:''' Implement API calls to save/load student topic bookmarks instead of using local state.&lt;br /&gt;
* '''Partner Ad Feature:''' Fully implement the &amp;quot;Apply to partner ad&amp;quot; functionality hinted at in `TopicsTab`.&lt;br /&gt;
* '''Complete Assignment Tabs:''' Implement the remaining tabs in `AssignmentEditPage` (Rubrics, Review Strategy, Due Dates, Etc.).&lt;br /&gt;
* '''Refine General Tab/AssignmentEditor:''' Decide whether general assignment settings remain in `AssignmentEditor` modal or move entirely to a &amp;quot;General&amp;quot; tab within `AssignmentEditPage`.&lt;br /&gt;
* '''Error Handling (Frontend):''' Enhance user feedback for API errors during topic operations (create/edit/delete/signup/drop).&lt;br /&gt;
* '''Authorization Checks:''' Ensure robust authorization checks are in place for all new/modified backend endpoints.&lt;br /&gt;
&lt;br /&gt;
=== Conclusion ===&lt;br /&gt;
This project successfully refactored the core topic management and signup system in Expertiza, replacing `SignUpTopic` with `ProjectTopic` and significantly improving the underlying logic by moving it into the models. New frontend interfaces provide a much-improved experience for both instructors managing topics and students signing up for them. The addition of features like topic bookmarking and a streamlined student signup flow enhances usability. The changes establish a more maintainable and understandable codebase for future development.&lt;br /&gt;
&lt;br /&gt;
=== References ===&lt;br /&gt;
# [https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
# [https://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
# [http://wikis.lib.ncsu.edu/index.php/Expertiza Expertiza project documentation wiki]&lt;br /&gt;
# ''(Add links to your specific project fork/PRs if needed)''&lt;br /&gt;
# [https://guides.rubyonrails.org/ Ruby on Rails Guides]&lt;br /&gt;
# [https://react.dev/ React Documentation]&lt;br /&gt;
# [https://relishapp.com/rspec Rspec Documentation]&lt;br /&gt;
&lt;br /&gt;
=== Code Repositories ===&lt;br /&gt;
'''Backend PR:''' ''(Insert Link to Backend PR)''&lt;br /&gt;
'''Frontend PR:''' ''(Insert Link to Frontend PR)''&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166831</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166831"/>
		<updated>2025-10-29T00:58:57Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== E 2552. Refactoring Topics and Enhancing Assignment Management ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
Expertiza is an educational web application created and maintained by the joint efforts of the students and the faculty at NCSU. It’s an open source project developed on Ruby on Rails platform and its code is available on Github. It allows students to review each other’s work and improve their work upon this feedback. The current effort involves reimplementing the application with a Ruby on Rails API backend and a React/Typescript frontend&lt;br /&gt;
&lt;br /&gt;
==== Background ====&lt;br /&gt;
Expertiza utilizes a system for instructors to define topics within assignments, allowing students (often in teams) to sign up for these topics. The previous implementation, centered around the `SignUpTopic` model and associated controllers (`SignUpTopicsController`, `SignedUpTeamsController`), lacked clarity in naming and had business logic distributed across controllers rather than encapsulated within models. Furthermore, the user interface for managing assignment topics by instructors and for students signing up for topics required modernization and improved functionality.&lt;br /&gt;
&lt;br /&gt;
==== Motivation ====&lt;br /&gt;
This project aimed to improve the maintainability, clarity, and functionality of the topic management and signup features within Expertiza. Key motivations included:&lt;br /&gt;
* Renaming core components (`SignUpTopic` -&amp;gt; `ProjectTopic`) to better reflect their purpose.&lt;br /&gt;
* Centralizing business logic within models for better separation of concerns and testability.&lt;br /&gt;
* Creating a more intuitive and feature-rich interface for instructors managing assignment topics.&lt;br /&gt;
* Developing a dedicated and user-friendly interface for students to view, select, and manage their topic signups.&lt;br /&gt;
* Introducing features like bookmarking topics and streamlining the student signup/drop process.&lt;br /&gt;
* Updating dependencies to keep the application current.&lt;br /&gt;
&lt;br /&gt;
==== Tasks Accomplished ====&lt;br /&gt;
* Renamed `SignUpTopic` to `ProjectTopic` throughout the backend (models, controllers, routes, tests, database).&lt;br /&gt;
* Refactored `ProjectTopic` and `SignedUpTeam` models to encapsulate business logic (topic creation/update/deletion, team signup/waitlisting, slot management, student signup/drop).&lt;br /&gt;
* Removed `SignUpTopicsController` and implemented `ProjectTopicsController` using the refactored model logic.&lt;br /&gt;
* Refactored `SignedUpTeamsController` to utilize new model methods and added new actions (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
* Added `allow_bookmarks` attribute to the `Assignment` model and associated backend/frontend logic.&lt;br /&gt;
* Created a new frontend page (`AssignmentEditPage.tsx`) with a tabbed interface for instructors to manage assignments, including a dedicated &amp;quot;Topics&amp;quot; tab.&lt;br /&gt;
* Implemented modals for creating, editing, importing, and deleting topics on the frontend.&lt;br /&gt;
* Developed a reusable `TopicsTable.tsx` component for displaying topics in instructor and student views.&lt;br /&gt;
* Created a new frontend page (`StudentTasks.tsx`) for students to view assignment topics, bookmark (if enabled), and sign up/drop topics.&lt;br /&gt;
* Updated backend dependencies (Rails, Puma, Nokogiri, etc.) and Docker configuration.&lt;br /&gt;
* Added/updated RSpec tests for `ProjectTopic` and `SignedUpTeam` models and updated relevant existing tests.&lt;br /&gt;
* Updated Swagger API documentation.&lt;br /&gt;
&lt;br /&gt;
==== Files ====&lt;br /&gt;
'''New Backend Files Created:'''&lt;br /&gt;
* `app/controllers/project_topics_controller.rb`&lt;br /&gt;
* `app/models/project_topic.rb`&lt;br /&gt;
* `db/migrate/20250319015434_rename_sign_up_topics_to_project_topics.rb`&lt;br /&gt;
* `db/migrate/20250321222753_rename_sign_up_topic_to_project_topic_in_signed_up_teams.rb`&lt;br /&gt;
* `db/migrate/20251028200538_add_allow_bookmarks_to_assignments.rb`&lt;br /&gt;
* `spec/factories/project_topics.rb`&lt;br /&gt;
* `spec/models/project_topic_spec.rb`&lt;br /&gt;
* `spec/models/signed_up_team_spec.rb`&lt;br /&gt;
* `spec/routing/project_topics_routing_spec.rb`&lt;br /&gt;
&lt;br /&gt;
'''Modified Backend Files:'''&lt;br /&gt;
* `.ruby-version`, `Gemfile`, `Gemfile.lock`&lt;br /&gt;
* `app/controllers/assignments_controller.rb`&lt;br /&gt;
* `app/controllers/signed_up_teams_controller.rb`&lt;br /&gt;
* `app/models/assignment.rb`&lt;br /&gt;
* `app/models/bookmark.rb`&lt;br /&gt;
* `app/models/signed_up_team.rb`&lt;br /&gt;
* `app/models/user.rb`&lt;br /&gt;
* `config/routes.rb`&lt;br /&gt;
* `db/migrate/20231129050431_create_sign_up_topics.rb` (Renamed table)&lt;br /&gt;
* `db/schema.rb`&lt;br /&gt;
* `db/seeds.rb`&lt;br /&gt;
* `docker-compose.yml`&lt;br /&gt;
* `spec/factories/assignments.rb`&lt;br /&gt;
* `spec/models/due_date_spec.rb`&lt;br /&gt;
* `spec/rails_helper.rb`&lt;br /&gt;
* `swagger/v1/swagger.yaml`&lt;br /&gt;
&lt;br /&gt;
'''Deleted Backend Files:'''&lt;br /&gt;
* `app/controllers/sign_up_topics_controller.rb`&lt;br /&gt;
* `app/models/sign_up_topic.rb`&lt;br /&gt;
* `spec/routing/sign_up_topics_routing_spec.rb`&lt;br /&gt;
&lt;br /&gt;
'''New Frontend Files Created:'''&lt;br /&gt;
* `public/assets/icons/Check-icon.png`&lt;br /&gt;
* `src/pages/Assignments/AssignmentEditPage.tsx`&lt;br /&gt;
* `src/pages/Assignments/components/TopicsTable.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/DueDatesTab.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/EtcTab.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/GeneralTab.tsx` (Note: This might be redundant if general editing stays in AssignmentEditor)&lt;br /&gt;
* `src/pages/Assignments/tabs/ReviewStrategyTab.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/RubricsTab.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/TopicsTab.tsx`&lt;br /&gt;
* `src/pages/StudentTasks/StudentTasks.tsx`&lt;br /&gt;
&lt;br /&gt;
'''Modified Frontend Files:'''&lt;br /&gt;
* `src/App.tsx` (Routing changes)&lt;br /&gt;
* `src/components/Table/Table.tsx` (Added selected row styling)&lt;br /&gt;
* `src/hooks/useAPI.ts` (Minor adjustment to isLoading)&lt;br /&gt;
* `src/layout/Header.tsx` (Conditional assignments link for students)&lt;br /&gt;
* `src/pages/Assignments/Assignment.tsx` (Adjusted to accommodate new edit page link)&lt;br /&gt;
* `src/pages/Assignments/AssignmentEditor.tsx` (Potentially simplified if general settings move to GeneralTab)&lt;br /&gt;
&lt;br /&gt;
=== Problem Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Issues with Previous Implementation ====&lt;br /&gt;
&lt;br /&gt;
==== Naming Convention ====&lt;br /&gt;
The name `SignUpTopic` was ambiguous. Renaming to `ProjectTopic` clarifies that these are topics related to the core project/assignment work students sign up for.&lt;br /&gt;
&lt;br /&gt;
==== Distributed Business Logic ====&lt;br /&gt;
Logic for creating topics, signing up teams, managing waitlists, and checking slots was spread across `SignUpTopicsController` and `SignedUpTeamsController`. This violated the principle of &amp;quot;fat model, skinny controller&amp;quot;, making the code harder to understand, test, and maintain.&lt;br /&gt;
&lt;br /&gt;
==== Inefficient Data Fetching ====&lt;br /&gt;
Frontend components often needed to make multiple API calls or perform calculations (like available slots) that could be handled more efficiently on the backend. The previous `SignUpTopic` API didn't provide computed data like assigned/waitlisted teams directly.&lt;br /&gt;
&lt;br /&gt;
==== Lack of Dedicated Student View ====&lt;br /&gt;
Students lacked a clear, dedicated interface to view available topics for an assignment and manage their selection. The signup process was not streamlined.&lt;br /&gt;
&lt;br /&gt;
==== Inconsistent Assignment Editing ====&lt;br /&gt;
The existing `AssignmentEditor` modal combined general settings with links to other management pages (like topics, participants) in an ad-hoc manner. A more structured approach was needed.&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== Architecture Decisions ===&lt;br /&gt;
* '''Model-Centric Logic:''' Shifted primary business logic for topic management and team signups into the `ProjectTopic` and `SignedUpTeam` models, respectively. Controllers now primarily handle request/response flow and delegate actions to the models.&lt;br /&gt;
* '''Dedicated Edit Page (Frontend):''' Created a new full page (`AssignmentEditPage`) for editing assignments instead of using a modal, allowing for a more complex, tabbed interface.&lt;br /&gt;
* '''Reusable Table Component (Frontend):''' Developed `TopicsTable` to handle the display and core interactions for topics in different contexts (instructor vs. student), promoting DRY principles.&lt;br /&gt;
* '''API Enhancements:''' Modified the `ProjectTopic` index endpoint (`/api/v1/project_topics`) to accept `assignment_id` and return topics with computed data (`to_json_with_computed_data`), reducing frontend calculation needs. Added specific endpoints for student signup (`sign_up_student`) and dropping topics (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
&lt;br /&gt;
==== Core Functionality Implemented ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Backend Changes !! Frontend Changes&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Renaming''' || Renamed `SignUpTopic` model, controller, routes, DB table to `ProjectTopic`. Updated associations. || Updated API endpoints used.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Management (Instructor)''' || `ProjectTopicsController` CRUD actions delegating to `ProjectTopic` model methods (`create_topic_with_assignment`, `update_topic`, `delete_by_assignment_and_topic_ids`). API returns computed data. || New `AssignmentEditPage` with `TopicsTab`. Uses `TopicsTable` (instructor mode). Modals for create, edit, import, delete. API calls for CRUD.&lt;br /&gt;
|-&lt;br /&gt;
| '''Team Signup Logic''' || `ProjectTopic` methods (`sign_team_up`, `drop_team`, `promote_waitlisted_team`). `SignedUpTeam` methods (`create_signed_up_team`, `remove_team_signups`). || Instructor view shows assigned/waitlisted teams in `TopicsTable` details. Drop team button calls backend.&lt;br /&gt;
|-&lt;br /&gt;
| '''Student Signup/Drop''' || `SignedUpTeamsController` actions (`sign_up_student`, `drop_topic`) delegating to `SignedUpTeam` model methods (`sign_up_student_for_topic`, `drop_topic_for_student`). Automatic handling of switching topics. || New `StudentTasks` page. Uses `TopicsTable` (student mode). Select/deselect buttons trigger API calls. Optimistic UI updates for slots. Displays current selection.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Bookmarking''' || Added `allow_bookmarks` boolean to `Assignment`. Added `project_topic_params` permit `allow_bookmarks` in `AssignmentsController`. || `AssignmentEditPage` allows instructors to toggle `allow_bookmarks` (persisted via PATCH). `StudentTasks` shows bookmark toggle if `allow_bookmarks` is true (local state for now).&lt;br /&gt;
|-&lt;br /&gt;
| '''Assignment Editing UI''' || N/A || New `AssignmentEditPage` with tabbed structure. `AssignmentEditor` might be simplified or removed for general settings.&lt;br /&gt;
|-&lt;br /&gt;
| '''Dependency Updates''' || Updated Ruby, Rails, Puma, Nokogiri etc. Added required gems. || N/A&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Key Backend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== ProjectTopic Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Handles team signup, considering available slots and waitlisting&lt;br /&gt;
# Renamed from signup_team for clarity&lt;br /&gt;
def sign_team_up(team)&lt;br /&gt;
  return false if signed_up_teams.exists?(team: team)&lt;br /&gt;
  ActiveRecord::Base.transaction do&lt;br /&gt;
    signed_up_team = signed_up_teams.create!(&lt;br /&gt;
      team: team,&lt;br /&gt;
      is_waitlisted: !slot_available?&lt;br /&gt;
    )&lt;br /&gt;
    # Remove team from other waitlists if confirmed here&lt;br /&gt;
    remove_from_waitlist(team) unless signed_up_team.is_waitlisted?&lt;br /&gt;
    true&lt;br /&gt;
  end&lt;br /&gt;
rescue ActiveRecord::RecordInvalid&lt;br /&gt;
  false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Handles dropping a team and promoting waitlisted if necessary&lt;br /&gt;
def drop_team(team)&lt;br /&gt;
  signed_up_team = signed_up_teams.find_by(team: team)&lt;br /&gt;
  return unless signed_up_team&lt;br /&gt;
  team_confirmed = !signed_up_team.is_waitlisted?&lt;br /&gt;
  signed_up_team.destroy!&lt;br /&gt;
  promote_waitlisted_team if team_confirmed # Promote only if a confirmed slot opened&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Calculates available slots&lt;br /&gt;
def available_slots&lt;br /&gt;
  max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Checks if slots are positive&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for creation, moved from controller&lt;br /&gt;
def self.create_topic_with_assignment(topic_params, assignment_id, micropayment = nil)&lt;br /&gt;
  # ... (find assignment, build topic, save, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for update, moved from controller&lt;br /&gt;
def update_topic(topic_params)&lt;br /&gt;
  # ... (update attributes, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Returns enhanced JSON including computed fields&lt;br /&gt;
def to_json_with_computed_data&lt;br /&gt;
  as_json.merge(&lt;br /&gt;
    available_slots: available_slots,&lt;br /&gt;
    confirmed_teams: confirmed_teams.map { |team| # ... format team data },&lt;br /&gt;
    waitlisted_teams: waitlisted_teams.map { |team| # ... format team data }&lt;br /&gt;
  )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
private&lt;br /&gt;
&lt;br /&gt;
# Helper for promotion logic&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
  # ... (find earliest waitlisted team, update is_waitlisted to false, remove from other waitlists)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to remove team from other topics' waitlists&lt;br /&gt;
def remove_from_waitlist(team)&lt;br /&gt;
  team.signed_up_teams.waitlisted.where.not(project_topic_id: id).destroy_all&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SignedUpTeam Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Scope for confirmed signups&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
# Scope for waitlisted signups&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&lt;br /&gt;
belongs_to :project_topic # Updated association&lt;br /&gt;
# ... validations ...&lt;br /&gt;
&lt;br /&gt;
# Business logic for student signup, including dropping previous topic&lt;br /&gt;
def self.sign_up_student_for_topic(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id) # Find student's team&lt;br /&gt;
  return { success: false, message: &amp;quot;User is not part of any team&amp;quot; } unless team_id&lt;br /&gt;
&lt;br /&gt;
  # Drop any existing topic signups for this team FIRST&lt;br /&gt;
  drop_existing_signups_for_team(team_id)&lt;br /&gt;
&lt;br /&gt;
  # Sign up for the new topic using create_signed_up_team (which calls topic.sign_team_up)&lt;br /&gt;
  signed_up_team = create_signed_up_team(topic_id, team_id)&lt;br /&gt;
&lt;br /&gt;
  if signed_up_team&lt;br /&gt;
    { success: true, message: &amp;quot;Signed up team successful!&amp;quot;, signed_up_team: signed_up_team, available_slots: signed_up_team.project_topic.available_slots }&lt;br /&gt;
  else&lt;br /&gt;
    { success: false, message: &amp;quot;Failed to sign up for topic. Topic may be full or already signed up.&amp;quot; }&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for dropping a topic&lt;br /&gt;
def self.drop_topic_for_student(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id)&lt;br /&gt;
  # ... (find topic, team, signed_up_team record) ...&lt;br /&gt;
  return { success: false, message: &amp;quot;Team is not signed up for this topic&amp;quot; } unless signed_up_team&lt;br /&gt;
&lt;br /&gt;
  # Delegate drop logic to ProjectTopic&lt;br /&gt;
  project_topic.drop_team(team)&lt;br /&gt;
&lt;br /&gt;
  { success: true, message: &amp;quot;Successfully dropped topic!&amp;quot;, available_slots: project_topic.available_slots }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to find and drop existing signups before signing up for a new one&lt;br /&gt;
private&lt;br /&gt;
def self.drop_existing_signups_for_team(team_id)&lt;br /&gt;
  existing_signups = where(team_id: team_id)&lt;br /&gt;
  existing_signups.each do |signup|&lt;br /&gt;
    signup.project_topic.drop_team(signup.team) # Use ProjectTopic's drop method&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Frontend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== AssignmentEditPage Component ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
// Manages overall state for assignment editing&lt;br /&gt;
const AssignmentEditPage = () =&amp;gt; {&lt;br /&gt;
  // ... hooks for fetching data (assignment, topics), state for active tab, topic settings, topics data ...&lt;br /&gt;
&lt;br /&gt;
  // Fetch assignment details on load&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (id) fetchAssignment({ url: `/assignments/${id}` });&lt;br /&gt;
  }, [id, fetchAssignment]);&lt;br /&gt;
&lt;br /&gt;
  // Update local state when assignment data is loaded (e.g., name, allow_bookmarks)&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (assignmentResponse?.data) {&lt;br /&gt;
      setAssignmentName(assignmentResponse.data.name || &amp;quot;&amp;quot;);&lt;br /&gt;
      setTopicSettings(prev =&amp;gt; ({ ...prev, allowBookmarks: assignmentResponse.data.allow_bookmarks }));&lt;br /&gt;
    }&lt;br /&gt;
  }, [assignmentResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Fetch topics when assignment ID is known&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (id) fetchTopics({ url: `/project_topics?assignment_id=${id}` });&lt;br /&gt;
  }, [id, fetchTopics]);&lt;br /&gt;
&lt;br /&gt;
  // Process fetched topics into format needed by TopicsTable&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
     if (topicsResponse?.data) {&lt;br /&gt;
       // ... transform backend topic structure to frontend TopicData structure ...&lt;br /&gt;
       setTopicsData(transformedTopics);&lt;br /&gt;
     }&lt;br /&gt;
  }, [topicsResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Handler for topic setting changes (e.g., checkboxes)&lt;br /&gt;
  const handleTopicSettingChange = useCallback((setting: string, value: boolean) =&amp;gt; {&lt;br /&gt;
    setTopicSettings((prev) =&amp;gt; ({ ...prev, [setting]: value }));&lt;br /&gt;
    // Persist allowBookmarks change immediately&lt;br /&gt;
    if (setting === 'allowBookmarks' &amp;amp;&amp;amp; id) {&lt;br /&gt;
      updateAssignment({ /* ... PATCH request data ... */ });&lt;br /&gt;
    }&lt;br /&gt;
  }, [id, updateAssignment]);&lt;br /&gt;
&lt;br /&gt;
  // Handlers for topic CRUD operations (passed down to TopicsTab)&lt;br /&gt;
  const handleDeleteTopic = useCallback((topicId: string) =&amp;gt; {&lt;br /&gt;
    // ... call deleteTopic API ...&lt;br /&gt;
  }, [id, deleteTopic]);&lt;br /&gt;
  // ... other handlers (create, edit, drop team) ...&lt;br /&gt;
&lt;br /&gt;
  // Renders the content based on the active tab state&lt;br /&gt;
  const renderTabContent = () =&amp;gt; {&lt;br /&gt;
    switch (activeTab) {&lt;br /&gt;
      case &amp;quot;topics&amp;quot;:&lt;br /&gt;
        return &amp;lt;TopicsTab /* pass props: settings, data, handlers */ /&amp;gt;;&lt;br /&gt;
      // ... other cases for RubricsTab, DueDatesTab etc. ...&lt;br /&gt;
    }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  return (&lt;br /&gt;
    // ... JSX for layout, tab buttons, calling renderTabContent ...&lt;br /&gt;
  );&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== StudentTasks Component ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
// Page for students to sign up for topics&lt;br /&gt;
const StudentTasks: React.FC = () =&amp;gt; {&lt;br /&gt;
  // ... hooks for fetching (assignments, topics), signing up, dropping ...&lt;br /&gt;
  // ... state for bookmarks, selectedTopic, loading states, optimistic updates ...&lt;br /&gt;
&lt;br /&gt;
  // Fetch assignment and then topics&lt;br /&gt;
  useEffect(() =&amp;gt; { /* ... fetch assignment data ... */ }, [/* dependencies */]);&lt;br /&gt;
  useEffect(() =&amp;gt; { /* ... fetch topics based on assignment id ... */ }, [/* dependencies */]);&lt;br /&gt;
&lt;br /&gt;
  // Process topics data, applying optimistic updates&lt;br /&gt;
  const topics = useMemo(() =&amp;gt; {&lt;br /&gt;
    // ... map topicsResponse.data, check optimisticSlotChanges map ...&lt;br /&gt;
  }, [/* dependencies */]);&lt;br /&gt;
&lt;br /&gt;
  // Check if bookmarks allowed&lt;br /&gt;
  const allowBookmarks = useMemo(() =&amp;gt; {&lt;br /&gt;
     // ... check assignmentResponse.data.allow_bookmarks ...&lt;br /&gt;
  }, [assignmentResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Handle selecting/deselecting a topic&lt;br /&gt;
  const handleTopicSelect = useCallback(async (topicId: string) =&amp;gt; {&lt;br /&gt;
    if (selectedTopic === topicId) { // Deselecting&lt;br /&gt;
      // Optimistically update slots (+1)&lt;br /&gt;
      // Set selectedTopic to null&lt;br /&gt;
      // Call dropAPI&lt;br /&gt;
    } else { // Selecting a new topic&lt;br /&gt;
      // Optimistically update slots (-1 for new, +1 for old if exists)&lt;br /&gt;
      // Call dropAPI for old topic if selectedTopic is not null&lt;br /&gt;
      // Set selectedTopic to topicId&lt;br /&gt;
      // Call signUpAPI&lt;br /&gt;
    }&lt;br /&gt;
  }, [/* dependencies: selectedTopic, currentUser, dropAPI, signUpAPI, topics */]);&lt;br /&gt;
&lt;br /&gt;
  // Handle bookmark toggle (local state)&lt;br /&gt;
  const handleBookmarkToggle = useCallback((topicId: string) =&amp;gt; { /* ... update bookmarkedTopics set ... */ }, []);&lt;br /&gt;
&lt;br /&gt;
  // Prepare data for TopicsTable&lt;br /&gt;
  const topicRows: TopicRow[] = useMemo(() =&amp;gt; topics.map(t =&amp;gt; ({ /* ... map topic data ... */ })), [topics]);&lt;br /&gt;
&lt;br /&gt;
  // ... return JSX ...&lt;br /&gt;
  return (&lt;br /&gt;
    &amp;lt;Container&amp;gt;&lt;br /&gt;
      {/* ... Title, Current Selection display ... */}&lt;br /&gt;
      {topicsLoading ? &amp;lt;Spinner /&amp;gt; : topicsError ? &amp;lt;Alert variant=&amp;quot;danger&amp;quot;&amp;gt;{topicsError}&amp;lt;/Alert&amp;gt; : (&lt;br /&gt;
        &amp;lt;TopicsTable&lt;br /&gt;
          data={topicRows}&lt;br /&gt;
          mode=&amp;quot;student&amp;quot;&lt;br /&gt;
          onBookmarkToggle={handleBookmarkToggle}&lt;br /&gt;
          onSelectTopic={handleTopicSelect}&lt;br /&gt;
          isSigningUp={isSigningUp}&lt;br /&gt;
          selectedTopicId={selectedTopic}&lt;br /&gt;
          showBookmarks={allowBookmarks}&lt;br /&gt;
          // ... other props ...&lt;br /&gt;
        /&amp;gt;&lt;br /&gt;
      )}&lt;br /&gt;
    &amp;lt;/Container&amp;gt;&lt;br /&gt;
  );&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Database Migrations ====&lt;br /&gt;
* Renamed `sign_up_topics` table to `project_topics`.&lt;br /&gt;
* Updated `signed_up_teams` table: renamed `sign_up_topic_id` foreign key to `project_topic_id` and updated index name.&lt;br /&gt;
* Added `allow_bookmarks` boolean column to `assignments` table.&lt;br /&gt;
* Renamed `teams_users` join table to `teams_participants`.&lt;br /&gt;
&lt;br /&gt;
==== Testing ====&lt;br /&gt;
&lt;br /&gt;
==== RSpec Tests (Backend) ====&lt;br /&gt;
* '''ProjectTopic Model (`project_topic_spec.rb`):''' Added extensive tests covering:&lt;br /&gt;
    * `sign_team_up`: Confirmed vs. waitlisted based on `max_choosers`, removal from other waitlists.&lt;br /&gt;
    * `drop_team`: Team removal, promotion of earliest waitlisted team.&lt;br /&gt;
    * `available_slots`, `slot_available?`: Correct calculations before/after signups/drops.&lt;br /&gt;
    * `confirmed_teams`, `waitlisted_teams`: Correct retrieval and ordering.&lt;br /&gt;
    * Validations: Presence of `topic_name`, non-negative `max_choosers` (including zero).&lt;br /&gt;
* '''SignedUpTeam Model (`signed_up_team_spec.rb`):''' Added tests covering:&lt;br /&gt;
    * Validations: Presence of topic/team, uniqueness scope.&lt;br /&gt;
    * Scopes: `:confirmed`, `:waitlisted`.&lt;br /&gt;
    * Class methods: Signup logic delegation, removal logic, participant/topic finding.&lt;br /&gt;
    * Waitlisting behavior when topic is full.&lt;br /&gt;
* '''Updates:''' Modified existing tests (e.g., `due_date_spec.rb`) to reference `ProjectTopic`.&lt;br /&gt;
&lt;br /&gt;
==== Manual Tests (UI) ====&lt;br /&gt;
* '''Instructor Flow:''' Verified assignment editing via `/assignments/edit/:id`, topic creation/editing/deletion/import via modals, toggling `allow_bookmarks`, dropping teams from topics.&lt;br /&gt;
* '''Student Flow:''' Verified topic viewing via `/student_tasks/:assignmentId`, selecting/deselecting topics (including automatic drop of previous), bookmarking (when enabled), correct display of slots and waitlists, disabled selection for full topics.&lt;br /&gt;
&lt;br /&gt;
=== Impact Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Summary of Changes ====&lt;br /&gt;
* '''Backend:''' Major refactoring of topic-related models and controllers, database schema changes, new API endpoints, updated dependencies. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily models, controllers, specs, migrations).&lt;br /&gt;
* '''Frontend:''' New assignment editing page with tabbed UI, new student task page for topic signup, reusable `TopicsTable` component, new routes. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily in `src/pages/Assignments`, `src/pages/StudentTasks`, `src/components`).&lt;br /&gt;
&lt;br /&gt;
==== Achievements ====&lt;br /&gt;
* ✓ Successfully refactored `SignUpTopic` to `ProjectTopic` for improved clarity.&lt;br /&gt;
* ✓ Centralized business logic in models, resulting in cleaner controllers.&lt;br /&gt;
* ✓ Implemented a modern, tabbed interface for assignment editing.&lt;br /&gt;
* ✓ Created a dedicated, streamlined UI for student topic signup.&lt;br /&gt;
* ✓ Added topic bookmarking functionality.&lt;br /&gt;
* ✓ Enhanced API endpoints for better data provision to the frontend.&lt;br /&gt;
* ✓ Updated key dependencies (Rails 8).&lt;br /&gt;
* ✓ Added comprehensive RSpec tests for new model logic.&lt;br /&gt;
&lt;br /&gt;
=== Future Work ===&lt;br /&gt;
* '''Frontend Bookmark Persistence:''' Implement API calls to save/load student topic bookmarks instead of using local state.&lt;br /&gt;
* '''Partner Ad Feature:''' Fully implement the &amp;quot;Apply to partner ad&amp;quot; functionality hinted at in `TopicsTab`.&lt;br /&gt;
* '''Complete Assignment Tabs:''' Implement the remaining tabs in `AssignmentEditPage` (Rubrics, Review Strategy, Due Dates, Etc.).&lt;br /&gt;
* '''Refine General Tab/AssignmentEditor:''' Decide whether general assignment settings remain in `AssignmentEditor` modal or move entirely to a &amp;quot;General&amp;quot; tab within `AssignmentEditPage`.&lt;br /&gt;
* '''Error Handling (Frontend):''' Enhance user feedback for API errors during topic operations (create/edit/delete/signup/drop).&lt;br /&gt;
* '''Authorization Checks:''' Ensure robust authorization checks are in place for all new/modified backend endpoints.&lt;br /&gt;
&lt;br /&gt;
=== Conclusion ===&lt;br /&gt;
This project successfully refactored the core topic management and signup system in Expertiza, replacing `SignUpTopic` with `ProjectTopic` and significantly improving the underlying logic by moving it into the models. New frontend interfaces provide a much-improved experience for both instructors managing topics and students signing up for them. The addition of features like topic bookmarking and a streamlined student signup flow enhances usability. The changes establish a more maintainable and understandable codebase for future development.&lt;br /&gt;
&lt;br /&gt;
=== References ===&lt;br /&gt;
# [https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
# [https://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
# [http://wikis.lib.ncsu.edu/index.php/Expertiza Expertiza project documentation wiki]&lt;br /&gt;
# ''(Add links to your specific project fork/PRs if needed)''&lt;br /&gt;
# [https://guides.rubyonrails.org/ Ruby on Rails Guides]&lt;br /&gt;
# [https://react.dev/ React Documentation]&lt;br /&gt;
# [https://relishapp.com/rspec Rspec Documentation]&lt;br /&gt;
&lt;br /&gt;
=== Code Repositories ===&lt;br /&gt;
'''Backend PR:''' ''(Insert Link to Backend PR)''&lt;br /&gt;
'''Frontend PR:''' ''(Insert Link to Frontend PR)''&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166830</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166830"/>
		<updated>2025-10-29T00:58:02Z</updated>

		<summary type="html">&lt;p&gt;Dananth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== E 2552. Refactoring Topics and Enhancing Assignment Management ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
==== Background ====&lt;br /&gt;
Expertiza utilizes a system for instructors to define topics within assignments, allowing students (often in teams) to sign up for these topics. The previous implementation, centered around the `SignUpTopic` model and associated controllers (`SignUpTopicsController`, `SignedUpTeamsController`), lacked clarity in naming and had business logic distributed across controllers rather than encapsulated within models. Furthermore, the user interface for managing assignment topics by instructors and for students signing up for topics required modernization and improved functionality.&lt;br /&gt;
&lt;br /&gt;
==== Motivation ====&lt;br /&gt;
This project aimed to improve the maintainability, clarity, and functionality of the topic management and signup features within Expertiza. Key motivations included:&lt;br /&gt;
* Renaming core components (`SignUpTopic` -&amp;gt; `ProjectTopic`) to better reflect their purpose.&lt;br /&gt;
* Centralizing business logic within models for better separation of concerns and testability.&lt;br /&gt;
* Creating a more intuitive and feature-rich interface for instructors managing assignment topics.&lt;br /&gt;
* Developing a dedicated and user-friendly interface for students to view, select, and manage their topic signups.&lt;br /&gt;
* Introducing features like bookmarking topics and streamlining the student signup/drop process.&lt;br /&gt;
* Updating dependencies to keep the application current.&lt;br /&gt;
&lt;br /&gt;
==== Tasks Accomplished ====&lt;br /&gt;
* Renamed `SignUpTopic` to `ProjectTopic` throughout the backend (models, controllers, routes, tests, database).&lt;br /&gt;
* Refactored `ProjectTopic` and `SignedUpTeam` models to encapsulate business logic (topic creation/update/deletion, team signup/waitlisting, slot management, student signup/drop).&lt;br /&gt;
* Removed `SignUpTopicsController` and implemented `ProjectTopicsController` using the refactored model logic.&lt;br /&gt;
* Refactored `SignedUpTeamsController` to utilize new model methods and added new actions (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
* Added `allow_bookmarks` attribute to the `Assignment` model and associated backend/frontend logic.&lt;br /&gt;
* Created a new frontend page (`AssignmentEditPage.tsx`) with a tabbed interface for instructors to manage assignments, including a dedicated &amp;quot;Topics&amp;quot; tab.&lt;br /&gt;
* Implemented modals for creating, editing, importing, and deleting topics on the frontend.&lt;br /&gt;
* Developed a reusable `TopicsTable.tsx` component for displaying topics in instructor and student views.&lt;br /&gt;
* Created a new frontend page (`StudentTasks.tsx`) for students to view assignment topics, bookmark (if enabled), and sign up/drop topics.&lt;br /&gt;
* Updated backend dependencies (Rails, Puma, Nokogiri, etc.) and Docker configuration.&lt;br /&gt;
* Added/updated RSpec tests for `ProjectTopic` and `SignedUpTeam` models and updated relevant existing tests.&lt;br /&gt;
* Updated Swagger API documentation.&lt;br /&gt;
&lt;br /&gt;
==== Files ====&lt;br /&gt;
'''New Backend Files Created:'''&lt;br /&gt;
* `app/controllers/project_topics_controller.rb`&lt;br /&gt;
* `app/models/project_topic.rb`&lt;br /&gt;
* `db/migrate/20250319015434_rename_sign_up_topics_to_project_topics.rb`&lt;br /&gt;
* `db/migrate/20250321222753_rename_sign_up_topic_to_project_topic_in_signed_up_teams.rb`&lt;br /&gt;
* `db/migrate/20251028200538_add_allow_bookmarks_to_assignments.rb`&lt;br /&gt;
* `spec/factories/project_topics.rb`&lt;br /&gt;
* `spec/models/project_topic_spec.rb`&lt;br /&gt;
* `spec/models/signed_up_team_spec.rb`&lt;br /&gt;
* `spec/routing/project_topics_routing_spec.rb`&lt;br /&gt;
&lt;br /&gt;
'''Modified Backend Files:'''&lt;br /&gt;
* `.ruby-version`, `Gemfile`, `Gemfile.lock`&lt;br /&gt;
* `app/controllers/assignments_controller.rb`&lt;br /&gt;
* `app/controllers/signed_up_teams_controller.rb`&lt;br /&gt;
* `app/models/assignment.rb`&lt;br /&gt;
* `app/models/bookmark.rb`&lt;br /&gt;
* `app/models/signed_up_team.rb`&lt;br /&gt;
* `app/models/user.rb`&lt;br /&gt;
* `config/routes.rb`&lt;br /&gt;
* `db/migrate/20231129050431_create_sign_up_topics.rb` (Renamed table)&lt;br /&gt;
* `db/schema.rb`&lt;br /&gt;
* `db/seeds.rb`&lt;br /&gt;
* `docker-compose.yml`&lt;br /&gt;
* `spec/factories/assignments.rb`&lt;br /&gt;
* `spec/models/due_date_spec.rb`&lt;br /&gt;
* `spec/rails_helper.rb`&lt;br /&gt;
* `swagger/v1/swagger.yaml`&lt;br /&gt;
&lt;br /&gt;
'''Deleted Backend Files:'''&lt;br /&gt;
* `app/controllers/sign_up_topics_controller.rb`&lt;br /&gt;
* `app/models/sign_up_topic.rb`&lt;br /&gt;
* `spec/routing/sign_up_topics_routing_spec.rb`&lt;br /&gt;
&lt;br /&gt;
'''New Frontend Files Created:'''&lt;br /&gt;
* `public/assets/icons/Check-icon.png`&lt;br /&gt;
* `src/pages/Assignments/AssignmentEditPage.tsx`&lt;br /&gt;
* `src/pages/Assignments/components/TopicsTable.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/DueDatesTab.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/EtcTab.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/GeneralTab.tsx` (Note: This might be redundant if general editing stays in AssignmentEditor)&lt;br /&gt;
* `src/pages/Assignments/tabs/ReviewStrategyTab.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/RubricsTab.tsx`&lt;br /&gt;
* `src/pages/Assignments/tabs/TopicsTab.tsx`&lt;br /&gt;
* `src/pages/StudentTasks/StudentTasks.tsx`&lt;br /&gt;
&lt;br /&gt;
'''Modified Frontend Files:'''&lt;br /&gt;
* `src/App.tsx` (Routing changes)&lt;br /&gt;
* `src/components/Table/Table.tsx` (Added selected row styling)&lt;br /&gt;
* `src/hooks/useAPI.ts` (Minor adjustment to isLoading)&lt;br /&gt;
* `src/layout/Header.tsx` (Conditional assignments link for students)&lt;br /&gt;
* `src/pages/Assignments/Assignment.tsx` (Adjusted to accommodate new edit page link)&lt;br /&gt;
* `src/pages/Assignments/AssignmentEditor.tsx` (Potentially simplified if general settings move to GeneralTab)&lt;br /&gt;
&lt;br /&gt;
=== Problem Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Issues with Previous Implementation ====&lt;br /&gt;
&lt;br /&gt;
==== Naming Convention ====&lt;br /&gt;
The name `SignUpTopic` was ambiguous. Renaming to `ProjectTopic` clarifies that these are topics related to the core project/assignment work students sign up for.&lt;br /&gt;
&lt;br /&gt;
==== Distributed Business Logic ====&lt;br /&gt;
Logic for creating topics, signing up teams, managing waitlists, and checking slots was spread across `SignUpTopicsController` and `SignedUpTeamsController`. This violated the principle of &amp;quot;fat model, skinny controller&amp;quot;, making the code harder to understand, test, and maintain.&lt;br /&gt;
&lt;br /&gt;
==== Inefficient Data Fetching ====&lt;br /&gt;
Frontend components often needed to make multiple API calls or perform calculations (like available slots) that could be handled more efficiently on the backend. The previous `SignUpTopic` API didn't provide computed data like assigned/waitlisted teams directly.&lt;br /&gt;
&lt;br /&gt;
==== Lack of Dedicated Student View ====&lt;br /&gt;
Students lacked a clear, dedicated interface to view available topics for an assignment and manage their selection. The signup process was not streamlined.&lt;br /&gt;
&lt;br /&gt;
==== Inconsistent Assignment Editing ====&lt;br /&gt;
The existing `AssignmentEditor` modal combined general settings with links to other management pages (like topics, participants) in an ad-hoc manner. A more structured approach was needed.&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== Architecture Decisions ===&lt;br /&gt;
* '''Model-Centric Logic:''' Shifted primary business logic for topic management and team signups into the `ProjectTopic` and `SignedUpTeam` models, respectively. Controllers now primarily handle request/response flow and delegate actions to the models.&lt;br /&gt;
* '''Dedicated Edit Page (Frontend):''' Created a new full page (`AssignmentEditPage`) for editing assignments instead of using a modal, allowing for a more complex, tabbed interface.&lt;br /&gt;
* '''Reusable Table Component (Frontend):''' Developed `TopicsTable` to handle the display and core interactions for topics in different contexts (instructor vs. student), promoting DRY principles.&lt;br /&gt;
* '''API Enhancements:''' Modified the `ProjectTopic` index endpoint (`/api/v1/project_topics`) to accept `assignment_id` and return topics with computed data (`to_json_with_computed_data`), reducing frontend calculation needs. Added specific endpoints for student signup (`sign_up_student`) and dropping topics (`drop_topic`, `drop_team_from_topic`).&lt;br /&gt;
&lt;br /&gt;
==== Core Functionality Implemented ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Backend Changes !! Frontend Changes&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Renaming''' || Renamed `SignUpTopic` model, controller, routes, DB table to `ProjectTopic`. Updated associations. || Updated API endpoints used.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Management (Instructor)''' || `ProjectTopicsController` CRUD actions delegating to `ProjectTopic` model methods (`create_topic_with_assignment`, `update_topic`, `delete_by_assignment_and_topic_ids`). API returns computed data. || New `AssignmentEditPage` with `TopicsTab`. Uses `TopicsTable` (instructor mode). Modals for create, edit, import, delete. API calls for CRUD.&lt;br /&gt;
|-&lt;br /&gt;
| '''Team Signup Logic''' || `ProjectTopic` methods (`sign_team_up`, `drop_team`, `promote_waitlisted_team`). `SignedUpTeam` methods (`create_signed_up_team`, `remove_team_signups`). || Instructor view shows assigned/waitlisted teams in `TopicsTable` details. Drop team button calls backend.&lt;br /&gt;
|-&lt;br /&gt;
| '''Student Signup/Drop''' || `SignedUpTeamsController` actions (`sign_up_student`, `drop_topic`) delegating to `SignedUpTeam` model methods (`sign_up_student_for_topic`, `drop_topic_for_student`). Automatic handling of switching topics. || New `StudentTasks` page. Uses `TopicsTable` (student mode). Select/deselect buttons trigger API calls. Optimistic UI updates for slots. Displays current selection.&lt;br /&gt;
|-&lt;br /&gt;
| '''Topic Bookmarking''' || Added `allow_bookmarks` boolean to `Assignment`. Added `project_topic_params` permit `allow_bookmarks` in `AssignmentsController`. || `AssignmentEditPage` allows instructors to toggle `allow_bookmarks` (persisted via PATCH). `StudentTasks` shows bookmark toggle if `allow_bookmarks` is true (local state for now).&lt;br /&gt;
|-&lt;br /&gt;
| '''Assignment Editing UI''' || N/A || New `AssignmentEditPage` with tabbed structure. `AssignmentEditor` might be simplified or removed for general settings.&lt;br /&gt;
|-&lt;br /&gt;
| '''Dependency Updates''' || Updated Ruby, Rails, Puma, Nokogiri etc. Added required gems. || N/A&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Key Backend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== ProjectTopic Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Handles team signup, considering available slots and waitlisting&lt;br /&gt;
# Renamed from signup_team for clarity&lt;br /&gt;
def sign_team_up(team)&lt;br /&gt;
  return false if signed_up_teams.exists?(team: team)&lt;br /&gt;
  ActiveRecord::Base.transaction do&lt;br /&gt;
    signed_up_team = signed_up_teams.create!(&lt;br /&gt;
      team: team,&lt;br /&gt;
      is_waitlisted: !slot_available?&lt;br /&gt;
    )&lt;br /&gt;
    # Remove team from other waitlists if confirmed here&lt;br /&gt;
    remove_from_waitlist(team) unless signed_up_team.is_waitlisted?&lt;br /&gt;
    true&lt;br /&gt;
  end&lt;br /&gt;
rescue ActiveRecord::RecordInvalid&lt;br /&gt;
  false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Handles dropping a team and promoting waitlisted if necessary&lt;br /&gt;
def drop_team(team)&lt;br /&gt;
  signed_up_team = signed_up_teams.find_by(team: team)&lt;br /&gt;
  return unless signed_up_team&lt;br /&gt;
  team_confirmed = !signed_up_team.is_waitlisted?&lt;br /&gt;
  signed_up_team.destroy!&lt;br /&gt;
  promote_waitlisted_team if team_confirmed # Promote only if a confirmed slot opened&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Calculates available slots&lt;br /&gt;
def available_slots&lt;br /&gt;
  max_choosers - confirmed_teams_count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Checks if slots are positive&lt;br /&gt;
def slot_available?&lt;br /&gt;
  available_slots.positive?&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for creation, moved from controller&lt;br /&gt;
def self.create_topic_with_assignment(topic_params, assignment_id, micropayment = nil)&lt;br /&gt;
  # ... (find assignment, build topic, save, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for update, moved from controller&lt;br /&gt;
def update_topic(topic_params)&lt;br /&gt;
  # ... (update attributes, return hash { success:, message:, topic:/errors: })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Returns enhanced JSON including computed fields&lt;br /&gt;
def to_json_with_computed_data&lt;br /&gt;
  as_json.merge(&lt;br /&gt;
    available_slots: available_slots,&lt;br /&gt;
    confirmed_teams: confirmed_teams.map { |team| # ... format team data },&lt;br /&gt;
    waitlisted_teams: waitlisted_teams.map { |team| # ... format team data }&lt;br /&gt;
  )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
private&lt;br /&gt;
&lt;br /&gt;
# Helper for promotion logic&lt;br /&gt;
def promote_waitlisted_team&lt;br /&gt;
  # ... (find earliest waitlisted team, update is_waitlisted to false, remove from other waitlists)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to remove team from other topics' waitlists&lt;br /&gt;
def remove_from_waitlist(team)&lt;br /&gt;
  team.signed_up_teams.waitlisted.where.not(project_topic_id: id).destroy_all&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SignedUpTeam Model ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
# Scope for confirmed signups&lt;br /&gt;
scope :confirmed, -&amp;gt; { where(is_waitlisted: false) }&lt;br /&gt;
# Scope for waitlisted signups&lt;br /&gt;
scope :waitlisted, -&amp;gt; { where(is_waitlisted: true) }&lt;br /&gt;
&lt;br /&gt;
belongs_to :project_topic # Updated association&lt;br /&gt;
# ... validations ...&lt;br /&gt;
&lt;br /&gt;
# Business logic for student signup, including dropping previous topic&lt;br /&gt;
def self.sign_up_student_for_topic(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id) # Find student's team&lt;br /&gt;
  return { success: false, message: &amp;quot;User is not part of any team&amp;quot; } unless team_id&lt;br /&gt;
&lt;br /&gt;
  # Drop any existing topic signups for this team FIRST&lt;br /&gt;
  drop_existing_signups_for_team(team_id)&lt;br /&gt;
&lt;br /&gt;
  # Sign up for the new topic using create_signed_up_team (which calls topic.sign_team_up)&lt;br /&gt;
  signed_up_team = create_signed_up_team(topic_id, team_id)&lt;br /&gt;
&lt;br /&gt;
  if signed_up_team&lt;br /&gt;
    { success: true, message: &amp;quot;Signed up team successful!&amp;quot;, signed_up_team: signed_up_team, available_slots: signed_up_team.project_topic.available_slots }&lt;br /&gt;
  else&lt;br /&gt;
    { success: false, message: &amp;quot;Failed to sign up for topic. Topic may be full or already signed up.&amp;quot; }&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Business logic for dropping a topic&lt;br /&gt;
def self.drop_topic_for_student(user_id, topic_id)&lt;br /&gt;
  team_id = get_team_participants(user_id)&lt;br /&gt;
  # ... (find topic, team, signed_up_team record) ...&lt;br /&gt;
  return { success: false, message: &amp;quot;Team is not signed up for this topic&amp;quot; } unless signed_up_team&lt;br /&gt;
&lt;br /&gt;
  # Delegate drop logic to ProjectTopic&lt;br /&gt;
  project_topic.drop_team(team)&lt;br /&gt;
&lt;br /&gt;
  { success: true, message: &amp;quot;Successfully dropped topic!&amp;quot;, available_slots: project_topic.available_slots }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# Helper to find and drop existing signups before signing up for a new one&lt;br /&gt;
private&lt;br /&gt;
def self.drop_existing_signups_for_team(team_id)&lt;br /&gt;
  existing_signups = where(team_id: team_id)&lt;br /&gt;
  existing_signups.each do |signup|&lt;br /&gt;
    signup.project_topic.drop_team(signup.team) # Use ProjectTopic's drop method&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Frontend Improvements ====&lt;br /&gt;
&lt;br /&gt;
==== AssignmentEditPage Component ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
// Manages overall state for assignment editing&lt;br /&gt;
const AssignmentEditPage = () =&amp;gt; {&lt;br /&gt;
  // ... hooks for fetching data (assignment, topics), state for active tab, topic settings, topics data ...&lt;br /&gt;
&lt;br /&gt;
  // Fetch assignment details on load&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (id) fetchAssignment({ url: `/assignments/${id}` });&lt;br /&gt;
  }, [id, fetchAssignment]);&lt;br /&gt;
&lt;br /&gt;
  // Update local state when assignment data is loaded (e.g., name, allow_bookmarks)&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (assignmentResponse?.data) {&lt;br /&gt;
      setAssignmentName(assignmentResponse.data.name || &amp;quot;&amp;quot;);&lt;br /&gt;
      setTopicSettings(prev =&amp;gt; ({ ...prev, allowBookmarks: assignmentResponse.data.allow_bookmarks }));&lt;br /&gt;
    }&lt;br /&gt;
  }, [assignmentResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Fetch topics when assignment ID is known&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
    if (id) fetchTopics({ url: `/project_topics?assignment_id=${id}` });&lt;br /&gt;
  }, [id, fetchTopics]);&lt;br /&gt;
&lt;br /&gt;
  // Process fetched topics into format needed by TopicsTable&lt;br /&gt;
  useEffect(() =&amp;gt; {&lt;br /&gt;
     if (topicsResponse?.data) {&lt;br /&gt;
       // ... transform backend topic structure to frontend TopicData structure ...&lt;br /&gt;
       setTopicsData(transformedTopics);&lt;br /&gt;
     }&lt;br /&gt;
  }, [topicsResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Handler for topic setting changes (e.g., checkboxes)&lt;br /&gt;
  const handleTopicSettingChange = useCallback((setting: string, value: boolean) =&amp;gt; {&lt;br /&gt;
    setTopicSettings((prev) =&amp;gt; ({ ...prev, [setting]: value }));&lt;br /&gt;
    // Persist allowBookmarks change immediately&lt;br /&gt;
    if (setting === 'allowBookmarks' &amp;amp;&amp;amp; id) {&lt;br /&gt;
      updateAssignment({ /* ... PATCH request data ... */ });&lt;br /&gt;
    }&lt;br /&gt;
  }, [id, updateAssignment]);&lt;br /&gt;
&lt;br /&gt;
  // Handlers for topic CRUD operations (passed down to TopicsTab)&lt;br /&gt;
  const handleDeleteTopic = useCallback((topicId: string) =&amp;gt; {&lt;br /&gt;
    // ... call deleteTopic API ...&lt;br /&gt;
  }, [id, deleteTopic]);&lt;br /&gt;
  // ... other handlers (create, edit, drop team) ...&lt;br /&gt;
&lt;br /&gt;
  // Renders the content based on the active tab state&lt;br /&gt;
  const renderTabContent = () =&amp;gt; {&lt;br /&gt;
    switch (activeTab) {&lt;br /&gt;
      case &amp;quot;topics&amp;quot;:&lt;br /&gt;
        return &amp;lt;TopicsTab /* pass props: settings, data, handlers */ /&amp;gt;;&lt;br /&gt;
      // ... other cases for RubricsTab, DueDatesTab etc. ...&lt;br /&gt;
    }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  return (&lt;br /&gt;
    // ... JSX for layout, tab buttons, calling renderTabContent ...&lt;br /&gt;
  );&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== StudentTasks Component ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
// Page for students to sign up for topics&lt;br /&gt;
const StudentTasks: React.FC = () =&amp;gt; {&lt;br /&gt;
  // ... hooks for fetching (assignments, topics), signing up, dropping ...&lt;br /&gt;
  // ... state for bookmarks, selectedTopic, loading states, optimistic updates ...&lt;br /&gt;
&lt;br /&gt;
  // Fetch assignment and then topics&lt;br /&gt;
  useEffect(() =&amp;gt; { /* ... fetch assignment data ... */ }, [/* dependencies */]);&lt;br /&gt;
  useEffect(() =&amp;gt; { /* ... fetch topics based on assignment id ... */ }, [/* dependencies */]);&lt;br /&gt;
&lt;br /&gt;
  // Process topics data, applying optimistic updates&lt;br /&gt;
  const topics = useMemo(() =&amp;gt; {&lt;br /&gt;
    // ... map topicsResponse.data, check optimisticSlotChanges map ...&lt;br /&gt;
  }, [/* dependencies */]);&lt;br /&gt;
&lt;br /&gt;
  // Check if bookmarks allowed&lt;br /&gt;
  const allowBookmarks = useMemo(() =&amp;gt; {&lt;br /&gt;
     // ... check assignmentResponse.data.allow_bookmarks ...&lt;br /&gt;
  }, [assignmentResponse]);&lt;br /&gt;
&lt;br /&gt;
  // Handle selecting/deselecting a topic&lt;br /&gt;
  const handleTopicSelect = useCallback(async (topicId: string) =&amp;gt; {&lt;br /&gt;
    if (selectedTopic === topicId) { // Deselecting&lt;br /&gt;
      // Optimistically update slots (+1)&lt;br /&gt;
      // Set selectedTopic to null&lt;br /&gt;
      // Call dropAPI&lt;br /&gt;
    } else { // Selecting a new topic&lt;br /&gt;
      // Optimistically update slots (-1 for new, +1 for old if exists)&lt;br /&gt;
      // Call dropAPI for old topic if selectedTopic is not null&lt;br /&gt;
      // Set selectedTopic to topicId&lt;br /&gt;
      // Call signUpAPI&lt;br /&gt;
    }&lt;br /&gt;
  }, [/* dependencies: selectedTopic, currentUser, dropAPI, signUpAPI, topics */]);&lt;br /&gt;
&lt;br /&gt;
  // Handle bookmark toggle (local state)&lt;br /&gt;
  const handleBookmarkToggle = useCallback((topicId: string) =&amp;gt; { /* ... update bookmarkedTopics set ... */ }, []);&lt;br /&gt;
&lt;br /&gt;
  // Prepare data for TopicsTable&lt;br /&gt;
  const topicRows: TopicRow[] = useMemo(() =&amp;gt; topics.map(t =&amp;gt; ({ /* ... map topic data ... */ })), [topics]);&lt;br /&gt;
&lt;br /&gt;
  // ... return JSX ...&lt;br /&gt;
  return (&lt;br /&gt;
    &amp;lt;Container&amp;gt;&lt;br /&gt;
      {/* ... Title, Current Selection display ... */}&lt;br /&gt;
      {topicsLoading ? &amp;lt;Spinner /&amp;gt; : topicsError ? &amp;lt;Alert variant=&amp;quot;danger&amp;quot;&amp;gt;{topicsError}&amp;lt;/Alert&amp;gt; : (&lt;br /&gt;
        &amp;lt;TopicsTable&lt;br /&gt;
          data={topicRows}&lt;br /&gt;
          mode=&amp;quot;student&amp;quot;&lt;br /&gt;
          onBookmarkToggle={handleBookmarkToggle}&lt;br /&gt;
          onSelectTopic={handleTopicSelect}&lt;br /&gt;
          isSigningUp={isSigningUp}&lt;br /&gt;
          selectedTopicId={selectedTopic}&lt;br /&gt;
          showBookmarks={allowBookmarks}&lt;br /&gt;
          // ... other props ...&lt;br /&gt;
        /&amp;gt;&lt;br /&gt;
      )}&lt;br /&gt;
    &amp;lt;/Container&amp;gt;&lt;br /&gt;
  );&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Database Migrations ====&lt;br /&gt;
* Renamed `sign_up_topics` table to `project_topics`.&lt;br /&gt;
* Updated `signed_up_teams` table: renamed `sign_up_topic_id` foreign key to `project_topic_id` and updated index name.&lt;br /&gt;
* Added `allow_bookmarks` boolean column to `assignments` table.&lt;br /&gt;
* Renamed `teams_users` join table to `teams_participants`.&lt;br /&gt;
&lt;br /&gt;
==== Testing ====&lt;br /&gt;
&lt;br /&gt;
==== RSpec Tests (Backend) ====&lt;br /&gt;
* '''ProjectTopic Model (`project_topic_spec.rb`):''' Added extensive tests covering:&lt;br /&gt;
    * `sign_team_up`: Confirmed vs. waitlisted based on `max_choosers`, removal from other waitlists.&lt;br /&gt;
    * `drop_team`: Team removal, promotion of earliest waitlisted team.&lt;br /&gt;
    * `available_slots`, `slot_available?`: Correct calculations before/after signups/drops.&lt;br /&gt;
    * `confirmed_teams`, `waitlisted_teams`: Correct retrieval and ordering.&lt;br /&gt;
    * Validations: Presence of `topic_name`, non-negative `max_choosers` (including zero).&lt;br /&gt;
* '''SignedUpTeam Model (`signed_up_team_spec.rb`):''' Added tests covering:&lt;br /&gt;
    * Validations: Presence of topic/team, uniqueness scope.&lt;br /&gt;
    * Scopes: `:confirmed`, `:waitlisted`.&lt;br /&gt;
    * Class methods: Signup logic delegation, removal logic, participant/topic finding.&lt;br /&gt;
    * Waitlisting behavior when topic is full.&lt;br /&gt;
* '''Updates:''' Modified existing tests (e.g., `due_date_spec.rb`) to reference `ProjectTopic`.&lt;br /&gt;
&lt;br /&gt;
==== Manual Tests (UI) ====&lt;br /&gt;
* '''Instructor Flow:''' Verified assignment editing via `/assignments/edit/:id`, topic creation/editing/deletion/import via modals, toggling `allow_bookmarks`, dropping teams from topics.&lt;br /&gt;
* '''Student Flow:''' Verified topic viewing via `/student_tasks/:assignmentId`, selecting/deselecting topics (including automatic drop of previous), bookmarking (when enabled), correct display of slots and waitlists, disabled selection for full topics.&lt;br /&gt;
&lt;br /&gt;
=== Impact Analysis ===&lt;br /&gt;
&lt;br /&gt;
==== Summary of Changes ====&lt;br /&gt;
* '''Backend:''' Major refactoring of topic-related models and controllers, database schema changes, new API endpoints, updated dependencies. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily models, controllers, specs, migrations).&lt;br /&gt;
* '''Frontend:''' New assignment editing page with tabbed UI, new student task page for topic signup, reusable `TopicsTable` component, new routes. Approximately [Count Lines] lines added/modified across [Count Files] files (primarily in `src/pages/Assignments`, `src/pages/StudentTasks`, `src/components`).&lt;br /&gt;
&lt;br /&gt;
==== Achievements ====&lt;br /&gt;
* ✓ Successfully refactored `SignUpTopic` to `ProjectTopic` for improved clarity.&lt;br /&gt;
* ✓ Centralized business logic in models, resulting in cleaner controllers.&lt;br /&gt;
* ✓ Implemented a modern, tabbed interface for assignment editing.&lt;br /&gt;
* ✓ Created a dedicated, streamlined UI for student topic signup.&lt;br /&gt;
* ✓ Added topic bookmarking functionality.&lt;br /&gt;
* ✓ Enhanced API endpoints for better data provision to the frontend.&lt;br /&gt;
* ✓ Updated key dependencies (Rails 8).&lt;br /&gt;
* ✓ Added comprehensive RSpec tests for new model logic.&lt;br /&gt;
&lt;br /&gt;
=== Future Work ===&lt;br /&gt;
* '''Frontend Bookmark Persistence:''' Implement API calls to save/load student topic bookmarks instead of using local state.&lt;br /&gt;
* '''Partner Ad Feature:''' Fully implement the &amp;quot;Apply to partner ad&amp;quot; functionality hinted at in `TopicsTab`.&lt;br /&gt;
* '''Complete Assignment Tabs:''' Implement the remaining tabs in `AssignmentEditPage` (Rubrics, Review Strategy, Due Dates, Etc.).&lt;br /&gt;
* '''Refine General Tab/AssignmentEditor:''' Decide whether general assignment settings remain in `AssignmentEditor` modal or move entirely to a &amp;quot;General&amp;quot; tab within `AssignmentEditPage`.&lt;br /&gt;
* '''Error Handling (Frontend):''' Enhance user feedback for API errors during topic operations (create/edit/delete/signup/drop).&lt;br /&gt;
* '''Authorization Checks:''' Ensure robust authorization checks are in place for all new/modified backend endpoints.&lt;br /&gt;
&lt;br /&gt;
=== Conclusion ===&lt;br /&gt;
This project successfully refactored the core topic management and signup system in Expertiza, replacing `SignUpTopic` with `ProjectTopic` and significantly improving the underlying logic by moving it into the models. New frontend interfaces provide a much-improved experience for both instructors managing topics and students signing up for them. The addition of features like topic bookmarking and a streamlined student signup flow enhances usability. The changes establish a more maintainable and understandable codebase for future development.&lt;br /&gt;
&lt;br /&gt;
=== References ===&lt;br /&gt;
# [https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
# [https://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
# [http://wikis.lib.ncsu.edu/index.php/Expertiza Expertiza project documentation wiki]&lt;br /&gt;
# ''(Add links to your specific project fork/PRs if needed)''&lt;br /&gt;
# [https://guides.rubyonrails.org/ Ruby on Rails Guides]&lt;br /&gt;
# [https://react.dev/ React Documentation]&lt;br /&gt;
# [https://relishapp.com/rspec Rspec Documentation]&lt;br /&gt;
&lt;br /&gt;
=== Code Repositories ===&lt;br /&gt;
'''Backend PR:''' ''(Insert Link to Backend PR)''&lt;br /&gt;
'''Frontend PR:''' ''(Insert Link to Frontend PR)''&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166829</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166829"/>
		<updated>2025-10-29T00:55:46Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* Peer Review Information */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This wiki page describes the changes made for the '''E2552 OSS assignment''' in Fall 2025 for CSC/ECE 517.&lt;br /&gt;
&lt;br /&gt;
== About Expertiza ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an educational web application created and maintained by the joint efforts of the students and the faculty at NCSU. It’s an open source project developed on Ruby on Rails platform and its code is available on Github. It allows students to review each other’s work and improve their work upon this feedback. The current effort involves reimplementing the application with a Ruby on Rails API backend and a React/Typescript frontend.&lt;br /&gt;
&lt;br /&gt;
== Description of the current project (E2552) ==&lt;br /&gt;
&lt;br /&gt;
This project focuses on the reimplementation of the '''Project Topic''' and '''Signed Up Team''' functionalities within Expertiza. In Expertiza, assignments can require students or teams to choose a topic. The &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; class (originally &amp;lt;code&amp;gt;SignUpTopic&amp;lt;/code&amp;gt;) manages these topics, and when a team selects one, a &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; object is created to link the team and the topic.&lt;br /&gt;
&lt;br /&gt;
This project involved integrating and refining backend code previously developed (but not merged) in project E2513 and implementing the corresponding frontend interface for both instructors and students. The backend work included renaming classes and methods based on prior feedback, improving code structure using ActiveRecord features, optimizing logic, and adding validations. The frontend work involved creating new UI components in React/Typescript to manage and display topics, handle topic selection/signup, and provide distinct views for instructors and students, closely mirroring the existing Expertiza interface.&lt;br /&gt;
&lt;br /&gt;
== Files modified/created in current project ==&lt;br /&gt;
&lt;br /&gt;
'''Backend (Ruby on Rails API):'''&amp;lt;br/&amp;gt;&lt;br /&gt;
* '''Models:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/project_topic.rb&amp;lt;/code&amp;gt; (Created, replacing &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/signed_up_team.rb&amp;lt;/code&amp;gt; (Modified extensively)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/assignment.rb&amp;lt;/code&amp;gt; (Modified associations)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/bookmark.rb&amp;lt;/code&amp;gt; (Modified association comment)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/user.rb&amp;lt;/code&amp;gt; (Modified associations)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/sign_up_topic.rb&amp;lt;/code&amp;gt; (Deleted)&lt;br /&gt;
* '''Controllers:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/project_topics_controller.rb&amp;lt;/code&amp;gt; (Created, replacing &amp;lt;code&amp;gt;sign_up_topics_controller.rb&amp;lt;/code&amp;gt;)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/signed_up_teams_controller.rb&amp;lt;/code&amp;gt; (Modified extensively)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/assignments_controller.rb&amp;lt;/code&amp;gt; (Modified &amp;lt;code&amp;gt;assignment_params&amp;lt;/code&amp;gt;, comment)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/sign_up_topics_controller.rb&amp;lt;/code&amp;gt; (Deleted)&lt;br /&gt;
* '''Database:'''&lt;br /&gt;
** Migrations created/modified for renaming tables/columns (&amp;lt;code&amp;gt;sign_up_topic&amp;lt;/code&amp;gt; -&amp;gt; &amp;lt;code&amp;gt;project_topic&amp;lt;/code&amp;gt;) and adding &amp;lt;code&amp;gt;allow_bookmarks&amp;lt;/code&amp;gt; to assignments.&lt;br /&gt;
** &amp;lt;code&amp;gt;db/schema.rb&amp;lt;/code&amp;gt; (Updated)&lt;br /&gt;
** &amp;lt;code&amp;gt;db/seeds.rb&amp;lt;/code&amp;gt; (Updated to use &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt;, added test student)&lt;br /&gt;
* '''Configuration:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;config/routes.rb&amp;lt;/code&amp;gt; (Updated for &amp;lt;code&amp;gt;project_topics&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signed_up_teams&amp;lt;/code&amp;gt; endpoints)&lt;br /&gt;
* '''Tests (RSpec):'''&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/models/project_topic_spec.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/models/signed_up_team_spec.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/models/due_date_spec.rb&amp;lt;/code&amp;gt; (Modified)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/routing/project_topics_routing_spec.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/factories/project_topics.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/rails_helper.rb&amp;lt;/code&amp;gt; (Minor configuration change)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/routing/sign_up_topics_routing_spec.rb&amp;lt;/code&amp;gt; (Deleted)&lt;br /&gt;
* '''Dependencies:''' &amp;lt;code&amp;gt;Gemfile&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Gemfile.lock&amp;lt;/code&amp;gt; (Updated versions, added/removed gems)&lt;br /&gt;
* '''Swagger Documentation:''' &amp;lt;code&amp;gt;swagger/v1/swagger.yaml&amp;lt;/code&amp;gt; (Updated paths and definitions)&lt;br /&gt;
* '''Docker:''' &amp;lt;code&amp;gt;docker-compose.yml&amp;lt;/code&amp;gt; (Updated command)&lt;br /&gt;
&lt;br /&gt;
'''Frontend (React/Typescript):'''&amp;lt;br/&amp;gt;&lt;br /&gt;
* '''Pages:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/AssignmentEditPage.tsx&amp;lt;/code&amp;gt; (Created - Main page for editing assignments with tabs)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/tabs/TopicsTab.tsx&amp;lt;/code&amp;gt; (Created - Instructor view for managing topics)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/tabs/RubricsTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ReviewStrategyTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DueDatesTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;EtcTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GeneralTab.tsx&amp;lt;/code&amp;gt; (Created - Placeholder tabs)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/StudentTasks/StudentTasks.tsx&amp;lt;/code&amp;gt; (Created - Student view for signing up for topics)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/Assignment.tsx&amp;lt;/code&amp;gt; (Modified - Integrated new edit page link)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; (Modified - Simplified, as detailed editing moved to &amp;lt;code&amp;gt;AssignmentEditPage&amp;lt;/code&amp;gt;)&lt;br /&gt;
* '''Components:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/components/Table/Table.tsx&amp;lt;/code&amp;gt; (Modified - Added row highlighting for selected topics)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/components/TopicsTable.tsx&amp;lt;/code&amp;gt; (Created - Reusable table component for displaying topics)&lt;br /&gt;
* '''Routing:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/App.tsx&amp;lt;/code&amp;gt; (Modified - Added routes for &amp;lt;code&amp;gt;AssignmentEditPage&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;StudentTasks&amp;lt;/code&amp;gt;)&lt;br /&gt;
* '''Layout:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/layout/Header.tsx&amp;lt;/code&amp;gt; (Modified - Conditionally show Assignments link for students)&lt;br /&gt;
* '''Hooks:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/hooks/useAPI.ts&amp;lt;/code&amp;gt; (Modified - Minor change in &amp;lt;code&amp;gt;then&amp;lt;/code&amp;gt; block)&lt;br /&gt;
* '''Assets:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;public/assets/icons/Check-icon.png&amp;lt;/code&amp;gt; (Added)&lt;br /&gt;
&lt;br /&gt;
== List of changes / Features Implemented ==&lt;br /&gt;
&lt;br /&gt;
Based on the project description and feedback from E2513:&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Backend:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# '''Renamed &amp;lt;code&amp;gt;SignUpTopic&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt;:''' Refactored the model, controller, routes, database table, associations, and tests to use the new naming convention consistently.&lt;br /&gt;
# '''Refactored &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; Logic:''' Moved business logic from the controller into the &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; models, utilizing ActiveRecord features like transactions and scopes. Implemented methods for signing up students/teams, dropping topics, finding participants, and handling waitlists.&lt;br /&gt;
# '''Addressed E2513 Feedback:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
#* Renamed &amp;lt;code&amp;gt;signup_team&amp;lt;/code&amp;gt; method to &amp;lt;code&amp;gt;sign_team_up&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Renamed &amp;lt;code&amp;gt;signup_for_topic&amp;lt;/code&amp;gt; method to &amp;lt;code&amp;gt;sign_up_for_topic&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Addressed DRY violation between &amp;lt;code&amp;gt;find_team_participants&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;find_project_topic_team_users&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Ensured files terminate with a newline.&lt;br /&gt;
# '''Updated &amp;lt;code&amp;gt;Assignment&amp;lt;/code&amp;gt; Model:''' Added &amp;lt;code&amp;gt;allow_bookmarks&amp;lt;/code&amp;gt; attribute and updated associations related to topics.&lt;br /&gt;
# '''API Endpoints:''' Created/updated API endpoints for CRUD operations on &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; and actions related to &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; (signup, drop topic).&lt;br /&gt;
# '''Testing:''' Added comprehensive RSpec tests for &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; models. Updated existing tests (&amp;lt;code&amp;gt;due_date_spec.rb&amp;lt;/code&amp;gt;). Added routing specs.&lt;br /&gt;
&lt;br /&gt;
'''Frontend:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# '''New Assignment Edit Page:''' Created &amp;lt;code&amp;gt;AssignmentEditPage&amp;lt;/code&amp;gt; with a tabbed interface for editing assignments.&lt;br /&gt;
# '''Instructor Topics Tab:''' Implemented &amp;lt;code&amp;gt;TopicsTab&amp;lt;/code&amp;gt; component allowing instructors to:&lt;br /&gt;
#* View/manage topics via &amp;lt;code&amp;gt;TopicsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Configure topic settings (e.g., allow bookmarks).&lt;br /&gt;
#* View assigned/waitlisted teams and drop teams.&lt;br /&gt;
#* Toggle display of user names/IDs.&lt;br /&gt;
#* Create, import, edit, delete topics via modals.&lt;br /&gt;
#* View bookmark counts.&lt;br /&gt;
#* Access Partner Ad functionality (UI added).&lt;br /&gt;
# '''Student Task/Signup Page:''' Created &amp;lt;code&amp;gt;StudentTasks&amp;lt;/code&amp;gt; page allowing students to:&lt;br /&gt;
#* View available topics via &amp;lt;code&amp;gt;TopicsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* See available slots and waitlist numbers.&lt;br /&gt;
#* View their selected topic.&lt;br /&gt;
#* Select/deselect (drop) a topic.&lt;br /&gt;
#* Bookmark topics (if enabled).&lt;br /&gt;
# '''Reusable &amp;lt;code&amp;gt;TopicsTable&amp;lt;/code&amp;gt; Component:''' Developed adaptable table for student/instructor views with row expansion, selection, and custom actions.&lt;br /&gt;
# '''API Integration:''' Connected frontend components to backend API for fetching/updating topics, assignment settings, and handling signups/drops.&lt;br /&gt;
# '''UI Enhancements:''' Added selected topic highlighting, action icons, and modals for various operations.&lt;br /&gt;
&lt;br /&gt;
== Testing Details==&lt;br /&gt;
&lt;br /&gt;
=== Backend (RSpec) ===&lt;br /&gt;
New spec files (&amp;lt;code&amp;gt;project_topic_spec.rb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;signed_up_team_spec.rb&amp;lt;/code&amp;gt;) were created with extensive test coverage for the core models, including various scenarios like signup, waitlisting, dropping teams, and validations. Existing specs (&amp;lt;code&amp;gt;due_date_spec.rb&amp;lt;/code&amp;gt;) were updated. Routing specs were added. Tests confirmed the refactored code integrates correctly.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Manual testing was performed following scenarios for instructors and students:&lt;br /&gt;
&lt;br /&gt;
'''Instructor UI:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# Login as instructor6.&lt;br /&gt;
# Navigate to an assignment (e.g., &amp;quot;OSS project &amp;amp; documentation&amp;quot;) and click 'Edit'.&lt;br /&gt;
# Go to the 'Topics' tab.&lt;br /&gt;
# '''Verify topic list display:''' Check columns (Checkbox, ID, Name, Questionnaire, Slots, Available, Waitlist, Bookmarks, Actions).&lt;br /&gt;
# '''Verify topic settings:''' Test checkboxes, especially 'Allow participants to create bookmarks?'. Backend save confirmed via API call.&lt;br /&gt;
# '''Test topic actions:'''&lt;br /&gt;
#* Create a new topic via 'New topic' button/modal.&lt;br /&gt;
#* Edit an existing topic via edit icon/modal.&lt;br /&gt;
#* Delete topic(s) via delete icon or selecting checkboxes and using 'Delete selected topics'.&lt;br /&gt;
#* Import topics via 'Import topics' button/modal.&lt;br /&gt;
# Expand a topic row to view assigned/waitlisted teams. Test dropping a team via 'X' icon.&lt;br /&gt;
# Test 'Display User Names' toggle.&lt;br /&gt;
&lt;br /&gt;
'''Student UI:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# Login as teststudent.&lt;br /&gt;
# Navigate to 'Assignments' via header link.&lt;br /&gt;
# Verify signup sheet loads.&lt;br /&gt;
# '''Verify topic list display:''' Check columns (ID, Name, Available Slots, Num. on Waitlist, Bookmarks [if enabled], Actions).&lt;br /&gt;
# '''Test topic selection:''' Click checkmark icon. Verify 'Your topic(s)' updates, row highlights yellow, slots update optimistically, and API call is made.&lt;br /&gt;
# '''Test topic deselection (drop):''' Click 'X' icon on selected topic row. Verify topic is dropped, highlighting removed, slots update, and API call is made.&lt;br /&gt;
# '''Test bookmarking (if enabled):''' Click bookmark icon to toggle status.&lt;br /&gt;
# Verify actions are disabled for full topics (0 available slots).&lt;br /&gt;
&lt;br /&gt;
== Scope for future improvement ==&lt;br /&gt;
# '''Complete Placeholder Tabs:''' Implement functionality for 'Rubrics', 'Review Strategy', 'Due Dates', and 'Etc.' tabs in instructor view.&lt;br /&gt;
# '''Partner Ad Backend:''' Implement backend logic for partner ads and applications.&lt;br /&gt;
# '''Bookmark Implementation:''' Fully implement bookmark creation/viewing functionality.&lt;br /&gt;
# '''Topic Suggestions:''' Implement student topic suggestion feature.&lt;br /&gt;
# '''Bidding Features:''' Implement topic/reviewer bidding.&lt;br /&gt;
# '''Refined UI/UX:''' Enhance UI based on feedback, e.g., team display within rows.&lt;br /&gt;
# '''Automated Frontend Testing:''' Add&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166828</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166828"/>
		<updated>2025-10-29T00:55:36Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* Expertiza Background */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This wiki page describes the changes made for the '''E2552 OSS assignment''' in Fall 2025 for CSC/ECE 517.&lt;br /&gt;
&lt;br /&gt;
== Peer Review Information ==&lt;br /&gt;
&lt;br /&gt;
For users intending to view the deployed Expertiza associated with this assignment, the credentials are below:&lt;br /&gt;
* Instructor login: username -&amp;gt; admin, password -&amp;gt; password123&lt;br /&gt;
* Student login: username -&amp;gt; teststudent, password -&amp;gt; password123&lt;br /&gt;
* ''(Add other relevant student logins if needed)''&lt;br /&gt;
&lt;br /&gt;
== About Expertiza ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an educational web application created and maintained by the joint efforts of the students and the faculty at NCSU. It’s an open source project developed on Ruby on Rails platform and its code is available on Github. It allows students to review each other’s work and improve their work upon this feedback. The current effort involves reimplementing the application with a Ruby on Rails API backend and a React/Typescript frontend.&lt;br /&gt;
&lt;br /&gt;
== Description of the current project (E2552) ==&lt;br /&gt;
&lt;br /&gt;
This project focuses on the reimplementation of the '''Project Topic''' and '''Signed Up Team''' functionalities within Expertiza. In Expertiza, assignments can require students or teams to choose a topic. The &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; class (originally &amp;lt;code&amp;gt;SignUpTopic&amp;lt;/code&amp;gt;) manages these topics, and when a team selects one, a &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; object is created to link the team and the topic.&lt;br /&gt;
&lt;br /&gt;
This project involved integrating and refining backend code previously developed (but not merged) in project E2513 and implementing the corresponding frontend interface for both instructors and students. The backend work included renaming classes and methods based on prior feedback, improving code structure using ActiveRecord features, optimizing logic, and adding validations. The frontend work involved creating new UI components in React/Typescript to manage and display topics, handle topic selection/signup, and provide distinct views for instructors and students, closely mirroring the existing Expertiza interface.&lt;br /&gt;
&lt;br /&gt;
== Files modified/created in current project ==&lt;br /&gt;
&lt;br /&gt;
'''Backend (Ruby on Rails API):'''&amp;lt;br/&amp;gt;&lt;br /&gt;
* '''Models:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/project_topic.rb&amp;lt;/code&amp;gt; (Created, replacing &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/signed_up_team.rb&amp;lt;/code&amp;gt; (Modified extensively)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/assignment.rb&amp;lt;/code&amp;gt; (Modified associations)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/bookmark.rb&amp;lt;/code&amp;gt; (Modified association comment)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/user.rb&amp;lt;/code&amp;gt; (Modified associations)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/sign_up_topic.rb&amp;lt;/code&amp;gt; (Deleted)&lt;br /&gt;
* '''Controllers:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/project_topics_controller.rb&amp;lt;/code&amp;gt; (Created, replacing &amp;lt;code&amp;gt;sign_up_topics_controller.rb&amp;lt;/code&amp;gt;)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/signed_up_teams_controller.rb&amp;lt;/code&amp;gt; (Modified extensively)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/assignments_controller.rb&amp;lt;/code&amp;gt; (Modified &amp;lt;code&amp;gt;assignment_params&amp;lt;/code&amp;gt;, comment)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/sign_up_topics_controller.rb&amp;lt;/code&amp;gt; (Deleted)&lt;br /&gt;
* '''Database:'''&lt;br /&gt;
** Migrations created/modified for renaming tables/columns (&amp;lt;code&amp;gt;sign_up_topic&amp;lt;/code&amp;gt; -&amp;gt; &amp;lt;code&amp;gt;project_topic&amp;lt;/code&amp;gt;) and adding &amp;lt;code&amp;gt;allow_bookmarks&amp;lt;/code&amp;gt; to assignments.&lt;br /&gt;
** &amp;lt;code&amp;gt;db/schema.rb&amp;lt;/code&amp;gt; (Updated)&lt;br /&gt;
** &amp;lt;code&amp;gt;db/seeds.rb&amp;lt;/code&amp;gt; (Updated to use &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt;, added test student)&lt;br /&gt;
* '''Configuration:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;config/routes.rb&amp;lt;/code&amp;gt; (Updated for &amp;lt;code&amp;gt;project_topics&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signed_up_teams&amp;lt;/code&amp;gt; endpoints)&lt;br /&gt;
* '''Tests (RSpec):'''&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/models/project_topic_spec.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/models/signed_up_team_spec.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/models/due_date_spec.rb&amp;lt;/code&amp;gt; (Modified)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/routing/project_topics_routing_spec.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/factories/project_topics.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/rails_helper.rb&amp;lt;/code&amp;gt; (Minor configuration change)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/routing/sign_up_topics_routing_spec.rb&amp;lt;/code&amp;gt; (Deleted)&lt;br /&gt;
* '''Dependencies:''' &amp;lt;code&amp;gt;Gemfile&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Gemfile.lock&amp;lt;/code&amp;gt; (Updated versions, added/removed gems)&lt;br /&gt;
* '''Swagger Documentation:''' &amp;lt;code&amp;gt;swagger/v1/swagger.yaml&amp;lt;/code&amp;gt; (Updated paths and definitions)&lt;br /&gt;
* '''Docker:''' &amp;lt;code&amp;gt;docker-compose.yml&amp;lt;/code&amp;gt; (Updated command)&lt;br /&gt;
&lt;br /&gt;
'''Frontend (React/Typescript):'''&amp;lt;br/&amp;gt;&lt;br /&gt;
* '''Pages:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/AssignmentEditPage.tsx&amp;lt;/code&amp;gt; (Created - Main page for editing assignments with tabs)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/tabs/TopicsTab.tsx&amp;lt;/code&amp;gt; (Created - Instructor view for managing topics)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/tabs/RubricsTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ReviewStrategyTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DueDatesTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;EtcTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GeneralTab.tsx&amp;lt;/code&amp;gt; (Created - Placeholder tabs)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/StudentTasks/StudentTasks.tsx&amp;lt;/code&amp;gt; (Created - Student view for signing up for topics)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/Assignment.tsx&amp;lt;/code&amp;gt; (Modified - Integrated new edit page link)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; (Modified - Simplified, as detailed editing moved to &amp;lt;code&amp;gt;AssignmentEditPage&amp;lt;/code&amp;gt;)&lt;br /&gt;
* '''Components:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/components/Table/Table.tsx&amp;lt;/code&amp;gt; (Modified - Added row highlighting for selected topics)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/components/TopicsTable.tsx&amp;lt;/code&amp;gt; (Created - Reusable table component for displaying topics)&lt;br /&gt;
* '''Routing:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/App.tsx&amp;lt;/code&amp;gt; (Modified - Added routes for &amp;lt;code&amp;gt;AssignmentEditPage&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;StudentTasks&amp;lt;/code&amp;gt;)&lt;br /&gt;
* '''Layout:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/layout/Header.tsx&amp;lt;/code&amp;gt; (Modified - Conditionally show Assignments link for students)&lt;br /&gt;
* '''Hooks:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/hooks/useAPI.ts&amp;lt;/code&amp;gt; (Modified - Minor change in &amp;lt;code&amp;gt;then&amp;lt;/code&amp;gt; block)&lt;br /&gt;
* '''Assets:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;public/assets/icons/Check-icon.png&amp;lt;/code&amp;gt; (Added)&lt;br /&gt;
&lt;br /&gt;
== List of changes / Features Implemented ==&lt;br /&gt;
&lt;br /&gt;
Based on the project description and feedback from E2513:&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Backend:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# '''Renamed &amp;lt;code&amp;gt;SignUpTopic&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt;:''' Refactored the model, controller, routes, database table, associations, and tests to use the new naming convention consistently.&lt;br /&gt;
# '''Refactored &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; Logic:''' Moved business logic from the controller into the &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; models, utilizing ActiveRecord features like transactions and scopes. Implemented methods for signing up students/teams, dropping topics, finding participants, and handling waitlists.&lt;br /&gt;
# '''Addressed E2513 Feedback:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
#* Renamed &amp;lt;code&amp;gt;signup_team&amp;lt;/code&amp;gt; method to &amp;lt;code&amp;gt;sign_team_up&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Renamed &amp;lt;code&amp;gt;signup_for_topic&amp;lt;/code&amp;gt; method to &amp;lt;code&amp;gt;sign_up_for_topic&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Addressed DRY violation between &amp;lt;code&amp;gt;find_team_participants&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;find_project_topic_team_users&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Ensured files terminate with a newline.&lt;br /&gt;
# '''Updated &amp;lt;code&amp;gt;Assignment&amp;lt;/code&amp;gt; Model:''' Added &amp;lt;code&amp;gt;allow_bookmarks&amp;lt;/code&amp;gt; attribute and updated associations related to topics.&lt;br /&gt;
# '''API Endpoints:''' Created/updated API endpoints for CRUD operations on &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; and actions related to &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; (signup, drop topic).&lt;br /&gt;
# '''Testing:''' Added comprehensive RSpec tests for &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; models. Updated existing tests (&amp;lt;code&amp;gt;due_date_spec.rb&amp;lt;/code&amp;gt;). Added routing specs.&lt;br /&gt;
&lt;br /&gt;
'''Frontend:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# '''New Assignment Edit Page:''' Created &amp;lt;code&amp;gt;AssignmentEditPage&amp;lt;/code&amp;gt; with a tabbed interface for editing assignments.&lt;br /&gt;
# '''Instructor Topics Tab:''' Implemented &amp;lt;code&amp;gt;TopicsTab&amp;lt;/code&amp;gt; component allowing instructors to:&lt;br /&gt;
#* View/manage topics via &amp;lt;code&amp;gt;TopicsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Configure topic settings (e.g., allow bookmarks).&lt;br /&gt;
#* View assigned/waitlisted teams and drop teams.&lt;br /&gt;
#* Toggle display of user names/IDs.&lt;br /&gt;
#* Create, import, edit, delete topics via modals.&lt;br /&gt;
#* View bookmark counts.&lt;br /&gt;
#* Access Partner Ad functionality (UI added).&lt;br /&gt;
# '''Student Task/Signup Page:''' Created &amp;lt;code&amp;gt;StudentTasks&amp;lt;/code&amp;gt; page allowing students to:&lt;br /&gt;
#* View available topics via &amp;lt;code&amp;gt;TopicsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* See available slots and waitlist numbers.&lt;br /&gt;
#* View their selected topic.&lt;br /&gt;
#* Select/deselect (drop) a topic.&lt;br /&gt;
#* Bookmark topics (if enabled).&lt;br /&gt;
# '''Reusable &amp;lt;code&amp;gt;TopicsTable&amp;lt;/code&amp;gt; Component:''' Developed adaptable table for student/instructor views with row expansion, selection, and custom actions.&lt;br /&gt;
# '''API Integration:''' Connected frontend components to backend API for fetching/updating topics, assignment settings, and handling signups/drops.&lt;br /&gt;
# '''UI Enhancements:''' Added selected topic highlighting, action icons, and modals for various operations.&lt;br /&gt;
&lt;br /&gt;
== Testing Details==&lt;br /&gt;
&lt;br /&gt;
=== Backend (RSpec) ===&lt;br /&gt;
New spec files (&amp;lt;code&amp;gt;project_topic_spec.rb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;signed_up_team_spec.rb&amp;lt;/code&amp;gt;) were created with extensive test coverage for the core models, including various scenarios like signup, waitlisting, dropping teams, and validations. Existing specs (&amp;lt;code&amp;gt;due_date_spec.rb&amp;lt;/code&amp;gt;) were updated. Routing specs were added. Tests confirmed the refactored code integrates correctly.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Manual testing was performed following scenarios for instructors and students:&lt;br /&gt;
&lt;br /&gt;
'''Instructor UI:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# Login as instructor6.&lt;br /&gt;
# Navigate to an assignment (e.g., &amp;quot;OSS project &amp;amp; documentation&amp;quot;) and click 'Edit'.&lt;br /&gt;
# Go to the 'Topics' tab.&lt;br /&gt;
# '''Verify topic list display:''' Check columns (Checkbox, ID, Name, Questionnaire, Slots, Available, Waitlist, Bookmarks, Actions).&lt;br /&gt;
# '''Verify topic settings:''' Test checkboxes, especially 'Allow participants to create bookmarks?'. Backend save confirmed via API call.&lt;br /&gt;
# '''Test topic actions:'''&lt;br /&gt;
#* Create a new topic via 'New topic' button/modal.&lt;br /&gt;
#* Edit an existing topic via edit icon/modal.&lt;br /&gt;
#* Delete topic(s) via delete icon or selecting checkboxes and using 'Delete selected topics'.&lt;br /&gt;
#* Import topics via 'Import topics' button/modal.&lt;br /&gt;
# Expand a topic row to view assigned/waitlisted teams. Test dropping a team via 'X' icon.&lt;br /&gt;
# Test 'Display User Names' toggle.&lt;br /&gt;
&lt;br /&gt;
'''Student UI:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# Login as teststudent.&lt;br /&gt;
# Navigate to 'Assignments' via header link.&lt;br /&gt;
# Verify signup sheet loads.&lt;br /&gt;
# '''Verify topic list display:''' Check columns (ID, Name, Available Slots, Num. on Waitlist, Bookmarks [if enabled], Actions).&lt;br /&gt;
# '''Test topic selection:''' Click checkmark icon. Verify 'Your topic(s)' updates, row highlights yellow, slots update optimistically, and API call is made.&lt;br /&gt;
# '''Test topic deselection (drop):''' Click 'X' icon on selected topic row. Verify topic is dropped, highlighting removed, slots update, and API call is made.&lt;br /&gt;
# '''Test bookmarking (if enabled):''' Click bookmark icon to toggle status.&lt;br /&gt;
# Verify actions are disabled for full topics (0 available slots).&lt;br /&gt;
&lt;br /&gt;
== Scope for future improvement ==&lt;br /&gt;
# '''Complete Placeholder Tabs:''' Implement functionality for 'Rubrics', 'Review Strategy', 'Due Dates', and 'Etc.' tabs in instructor view.&lt;br /&gt;
# '''Partner Ad Backend:''' Implement backend logic for partner ads and applications.&lt;br /&gt;
# '''Bookmark Implementation:''' Fully implement bookmark creation/viewing functionality.&lt;br /&gt;
# '''Topic Suggestions:''' Implement student topic suggestion feature.&lt;br /&gt;
# '''Bidding Features:''' Implement topic/reviewer bidding.&lt;br /&gt;
# '''Refined UI/UX:''' Enhance UI based on feedback, e.g., team display within rows.&lt;br /&gt;
# '''Automated Frontend Testing:''' Add&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166827</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166827"/>
		<updated>2025-10-29T00:54:20Z</updated>

		<summary type="html">&lt;p&gt;Dananth: /* Peer Review Information */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This wiki page describes the changes made for the '''E2552 OSS assignment''' in Fall 2025 for CSC/ECE 517.&lt;br /&gt;
&lt;br /&gt;
== Peer Review Information ==&lt;br /&gt;
&lt;br /&gt;
For users intending to view the deployed Expertiza associated with this assignment, the credentials are below:&lt;br /&gt;
* Instructor login: username -&amp;gt; admin, password -&amp;gt; password123&lt;br /&gt;
* Student login: username -&amp;gt; teststudent, password -&amp;gt; password123&lt;br /&gt;
* ''(Add other relevant student logins if needed)''&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an educational web application created and maintained by the joint efforts of the students and the faculty at NCSU. It’s an open source project developed on Ruby on Rails platform and its code is available on Github. It allows students to review each other’s work and improve their work upon this feedback. The current effort involves reimplementing the application with a Ruby on Rails API backend and a React/Typescript frontend.&lt;br /&gt;
&lt;br /&gt;
== Description of the current project (E2552) ==&lt;br /&gt;
&lt;br /&gt;
This project focuses on the reimplementation of the '''Project Topic''' and '''Signed Up Team''' functionalities within Expertiza. In Expertiza, assignments can require students or teams to choose a topic. The &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; class (originally &amp;lt;code&amp;gt;SignUpTopic&amp;lt;/code&amp;gt;) manages these topics, and when a team selects one, a &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; object is created to link the team and the topic.&lt;br /&gt;
&lt;br /&gt;
This project involved integrating and refining backend code previously developed (but not merged) in project E2513 and implementing the corresponding frontend interface for both instructors and students. The backend work included renaming classes and methods based on prior feedback, improving code structure using ActiveRecord features, optimizing logic, and adding validations. The frontend work involved creating new UI components in React/Typescript to manage and display topics, handle topic selection/signup, and provide distinct views for instructors and students, closely mirroring the existing Expertiza interface.&lt;br /&gt;
&lt;br /&gt;
== Files modified/created in current project ==&lt;br /&gt;
&lt;br /&gt;
'''Backend (Ruby on Rails API):'''&amp;lt;br/&amp;gt;&lt;br /&gt;
* '''Models:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/project_topic.rb&amp;lt;/code&amp;gt; (Created, replacing &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/signed_up_team.rb&amp;lt;/code&amp;gt; (Modified extensively)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/assignment.rb&amp;lt;/code&amp;gt; (Modified associations)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/bookmark.rb&amp;lt;/code&amp;gt; (Modified association comment)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/user.rb&amp;lt;/code&amp;gt; (Modified associations)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/sign_up_topic.rb&amp;lt;/code&amp;gt; (Deleted)&lt;br /&gt;
* '''Controllers:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/project_topics_controller.rb&amp;lt;/code&amp;gt; (Created, replacing &amp;lt;code&amp;gt;sign_up_topics_controller.rb&amp;lt;/code&amp;gt;)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/signed_up_teams_controller.rb&amp;lt;/code&amp;gt; (Modified extensively)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/assignments_controller.rb&amp;lt;/code&amp;gt; (Modified &amp;lt;code&amp;gt;assignment_params&amp;lt;/code&amp;gt;, comment)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/sign_up_topics_controller.rb&amp;lt;/code&amp;gt; (Deleted)&lt;br /&gt;
* '''Database:'''&lt;br /&gt;
** Migrations created/modified for renaming tables/columns (&amp;lt;code&amp;gt;sign_up_topic&amp;lt;/code&amp;gt; -&amp;gt; &amp;lt;code&amp;gt;project_topic&amp;lt;/code&amp;gt;) and adding &amp;lt;code&amp;gt;allow_bookmarks&amp;lt;/code&amp;gt; to assignments.&lt;br /&gt;
** &amp;lt;code&amp;gt;db/schema.rb&amp;lt;/code&amp;gt; (Updated)&lt;br /&gt;
** &amp;lt;code&amp;gt;db/seeds.rb&amp;lt;/code&amp;gt; (Updated to use &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt;, added test student)&lt;br /&gt;
* '''Configuration:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;config/routes.rb&amp;lt;/code&amp;gt; (Updated for &amp;lt;code&amp;gt;project_topics&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signed_up_teams&amp;lt;/code&amp;gt; endpoints)&lt;br /&gt;
* '''Tests (RSpec):'''&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/models/project_topic_spec.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/models/signed_up_team_spec.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/models/due_date_spec.rb&amp;lt;/code&amp;gt; (Modified)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/routing/project_topics_routing_spec.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/factories/project_topics.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/rails_helper.rb&amp;lt;/code&amp;gt; (Minor configuration change)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/routing/sign_up_topics_routing_spec.rb&amp;lt;/code&amp;gt; (Deleted)&lt;br /&gt;
* '''Dependencies:''' &amp;lt;code&amp;gt;Gemfile&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Gemfile.lock&amp;lt;/code&amp;gt; (Updated versions, added/removed gems)&lt;br /&gt;
* '''Swagger Documentation:''' &amp;lt;code&amp;gt;swagger/v1/swagger.yaml&amp;lt;/code&amp;gt; (Updated paths and definitions)&lt;br /&gt;
* '''Docker:''' &amp;lt;code&amp;gt;docker-compose.yml&amp;lt;/code&amp;gt; (Updated command)&lt;br /&gt;
&lt;br /&gt;
'''Frontend (React/Typescript):'''&amp;lt;br/&amp;gt;&lt;br /&gt;
* '''Pages:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/AssignmentEditPage.tsx&amp;lt;/code&amp;gt; (Created - Main page for editing assignments with tabs)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/tabs/TopicsTab.tsx&amp;lt;/code&amp;gt; (Created - Instructor view for managing topics)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/tabs/RubricsTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ReviewStrategyTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DueDatesTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;EtcTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GeneralTab.tsx&amp;lt;/code&amp;gt; (Created - Placeholder tabs)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/StudentTasks/StudentTasks.tsx&amp;lt;/code&amp;gt; (Created - Student view for signing up for topics)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/Assignment.tsx&amp;lt;/code&amp;gt; (Modified - Integrated new edit page link)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; (Modified - Simplified, as detailed editing moved to &amp;lt;code&amp;gt;AssignmentEditPage&amp;lt;/code&amp;gt;)&lt;br /&gt;
* '''Components:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/components/Table/Table.tsx&amp;lt;/code&amp;gt; (Modified - Added row highlighting for selected topics)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/components/TopicsTable.tsx&amp;lt;/code&amp;gt; (Created - Reusable table component for displaying topics)&lt;br /&gt;
* '''Routing:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/App.tsx&amp;lt;/code&amp;gt; (Modified - Added routes for &amp;lt;code&amp;gt;AssignmentEditPage&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;StudentTasks&amp;lt;/code&amp;gt;)&lt;br /&gt;
* '''Layout:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/layout/Header.tsx&amp;lt;/code&amp;gt; (Modified - Conditionally show Assignments link for students)&lt;br /&gt;
* '''Hooks:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/hooks/useAPI.ts&amp;lt;/code&amp;gt; (Modified - Minor change in &amp;lt;code&amp;gt;then&amp;lt;/code&amp;gt; block)&lt;br /&gt;
* '''Assets:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;public/assets/icons/Check-icon.png&amp;lt;/code&amp;gt; (Added)&lt;br /&gt;
&lt;br /&gt;
== List of changes / Features Implemented ==&lt;br /&gt;
&lt;br /&gt;
Based on the project description and feedback from E2513:&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Backend:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# '''Renamed &amp;lt;code&amp;gt;SignUpTopic&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt;:''' Refactored the model, controller, routes, database table, associations, and tests to use the new naming convention consistently.&lt;br /&gt;
# '''Refactored &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; Logic:''' Moved business logic from the controller into the &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; models, utilizing ActiveRecord features like transactions and scopes. Implemented methods for signing up students/teams, dropping topics, finding participants, and handling waitlists.&lt;br /&gt;
# '''Addressed E2513 Feedback:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
#* Renamed &amp;lt;code&amp;gt;signup_team&amp;lt;/code&amp;gt; method to &amp;lt;code&amp;gt;sign_team_up&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Renamed &amp;lt;code&amp;gt;signup_for_topic&amp;lt;/code&amp;gt; method to &amp;lt;code&amp;gt;sign_up_for_topic&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Addressed DRY violation between &amp;lt;code&amp;gt;find_team_participants&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;find_project_topic_team_users&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Ensured files terminate with a newline.&lt;br /&gt;
# '''Updated &amp;lt;code&amp;gt;Assignment&amp;lt;/code&amp;gt; Model:''' Added &amp;lt;code&amp;gt;allow_bookmarks&amp;lt;/code&amp;gt; attribute and updated associations related to topics.&lt;br /&gt;
# '''API Endpoints:''' Created/updated API endpoints for CRUD operations on &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; and actions related to &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; (signup, drop topic).&lt;br /&gt;
# '''Testing:''' Added comprehensive RSpec tests for &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; models. Updated existing tests (&amp;lt;code&amp;gt;due_date_spec.rb&amp;lt;/code&amp;gt;). Added routing specs.&lt;br /&gt;
&lt;br /&gt;
'''Frontend:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# '''New Assignment Edit Page:''' Created &amp;lt;code&amp;gt;AssignmentEditPage&amp;lt;/code&amp;gt; with a tabbed interface for editing assignments.&lt;br /&gt;
# '''Instructor Topics Tab:''' Implemented &amp;lt;code&amp;gt;TopicsTab&amp;lt;/code&amp;gt; component allowing instructors to:&lt;br /&gt;
#* View/manage topics via &amp;lt;code&amp;gt;TopicsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Configure topic settings (e.g., allow bookmarks).&lt;br /&gt;
#* View assigned/waitlisted teams and drop teams.&lt;br /&gt;
#* Toggle display of user names/IDs.&lt;br /&gt;
#* Create, import, edit, delete topics via modals.&lt;br /&gt;
#* View bookmark counts.&lt;br /&gt;
#* Access Partner Ad functionality (UI added).&lt;br /&gt;
# '''Student Task/Signup Page:''' Created &amp;lt;code&amp;gt;StudentTasks&amp;lt;/code&amp;gt; page allowing students to:&lt;br /&gt;
#* View available topics via &amp;lt;code&amp;gt;TopicsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* See available slots and waitlist numbers.&lt;br /&gt;
#* View their selected topic.&lt;br /&gt;
#* Select/deselect (drop) a topic.&lt;br /&gt;
#* Bookmark topics (if enabled).&lt;br /&gt;
# '''Reusable &amp;lt;code&amp;gt;TopicsTable&amp;lt;/code&amp;gt; Component:''' Developed adaptable table for student/instructor views with row expansion, selection, and custom actions.&lt;br /&gt;
# '''API Integration:''' Connected frontend components to backend API for fetching/updating topics, assignment settings, and handling signups/drops.&lt;br /&gt;
# '''UI Enhancements:''' Added selected topic highlighting, action icons, and modals for various operations.&lt;br /&gt;
&lt;br /&gt;
== Testing Details==&lt;br /&gt;
&lt;br /&gt;
=== Backend (RSpec) ===&lt;br /&gt;
New spec files (&amp;lt;code&amp;gt;project_topic_spec.rb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;signed_up_team_spec.rb&amp;lt;/code&amp;gt;) were created with extensive test coverage for the core models, including various scenarios like signup, waitlisting, dropping teams, and validations. Existing specs (&amp;lt;code&amp;gt;due_date_spec.rb&amp;lt;/code&amp;gt;) were updated. Routing specs were added. Tests confirmed the refactored code integrates correctly.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Manual testing was performed following scenarios for instructors and students:&lt;br /&gt;
&lt;br /&gt;
'''Instructor UI:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# Login as instructor6.&lt;br /&gt;
# Navigate to an assignment (e.g., &amp;quot;OSS project &amp;amp; documentation&amp;quot;) and click 'Edit'.&lt;br /&gt;
# Go to the 'Topics' tab.&lt;br /&gt;
# '''Verify topic list display:''' Check columns (Checkbox, ID, Name, Questionnaire, Slots, Available, Waitlist, Bookmarks, Actions).&lt;br /&gt;
# '''Verify topic settings:''' Test checkboxes, especially 'Allow participants to create bookmarks?'. Backend save confirmed via API call.&lt;br /&gt;
# '''Test topic actions:'''&lt;br /&gt;
#* Create a new topic via 'New topic' button/modal.&lt;br /&gt;
#* Edit an existing topic via edit icon/modal.&lt;br /&gt;
#* Delete topic(s) via delete icon or selecting checkboxes and using 'Delete selected topics'.&lt;br /&gt;
#* Import topics via 'Import topics' button/modal.&lt;br /&gt;
# Expand a topic row to view assigned/waitlisted teams. Test dropping a team via 'X' icon.&lt;br /&gt;
# Test 'Display User Names' toggle.&lt;br /&gt;
&lt;br /&gt;
'''Student UI:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# Login as teststudent.&lt;br /&gt;
# Navigate to 'Assignments' via header link.&lt;br /&gt;
# Verify signup sheet loads.&lt;br /&gt;
# '''Verify topic list display:''' Check columns (ID, Name, Available Slots, Num. on Waitlist, Bookmarks [if enabled], Actions).&lt;br /&gt;
# '''Test topic selection:''' Click checkmark icon. Verify 'Your topic(s)' updates, row highlights yellow, slots update optimistically, and API call is made.&lt;br /&gt;
# '''Test topic deselection (drop):''' Click 'X' icon on selected topic row. Verify topic is dropped, highlighting removed, slots update, and API call is made.&lt;br /&gt;
# '''Test bookmarking (if enabled):''' Click bookmark icon to toggle status.&lt;br /&gt;
# Verify actions are disabled for full topics (0 available slots).&lt;br /&gt;
&lt;br /&gt;
== Scope for future improvement ==&lt;br /&gt;
# '''Complete Placeholder Tabs:''' Implement functionality for 'Rubrics', 'Review Strategy', 'Due Dates', and 'Etc.' tabs in instructor view.&lt;br /&gt;
# '''Partner Ad Backend:''' Implement backend logic for partner ads and applications.&lt;br /&gt;
# '''Bookmark Implementation:''' Fully implement bookmark creation/viewing functionality.&lt;br /&gt;
# '''Topic Suggestions:''' Implement student topic suggestion feature.&lt;br /&gt;
# '''Bidding Features:''' Implement topic/reviewer bidding.&lt;br /&gt;
# '''Refined UI/UX:''' Enhance UI based on feedback, e.g., team display within rows.&lt;br /&gt;
# '''Automated Frontend Testing:''' Add&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166826</id>
		<title>CSC/ECE 517 Fall 2025 - E2552. ProjectTopic and SignedUpTeam</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2025_-_E2552._ProjectTopic_and_SignedUpTeam&amp;diff=166826"/>
		<updated>2025-10-29T00:53:35Z</updated>

		<summary type="html">&lt;p&gt;Dananth: Created page with &amp;quot;This wiki page describes the changes made for the '''E2552 OSS assignment''' in Fall 2025 for CSC/ECE 517.  == Peer Review Information ==  For users intending to view the deployed Expertiza associated with this assignment, the credentials are below: * Instructor login: username -&amp;gt; instructor6, password -&amp;gt; password * Student login: username -&amp;gt; teststudent, password -&amp;gt; password123 * ''(Add other relevant student logins if needed)''  == Expertiza Background==  Expertiza is...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This wiki page describes the changes made for the '''E2552 OSS assignment''' in Fall 2025 for CSC/ECE 517.&lt;br /&gt;
&lt;br /&gt;
== Peer Review Information ==&lt;br /&gt;
&lt;br /&gt;
For users intending to view the deployed Expertiza associated with this assignment, the credentials are below:&lt;br /&gt;
* Instructor login: username -&amp;gt; instructor6, password -&amp;gt; password&lt;br /&gt;
* Student login: username -&amp;gt; teststudent, password -&amp;gt; password123&lt;br /&gt;
* ''(Add other relevant student logins if needed)''&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an educational web application created and maintained by the joint efforts of the students and the faculty at NCSU. It’s an open source project developed on Ruby on Rails platform and its code is available on Github. It allows students to review each other’s work and improve their work upon this feedback. The current effort involves reimplementing the application with a Ruby on Rails API backend and a React/Typescript frontend.&lt;br /&gt;
&lt;br /&gt;
== Description of the current project (E2552) ==&lt;br /&gt;
&lt;br /&gt;
This project focuses on the reimplementation of the '''Project Topic''' and '''Signed Up Team''' functionalities within Expertiza. In Expertiza, assignments can require students or teams to choose a topic. The &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; class (originally &amp;lt;code&amp;gt;SignUpTopic&amp;lt;/code&amp;gt;) manages these topics, and when a team selects one, a &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; object is created to link the team and the topic.&lt;br /&gt;
&lt;br /&gt;
This project involved integrating and refining backend code previously developed (but not merged) in project E2513 and implementing the corresponding frontend interface for both instructors and students. The backend work included renaming classes and methods based on prior feedback, improving code structure using ActiveRecord features, optimizing logic, and adding validations. The frontend work involved creating new UI components in React/Typescript to manage and display topics, handle topic selection/signup, and provide distinct views for instructors and students, closely mirroring the existing Expertiza interface.&lt;br /&gt;
&lt;br /&gt;
== Files modified/created in current project ==&lt;br /&gt;
&lt;br /&gt;
'''Backend (Ruby on Rails API):'''&amp;lt;br/&amp;gt;&lt;br /&gt;
* '''Models:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/project_topic.rb&amp;lt;/code&amp;gt; (Created, replacing &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/signed_up_team.rb&amp;lt;/code&amp;gt; (Modified extensively)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/assignment.rb&amp;lt;/code&amp;gt; (Modified associations)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/bookmark.rb&amp;lt;/code&amp;gt; (Modified association comment)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/user.rb&amp;lt;/code&amp;gt; (Modified associations)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/models/sign_up_topic.rb&amp;lt;/code&amp;gt; (Deleted)&lt;br /&gt;
* '''Controllers:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/project_topics_controller.rb&amp;lt;/code&amp;gt; (Created, replacing &amp;lt;code&amp;gt;sign_up_topics_controller.rb&amp;lt;/code&amp;gt;)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/signed_up_teams_controller.rb&amp;lt;/code&amp;gt; (Modified extensively)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/assignments_controller.rb&amp;lt;/code&amp;gt; (Modified &amp;lt;code&amp;gt;assignment_params&amp;lt;/code&amp;gt;, comment)&lt;br /&gt;
** &amp;lt;code&amp;gt;app/controllers/sign_up_topics_controller.rb&amp;lt;/code&amp;gt; (Deleted)&lt;br /&gt;
* '''Database:'''&lt;br /&gt;
** Migrations created/modified for renaming tables/columns (&amp;lt;code&amp;gt;sign_up_topic&amp;lt;/code&amp;gt; -&amp;gt; &amp;lt;code&amp;gt;project_topic&amp;lt;/code&amp;gt;) and adding &amp;lt;code&amp;gt;allow_bookmarks&amp;lt;/code&amp;gt; to assignments.&lt;br /&gt;
** &amp;lt;code&amp;gt;db/schema.rb&amp;lt;/code&amp;gt; (Updated)&lt;br /&gt;
** &amp;lt;code&amp;gt;db/seeds.rb&amp;lt;/code&amp;gt; (Updated to use &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt;, added test student)&lt;br /&gt;
* '''Configuration:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;config/routes.rb&amp;lt;/code&amp;gt; (Updated for &amp;lt;code&amp;gt;project_topics&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signed_up_teams&amp;lt;/code&amp;gt; endpoints)&lt;br /&gt;
* '''Tests (RSpec):'''&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/models/project_topic_spec.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/models/signed_up_team_spec.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/models/due_date_spec.rb&amp;lt;/code&amp;gt; (Modified)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/routing/project_topics_routing_spec.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/factories/project_topics.rb&amp;lt;/code&amp;gt; (Created)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/rails_helper.rb&amp;lt;/code&amp;gt; (Minor configuration change)&lt;br /&gt;
** &amp;lt;code&amp;gt;spec/routing/sign_up_topics_routing_spec.rb&amp;lt;/code&amp;gt; (Deleted)&lt;br /&gt;
* '''Dependencies:''' &amp;lt;code&amp;gt;Gemfile&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Gemfile.lock&amp;lt;/code&amp;gt; (Updated versions, added/removed gems)&lt;br /&gt;
* '''Swagger Documentation:''' &amp;lt;code&amp;gt;swagger/v1/swagger.yaml&amp;lt;/code&amp;gt; (Updated paths and definitions)&lt;br /&gt;
* '''Docker:''' &amp;lt;code&amp;gt;docker-compose.yml&amp;lt;/code&amp;gt; (Updated command)&lt;br /&gt;
&lt;br /&gt;
'''Frontend (React/Typescript):'''&amp;lt;br/&amp;gt;&lt;br /&gt;
* '''Pages:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/AssignmentEditPage.tsx&amp;lt;/code&amp;gt; (Created - Main page for editing assignments with tabs)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/tabs/TopicsTab.tsx&amp;lt;/code&amp;gt; (Created - Instructor view for managing topics)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/tabs/RubricsTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ReviewStrategyTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DueDatesTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;EtcTab.tsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GeneralTab.tsx&amp;lt;/code&amp;gt; (Created - Placeholder tabs)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/StudentTasks/StudentTasks.tsx&amp;lt;/code&amp;gt; (Created - Student view for signing up for topics)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/Assignment.tsx&amp;lt;/code&amp;gt; (Modified - Integrated new edit page link)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/AssignmentEditor.tsx&amp;lt;/code&amp;gt; (Modified - Simplified, as detailed editing moved to &amp;lt;code&amp;gt;AssignmentEditPage&amp;lt;/code&amp;gt;)&lt;br /&gt;
* '''Components:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/components/Table/Table.tsx&amp;lt;/code&amp;gt; (Modified - Added row highlighting for selected topics)&lt;br /&gt;
** &amp;lt;code&amp;gt;src/pages/Assignments/components/TopicsTable.tsx&amp;lt;/code&amp;gt; (Created - Reusable table component for displaying topics)&lt;br /&gt;
* '''Routing:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/App.tsx&amp;lt;/code&amp;gt; (Modified - Added routes for &amp;lt;code&amp;gt;AssignmentEditPage&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;StudentTasks&amp;lt;/code&amp;gt;)&lt;br /&gt;
* '''Layout:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/layout/Header.tsx&amp;lt;/code&amp;gt; (Modified - Conditionally show Assignments link for students)&lt;br /&gt;
* '''Hooks:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;src/hooks/useAPI.ts&amp;lt;/code&amp;gt; (Modified - Minor change in &amp;lt;code&amp;gt;then&amp;lt;/code&amp;gt; block)&lt;br /&gt;
* '''Assets:'''&lt;br /&gt;
** &amp;lt;code&amp;gt;public/assets/icons/Check-icon.png&amp;lt;/code&amp;gt; (Added)&lt;br /&gt;
&lt;br /&gt;
== List of changes / Features Implemented ==&lt;br /&gt;
&lt;br /&gt;
Based on the project description and feedback from E2513:&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Backend:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# '''Renamed &amp;lt;code&amp;gt;SignUpTopic&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt;:''' Refactored the model, controller, routes, database table, associations, and tests to use the new naming convention consistently.&lt;br /&gt;
# '''Refactored &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; Logic:''' Moved business logic from the controller into the &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; models, utilizing ActiveRecord features like transactions and scopes. Implemented methods for signing up students/teams, dropping topics, finding participants, and handling waitlists.&lt;br /&gt;
# '''Addressed E2513 Feedback:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
#* Renamed &amp;lt;code&amp;gt;signup_team&amp;lt;/code&amp;gt; method to &amp;lt;code&amp;gt;sign_team_up&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Renamed &amp;lt;code&amp;gt;signup_for_topic&amp;lt;/code&amp;gt; method to &amp;lt;code&amp;gt;sign_up_for_topic&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Addressed DRY violation between &amp;lt;code&amp;gt;find_team_participants&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;find_project_topic_team_users&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Ensured files terminate with a newline.&lt;br /&gt;
# '''Updated &amp;lt;code&amp;gt;Assignment&amp;lt;/code&amp;gt; Model:''' Added &amp;lt;code&amp;gt;allow_bookmarks&amp;lt;/code&amp;gt; attribute and updated associations related to topics.&lt;br /&gt;
# '''API Endpoints:''' Created/updated API endpoints for CRUD operations on &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; and actions related to &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; (signup, drop topic).&lt;br /&gt;
# '''Testing:''' Added comprehensive RSpec tests for &amp;lt;code&amp;gt;ProjectTopic&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;SignedUpTeam&amp;lt;/code&amp;gt; models. Updated existing tests (&amp;lt;code&amp;gt;due_date_spec.rb&amp;lt;/code&amp;gt;). Added routing specs.&lt;br /&gt;
&lt;br /&gt;
'''Frontend:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# '''New Assignment Edit Page:''' Created &amp;lt;code&amp;gt;AssignmentEditPage&amp;lt;/code&amp;gt; with a tabbed interface for editing assignments.&lt;br /&gt;
# '''Instructor Topics Tab:''' Implemented &amp;lt;code&amp;gt;TopicsTab&amp;lt;/code&amp;gt; component allowing instructors to:&lt;br /&gt;
#* View/manage topics via &amp;lt;code&amp;gt;TopicsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* Configure topic settings (e.g., allow bookmarks).&lt;br /&gt;
#* View assigned/waitlisted teams and drop teams.&lt;br /&gt;
#* Toggle display of user names/IDs.&lt;br /&gt;
#* Create, import, edit, delete topics via modals.&lt;br /&gt;
#* View bookmark counts.&lt;br /&gt;
#* Access Partner Ad functionality (UI added).&lt;br /&gt;
# '''Student Task/Signup Page:''' Created &amp;lt;code&amp;gt;StudentTasks&amp;lt;/code&amp;gt; page allowing students to:&lt;br /&gt;
#* View available topics via &amp;lt;code&amp;gt;TopicsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* See available slots and waitlist numbers.&lt;br /&gt;
#* View their selected topic.&lt;br /&gt;
#* Select/deselect (drop) a topic.&lt;br /&gt;
#* Bookmark topics (if enabled).&lt;br /&gt;
# '''Reusable &amp;lt;code&amp;gt;TopicsTable&amp;lt;/code&amp;gt; Component:''' Developed adaptable table for student/instructor views with row expansion, selection, and custom actions.&lt;br /&gt;
# '''API Integration:''' Connected frontend components to backend API for fetching/updating topics, assignment settings, and handling signups/drops.&lt;br /&gt;
# '''UI Enhancements:''' Added selected topic highlighting, action icons, and modals for various operations.&lt;br /&gt;
&lt;br /&gt;
== Testing Details==&lt;br /&gt;
&lt;br /&gt;
=== Backend (RSpec) ===&lt;br /&gt;
New spec files (&amp;lt;code&amp;gt;project_topic_spec.rb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;signed_up_team_spec.rb&amp;lt;/code&amp;gt;) were created with extensive test coverage for the core models, including various scenarios like signup, waitlisting, dropping teams, and validations. Existing specs (&amp;lt;code&amp;gt;due_date_spec.rb&amp;lt;/code&amp;gt;) were updated. Routing specs were added. Tests confirmed the refactored code integrates correctly.&lt;br /&gt;
&lt;br /&gt;
=== UI Testing ===&lt;br /&gt;
&lt;br /&gt;
Manual testing was performed following scenarios for instructors and students:&lt;br /&gt;
&lt;br /&gt;
'''Instructor UI:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# Login as instructor6.&lt;br /&gt;
# Navigate to an assignment (e.g., &amp;quot;OSS project &amp;amp; documentation&amp;quot;) and click 'Edit'.&lt;br /&gt;
# Go to the 'Topics' tab.&lt;br /&gt;
# '''Verify topic list display:''' Check columns (Checkbox, ID, Name, Questionnaire, Slots, Available, Waitlist, Bookmarks, Actions).&lt;br /&gt;
# '''Verify topic settings:''' Test checkboxes, especially 'Allow participants to create bookmarks?'. Backend save confirmed via API call.&lt;br /&gt;
# '''Test topic actions:'''&lt;br /&gt;
#* Create a new topic via 'New topic' button/modal.&lt;br /&gt;
#* Edit an existing topic via edit icon/modal.&lt;br /&gt;
#* Delete topic(s) via delete icon or selecting checkboxes and using 'Delete selected topics'.&lt;br /&gt;
#* Import topics via 'Import topics' button/modal.&lt;br /&gt;
# Expand a topic row to view assigned/waitlisted teams. Test dropping a team via 'X' icon.&lt;br /&gt;
# Test 'Display User Names' toggle.&lt;br /&gt;
&lt;br /&gt;
'''Student UI:'''&amp;lt;br/&amp;gt;&lt;br /&gt;
# Login as teststudent.&lt;br /&gt;
# Navigate to 'Assignments' via header link.&lt;br /&gt;
# Verify signup sheet loads.&lt;br /&gt;
# '''Verify topic list display:''' Check columns (ID, Name, Available Slots, Num. on Waitlist, Bookmarks [if enabled], Actions).&lt;br /&gt;
# '''Test topic selection:''' Click checkmark icon. Verify 'Your topic(s)' updates, row highlights yellow, slots update optimistically, and API call is made.&lt;br /&gt;
# '''Test topic deselection (drop):''' Click 'X' icon on selected topic row. Verify topic is dropped, highlighting removed, slots update, and API call is made.&lt;br /&gt;
# '''Test bookmarking (if enabled):''' Click bookmark icon to toggle status.&lt;br /&gt;
# Verify actions are disabled for full topics (0 available slots).&lt;br /&gt;
&lt;br /&gt;
== Scope for future improvement ==&lt;br /&gt;
# '''Complete Placeholder Tabs:''' Implement functionality for 'Rubrics', 'Review Strategy', 'Due Dates', and 'Etc.' tabs in instructor view.&lt;br /&gt;
# '''Partner Ad Backend:''' Implement backend logic for partner ads and applications.&lt;br /&gt;
# '''Bookmark Implementation:''' Fully implement bookmark creation/viewing functionality.&lt;br /&gt;
# '''Topic Suggestions:''' Implement student topic suggestion feature.&lt;br /&gt;
# '''Bidding Features:''' Implement topic/reviewer bidding.&lt;br /&gt;
# '''Refined UI/UX:''' Enhance UI based on feedback, e.g., team display within rows.&lt;br /&gt;
# '''Automated Frontend Testing:''' Add&lt;/div&gt;</summary>
		<author><name>Dananth</name></author>
	</entry>
</feed>